This is a manual merge of branch drop split view intro trunk.
[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 "widgets/modest-main-window.h"
37 #include "widgets/modest-msg-edit-window.h"
38 #include "widgets/modest-msg-view-window.h"
39 #include "modest-debug.h"
40
41
42 /* 'private'/'protected' functions */
43 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
44 static void modest_window_mgr_init       (ModestWindowMgr *obj);
45 static void modest_window_mgr_finalize   (GObject *obj);
46
47 static gboolean modest_window_mgr_register_window_default (ModestWindowMgr *self, 
48                                                            ModestWindow *window,
49                                                            ModestWindow *parent);
50 static void modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
51                                                          ModestWindow *window);
52 static void modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
53                                                            gboolean on);
54 static gboolean modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self);
55 static void modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
56                                                      GType window_type,
57                                                      gboolean show_toolbars,
58                                                      gboolean fullscreen);
59 static ModestWindow* modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show);
60 static GtkWindow *modest_window_mgr_get_modal_default (ModestWindowMgr *self);
61 static void modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
62                                                  GtkWindow *window,
63                                                  GtkWindow *parent);
64 static gboolean modest_window_mgr_close_all_windows_default (ModestWindowMgr *self);
65 static gboolean modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, 
66                                                                   TnyHeader *header,
67                                                                   ModestWindow **win);
68 static GList *modest_window_mgr_get_window_list_default (ModestWindowMgr *self);
69 static ModestWindow *modest_window_mgr_show_initial_window_default (ModestWindowMgr *self);
70
71 /* list my signals  */
72 enum {
73         WINDOW_LIST_EMPTY_SIGNAL,
74         NUM_SIGNALS
75 };
76
77 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
78 struct _ModestWindowMgrPrivate {
79         guint         banner_counter;
80
81         ModestWindow *main_window;
82
83         GSList       *windows_that_prevent_hibernation;
84         GSList       *preregistered_uids;
85         
86         guint        closing_time;
87
88         GtkWidget    *cached_view;
89         GtkWidget    *cached_editor;
90         guint        idle_load_view_id;
91         guint        idle_load_editor_id;
92 };
93
94 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95                                                MODEST_TYPE_WINDOW_MGR, \
96                                                ModestWindowMgrPrivate))
97 /* globals */
98 static GObjectClass *parent_class = NULL;
99
100 /* uncomment the following if you have defined any signals */
101 static guint signals[NUM_SIGNALS] = {0};
102
103 GType
104 modest_window_mgr_get_type (void)
105 {
106         static GType my_type = 0;
107         if (!my_type) {
108                 static const GTypeInfo my_info = {
109                         sizeof(ModestWindowMgrClass),
110                         NULL,           /* base init */
111                         NULL,           /* base finalize */
112                         (GClassInitFunc) modest_window_mgr_class_init,
113                         NULL,           /* class finalize */
114                         NULL,           /* class data */
115                         sizeof(ModestWindowMgr),
116                         1,              /* n_preallocs */
117                         (GInstanceInitFunc) modest_window_mgr_init,
118                         NULL
119                 };
120                 my_type = g_type_register_static (G_TYPE_OBJECT,
121                                                   "ModestWindowMgr",
122                                                   &my_info, 0);
123         }
124         return my_type;
125 }
126
127 static void
128 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
129 {
130         GObjectClass *gobject_class;
131         ModestWindowMgrClass *mgr_class;
132
133         gobject_class = (GObjectClass*) klass;
134         mgr_class = (ModestWindowMgrClass *) klass;
135
136         parent_class            = g_type_class_peek_parent (klass);
137         gobject_class->finalize = modest_window_mgr_finalize;
138         mgr_class->register_window = modest_window_mgr_register_window_default;
139         mgr_class->unregister_window = modest_window_mgr_unregister_window_default;
140         mgr_class->set_fullscreen_mode = modest_window_mgr_set_fullscreen_mode_default;
141         mgr_class->get_fullscreen_mode = modest_window_mgr_get_fullscreen_mode_default;
142         mgr_class->show_toolbars = modest_window_mgr_show_toolbars_default;
143         mgr_class->get_main_window = modest_window_mgr_get_main_window_default;
144         mgr_class->get_modal = modest_window_mgr_get_modal_default;
145         mgr_class->set_modal = modest_window_mgr_set_modal_default;
146         mgr_class->close_all_windows = modest_window_mgr_close_all_windows_default;
147         mgr_class->find_registered_header = modest_window_mgr_find_registered_header_default;
148         mgr_class->get_window_list = modest_window_mgr_get_window_list_default;
149         mgr_class->show_initial_window = modest_window_mgr_show_initial_window_default;
150
151         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
152
153
154         /**
155          * ModestWindowMgr::window-list-empty
156          * @self: the #ModestWindowMgr that emits the signal
157          * @user_data: user data set when the signal handler was connected
158          *
159          * Issued whenever the window list becomes empty
160          */
161         signals[WINDOW_LIST_EMPTY_SIGNAL] =
162                 g_signal_new ("window-list-empty",
163                               G_TYPE_FROM_CLASS (gobject_class),
164                               G_SIGNAL_RUN_FIRST,
165                               G_STRUCT_OFFSET (ModestWindowMgrClass, window_list_empty),
166                               NULL, NULL,
167                               g_cclosure_marshal_VOID__VOID,
168                               G_TYPE_NONE, 0);
169 }
170
171 static gboolean
172 idle_load_view (ModestWindowMgr *mgr)
173 {
174         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
175         
176         priv->cached_view = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
177         priv->idle_load_view_id = 0;
178         return FALSE;
179 }
180
181 static gboolean
182 idle_load_editor (ModestWindowMgr *mgr)
183 {
184         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
185         
186         priv->cached_editor = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
187         priv->idle_load_editor_id = 0;
188         return FALSE;
189 }
190
191 static void
192 load_new_view (ModestWindowMgr *self)
193 {
194         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
195         if ((priv->cached_view == NULL) && (priv->idle_load_view_id == 0))
196                 priv->idle_load_view_id = g_idle_add ((GSourceFunc) idle_load_view, self);
197 }
198
199 static void
200 load_new_editor (ModestWindowMgr *self)
201 {
202         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
203         if ((priv->cached_editor == NULL) && (priv->idle_load_editor_id == 0))
204                 priv->idle_load_editor_id = g_idle_add ((GSourceFunc) idle_load_editor, self);
205 }
206
207 static void
208 modest_window_mgr_init (ModestWindowMgr *obj)
209 {
210         ModestWindowMgrPrivate *priv;
211
212         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
213         priv->banner_counter = 0;
214         priv->main_window = NULL;
215
216         priv->preregistered_uids = NULL;
217
218         priv->closing_time = 0;
219
220         priv->cached_view = NULL;
221         priv->cached_editor = NULL;
222
223         priv->windows_that_prevent_hibernation = NULL;
224 }
225
226 static void
227 modest_window_mgr_finalize (GObject *obj)
228 {
229         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
230
231         if (priv->idle_load_view_id > 0) {
232                 g_source_remove (priv->idle_load_view_id);
233                 priv->idle_load_view_id = 0;
234         }
235         
236         if (priv->idle_load_editor_id > 0) {
237                 g_source_remove (priv->idle_load_editor_id);
238                 priv->idle_load_editor_id = 0;
239         }
240         
241         if (priv->cached_view) {
242                 gtk_widget_destroy (priv->cached_view);
243                 priv->cached_view = NULL;
244         }
245         if (priv->cached_editor) {
246                 gtk_widget_destroy (priv->cached_editor);
247                 priv->cached_editor = NULL;
248         }
249
250         if (priv->windows_that_prevent_hibernation) {
251                 g_slist_free (priv->windows_that_prevent_hibernation);
252                 priv->cached_editor = NULL;
253         }
254
255         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
256         g_slist_free (priv->preregistered_uids);
257
258         G_OBJECT_CLASS(parent_class)->finalize (obj);
259 }
260
261 ModestWindowMgr*
262 modest_window_mgr_new (void)
263 {
264         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
265 }
266
267
268
269
270 /* do we have uid? */
271 static gboolean
272 has_uid (GSList *list, const gchar *uid)
273 {
274         GSList *cursor = list;
275
276         if (!uid)
277                 return FALSE;
278         
279         while (cursor) {
280                 if (cursor->data && strcmp (cursor->data, uid) == 0)
281                         return TRUE;
282                 cursor = g_slist_next (cursor);
283         }
284         return FALSE;
285 }
286
287
288 /* remove all from the list have have uid = uid */
289 static GSList*
290 remove_uid (GSList *list, const gchar *uid)
291 {
292         GSList *cursor = list, *start = list;
293         
294         if (!uid)
295                 return list;
296         
297         while (cursor) {
298                 GSList *next = g_slist_next (cursor);
299                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
300                         g_free (cursor->data);
301                         start = g_slist_delete_link (start, cursor);
302                 }
303                 cursor = next;
304         }
305         return start;
306 }
307
308
309 static GSList *
310 append_uid (GSList *list, const gchar *uid)
311 {
312         return g_slist_append (list, g_strdup(uid));
313 }
314
315
316
317 void 
318 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header, const gchar *alt_uid)
319 {
320         ModestWindowMgrPrivate *priv;
321         gchar* uid;
322         
323         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
324         g_return_if_fail (TNY_IS_HEADER(header));
325                 
326         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
327         uid = modest_tny_folder_get_header_unique_id (header);
328
329         if (uid == NULL)
330                 uid = g_strdup (alt_uid);
331         
332         if (!has_uid (priv->preregistered_uids, uid)) {
333                 MODEST_DEBUG_BLOCK(g_debug ("registering new uid %s", uid););
334                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
335         } else
336                 MODEST_DEBUG_BLOCK(g_debug ("already had uid %s", uid););
337         
338         g_free (uid);
339 }
340
341 void 
342 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
343 {
344         ModestWindowMgrPrivate *priv;
345         gchar* uid;
346         
347         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
348         g_return_if_fail (TNY_IS_HEADER(header));
349                 
350         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
351         uid = modest_tny_folder_get_header_unique_id (header);
352
353         if (!has_uid (priv->preregistered_uids, uid)) {
354                 MODEST_DEBUG_BLOCK(g_debug ("trying to unregister non-existing uid %s", uid););
355                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
356         } else
357                 MODEST_DEBUG_BLOCK(g_debug ("unregistering uid %s", uid););
358         
359         if (has_uid (priv->preregistered_uids, uid)) {
360                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
361                 if (has_uid (priv->preregistered_uids, uid))
362                         g_debug ("BUG: uid %s NOT removed", uid);
363                 else
364                         MODEST_DEBUG_BLOCK(g_debug ("uid %s removed", uid););
365         }
366                 
367         g_free (uid);
368 }
369
370
371 #define MODEST_WINDOW_HELP_ID_PARAM "help-id"
372
373 void
374 modest_window_mgr_register_help_id (ModestWindowMgr *self, GtkWindow *win, const gchar* help_id)
375 {
376         /* we don't need 'self', but for API consistency... */
377         g_return_if_fail (self && MODEST_IS_WINDOW_MGR(self));
378
379         g_return_if_fail (win && GTK_IS_WINDOW(win));
380         g_return_if_fail (help_id);
381         
382         g_object_set_data_full (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM,
383                                 g_strdup(help_id), g_free);
384 }
385
386
387 const gchar*
388 modest_window_mgr_get_help_id (ModestWindowMgr *self, GtkWindow *win)
389 {
390         /* we don't need 'self', but for API consistency... */
391         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR (self), NULL);
392         g_return_val_if_fail (win, NULL);
393
394         return g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM);
395 }
396
397 gboolean
398 modest_window_mgr_close_all_windows (ModestWindowMgr *self)
399 {
400         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_windows (self);
401 }
402
403 static gboolean
404 modest_window_mgr_close_all_windows_default (ModestWindowMgr *self)
405 {
406         return TRUE;
407 }
408
409
410 gboolean
411 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
412                                                   ModestWindow **win)
413 {
414         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_header (self, header, win);
415 }
416
417 static gboolean
418 modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, TnyHeader *header,
419                                                   ModestWindow **win)
420 {
421         ModestWindowMgrPrivate *priv = NULL;
422         gchar* uid = NULL;
423         gboolean has_header = FALSE;
424
425         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
426         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
427         
428         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
429
430         uid = modest_tny_folder_get_header_unique_id (header);
431         
432         if (win)
433                 *win = NULL;
434
435         has_header = has_uid (priv->preregistered_uids, uid);
436
437         return has_header;
438 }
439
440 GList *
441 modest_window_mgr_get_window_list (ModestWindowMgr *self)
442 {
443         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_window_list (self);
444 }
445
446 static GList *
447 modest_window_mgr_get_window_list_default (ModestWindowMgr *self)
448 {
449         return NULL;
450 }
451
452 gboolean
453 modest_window_mgr_register_window (ModestWindowMgr *self, 
454                                    ModestWindow *window,
455                                    ModestWindow *parent)
456 {
457         return MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
458 }
459
460 static gboolean
461 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
462                                            ModestWindow *window,
463                                            ModestWindow *parent)
464 {
465         ModestWindowMgrPrivate *priv;
466
467         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
468         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
469
470         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
471
472         /* Check that it's not a second main window */
473         if (MODEST_IS_MAIN_WINDOW (window)) {
474                 if (priv->main_window) {
475                         g_warning ("%s: trying to register a second main window",
476                                    __FUNCTION__);
477                         return FALSE;
478                 } else {
479                         priv->main_window = window;
480                         load_new_view (self);
481                         load_new_editor (self);
482                 }
483         }
484
485         /* remove from the list of pre-registered uids */
486         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
487                 const gchar *uid = modest_msg_view_window_get_message_uid
488                         (MODEST_MSG_VIEW_WINDOW (window));
489
490                 if (!has_uid (priv->preregistered_uids, uid)) 
491                         g_debug ("weird: no uid for window (%s)", uid);
492                 
493                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
494                 
495                 priv->preregistered_uids = 
496                         remove_uid (priv->preregistered_uids,
497                                     modest_msg_view_window_get_message_uid
498                                     (MODEST_MSG_VIEW_WINDOW (window)));
499         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
500                 const gchar *uid = modest_msg_edit_window_get_message_uid
501                         (MODEST_MSG_EDIT_WINDOW (window));
502                 
503                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
504
505                 priv->preregistered_uids = 
506                         remove_uid (priv->preregistered_uids,
507                                     modest_msg_edit_window_get_message_uid
508                                     (MODEST_MSG_EDIT_WINDOW (window)));
509         }
510
511         return TRUE;
512 }
513
514 void 
515 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
516                                      ModestWindow *window)
517 {
518         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
519 }
520
521 static void 
522 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
523                                              ModestWindow *window)
524 {
525         ModestWindowMgrPrivate *priv;
526
527         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
528         g_return_if_fail (MODEST_IS_WINDOW (window));
529
530         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
531
532         /* Save state */
533         modest_window_save_state (window);
534
535         /* Disconnect all the window signals */
536         modest_window_disconnect_signals (window);
537         
538         /* Destroy the window */
539         gtk_widget_destroy (GTK_WIDGET (window));
540 }
541
542
543
544 void
545 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
546                                        gboolean on)
547 {
548         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
549 }
550
551 static void
552 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
553                                                gboolean on)
554 {
555         return;
556 }
557
558 gboolean
559 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
560 {
561         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
562 }
563
564 static gboolean
565 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
566 {
567         return FALSE;
568 }
569
570 void 
571 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
572                                  GType window_type,
573                                  gboolean show_toolbars,
574                                  gboolean fullscreen)
575 {
576         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
577 }
578
579 static void 
580 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
581                                          GType window_type,
582                                          gboolean show_toolbars,
583                                          gboolean fullscreen)
584 {
585         return;
586 }
587
588 void
589 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
590 {
591         ModestWindowMgrPrivate *priv;
592         
593         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
594
595         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
596         priv->main_window = win;
597 }
598
599 ModestWindow*  
600 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
601 {
602         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
603 }
604
605 static ModestWindow*  
606 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
607 {
608         ModestWindowMgrPrivate *priv;
609         
610         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
611
612         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
613         if (priv->main_window)
614                 return priv->main_window;
615
616         if (show) 
617                 return modest_main_window_new ();
618         else return NULL;
619 }
620
621
622 gboolean
623 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
624 {
625         ModestWindowMgrPrivate *priv;
626         
627         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
628         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
629
630         return priv->main_window != NULL;
631 }
632
633
634 GtkWindow *
635 modest_window_mgr_get_modal (ModestWindowMgr *self)
636 {
637         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
638 }
639
640 static GtkWindow *
641 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
642 {
643         return NULL;
644 }
645
646
647 void
648 modest_window_mgr_set_modal (ModestWindowMgr *self, 
649                              GtkWindow *window,
650                              GtkWindow *parent)
651 {
652         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
653 }
654
655 static void
656 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
657                                      GtkWindow *window,
658                                      GtkWindow *parent)
659 {
660         return;
661 }
662
663
664 static void
665 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
666 {
667         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
668         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
669         
670         /* Forget this window,
671          * so hibernation will be allowed again if no windows are remembered: */
672         priv->windows_that_prevent_hibernation =
673                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
674 }
675
676 static void
677 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
678 {
679         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
680         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
681         
682         GtkWindow *window = GTK_WINDOW (widget);
683         
684         priv->windows_that_prevent_hibernation = 
685                         g_slist_append (priv->windows_that_prevent_hibernation, window);
686         
687         /* Allow hibernation again when the window has been hidden: */
688         g_signal_connect (window, "hide", 
689                 G_CALLBACK (on_nonhibernating_window_hide), self);
690 }
691
692 void
693 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
694                                                                   GtkWindow *window)
695 {
696         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
697         
698         if (GTK_WIDGET_VISIBLE(window)) {
699                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
700         } else {
701                 /* Wait for it to be shown: */
702                 g_signal_connect (window, "show", 
703                         G_CALLBACK (on_nonhibernating_window_show), self);      
704         }
705 }
706
707 gboolean
708 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
709 {
710         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
711         
712         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
713         
714         /* Prevent hibernation if any open windows are currently 
715          * preventing hibernation: */
716         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
717 }
718
719
720 void
721 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
722 {
723         GList *window_list;
724         GList *node;
725         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
726         
727         /* Iterate over all windows */
728         window_list = modest_window_mgr_get_window_list (self);
729         node = window_list;
730         while (node) {
731                 ModestWindow *window = MODEST_WINDOW (node->data);
732                 if (window) {
733                         /* This calls the vfunc, 
734                          * so each window can do its own thing: */
735                         modest_window_save_state (window);
736                 }
737
738                 node = g_list_next (node);
739         }
740         g_list_free (window_list);
741 }
742
743 guint
744 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
745 {
746         ModestWindowMgrPrivate *priv;
747         gint num_windows = 0;
748         GList *window_list;
749
750         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
751
752         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
753
754         window_list = modest_window_mgr_get_window_list (self);
755
756         if (window_list) {
757                 num_windows = g_list_length (window_list);
758                 g_list_free (window_list);
759         }
760
761         /* Do not take into account the main window if it was hidden */
762         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
763                 num_windows--;
764
765         return num_windows + priv->banner_counter;
766 }
767
768 GtkWidget *   
769 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
770 {
771         GtkWidget *result;
772         ModestWindowMgrPrivate *priv;
773
774         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
775
776         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
777                 
778         if (priv->cached_editor) {
779                 result = priv->cached_editor;
780                 priv->cached_editor = NULL;
781                 load_new_editor (self);
782         } else {
783                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
784         }
785
786         return result;
787 }
788
789 GtkWidget *   
790 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
791 {
792         GtkWidget *result;
793         ModestWindowMgrPrivate *priv;
794
795         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
796         
797         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
798
799         if (priv->cached_view) {
800                 result = priv->cached_view;
801                 priv->cached_view = NULL;
802                 load_new_view (self);
803         } else {
804                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
805         }
806
807         return result;
808 }
809
810 void
811 modest_window_mgr_register_banner (ModestWindowMgr *self)
812 {
813         ModestWindowMgrPrivate *priv;
814
815         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
816         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
817
818         priv->banner_counter++;
819 }
820
821 void
822 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
823 {
824         ModestWindowMgrPrivate *priv;
825
826         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
827         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
828
829         priv->banner_counter--;
830         if (modest_window_mgr_get_num_windows (self) == 0)
831                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
832 }
833
834 ModestWindow *
835 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
836 {
837         ModestWindow *window = NULL;
838
839         /* Call the children */
840         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
841
842         if (window) {
843                 ModestAccountMgr *mgr;
844
845                 /* Show the initial window */
846                 gtk_widget_show (GTK_WIDGET (window));
847
848                 /* If there are no accounts then show the account wizard */
849                 mgr = modest_runtime_get_account_mgr();
850                 if (!modest_account_mgr_has_accounts (mgr, TRUE))
851                         modest_ui_actions_run_account_setup_wizard (window);
852         }
853
854         return window;
855 }
856
857 static ModestWindow *
858 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
859 {
860         /* By default it returns the main window creating it if
861            needed */
862         return modest_window_mgr_get_main_window (self, TRUE);
863 }