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