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