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