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