7dd86e39b41987820338813bf1b716dcbefadfb1
[modest] / src / widgets / modest-window-mgr.c
1 /* Copyright (c) 2006,2007 Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31 #include "modest-window-mgr.h"
32 #include "modest-runtime.h"
33 #include "modest-tny-folder.h"
34 #include "modest-ui-actions.h"
35 #include "modest-platform.h"
36 #include "modest-defs.h"
37 #include "widgets/modest-main-window.h"
38 #include "widgets/modest-msg-edit-window.h"
39 #include "widgets/modest-msg-view-window.h"
40 #include "modest-debug.h"
41 #include <tny-simple-list.h>
42
43
44 /* 'private'/'protected' functions */
45 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
46 static void modest_window_mgr_init       (ModestWindowMgr *obj);
47 static void modest_window_mgr_finalize   (GObject *obj);
48
49 static gboolean modest_window_mgr_register_window_default (ModestWindowMgr *self, 
50                                                            ModestWindow *window,
51                                                            ModestWindow *parent);
52 static void modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
53                                                          ModestWindow *window);
54 static void modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
55                                                            gboolean on);
56 static gboolean modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self);
57 static void modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
58                                                      GType window_type,
59                                                      gboolean show_toolbars,
60                                                      gboolean fullscreen);
61 #ifndef MODEST_TOOLKIT_HILDON2
62 static ModestWindow* modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show);
63 #endif
64 static GtkWindow *modest_window_mgr_get_modal_default (ModestWindowMgr *self);
65 static void modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
66                                                  GtkWindow *window,
67                                                  GtkWindow *parent);
68 static gboolean modest_window_mgr_close_all_windows_default (ModestWindowMgr *self);
69 static gboolean modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, 
70                                                                   TnyHeader *header,
71                                                                   ModestWindow **win);
72 static gboolean modest_window_mgr_find_registered_message_uid_default (ModestWindowMgr *self, 
73                                                                        const gchar *msg_uid,
74                                                                        ModestWindow **win);
75 static GList *modest_window_mgr_get_window_list_default (ModestWindowMgr *self);
76 static ModestWindow *modest_window_mgr_show_initial_window_default (ModestWindowMgr *self);
77 static ModestWindow *modest_window_mgr_get_current_top_default (ModestWindowMgr *self);
78 static gboolean modest_window_mgr_screen_is_on_default (ModestWindowMgr *self);
79 static void modest_window_mgr_create_caches_default (ModestWindowMgr *self);
80 static void modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
81                                                 ModestMailOperation *mail_op,
82                                                 ModestMailOperationQueueNotification type,
83                                                 ModestWindowMgr *self);
84 static void on_mail_operation_started (ModestMailOperation *mail_op,
85                                        gpointer user_data);
86 static void on_mail_operation_finished (ModestMailOperation *mail_op,
87                                         gpointer user_data);
88 static gboolean modest_window_mgr_close_all_but_initial_default (ModestWindowMgr *self);
89
90 /* list my signals  */
91 enum {
92         WINDOW_LIST_EMPTY_SIGNAL,
93         PROGRESS_LIST_CHANGED_SIGNAL,
94         NUM_SIGNALS
95 };
96
97 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
98 struct _ModestWindowMgrPrivate {
99         guint         banner_counter;
100
101 #ifndef MODEST_TOOLKIT_HILDON2
102         ModestWindow *main_window;
103 #endif
104         GSList       *windows_that_prevent_hibernation;
105         GSList       *preregistered_uids;
106
107         guint        closing_time;
108
109         GtkWidget    *cached_view;
110         GtkWidget    *cached_editor;
111         guint        idle_load_view_id;
112         guint        idle_load_editor_id;
113
114         guint        queue_change_handler;
115         TnyList      *progress_operations;
116         GSList       *sighandlers;
117 };
118
119 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
120                                                MODEST_TYPE_WINDOW_MGR, \
121                                                ModestWindowMgrPrivate))
122 /* globals */
123 static GObjectClass *parent_class = NULL;
124
125 /* uncomment the following if you have defined any signals */
126 static guint signals[NUM_SIGNALS] = {0};
127
128 GType
129 modest_window_mgr_get_type (void)
130 {
131         static GType my_type = 0;
132         if (!my_type) {
133                 static const GTypeInfo my_info = {
134                         sizeof(ModestWindowMgrClass),
135                         NULL,           /* base init */
136                         NULL,           /* base finalize */
137                         (GClassInitFunc) modest_window_mgr_class_init,
138                         NULL,           /* class finalize */
139                         NULL,           /* class data */
140                         sizeof(ModestWindowMgr),
141                         1,              /* n_preallocs */
142                         (GInstanceInitFunc) modest_window_mgr_init,
143                         NULL
144                 };
145                 my_type = g_type_register_static (G_TYPE_OBJECT,
146                                                   "ModestWindowMgr",
147                                                   &my_info, 0);
148         }
149         return my_type;
150 }
151
152 static void
153 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
154 {
155         GObjectClass *gobject_class;
156         ModestWindowMgrClass *mgr_class;
157
158         gobject_class = (GObjectClass*) klass;
159         mgr_class = (ModestWindowMgrClass *) klass;
160
161         parent_class            = g_type_class_peek_parent (klass);
162         gobject_class->finalize = modest_window_mgr_finalize;
163         mgr_class->register_window = modest_window_mgr_register_window_default;
164         mgr_class->unregister_window = modest_window_mgr_unregister_window_default;
165         mgr_class->set_fullscreen_mode = modest_window_mgr_set_fullscreen_mode_default;
166         mgr_class->get_fullscreen_mode = modest_window_mgr_get_fullscreen_mode_default;
167         mgr_class->show_toolbars = modest_window_mgr_show_toolbars_default;
168 #ifndef MODEST_TOOLKIT_HILDON2
169         mgr_class->get_main_window = modest_window_mgr_get_main_window_default;
170 #endif
171         mgr_class->get_modal = modest_window_mgr_get_modal_default;
172         mgr_class->set_modal = modest_window_mgr_set_modal_default;
173         mgr_class->close_all_windows = modest_window_mgr_close_all_windows_default;
174         mgr_class->find_registered_header = modest_window_mgr_find_registered_header_default;
175         mgr_class->find_registered_message_uid = modest_window_mgr_find_registered_message_uid_default;
176         mgr_class->get_window_list = modest_window_mgr_get_window_list_default;
177         mgr_class->show_initial_window = modest_window_mgr_show_initial_window_default;
178         mgr_class->get_current_top = modest_window_mgr_get_current_top_default;
179         mgr_class->screen_is_on = modest_window_mgr_screen_is_on_default;
180         mgr_class->create_caches = modest_window_mgr_create_caches_default;
181         mgr_class->close_all_but_initial = modest_window_mgr_close_all_but_initial_default;
182
183         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
184
185
186         /**
187          * ModestWindowMgr::window-list-empty
188          * @self: the #ModestWindowMgr that emits the signal
189          * @user_data: user data set when the signal handler was connected
190          *
191          * Issued whenever the window list becomes empty
192          */
193         signals[WINDOW_LIST_EMPTY_SIGNAL] =
194                 g_signal_new ("window-list-empty",
195                               G_TYPE_FROM_CLASS (gobject_class),
196                               G_SIGNAL_RUN_FIRST,
197                               G_STRUCT_OFFSET (ModestWindowMgrClass, window_list_empty),
198                               NULL, NULL,
199                               g_cclosure_marshal_VOID__VOID,
200                               G_TYPE_NONE, 0);
201
202         /**
203          * ModestWindowMgr::progress-list-changed
204          * @self: the #ModestWindowMgr that emits the signal
205          * @user_data: user data set when the signal handler was connected
206          *
207          * Issued whenever the progress mail operations list becomes changed
208          */
209         signals[PROGRESS_LIST_CHANGED_SIGNAL] =
210                 g_signal_new ("progress-list-changed",
211                               G_TYPE_FROM_CLASS (gobject_class),
212                               G_SIGNAL_RUN_FIRST,
213                               G_STRUCT_OFFSET (ModestWindowMgrClass, progress_list_changed),
214                               NULL, NULL,
215                               g_cclosure_marshal_VOID__VOID,
216                               G_TYPE_NONE, 0);
217 }
218
219 static gboolean
220 idle_load_view (ModestWindowMgr *mgr)
221 {
222         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
223         
224         priv->cached_view = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
225         priv->idle_load_view_id = 0;
226         return FALSE;
227 }
228
229 static gboolean
230 idle_load_editor (ModestWindowMgr *mgr)
231 {
232         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
233         
234         priv->cached_editor = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
235         priv->idle_load_editor_id = 0;
236         return FALSE;
237 }
238
239 static void
240 load_new_view (ModestWindowMgr *self)
241 {
242         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
243         if ((priv->cached_view == NULL) && (priv->idle_load_view_id == 0))
244                 priv->idle_load_view_id = g_timeout_add (2500, (GSourceFunc) idle_load_view, self);
245 }
246
247 static void
248 load_new_editor (ModestWindowMgr *self)
249 {
250         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
251         if ((priv->cached_editor == NULL) && (priv->idle_load_editor_id == 0))
252                 priv->idle_load_editor_id = g_timeout_add (5000, (GSourceFunc) idle_load_editor, self);
253 }
254
255 static void
256 modest_window_mgr_init (ModestWindowMgr *obj)
257 {
258         ModestWindowMgrPrivate *priv;
259
260         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
261         priv->banner_counter = 0;
262 #ifndef MODEST_TOOLKIT_HILDON2
263         priv->main_window = NULL;
264 #endif
265         priv->preregistered_uids = NULL;
266
267         priv->closing_time = 0;
268
269         priv->cached_view = NULL;
270         priv->cached_editor = NULL;
271
272         priv->windows_that_prevent_hibernation = NULL;
273
274         priv->queue_change_handler = 0;
275         priv->progress_operations = TNY_LIST (tny_simple_list_new ());
276 }
277
278 static void
279 modest_window_mgr_finalize (GObject *obj)
280 {
281         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
282
283         if (priv->idle_load_view_id > 0) {
284                 g_source_remove (priv->idle_load_view_id);
285                 priv->idle_load_view_id = 0;
286         }
287         
288         if (priv->idle_load_editor_id > 0) {
289                 g_source_remove (priv->idle_load_editor_id);
290                 priv->idle_load_editor_id = 0;
291         }
292         
293         if (priv->cached_view) {
294                 gtk_widget_destroy (priv->cached_view);
295                 priv->cached_view = NULL;
296         }
297         if (priv->cached_editor) {
298                 gtk_widget_destroy (priv->cached_editor);
299                 priv->cached_editor = NULL;
300         }
301
302         if (priv->windows_that_prevent_hibernation) {
303                 g_slist_free (priv->windows_that_prevent_hibernation);
304                 priv->cached_editor = NULL;
305         }
306
307         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
308         priv->sighandlers = NULL;
309
310         if (priv->queue_change_handler > 0) {
311                 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
312                                              priv->queue_change_handler);
313                 priv->queue_change_handler = 0;
314         }
315
316         if (priv->progress_operations) {
317                 g_object_unref (priv->progress_operations);
318                 priv->progress_operations = NULL;
319         }
320
321         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
322         g_slist_free (priv->preregistered_uids);
323
324         G_OBJECT_CLASS(parent_class)->finalize (obj);
325 }
326
327 ModestWindowMgr*
328 modest_window_mgr_new (void)
329 {
330         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
331 }
332
333
334
335
336 /* do we have uid? */
337 static gboolean
338 has_uid (GSList *list, const gchar *uid)
339 {
340         GSList *cursor = list;
341
342         if (!uid)
343                 return FALSE;
344         
345         while (cursor) {
346                 if (cursor->data && strcmp (cursor->data, uid) == 0)
347                         return TRUE;
348                 cursor = g_slist_next (cursor);
349         }
350         return FALSE;
351 }
352
353
354 /* remove all from the list have have uid = uid */
355 static GSList*
356 remove_uid (GSList *list, const gchar *uid)
357 {
358         GSList *cursor = list, *start = list;
359         
360         if (!uid)
361                 return list;
362         
363         while (cursor) {
364                 GSList *next = g_slist_next (cursor);
365                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
366                         g_free (cursor->data);
367                         start = g_slist_delete_link (start, cursor);
368                 }
369                 cursor = next;
370         }
371         return start;
372 }
373
374
375 static GSList *
376 append_uid (GSList *list, const gchar *uid)
377 {
378         return g_slist_append (list, g_strdup(uid));
379 }
380
381
382
383 void 
384 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header, const gchar *alt_uid)
385 {
386         ModestWindowMgrPrivate *priv;
387         gchar* uid;
388         
389         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
390         g_return_if_fail (TNY_IS_HEADER(header));
391                 
392         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
393         if (alt_uid != NULL) {
394                 uid = g_strdup (alt_uid);
395         } else {
396                 uid = modest_tny_folder_get_header_unique_id (header);
397         }
398
399         if (!has_uid (priv->preregistered_uids, uid)) {
400                 MODEST_DEBUG_BLOCK(g_debug ("registering new uid %s", uid););
401                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
402         } else
403                 MODEST_DEBUG_BLOCK(g_debug ("already had uid %s", uid););
404         
405         g_free (uid);
406 }
407
408 void 
409 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
410 {
411         ModestWindowMgrPrivate *priv;
412         gchar* uid;
413         
414         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
415         g_return_if_fail (TNY_IS_HEADER(header));
416                 
417         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
418         uid = modest_tny_folder_get_header_unique_id (header);
419
420         if (!has_uid (priv->preregistered_uids, uid)) {
421                 MODEST_DEBUG_BLOCK(g_debug ("trying to unregister non-existing uid %s", uid););
422                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
423         } else
424                 MODEST_DEBUG_BLOCK(g_debug ("unregistering uid %s", uid););
425         
426         if (has_uid (priv->preregistered_uids, uid)) {
427                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
428                 if (has_uid (priv->preregistered_uids, uid))
429                         g_debug ("BUG: uid %s NOT removed", uid);
430                 else
431                         MODEST_DEBUG_BLOCK(g_debug ("uid %s removed", uid););
432         }
433                 
434         g_free (uid);
435 }
436
437
438 #define MODEST_WINDOW_HELP_ID_PARAM "help-id"
439
440 void
441 modest_window_mgr_register_help_id (ModestWindowMgr *self, GtkWindow *win, const gchar* help_id)
442 {
443         /* we don't need 'self', but for API consistency... */
444         g_return_if_fail (self && MODEST_IS_WINDOW_MGR(self));
445
446         g_return_if_fail (win && GTK_IS_WINDOW(win));
447         g_return_if_fail (help_id);
448         
449         g_object_set_data_full (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM,
450                                 g_strdup(help_id), g_free);
451 }
452
453
454 const gchar*
455 modest_window_mgr_get_help_id (ModestWindowMgr *self, GtkWindow *win)
456 {
457         /* we don't need 'self', but for API consistency... */
458         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR (self), NULL);
459         g_return_val_if_fail (win, NULL);
460
461         return g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM);
462 }
463
464 gboolean
465 modest_window_mgr_close_all_windows (ModestWindowMgr *self)
466 {
467         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_windows (self);
468 }
469
470 static gboolean
471 modest_window_mgr_close_all_windows_default (ModestWindowMgr *self)
472 {
473         return TRUE;
474 }
475
476
477 gboolean
478 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
479                                                   ModestWindow **win)
480 {
481         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_header (self, header, win);
482 }
483
484 static gboolean
485 modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, TnyHeader *header,
486                                                   ModestWindow **win)
487 {
488         gchar* uid = NULL;
489
490         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
491         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
492
493         uid = modest_tny_folder_get_header_unique_id (header);
494
495         if (uid)
496                 return modest_window_mgr_find_registered_message_uid (self, uid, win);
497         else
498                 return FALSE;
499 }
500
501 gboolean
502 modest_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
503                                                ModestWindow **win)
504 {
505         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_message_uid (self, msg_uid, win);
506 }
507
508 static gboolean
509 modest_window_mgr_find_registered_message_uid_default (ModestWindowMgr *self, const gchar *msg_uid,
510                                                        ModestWindow **win)
511 {
512         ModestWindowMgrPrivate *priv = NULL;
513         gchar* uid = NULL;
514         gboolean has_header = FALSE;
515
516         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
517         g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
518
519         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
520
521         if (win)
522                 *win = NULL;
523
524         has_header = has_uid (priv->preregistered_uids, msg_uid);
525         g_free (uid);
526
527         return has_header;
528 }
529
530 GList *
531 modest_window_mgr_get_window_list (ModestWindowMgr *self)
532 {
533         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_window_list (self);
534 }
535
536 static GList *
537 modest_window_mgr_get_window_list_default (ModestWindowMgr *self)
538 {
539         return NULL;
540 }
541
542 gboolean
543 modest_window_mgr_register_window (ModestWindowMgr *self, 
544                                    ModestWindow *window,
545                                    ModestWindow *parent)
546 {
547         /* If this is the first registered window then reset the
548            status of the TnyDevice as it might be forced to be offline
549            when modest is running in the background (see
550            modest_tny_account_store_new()) */
551         if (modest_window_mgr_get_num_windows (self) == 0) {
552                 if (tny_device_is_forced (modest_runtime_get_device ()))
553                         tny_device_reset (modest_runtime_get_device ());
554         }
555
556         return MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
557 }
558
559 static gboolean
560 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
561                                            ModestWindow *window,
562                                            ModestWindow *parent)
563 {
564         ModestWindowMgrPrivate *priv;
565
566         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
567         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
568
569         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
570
571         /* We set up the queue change handler */
572         if (priv->queue_change_handler == 0) {
573                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
574                                                                "queue-changed",
575                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
576                                                                self);
577         }
578
579 #ifndef MODEST_TOOLKIT_HILDON2
580         /* Check that it's not a second main window */
581         if (MODEST_IS_MAIN_WINDOW (window)) {
582                 if (priv->main_window) {
583                         g_warning ("%s: trying to register a second main window",
584                                    __FUNCTION__);
585                         return FALSE;
586                 } else {
587                         priv->main_window = window;
588                 }
589         }
590 #endif
591
592         /* remove from the list of pre-registered uids */
593         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
594                 const gchar *uid = modest_msg_view_window_get_message_uid
595                         (MODEST_MSG_VIEW_WINDOW (window));
596
597                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
598
599                 if (has_uid (priv->preregistered_uids, uid)) {
600                         priv->preregistered_uids = 
601                                 remove_uid (priv->preregistered_uids,
602                                             modest_msg_view_window_get_message_uid
603                                             (MODEST_MSG_VIEW_WINDOW (window)));
604                 }
605         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
606                 const gchar *uid = modest_msg_edit_window_get_message_uid
607                         (MODEST_MSG_EDIT_WINDOW (window));
608
609                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
610
611                 priv->preregistered_uids = 
612                         remove_uid (priv->preregistered_uids,
613                                     modest_msg_edit_window_get_message_uid
614                                     (MODEST_MSG_EDIT_WINDOW (window)));
615         }
616
617         return TRUE;
618 }
619
620 void 
621 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
622                                      ModestWindow *window)
623 {
624         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
625 }
626
627 static void 
628 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
629                                              ModestWindow *window)
630 {
631         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
632         g_return_if_fail (MODEST_IS_WINDOW (window));
633
634         /* Save state */
635         modest_window_save_state (window);
636
637         /* Disconnect all the window signals */
638         modest_window_disconnect_signals (window);
639         
640         /* Destroy the window */
641         gtk_widget_destroy (GTK_WIDGET (window));
642 }
643
644
645
646 void
647 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
648                                        gboolean on)
649 {
650         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
651 }
652
653 static void
654 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
655                                                gboolean on)
656 {
657         return;
658 }
659
660 gboolean
661 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
662 {
663         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
664 }
665
666 static gboolean
667 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
668 {
669         return FALSE;
670 }
671
672 void
673 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
674                                  GType window_type,
675                                  gboolean show_toolbars,
676                                  gboolean fullscreen)
677 {
678         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
679 }
680
681 static void
682 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
683                                          GType window_type,
684                                          gboolean show_toolbars,
685                                          gboolean fullscreen)
686 {
687         return;
688 }
689
690 #ifndef MODEST_TOOLKIT_HILDON2
691 void
692 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
693 {
694         ModestWindowMgrPrivate *priv;
695
696         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
697
698         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
699         priv->main_window = win;
700 }
701
702 ModestWindow*
703 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
704 {
705         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
706 }
707
708 static ModestWindow*
709 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
710 {
711         ModestWindowMgrPrivate *priv;
712
713         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
714
715         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
716         if (priv->main_window)
717                 return priv->main_window;
718
719         if (show)
720                 return modest_main_window_new ();
721         else return NULL;
722 }
723
724
725 gboolean
726 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
727 {
728         ModestWindowMgrPrivate *priv;
729
730         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
731         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
732
733         return priv->main_window != NULL;
734 }
735 #endif
736
737 GtkWindow *
738 modest_window_mgr_get_modal (ModestWindowMgr *self)
739 {
740         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
741 }
742
743 static GtkWindow *
744 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
745 {
746         return NULL;
747 }
748
749
750 void
751 modest_window_mgr_set_modal (ModestWindowMgr *self, 
752                              GtkWindow *window,
753                              GtkWindow *parent)
754 {
755         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
756 }
757
758 static void
759 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
760                                      GtkWindow *window,
761                                      GtkWindow *parent)
762 {
763         return;
764 }
765
766
767 static void
768 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
769 {
770         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
771         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
772         
773         /* Forget this window,
774          * so hibernation will be allowed again if no windows are remembered: */
775         priv->windows_that_prevent_hibernation =
776                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
777 }
778
779 static void
780 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
781 {
782         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
783         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
784         
785         GtkWindow *window = GTK_WINDOW (widget);
786         
787         priv->windows_that_prevent_hibernation = 
788                         g_slist_append (priv->windows_that_prevent_hibernation, window);
789         
790         /* Allow hibernation again when the window has been hidden: */
791         g_signal_connect (window, "hide", 
792                 G_CALLBACK (on_nonhibernating_window_hide), self);
793 }
794
795 void
796 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
797                                                                   GtkWindow *window)
798 {
799         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
800         
801         if (GTK_WIDGET_VISIBLE(window)) {
802                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
803         } else {
804                 /* Wait for it to be shown: */
805                 g_signal_connect (window, "show", 
806                         G_CALLBACK (on_nonhibernating_window_show), self);      
807         }
808 }
809
810 gboolean
811 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
812 {
813         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
814         
815         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
816         
817         /* Prevent hibernation if any open windows are currently 
818          * preventing hibernation: */
819         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
820 }
821
822
823 void
824 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
825 {
826         GList *window_list;
827         GList *node;
828         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
829         
830         /* Iterate over all windows */
831         window_list = modest_window_mgr_get_window_list (self);
832         node = window_list;
833         while (node) {
834                 ModestWindow *window = MODEST_WINDOW (node->data);
835                 if (window) {
836                         /* This calls the vfunc, 
837                          * so each window can do its own thing: */
838                         modest_window_save_state (window);
839                 }
840
841                 node = g_list_next (node);
842         }
843         g_list_free (window_list);
844 }
845
846 guint
847 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
848 {
849         ModestWindowMgrPrivate *priv;
850         gint num_windows = 0;
851         GList *window_list;
852
853         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
854
855         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
856
857         window_list = modest_window_mgr_get_window_list (self);
858
859         if (window_list) {
860                 num_windows = g_list_length (window_list);
861                 g_list_free (window_list);
862         }
863
864 #ifndef MODEST_TOOLKIT_HILDON2
865         /* Do not take into account the main window if it was hidden */
866         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
867                 num_windows--;
868 #endif
869
870         return num_windows + priv->banner_counter;
871 }
872
873 GtkWidget *   
874 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
875 {
876         GtkWidget *result;
877         ModestWindowMgrPrivate *priv;
878
879         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
880
881         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
882                 
883         if (priv->cached_editor) {
884                 result = priv->cached_editor;
885                 priv->cached_editor = NULL;
886                 load_new_editor (self);
887         } else {
888                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
889         }
890
891         return result;
892 }
893
894 GtkWidget *   
895 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
896 {
897         GtkWidget *result;
898         ModestWindowMgrPrivate *priv;
899
900         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
901         
902         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
903
904         if (priv->cached_view) {
905                 result = priv->cached_view;
906                 priv->cached_view = NULL;
907                 load_new_view (self);
908         } else {
909                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
910         }
911
912         return result;
913 }
914
915 void
916 modest_window_mgr_register_banner (ModestWindowMgr *self)
917 {
918         ModestWindowMgrPrivate *priv;
919
920         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
921         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
922
923         priv->banner_counter++;
924 }
925
926 void
927 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
928 {
929         ModestWindowMgrPrivate *priv;
930
931         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
932         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
933
934         priv->banner_counter--;
935         if (modest_window_mgr_get_num_windows (self) == 0)
936                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
937 }
938
939 ModestWindow *
940 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
941 {
942         ModestWindow *window = NULL;
943
944         /* Call the children */
945         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
946
947         if (window) {
948                 ModestAccountMgr *mgr;
949
950                 /* Show the initial window */
951                 gtk_widget_show (GTK_WIDGET (window));
952
953                 /* If there are no accounts then show the account wizard */
954                 mgr = modest_runtime_get_account_mgr();
955                 if (!modest_account_mgr_has_accounts (mgr, TRUE)) {
956                         if (!modest_ui_actions_run_account_setup_wizard (window)) {
957                                 g_debug ("%s: couldn't show account setup wizard", __FUNCTION__);
958                         }
959                 }
960         }
961
962         return window;
963 }
964
965 static ModestWindow *
966 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
967 {
968 #ifndef MODEST_TOOLKIT_HILDON2
969         /* By default it returns the main window creating it if
970            needed */
971         return modest_window_mgr_get_main_window (self, TRUE);
972 #else
973         return NULL;
974 #endif
975 }
976
977
978 ModestWindow *
979 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
980 {
981         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
982 }
983
984
985 static ModestWindow *
986 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
987 {
988         g_return_val_if_reached (NULL);
989 }
990
991 gboolean
992 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
993 {
994         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
995 }
996
997 static gboolean
998 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
999 {
1000         /* Default implementation is assuming screen is always on */
1001
1002         return TRUE;
1003 }
1004
1005 void
1006 modest_window_mgr_create_caches (ModestWindowMgr *mgr)
1007 {
1008         MODEST_WINDOW_MGR_GET_CLASS (mgr)->create_caches (mgr);
1009 }
1010
1011 static void
1012 modest_window_mgr_create_caches_default (ModestWindowMgr *self)
1013 {
1014         load_new_editor (self);
1015         load_new_view (self);
1016 }
1017
1018 static gboolean
1019 tny_list_find (TnyList *list, GObject *item)
1020 {
1021         TnyIterator *iterator;
1022         gboolean found = FALSE;
1023
1024         for (iterator = tny_list_create_iterator (list);
1025              !tny_iterator_is_done (iterator) && !found;
1026              tny_iterator_next (iterator)) {
1027                 GObject *current = tny_iterator_get_current (iterator);
1028                 if (current == item)
1029                         found = TRUE;
1030                 g_object_unref (current);
1031         }
1032         g_object_unref (iterator);
1033         
1034         return found;
1035 }
1036
1037 static void
1038 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
1039                                     ModestMailOperation *mail_op,
1040                                     ModestMailOperationQueueNotification type,
1041                                     ModestWindowMgr *self)
1042 {       
1043         ModestWindowMgrPrivate *priv;
1044
1045         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1046
1047         /* We register to track progress */
1048         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
1049                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1050                                                                G_OBJECT (mail_op),
1051                                                                "operation-started",
1052                                                                G_CALLBACK (on_mail_operation_started),
1053                                                                self);
1054                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1055                                                                G_OBJECT (mail_op),
1056                                                                "operation-finished",
1057                                                                G_CALLBACK (on_mail_operation_finished),
1058                                                                self);
1059         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
1060                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1061                                                                   G_OBJECT (mail_op),
1062                                                                   "operation-started");
1063                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1064                                                                   G_OBJECT (mail_op),
1065                                                                   "operation-finished");
1066                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
1067                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1068                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1069                 }
1070         }
1071 }
1072
1073 static void 
1074 on_mail_operation_started (ModestMailOperation *mail_op,
1075                            gpointer user_data)
1076 {
1077         ModestWindowMgr *self;
1078         ModestWindowMgrPrivate *priv;
1079         ModestMailOperationTypeOperation op_type;
1080
1081         self = MODEST_WINDOW_MGR (user_data);
1082         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1083
1084         /* First we check if the operation is a send receive operation,
1085          * If now, we don't handle this */
1086         op_type = modest_mail_operation_get_type_operation (mail_op);
1087         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1088             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1089                 return;
1090         }
1091
1092         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1093                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1094                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1095         }
1096 }
1097
1098 static void 
1099 on_mail_operation_finished (ModestMailOperation *mail_op,
1100                             gpointer user_data)
1101 {
1102         ModestWindowMgr *self;
1103         ModestWindowMgrPrivate *priv;
1104
1105         self = MODEST_WINDOW_MGR (user_data);
1106         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1107
1108         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1109                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1110                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1111         }
1112 }
1113
1114 TnyList *
1115 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1116 {
1117         ModestWindowMgrPrivate *priv;
1118
1119         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1120
1121         return tny_list_copy (priv->progress_operations);
1122 }
1123
1124 gboolean 
1125 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1126 {
1127         ModestWindowMgrPrivate *priv;
1128
1129         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1130
1131         return tny_list_get_length (priv->progress_operations) > 0;
1132 }
1133
1134 gboolean 
1135 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1136                                                      const gchar *account_name)
1137 {
1138         ModestWindowMgrPrivate *priv;
1139         gint account_ops = 0;
1140         TnyIterator *iterator;
1141
1142         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1143
1144         if (account_name == NULL)
1145                 return 0;
1146
1147         for (iterator = tny_list_create_iterator (priv->progress_operations);
1148              !tny_iterator_is_done (iterator);
1149              tny_iterator_next (iterator)) {
1150                 ModestMailOperation *mail_op; 
1151                 TnyAccount *account;
1152
1153                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1154                 account = modest_mail_operation_get_account (mail_op);
1155
1156                 if (account != NULL) {
1157                         const gchar *current_name;
1158
1159                         current_name = tny_account_get_id (account);
1160                         if (current_name && strcmp (current_name, account_name) == 0)
1161                                 account_ops ++;
1162                         g_object_unref (account);
1163                 }
1164
1165                 g_object_unref (mail_op);
1166         }
1167         g_object_unref (iterator);
1168
1169         return account_ops;
1170 }
1171
1172 /* 'Protected method' must be only called by children */
1173 gboolean
1174 _modest_window_mgr_close_active_modals (ModestWindowMgr *self)
1175 {
1176         GtkWidget *modal;
1177
1178         /* Exit if there are no windows */
1179         if (!modest_window_mgr_get_num_windows (self)) {
1180                 g_warning ("%s: there are no windows to close", __FUNCTION__);
1181                 return FALSE;
1182         }
1183
1184         /* Check that there is no active modal dialog */
1185         modal = (GtkWidget *) modest_window_mgr_get_modal (self);
1186         while (modal && GTK_IS_DIALOG (modal)) {
1187                 GtkWidget *parent;
1188
1189 #if defined(MODEST_TOOLKIT_HILDON2) || defined(MODEST_TOOLKIT_HILDON)
1190 #include <hildon/hildon.h>
1191                 /* If it's a hildon note then don't try to close it as
1192                    this is the default behaviour of WM, delete event
1193                    is not issued for this kind of notes as we want the
1194                    user to always click on a button */
1195                 if (HILDON_IS_NOTE (modal)) {
1196                         gtk_window_present (GTK_WINDOW (modal));
1197                         return FALSE;
1198                 }
1199 #endif
1200
1201                 /* Get the parent */
1202                 parent = (GtkWidget *) gtk_window_get_transient_for (GTK_WINDOW (modal));
1203
1204                 /* Try to close it */
1205                 gtk_dialog_response (GTK_DIALOG (modal), GTK_RESPONSE_DELETE_EVENT);
1206
1207                 /* Maybe the dialog was not closed, because a close
1208                    confirmation dialog for example. Then ignore the
1209                    register process */
1210                 if (GTK_IS_WINDOW (modal)) {
1211                         gtk_window_present (GTK_WINDOW (modal));
1212                         return FALSE;
1213                 }
1214
1215                 /* Get next modal */
1216                 modal = parent;
1217         }
1218         return TRUE;
1219 }
1220
1221 gboolean
1222 modest_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1223 {
1224         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_but_initial (self);
1225 }
1226
1227 static gboolean
1228 modest_window_mgr_close_all_but_initial_default (ModestWindowMgr *self)
1229 {
1230         /* Empty default implementation */
1231         return FALSE;
1232 }