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