2007-07-31 Philip Van Hoof <pvanhoof@gnome.org>
[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 other impl specific header files */
40
41 /* 'private'/'protected' functions */
42 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
43 static void modest_window_mgr_init       (ModestWindowMgr *obj);
44 static void modest_window_mgr_finalize   (GObject *obj);
45
46 static gboolean on_window_destroy            (ModestWindow *window,
47                                               GdkEvent *event,
48                                               ModestWindowMgr *self);
49
50 /* list my signals  */
51 enum {
52         /* MY_SIGNAL_1, */
53         /* MY_SIGNAL_2, */
54         LAST_SIGNAL
55 };
56
57 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
58 struct _ModestWindowMgrPrivate {
59         GList        *window_list;
60         ModestWindow *main_window;
61         gboolean     fullscreen_mode;
62         gboolean     show_toolbars;
63         gboolean     show_toolbars_fullscreen;
64         
65         GSList       *windows_that_prevent_hibernation;
66         GSList       *preregistered_uids;
67         GHashTable   *destroy_handlers;
68         GHashTable   *viewer_handlers;
69 };
70 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
71                                                MODEST_TYPE_WINDOW_MGR, \
72                                                ModestWindowMgrPrivate))
73 /* globals */
74 static GObjectClass *parent_class = NULL;
75
76 /* uncomment the following if you have defined any signals */
77 /* static guint signals[LAST_SIGNAL] = {0}; */
78
79 GType
80 modest_window_mgr_get_type (void)
81 {
82         static GType my_type = 0;
83         if (!my_type) {
84                 static const GTypeInfo my_info = {
85                         sizeof(ModestWindowMgrClass),
86                         NULL,           /* base init */
87                         NULL,           /* base finalize */
88                         (GClassInitFunc) modest_window_mgr_class_init,
89                         NULL,           /* class finalize */
90                         NULL,           /* class data */
91                         sizeof(ModestWindowMgr),
92                         1,              /* n_preallocs */
93                         (GInstanceInitFunc) modest_window_mgr_init,
94                         NULL
95                 };
96                 my_type = g_type_register_static (G_TYPE_OBJECT,
97                                                   "ModestWindowMgr",
98                                                   &my_info, 0);
99         }
100         return my_type;
101 }
102
103 static void
104 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
105 {
106         GObjectClass *gobject_class;
107         gobject_class = (GObjectClass*) klass;
108
109         parent_class            = g_type_class_peek_parent (klass);
110         gobject_class->finalize = modest_window_mgr_finalize;
111
112         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
113 }
114
115 static void
116 modest_window_mgr_init (ModestWindowMgr *obj)
117 {
118         ModestWindowMgrPrivate *priv;
119
120         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
121         priv->window_list = NULL;
122         priv->main_window = NULL;
123         priv->fullscreen_mode = FALSE;
124
125         priv->preregistered_uids = NULL;
126
127         /* Could not initialize it from gconf, singletons are not
128            ready yet */
129         priv->show_toolbars = FALSE;
130         priv->show_toolbars_fullscreen = FALSE;
131         priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);   
132         priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
133 }
134
135 static void
136 modest_window_mgr_finalize (GObject *obj)
137 {
138         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
139
140         if (priv->window_list) {
141                 GList *iter = priv->window_list;
142                 /* unregister pending windows */
143                 while (iter) {
144                         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), 
145                                                              MODEST_WINDOW (iter->data));
146                         iter = g_list_next (iter);
147                 }
148                 g_list_free (priv->window_list);
149                 priv->window_list = NULL;
150         }
151
152         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
153         g_slist_free (priv->preregistered_uids);
154
155         
156         /* Free the hash table with the handlers */
157         if (priv->destroy_handlers) {
158                 g_hash_table_destroy (priv->destroy_handlers);
159                 priv->destroy_handlers = NULL;
160         }
161
162         if (priv->viewer_handlers) {
163                 g_hash_table_destroy (priv->viewer_handlers);
164                 priv->viewer_handlers = NULL;
165         }
166
167         /* Do not unref priv->main_window because it does not hold a
168            new reference */
169
170         G_OBJECT_CLASS(parent_class)->finalize (obj);
171 }
172
173 ModestWindowMgr*
174 modest_window_mgr_new (void)
175 {
176         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
177 }
178
179
180
181
182 /* do we have uid? */
183 static gboolean
184 has_uid (GSList *list, const gchar *uid)
185 {
186         GSList *cursor = list;
187
188         if (!uid)
189                 return FALSE;
190         
191         while (cursor) {
192                 if (cursor->data && strcmp (cursor->data, uid) == 0)
193                         return TRUE;
194                 cursor = g_slist_next (cursor);
195         }
196         return FALSE;
197 }
198
199
200 /* remove all from the list have have uid = uid */
201 static GSList*
202 remove_uid (GSList *list, const gchar *uid)
203 {
204         GSList *cursor = list, *start = list;
205         
206         if (!uid)
207                 return FALSE;
208         
209         while (cursor) {
210                 GSList *next = g_slist_next (cursor);
211                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
212                         g_free (cursor->data);
213                         start = g_slist_delete_link (start, cursor);
214                 }
215                 cursor = next;
216         }
217         return start;
218 }
219
220
221 static GSList *
222 append_uid (GSList *list, const gchar *uid)
223 {
224         return g_slist_append (list, g_strdup(uid));
225 }
226
227
228
229 void 
230 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header)
231 {
232         ModestWindowMgrPrivate *priv;
233         gchar* uid;
234         
235         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
236         g_return_if_fail (TNY_IS_HEADER(header));
237                 
238         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
239         uid = modest_tny_folder_get_header_unique_id (header);
240
241
242         if (!has_uid (priv->preregistered_uids, uid)) {
243                 g_debug ("registering new uid %s", uid);
244                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
245         } else
246                 g_debug ("already had uid %s", uid);
247
248         g_free (uid);
249 }
250
251 void 
252 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
253 {
254         ModestWindowMgrPrivate *priv;
255         gchar* uid;
256         
257         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
258         g_return_if_fail (TNY_IS_HEADER(header));
259                 
260         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
261         uid = modest_tny_folder_get_header_unique_id (header);
262         
263         if (!has_uid (priv->preregistered_uids, uid)) {
264                 g_debug ("trying to unregister non-existing uid %s", uid);
265                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
266         } else
267                 g_debug ("unregistering uid %s", uid);
268
269         if (has_uid (priv->preregistered_uids, uid)) {
270                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
271                 if (has_uid (priv->preregistered_uids, uid))
272                         g_debug ("BUG: uid %s NOT removed", uid);
273                 else
274                         g_debug ("uid %s removed", uid);
275         }
276
277         g_free (uid);
278 }
279
280 static gint
281 compare_msguids (ModestWindow *win,
282                  const gchar *uid)
283 {
284         const gchar *msg_uid;
285
286         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
287                 return 1;
288
289         /* Get message uid from msg window */
290         msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
291         
292         if (msg_uid && uid &&!strcmp (msg_uid, uid))
293                 return 0;
294         else
295                 return 1;
296 }
297
298
299
300 gboolean
301 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
302                                           ModestWindow **win)
303 {
304         ModestWindowMgrPrivate *priv;
305         gchar* uid;
306         gboolean has_header, has_window = FALSE;
307         GList *item = NULL;
308
309         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
310         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
311         
312         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
313
314         uid = modest_tny_folder_get_header_unique_id (header);
315         
316         if (win)
317                 *win = NULL;
318         
319 /*      g_debug ("windows in list: %d", g_list_length (priv->window_list)); */
320 /*      g_debug ("headers in list: %d", g_slist_length (priv->preregistered_uids)); */
321
322         has_header = has_uid (priv->preregistered_uids, uid);
323                 
324         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
325         if (item) {
326                 has_window = TRUE;
327                 if (win) {
328                         if (!MODEST_IS_MSG_VIEW_WINDOW(item->data))
329                                 g_debug ("not a valid window!");
330                         else {
331                                 g_debug ("found a window");
332                                 *win = MODEST_WINDOW (item->data);
333                         }
334                 }
335         }
336
337         g_free (uid);
338         return has_header || has_window;
339 }
340
341
342
343 void 
344 modest_window_mgr_register_window (ModestWindowMgr *self, 
345                                    ModestWindow *window)
346 {
347         static gboolean first_time = TRUE;
348         GList *win;
349         gboolean show;
350         ModestWindowMgrPrivate *priv;
351         gint *handler_id;
352
353         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
354         g_return_if_fail (MODEST_IS_WINDOW (window));
355
356         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
357
358         win = g_list_find (priv->window_list, window);
359         if (win) {
360                 g_warning ("Trying to register an already registered window");
361                 return;
362         }
363         
364         /* Check that it's not a second main window */
365         if (MODEST_IS_MAIN_WINDOW (window)) {
366                 if (priv->main_window) {
367                         g_warning ("Trying to register a second main window");
368                         return;
369                 } else {
370                         priv->main_window = window;
371                 }
372         }
373
374         /* remove from the list of pre-registered uids */
375         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
376                 const gchar *uid = modest_msg_view_window_get_message_uid
377                         (MODEST_MSG_VIEW_WINDOW (window));
378
379                 g_debug ("registering window for %s", uid);
380                                 
381                 if (!has_uid (priv->preregistered_uids, uid)) 
382                         g_debug ("weird: no uid for window (%s)", uid);
383
384                 priv->preregistered_uids = 
385                         remove_uid (priv->preregistered_uids,
386                                     modest_msg_view_window_get_message_uid
387                                     (MODEST_MSG_VIEW_WINDOW (window)));
388         }
389         
390         /* Add to list. Keep a reference to the window */
391         g_object_ref (window);
392         priv->window_list = g_list_prepend (priv->window_list, window);
393
394         /* Listen to object destruction */
395         handler_id = g_malloc0 (sizeof (gint));
396         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
397         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
398
399         /* If there is a msg view window, let the main window listen the msg-changed signal */
400         if (MODEST_IS_MSG_VIEW_WINDOW(window) && priv->main_window) {
401                 gulong *handler;
402                 handler = g_malloc0 (sizeof (gulong));
403                 *handler = g_signal_connect (window, "msg-changed", 
404                                              G_CALLBACK (modest_main_window_on_msg_view_window_msg_changed), 
405                                              priv->main_window);
406                 g_hash_table_insert (priv->viewer_handlers, window, handler);
407         }
408
409         /* Put into fullscreen if needed */
410         if (priv->fullscreen_mode)
411                 gtk_window_fullscreen (GTK_WINDOW (window));
412
413         /* Fill caches */
414         if (first_time) {
415                 ModestConf *conf = modest_runtime_get_conf ();
416                 priv->show_toolbars = 
417                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
418                 priv->show_toolbars_fullscreen = 
419                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
420                 first_time = FALSE;
421         }
422
423         /* Show/hide toolbar */
424         if (priv->fullscreen_mode)
425                 show = priv->show_toolbars_fullscreen;
426         else
427                 show = priv->show_toolbars;
428         modest_window_show_toolbar (window, show);
429 }
430
431 static gboolean
432 on_window_destroy (ModestWindow *window, 
433                    GdkEvent *event,
434                    ModestWindowMgr *self)
435 {
436         /* Specific stuff first */
437         if (MODEST_IS_MAIN_WINDOW (window)) {
438                 ModestWindowMgrPrivate *priv;
439                 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
440
441                 /* If more than one window already opened */
442                 if (g_list_length (priv->window_list) > 1) {
443
444                         /* If the user wants to close all the windows */
445                         if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
446                                 GList *iter = priv->window_list;
447                                 do {
448                                         if (iter->data != window) {
449                                                 GList *tmp = iter->next;
450                                                 on_window_destroy (MODEST_WINDOW (iter->data),
451                                                                    event,
452                                                                    self);
453                                                 iter = tmp;
454                                         } else {
455                                                 iter = g_list_next (iter);
456                                         }
457                                 } while (iter);
458                         }
459                 }
460         }
461         else {
462                 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
463                         gboolean sent = FALSE;
464                         gint response = GTK_RESPONSE_ACCEPT;
465                         sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
466                         /* Save currently edited message to Drafts if it was not sent */
467                         if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
468                                 
469                                 response =
470                                         modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
471                                                                                  _("mcen_nc_no_email_message_modified_save_changes"));
472                                 /* Save to drafts */
473                                 if (response != GTK_RESPONSE_CANCEL)                            
474                                         modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
475                                 
476                         } 
477                 }
478         }
479
480         /* Save configuration state (TODO: why edit window does not require this function ?) */
481         if (!MODEST_IS_MSG_EDIT_WINDOW (window)) 
482                 modest_window_save_state (MODEST_WINDOW(window));
483
484
485         /* Unregister window */
486         modest_window_mgr_unregister_window (self, window);
487         
488         return FALSE;
489 }
490
491 static void
492 disconnect_msg_changed (gpointer key, 
493                         gpointer value, 
494                         gpointer user_data)
495 {
496         gulong *handler_id;
497
498         handler_id = (gulong *) value;
499         g_signal_handler_disconnect (G_OBJECT (key), *handler_id);
500 }
501
502
503 void 
504 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
505                                      ModestWindow *window)
506 {
507         GList *win;
508         ModestWindowMgrPrivate *priv;
509         gulong *tmp, handler_id;
510
511         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
512         g_return_if_fail (MODEST_IS_WINDOW (window));
513
514         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
515
516         win = g_list_find (priv->window_list, window);
517         if (!win) {
518                 g_warning ("Trying to unregister a window that has not being registered yet");
519                 return;
520         }
521
522         /* If it's the main window unset it */
523         if (priv->main_window == window) {
524                 priv->main_window = NULL;
525
526                 /* Disconnect all emissions of msg-changed */
527                 g_hash_table_foreach (priv->viewer_handlers, 
528                                       disconnect_msg_changed, 
529                                       NULL);
530                 g_hash_table_destroy (priv->viewer_handlers);
531                 priv->viewer_handlers = NULL;
532         }
533
534         /* Remove the viewer window handler from the hash table. The
535            HashTable could not exist if the main window was closeed
536            when there were other windows remaining */
537         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
538                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
539                 g_signal_handler_disconnect (window, *tmp);
540                 g_hash_table_remove (priv->viewer_handlers, window);
541         }
542
543         /* Save state */
544         modest_window_save_state (window);
545
546         /* Remove from list & hash table */
547         priv->window_list = g_list_remove_link (priv->window_list, win);
548         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
549         handler_id = *tmp;
550         g_hash_table_remove (priv->destroy_handlers, window);
551
552         /* Disconnect the "delete-event" handler, we won't need it anymore */
553         g_signal_handler_disconnect (window, handler_id);
554
555         /* Disconnect all the window signals */
556         modest_window_disconnect_signals (window);
557
558         /* Destroy the window */
559         gtk_widget_destroy (win->data);
560
561         /* If there are no more windows registered then exit program */
562         if (priv->window_list == NULL) {
563                 ModestConf *conf = modest_runtime_get_conf ();
564
565                 /* Save show toolbar status */
566                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, 
567                                       priv->show_toolbars_fullscreen, NULL);
568                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR, 
569                                       priv->show_toolbars, NULL);
570
571                 /* Quit main loop */
572                 /* FIXME: do we ever need to do this here? */
573                 if (gtk_main_level() > 0)
574                         gtk_main_quit ();
575         }
576 }
577
578 void
579 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
580                                        gboolean on)
581 {
582         ModestWindowMgrPrivate *priv;
583         GList *win = NULL;
584
585         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
586
587         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
588
589         /* If there is no change do nothing */
590         if (priv->fullscreen_mode == on)
591                 return;
592
593         priv->fullscreen_mode = on;
594
595         /* Update windows */
596         win = priv->window_list;
597         while (win) {
598                 if (on) {
599                         gtk_window_fullscreen (GTK_WINDOW (win->data));
600                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
601                                                     priv->show_toolbars_fullscreen);
602                 } else {
603                         gtk_window_unfullscreen (GTK_WINDOW (win->data));
604                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
605                                                     priv->show_toolbars);
606                 }
607                 win = g_list_next (win);
608         }
609 }
610
611 gboolean
612 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
613 {
614         ModestWindowMgrPrivate *priv;
615
616         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
617
618         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
619
620         return priv->fullscreen_mode;
621 }
622
623 void 
624 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
625                                  gboolean show_toolbars,
626                                  gboolean fullscreen)
627 {
628         ModestWindowMgrPrivate *priv;
629
630         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
631
632         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
633
634         /* If nothing changes then return. Otherwise cache it, do not
635            save to GConf for the moment, it will be done when all
636            windows become unregistered in order to avoid unnecessary
637            ModestConf calls */
638         if (fullscreen) {
639                 if (priv->show_toolbars_fullscreen == show_toolbars)
640                         return;
641                 else
642                         priv->show_toolbars_fullscreen = show_toolbars;
643         } else {
644                 if (priv->show_toolbars == show_toolbars)
645                         return;
646                 else
647                         priv->show_toolbars = show_toolbars;
648         }
649
650         /* Apply now if the view mode is the right one */
651         if ((fullscreen && priv->fullscreen_mode) ||
652             (!fullscreen && !priv->fullscreen_mode)) {
653
654                 GList *win = priv->window_list;
655
656                 while (win) {
657                         modest_window_show_toolbar (MODEST_WINDOW (win->data),
658                                                     show_toolbars);
659                         win = g_list_next (win);
660                 }
661         }
662 }
663
664 ModestWindow*  
665 modest_window_mgr_get_main_window (ModestWindowMgr *self)
666 {
667         ModestWindowMgrPrivate *priv;
668
669         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
670
671         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
672
673         return priv->main_window;
674 }
675
676 static void
677 on_nonhibernating_window_hide(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         /* Forget this window,
683          * so hibernation will be allowed again if no windows are remembered: */
684         priv->windows_that_prevent_hibernation =
685                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
686 }
687
688 static void
689 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
690 {
691         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
692         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
693         
694         GtkWindow *window = GTK_WINDOW (widget);
695         
696         priv->windows_that_prevent_hibernation = 
697                         g_slist_append (priv->windows_that_prevent_hibernation, window);
698         
699         /* Allow hibernation again when the window has been hidden: */
700         g_signal_connect (window, "hide", 
701                 G_CALLBACK (on_nonhibernating_window_hide), self);
702 }
703
704 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
705                                                                   GtkWindow *window)
706 {
707         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
708         
709         if (GTK_WIDGET_VISIBLE(window)) {
710                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
711         } else {
712                 /* Wait for it to be shown: */
713                 g_signal_connect (window, "show", 
714                         G_CALLBACK (on_nonhibernating_window_show), self);      
715         }
716 }
717
718 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
719 {
720         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
721         
722         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
723         
724         /* Prevent hibernation if any open windows are currently 
725          * preventing hibernation: */
726         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
727 }
728
729
730 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
731 {
732         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
733         
734         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
735
736         /* Iterate over all windows */
737         GList *win = priv->window_list;
738         while (win) {
739                 ModestWindow *window = MODEST_WINDOW (win->data);
740                 if (window) {
741                         /* This calls the vfunc, 
742                          * so each window can do its own thing: */
743                         modest_window_save_state (window);
744                 }       
745                 
746                 win = g_list_next (win);
747         }
748 }