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