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