* remove some needless warnings (ie. edit windows don't have to
[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                 if (msg_uid && uid &&!strcmp (msg_uid, uid))
309                         return 0;
310         } else {
311                 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
312         }
313         
314         if (msg_uid && uid &&!strcmp (msg_uid, uid))
315                 return 0;
316         else
317                 return 1;
318 }
319
320
321 gboolean
322 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
323                                           ModestWindow **win)
324 {
325         ModestWindowMgrPrivate *priv;
326         gchar* uid;
327         gboolean has_header, has_window = FALSE;
328         GList *item = NULL;
329
330         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
331         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
332         
333         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
334
335         uid = modest_tny_folder_get_header_unique_id (header);
336         
337         if (win)
338                 *win = NULL;
339         
340         has_header = has_uid (priv->preregistered_uids, uid);
341                 
342         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
343         if (item) {
344                 has_window = TRUE;
345                 if (win) {
346                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
347                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
348                                 g_debug ("not a valid window!");
349                         else {
350                                 g_debug ("found a window");
351                                 *win = MODEST_WINDOW (item->data);
352                         }
353                 }
354         }
355
356         g_free (uid);
357         return has_header || has_window;
358 }
359
360
361
362 void 
363 modest_window_mgr_register_window (ModestWindowMgr *self, 
364                                    ModestWindow *window)
365 {
366         static gboolean first_time = TRUE;
367         GList *win;
368         gboolean show;
369         ModestWindowMgrPrivate *priv;
370         gint *handler_id;
371
372         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
373         g_return_if_fail (GTK_IS_WINDOW (window));
374
375         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
376
377         win = g_list_find (priv->window_list, window);
378         if (win) {
379                 g_warning ("%s: trying to re-register a window",
380                            __FUNCTION__);
381                 return;
382         }
383         
384         /* Check that it's not a second main window */
385         if (MODEST_IS_MAIN_WINDOW (window)) {
386                 if (priv->main_window) {
387                         g_warning ("%s: trying to register a second main window",
388                                    __FUNCTION__);
389                         return;
390                 } else {
391                         priv->main_window = window;
392                 }
393         }
394
395         /* remove from the list of pre-registered uids */
396         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
397                 const gchar *uid = modest_msg_view_window_get_message_uid
398                         (MODEST_MSG_VIEW_WINDOW (window));
399                 
400                 if (!has_uid (priv->preregistered_uids, uid)) 
401                         g_debug ("weird: no uid for window (%s)", uid);
402                 
403                 g_debug ("registering window for %s", uid ? uid : "<none>");
404
405                 priv->preregistered_uids = 
406                         remove_uid (priv->preregistered_uids,
407                                     modest_msg_view_window_get_message_uid
408                                     (MODEST_MSG_VIEW_WINDOW (window)));
409
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                 priv->preregistered_uids = 
417                         remove_uid (priv->preregistered_uids,
418                                     modest_msg_edit_window_get_message_uid
419                                     (MODEST_MSG_EDIT_WINDOW (window)));
420         }
421         
422         /* Add to list. Keep a reference to the window */
423         g_object_ref (window);
424         priv->window_list = g_list_prepend (priv->window_list, window);
425
426         /* Listen to object destruction */
427         handler_id = g_malloc0 (sizeof (gint));
428         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
429         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
430
431         /* If there is a msg view window, let the main window listen the msg-changed signal */
432         if (MODEST_IS_MSG_VIEW_WINDOW(window) && priv->main_window) {
433                 gulong *handler;
434                 handler = g_malloc0 (sizeof (gulong));
435                 *handler = g_signal_connect (window, "msg-changed", 
436                                              G_CALLBACK (modest_main_window_on_msg_view_window_msg_changed), 
437                                              priv->main_window);
438                 g_hash_table_insert (priv->viewer_handlers, window, handler);
439         }
440
441         /* Put into fullscreen if needed */
442         if (priv->fullscreen_mode)
443                 gtk_window_fullscreen (GTK_WINDOW (window));
444
445         /* Fill caches */
446         if (first_time) {
447                 ModestConf *conf = modest_runtime_get_conf ();
448                 priv->show_toolbars = 
449                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
450                 priv->show_toolbars_fullscreen = 
451                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
452                 first_time = FALSE;
453         }
454
455         /* Show/hide toolbar */
456         if (priv->fullscreen_mode)
457                 show = priv->show_toolbars_fullscreen;
458         else
459                 show = priv->show_toolbars;
460         modest_window_show_toolbar (window, show);
461 }
462
463 static gboolean
464 on_window_destroy (ModestWindow *window, 
465                    GdkEvent *event,
466                    ModestWindowMgr *self)
467 {
468         /* Specific stuff first */
469         if (MODEST_IS_MAIN_WINDOW (window)) {
470                 ModestWindowMgrPrivate *priv;
471                 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
472
473                 /* If more than one window already opened */
474                 if (g_list_length (priv->window_list) > 1) {
475
476                         /* If the user wants to close all the windows */
477                         if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
478                                 GList *iter = priv->window_list;
479                                 do {
480                                         if (iter->data != window) {
481                                                 GList *tmp = iter->next;
482                                                 on_window_destroy (MODEST_WINDOW (iter->data),
483                                                                    event,
484                                                                    self);
485                                                 iter = tmp;
486                                         } else {
487                                                 iter = g_list_next (iter);
488                                         }
489                                 } while (iter);
490                         }
491                 }
492         }
493         else {
494                 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
495                         gboolean sent = FALSE;
496                         gint response = GTK_RESPONSE_ACCEPT;
497                         sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
498                         /* Save currently edited message to Drafts if it was not sent */
499                         if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
500                                 
501                                 response =
502                                         modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
503                                                                                  _("mcen_nc_no_email_message_modified_save_changes"));
504                                 /* Save to drafts */
505                                 if (response != GTK_RESPONSE_CANCEL)                            
506                                         modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
507                                 
508                         } 
509                 }
510         }
511
512         /* Save configuration state (TODO: why edit window does not require this function ?) */
513         if (!MODEST_IS_MSG_EDIT_WINDOW (window)) 
514                 modest_window_save_state (MODEST_WINDOW(window));
515
516
517         /* Unregister window */
518         modest_window_mgr_unregister_window (self, window);
519         
520         return FALSE;
521 }
522
523 static void
524 disconnect_msg_changed (gpointer key, 
525                         gpointer value, 
526                         gpointer user_data)
527 {
528         gulong *handler_id;
529
530         handler_id = (gulong *) value;
531         g_signal_handler_disconnect (G_OBJECT (key), *handler_id);
532 }
533
534
535
536 /* interval before retrying to close the application */
537 #define CLOSING_RETRY_INTERVAL 3000 
538 /* interval before cancel whatever is left in the queue, and closing anyway */
539 #define MAX_WAIT_FOR_CLOSING 30 * 1000 
540
541 static gboolean
542 on_quit_maybe (ModestWindowMgr *self)
543 {
544         ModestWindowMgrPrivate *priv;
545         guint queue_num;
546         
547         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
548
549         /* it seems, in the meantime some windows were
550          * created. in that case, stop  'on_quit_maybe' */
551         if (priv->window_list) {
552                 priv->closing_time = 0;
553                 return FALSE;
554         }
555
556         if (priv->closing_time >= MAX_WAIT_FOR_CLOSING) {
557                 /* we waited long enough: cancel all remaining operations */
558                 g_debug ("%s: we waited long enough (%ds), cancelling queue and quiting",
559                          __FUNCTION__, priv->closing_time/1000);
560                 /* FIXME: below gives me a lot of:
561                  * GLIB CRITICAL ** default - modest_mail_operation_cancel:
562                  *                     assertion `priv->account' failed
563                  * which means there is no account for the given operation
564                  * so, we're not trying to be nice, we're just quiting.
565                  */
566                 //modest_mail_operation_queue_cancel_all
567                 //      (modest_runtime_get_mail_operation_queue());
568         } else {
569         
570                 /* if there is anything left in our operation queue,
571                  * wait another round
572                  */
573                 queue_num = modest_mail_operation_queue_num_elements
574                         (modest_runtime_get_mail_operation_queue()); 
575                 if  (queue_num > 0) {
576                         g_debug ("%s: waiting, there are still %d operation(s) queued",
577                                  __FUNCTION__, queue_num);
578                         priv->closing_time += CLOSING_RETRY_INTERVAL;
579                         return TRUE;
580                 }
581         }
582         
583         /* so: no windows left, nothing in the queue: quit */
584         priv->closing_time = 0;
585         gtk_main_quit ();
586         return FALSE;
587 }
588
589
590 void 
591 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
592                                      ModestWindow *window)
593 {
594         GList *win;
595         ModestWindowMgrPrivate *priv;
596         gulong *tmp, handler_id;
597
598         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
599         g_return_if_fail (MODEST_IS_WINDOW (window));
600
601         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
602
603         win = g_list_find (priv->window_list, window);
604         if (!win) {
605                 g_warning ("Trying to unregister a window that has not being registered yet");
606                 return;
607         }
608
609         /* If it's the main window unset it */
610         if (priv->main_window == window) {
611                 priv->main_window = NULL;
612
613                 /* Disconnect all emissions of msg-changed */
614                 if (priv->viewer_handlers) {
615                         g_hash_table_foreach (priv->viewer_handlers, 
616                                               disconnect_msg_changed, 
617                                               NULL);
618                         g_hash_table_destroy (priv->viewer_handlers);
619                         priv->viewer_handlers = NULL;
620                 }
621         }
622
623         /* Remove the viewer window handler from the hash table. The
624            HashTable could not exist if the main window was closeed
625            when there were other windows remaining */
626         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
627                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
628                 g_signal_handler_disconnect (window, *tmp);
629                 g_hash_table_remove (priv->viewer_handlers, window);
630         }
631
632         /* Save state */
633         modest_window_save_state (window);
634
635         /* Remove from list & hash table */
636         priv->window_list = g_list_remove_link (priv->window_list, win);
637         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
638         handler_id = *tmp;
639         g_hash_table_remove (priv->destroy_handlers, window);
640
641         /* Disconnect the "delete-event" handler, we won't need it anymore */
642         g_signal_handler_disconnect (window, handler_id);
643
644         /* Disconnect all the window signals */
645         modest_window_disconnect_signals (window);
646         
647         /* Destroy the window */
648         gtk_widget_destroy (win->data);
649         
650         /* If there are no more windows registered then exit program */
651         if (priv->window_list == NULL) {
652                 
653                 ModestConf *conf = modest_runtime_get_conf ();
654                 /* Save show toolbar status */
655                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, 
656                                       priv->show_toolbars_fullscreen, NULL);
657                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR, 
658                                       priv->show_toolbars, NULL);
659
660                 g_timeout_add (CLOSING_RETRY_INTERVAL,
661                                (GSourceFunc)on_quit_maybe, self);
662         }
663 }
664
665
666
667 void
668 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
669                                        gboolean on)
670 {
671         ModestWindowMgrPrivate *priv;
672         GList *win = NULL;
673
674         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
675
676         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
677
678         /* If there is no change do nothing */
679         if (priv->fullscreen_mode == on)
680                 return;
681
682         priv->fullscreen_mode = on;
683
684         /* Update windows */
685         win = priv->window_list;
686         while (win) {
687                 if (on) {
688                         gtk_window_fullscreen (GTK_WINDOW (win->data));
689                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
690                                                     priv->show_toolbars_fullscreen);
691                 } else {
692                         gtk_window_unfullscreen (GTK_WINDOW (win->data));
693                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
694                                                     priv->show_toolbars);
695                 }
696                 win = g_list_next (win);
697         }
698 }
699
700 gboolean
701 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
702 {
703         ModestWindowMgrPrivate *priv;
704
705         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
706
707         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
708
709         return priv->fullscreen_mode;
710 }
711
712 void 
713 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
714                                  gboolean show_toolbars,
715                                  gboolean fullscreen)
716 {
717         ModestWindowMgrPrivate *priv;
718
719         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
720
721         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
722
723         /* If nothing changes then return. Otherwise cache it, do not
724            save to GConf for the moment, it will be done when all
725            windows become unregistered in order to avoid unnecessary
726            ModestConf calls */
727         if (fullscreen) {
728                 if (priv->show_toolbars_fullscreen == show_toolbars)
729                         return;
730                 else
731                         priv->show_toolbars_fullscreen = show_toolbars;
732         } else {
733                 if (priv->show_toolbars == show_toolbars)
734                         return;
735                 else
736                         priv->show_toolbars = show_toolbars;
737         }
738
739         /* Apply now if the view mode is the right one */
740         if ((fullscreen && priv->fullscreen_mode) ||
741             (!fullscreen && !priv->fullscreen_mode)) {
742
743                 GList *win = priv->window_list;
744
745                 while (win) {
746                         modest_window_show_toolbar (MODEST_WINDOW (win->data),
747                                                     show_toolbars);
748                         win = g_list_next (win);
749                 }
750         }
751 }
752
753 ModestWindow*  
754 modest_window_mgr_get_main_window (ModestWindowMgr *self)
755 {
756         ModestWindowMgrPrivate *priv;
757         
758         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
759         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
760         
761         /* create the main window, if it hasn't been created yet */
762         if (!priv->main_window) {
763                 /* modest_window_mgr_register_window will set priv->main_window */
764                 modest_window_mgr_register_window (self, modest_main_window_new ());
765                 g_debug ("%s: created main window: %p\n", __FUNCTION__, priv->main_window);
766         }
767         
768         return priv->main_window;
769 }
770
771
772 GtkDialog*
773 modest_window_mgr_get_easysetup_dialog (ModestWindowMgr *self)
774 {
775         ModestWindowMgrPrivate *priv;
776         
777         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
778         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
779
780         return priv->easysetup_dialog;
781 }
782
783
784 GtkDialog*
785 modest_window_mgr_set_easysetup_dialog (ModestWindowMgr *self, GtkDialog *dialog)
786 {
787         ModestWindowMgrPrivate *priv;
788         
789         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
790         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
791
792         return priv->easysetup_dialog = dialog;
793 }
794
795
796 static void
797 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
798 {
799         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
800         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
801         
802         /* Forget this window,
803          * so hibernation will be allowed again if no windows are remembered: */
804         priv->windows_that_prevent_hibernation =
805                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
806 }
807
808 static void
809 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
810 {
811         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
812         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
813         
814         GtkWindow *window = GTK_WINDOW (widget);
815         
816         priv->windows_that_prevent_hibernation = 
817                         g_slist_append (priv->windows_that_prevent_hibernation, window);
818         
819         /* Allow hibernation again when the window has been hidden: */
820         g_signal_connect (window, "hide", 
821                 G_CALLBACK (on_nonhibernating_window_hide), self);
822 }
823
824 void
825 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
826                                                                   GtkWindow *window)
827 {
828         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
829         
830         if (GTK_WIDGET_VISIBLE(window)) {
831                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
832         } else {
833                 /* Wait for it to be shown: */
834                 g_signal_connect (window, "show", 
835                         G_CALLBACK (on_nonhibernating_window_show), self);      
836         }
837 }
838
839 gboolean
840 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
841 {
842         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
843         
844         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
845         
846         /* Prevent hibernation if any open windows are currently 
847          * preventing hibernation: */
848         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
849 }
850
851
852 void
853 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
854 {
855         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
856         
857         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
858
859         /* Iterate over all windows */
860         GList *win = priv->window_list;
861         while (win) {
862                 ModestWindow *window = MODEST_WINDOW (win->data);
863                 if (window) {
864                         /* This calls the vfunc, 
865                          * so each window can do its own thing: */
866                         modest_window_save_state (window);
867                 }       
868                 
869                 win = g_list_next (win);
870         }
871 }