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