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