c49b026ebaac9f98c8f8d3318aa59e488b733f87
[modest] / src / widgets / modest-window-mgr.c
1 /* Copyright (c) 2006,2007 Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31 #include "modest-window-mgr.h"
32 #include "modest-runtime.h"
33 #include "modest-tny-folder.h"
34 #include "modest-ui-actions.h"
35 #include "modest-platform.h"
36 #include "widgets/modest-main-window.h"
37 #include "widgets/modest-msg-edit-window.h"
38 #include "widgets/modest-msg-view-window.h"
39 /* include other impl specific header files */
40
41 /* 'private'/'protected' functions */
42 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
43 static void modest_window_mgr_init       (ModestWindowMgr *obj);
44 static void modest_window_mgr_finalize   (GObject *obj);
45
46 /* static void on_window_destroy            (ModestWindow *window,  */
47 /*                                        ModestWindowMgr *self); */
48 static gboolean on_window_destroy            (ModestWindow *window,
49                                               GdkEvent *event,
50                                               ModestWindowMgr *self);
51
52 /* list my signals  */
53 enum {
54         /* MY_SIGNAL_1, */
55         /* MY_SIGNAL_2, */
56         LAST_SIGNAL
57 };
58
59 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
60 struct _ModestWindowMgrPrivate {
61         GList        *window_list;
62         ModestWindow *main_window;
63         gboolean     fullscreen_mode;
64         gboolean     show_toolbars;
65         gboolean     show_toolbars_fullscreen;
66         
67         GSList       *windows_that_prevent_hibernation;
68         GSList       *preregistered_uids;
69         GHashTable   *destroy_handlers;
70 };
71 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
72                                                MODEST_TYPE_WINDOW_MGR, \
73                                                ModestWindowMgrPrivate))
74 /* globals */
75 static GObjectClass *parent_class = NULL;
76
77 /* uncomment the following if you have defined any signals */
78 /* static guint signals[LAST_SIGNAL] = {0}; */
79
80 GType
81 modest_window_mgr_get_type (void)
82 {
83         static GType my_type = 0;
84         if (!my_type) {
85                 static const GTypeInfo my_info = {
86                         sizeof(ModestWindowMgrClass),
87                         NULL,           /* base init */
88                         NULL,           /* base finalize */
89                         (GClassInitFunc) modest_window_mgr_class_init,
90                         NULL,           /* class finalize */
91                         NULL,           /* class data */
92                         sizeof(ModestWindowMgr),
93                         1,              /* n_preallocs */
94                         (GInstanceInitFunc) modest_window_mgr_init,
95                         NULL
96                 };
97                 my_type = g_type_register_static (G_TYPE_OBJECT,
98                                                   "ModestWindowMgr",
99                                                   &my_info, 0);
100         }
101         return my_type;
102 }
103
104 static void
105 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
106 {
107         GObjectClass *gobject_class;
108         gobject_class = (GObjectClass*) klass;
109
110         parent_class            = g_type_class_peek_parent (klass);
111         gobject_class->finalize = modest_window_mgr_finalize;
112
113         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
114 }
115
116 static void
117 modest_window_mgr_init (ModestWindowMgr *obj)
118 {
119         ModestWindowMgrPrivate *priv;
120
121         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
122         priv->window_list = NULL;
123         priv->main_window = NULL;
124         priv->fullscreen_mode = FALSE;
125
126         priv->preregistered_uids = NULL;
127
128         /* Could not initialize it from gconf, singletons are not
129            ready yet */
130         priv->show_toolbars = FALSE;
131         priv->show_toolbars_fullscreen = FALSE;
132         priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
133 }
134
135 static void
136 modest_window_mgr_finalize (GObject *obj)
137 {
138         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
139
140         if (priv->window_list) {
141                 GList *iter = priv->window_list;
142                 /* unregister pending windows */
143                 while (iter) {
144                         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), 
145                                                              MODEST_WINDOW (iter->data));
146                         iter = g_list_next (iter);
147                 }
148                 g_list_free (priv->window_list);
149                 priv->window_list = NULL;
150         }
151
152         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
153         g_slist_free (priv->preregistered_uids);
154
155         
156         /* Free the hash table with the handlers */
157         if (priv->destroy_handlers) {
158                 g_hash_table_destroy (priv->destroy_handlers);
159                 priv->destroy_handlers = NULL;
160         }
161
162         /* Do not unref priv->main_window because it does not hold a
163            new reference */
164
165         G_OBJECT_CLASS(parent_class)->finalize (obj);
166 }
167
168 ModestWindowMgr*
169 modest_window_mgr_new (void)
170 {
171         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
172 }
173
174
175
176
177 /* do we have uid? */
178 static gboolean
179 has_uid (GSList *list, const gchar *uid)
180 {
181         GSList *cursor = list;
182
183         if (!uid)
184                 return FALSE;
185         
186         while (cursor) {
187                 if (cursor->data && strcmp (cursor->data, uid) == 0)
188                         return TRUE;
189                 cursor = g_slist_next (cursor);
190         }
191         return FALSE;
192 }
193
194
195 /* remove all from the list have have uid = uid */
196 static GSList*
197 remove_uid (GSList *list, const gchar *uid)
198 {
199         GSList *cursor = list, *start = list;
200         
201         if (!uid)
202                 return FALSE;
203         
204         while (cursor) {
205                 GSList *next = g_slist_next (cursor);
206                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
207                         g_free (cursor->data);
208                         start = g_slist_delete_link (start, cursor);
209                 }
210                 cursor = next;
211         }
212         return start;
213 }
214
215
216 static GSList *
217 append_uid (GSList *list, const gchar *uid)
218 {
219         return g_slist_append (list, g_strdup(uid));
220 }
221
222
223
224 void 
225 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header)
226 {
227         ModestWindowMgrPrivate *priv;
228         gchar* uid;
229         
230         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
231         g_return_if_fail (TNY_IS_HEADER(header));
232                 
233         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
234         uid = modest_tny_folder_get_header_unique_id (header);
235         
236         if (!has_uid (priv->preregistered_uids, uid))
237                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
238
239         g_free (uid);
240 }
241
242 void 
243 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
244 {
245         ModestWindowMgrPrivate *priv;
246         gchar* uid;
247         
248         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
249         g_return_if_fail (TNY_IS_HEADER(header));
250                 
251         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
252         uid = modest_tny_folder_get_header_unique_id (header);
253         
254         if (has_uid (priv->preregistered_uids, uid))
255                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
256
257         g_free (uid);
258 }
259
260 static gint
261 compare_msguids (ModestWindow *win,
262                  const gchar *uid)
263 {
264         const gchar *msg_uid;
265
266         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
267                 return 1;
268
269         /* Get message uid from msg window */
270         msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
271         
272         if (msg_uid && uid &&!strcmp (msg_uid, uid))
273                 return 0;
274         else
275                 return 1;
276 }
277
278
279
280 gboolean
281 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
282                                           ModestWindow **win)
283 {
284         ModestWindowMgrPrivate *priv;
285         gchar* uid;
286         gboolean retval = FALSE;
287         GList *item = NULL;
288
289         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
290         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
291         
292         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
293
294         uid = modest_tny_folder_get_header_unique_id (header);
295         
296         /* first, look for the window */
297         /* note, the UID cannot be in both the window list and the preregistered uid list */
298         if (priv->window_list) {
299                 item = g_list_find_custom (priv->window_list, 
300                                            uid, (GCompareFunc) compare_msguids);
301                 if (item) 
302                         retval = TRUE;
303                 if (win)
304                         *win = item ? MODEST_WINDOW(item->data) : NULL;
305         }
306         
307
308         /* IF It's not in the window list. maybe it's in our uid list... */
309         retval = retval || has_uid (priv->preregistered_uids, uid);
310
311         g_free (uid);
312
313         return retval;
314 }
315
316
317
318 void 
319 modest_window_mgr_register_window (ModestWindowMgr *self, 
320                                    ModestWindow *window)
321 {
322         static gboolean first_time = TRUE;
323         GList *win;
324         gboolean show;
325         ModestWindowMgrPrivate *priv;
326         gint *handler_id;
327
328         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
329         g_return_if_fail (MODEST_IS_WINDOW (window));
330
331         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
332
333         win = g_list_find (priv->window_list, window);
334         if (win) {
335                 g_warning ("Trying to register an already registered window");
336                 return;
337         }
338
339         /* Check that it's not a second main window */
340         if (MODEST_IS_MAIN_WINDOW (window)) {
341                 if (priv->main_window) {
342                         g_warning ("Trying to register a second main window");
343                         return;
344                 } else {
345                         priv->main_window = window;
346                 }
347         }
348
349         /* remove from the list of pre-registered uids */
350         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
351                 priv->preregistered_uids = 
352                         remove_uid (priv->preregistered_uids,
353                                     modest_msg_view_window_get_message_uid
354                                     (MODEST_MSG_VIEW_WINDOW (window)));
355         }
356         
357         /* Add to list. Keep a reference to the window */
358         g_object_ref (window);
359         priv->window_list = g_list_prepend (priv->window_list, window);
360
361         /* Listen to object destruction */
362         handler_id = g_malloc0 (sizeof (gint));
363         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
364 /*      *handler_id = g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), self); */
365         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
366
367         /* Put into fullscreen if needed */
368         if (priv->fullscreen_mode)
369                 gtk_window_fullscreen (GTK_WINDOW (window));
370
371         /* Fill caches */
372         if (first_time) {
373                 ModestConf *conf = modest_runtime_get_conf ();
374                 priv->show_toolbars = 
375                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL);
376                 priv->show_toolbars_fullscreen = 
377                         modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL);
378                 first_time = FALSE;
379         }
380
381         /* Show/hide toolbar */
382         if (priv->fullscreen_mode)
383                 show = priv->show_toolbars_fullscreen;
384         else
385                 show = priv->show_toolbars;
386         modest_window_show_toolbar (window, show);
387 }
388
389 /* static void */
390 /* on_window_destroy (ModestWindow *window, ModestWindowMgr *self) */
391 static gboolean
392 on_window_destroy (ModestWindow *window, 
393                    GdkEvent *event,
394                    ModestWindowMgr *self)
395 {
396         /* Specific stuff first */
397         if (MODEST_IS_MAIN_WINDOW (window)) {
398                 ModestWindowMgrPrivate *priv;
399                 priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
400
401                 /* If more than one window already opened */
402                 if (g_list_length (priv->window_list) > 1) {
403
404                         /* If the user wants to close all the windows */
405                         if (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) {
406                                 GList *iter = priv->window_list;
407                                 do {
408                                         if (iter->data != window) {
409                                                 GList *tmp = iter->next;
410                                                 on_window_destroy (MODEST_WINDOW (iter->data),
411                                                                    event,
412                                                                    self);
413                                                 iter = tmp;
414                                         } else {
415                                                 iter = g_list_next (iter);
416                                         }
417                                 } while (iter);
418                         }
419                 }
420         }
421         else {
422                 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
423                         gboolean sent = FALSE;
424                         gint response = GTK_RESPONSE_ACCEPT;
425                         sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
426                         /* Save currently edited message to Drafts if it was not sent */
427                         if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
428                                 
429                                 response =
430                                         modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
431                                                                                  _("mcen_nc_no_email_message_modified_save_changes"));
432                                 /* Save to drafts */
433                                 if (response != GTK_RESPONSE_CANCEL)                            
434                                         modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window));
435                                 
436                         }
437                 }
438         }
439
440         /* Save configuration state (TODO: why edit window does not require this function ?) */
441         if (!MODEST_IS_MSG_EDIT_WINDOW (window)) 
442                 modest_window_save_state (MODEST_WINDOW(window));
443
444
445         /* Unregister window */
446         modest_window_mgr_unregister_window (self, window);
447         
448         return FALSE;
449 }
450
451 void 
452 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
453                                      ModestWindow *window)
454 {
455         GList *win;
456         ModestWindowMgrPrivate *priv;
457         gint *tmp, handler_id;
458
459         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
460         g_return_if_fail (MODEST_IS_WINDOW (window));
461
462         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
463
464         win = g_list_find (priv->window_list, window);
465         if (!win) {
466                 g_warning ("Trying to unregister a window that has not being registered yet");
467                 return;
468         }
469
470         /* If it's the main window unset it */
471         if (priv->main_window == window)
472                 priv->main_window = NULL;
473
474         /* Save state */
475         modest_window_save_state (window);
476
477         /* Remove from list & hash table */
478         priv->window_list = g_list_remove_link (priv->window_list, win);
479         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
480         handler_id = *tmp;
481         g_hash_table_remove (priv->destroy_handlers, window);
482
483         /* Remove the reference to the window. Disconnect also the
484            delete-event handler, we won't need it anymore */
485         g_signal_handler_disconnect (window, handler_id);
486         gtk_widget_destroy (win->data);
487
488         /* If there are no more windows registered then exit program */
489         if (priv->window_list == NULL) {
490                 ModestConf *conf = modest_runtime_get_conf ();
491
492                 /* Save show toolbar status */
493                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, 
494                                       priv->show_toolbars_fullscreen, NULL);
495                 modest_conf_set_bool (conf, MODEST_CONF_SHOW_TOOLBAR, 
496                                       priv->show_toolbars, NULL);
497
498                 /* Quit main loop */
499                 gtk_main_quit ();
500         }
501 }
502
503 void
504 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
505                                        gboolean on)
506 {
507         ModestWindowMgrPrivate *priv;
508         GList *win = NULL;
509
510         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
511
512         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
513
514         /* If there is no change do nothing */
515         if (priv->fullscreen_mode == on)
516                 return;
517
518         priv->fullscreen_mode = on;
519
520         /* Update windows */
521         win = priv->window_list;
522         while (win) {
523                 if (on) {
524                         gtk_window_fullscreen (GTK_WINDOW (win->data));
525                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
526                                                     priv->show_toolbars_fullscreen);
527                 } else {
528                         gtk_window_unfullscreen (GTK_WINDOW (win->data));
529                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
530                                                     priv->show_toolbars);
531                 }
532                 win = g_list_next (win);
533         }
534 }
535
536 gboolean
537 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
538 {
539         ModestWindowMgrPrivate *priv;
540
541         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
542
543         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
544
545         return priv->fullscreen_mode;
546 }
547
548 void 
549 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
550                                  gboolean show_toolbars,
551                                  gboolean fullscreen)
552 {
553         ModestWindowMgrPrivate *priv;
554
555         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
556
557         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
558
559         /* If nothing changes then return. Otherwise cache it, do not
560            save to GConf for the moment, it will be done when all
561            windows become unregistered in order to avoid unnecessary
562            ModestConf calls */
563         if (fullscreen) {
564                 if (priv->show_toolbars_fullscreen == show_toolbars)
565                         return;
566                 else
567                         priv->show_toolbars_fullscreen = show_toolbars;
568         } else {
569                 if (priv->show_toolbars == show_toolbars)
570                         return;
571                 else
572                         priv->show_toolbars = show_toolbars;
573         }
574
575         /* Apply now if the view mode is the right one */
576         if ((fullscreen && priv->fullscreen_mode) ||
577             (!fullscreen && !priv->fullscreen_mode)) {
578
579                 GList *win = priv->window_list;
580
581                 while (win) {
582                         modest_window_show_toolbar (MODEST_WINDOW (win->data),
583                                                     show_toolbars);
584                         win = g_list_next (win);
585                 }
586         }
587 }
588
589 ModestWindow*  
590 modest_window_mgr_get_main_window (ModestWindowMgr *self)
591 {
592         ModestWindowMgrPrivate *priv;
593
594         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
595
596         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
597
598         return priv->main_window;
599 }
600
601 static void
602 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
603 {
604         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
605         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
606         
607         /* Forget this window,
608          * so hibernation will be allowed again if no windows are remembered: */
609         priv->windows_that_prevent_hibernation =
610                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
611 }
612
613 static void
614 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
615 {
616         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
617         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
618         
619         GtkWindow *window = GTK_WINDOW (widget);
620         
621         priv->windows_that_prevent_hibernation = 
622                         g_slist_append (priv->windows_that_prevent_hibernation, window);
623         
624         /* Allow hibernation again when the window has been hidden: */
625         g_signal_connect (window, "hide", 
626                 G_CALLBACK (on_nonhibernating_window_hide), self);
627 }
628
629 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
630                                                                   GtkWindow *window)
631 {
632         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
633         
634         if (GTK_WIDGET_VISIBLE(window)) {
635                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
636         } else {
637                 /* Wait for it to be shown: */
638                 g_signal_connect (window, "show", 
639                         G_CALLBACK (on_nonhibernating_window_show), self);      
640         }
641 }
642
643 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
644 {
645         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
646         
647         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
648         
649         /* Prevent hibernation if any open windows are currently 
650          * preventing hibernation: */
651         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
652 }
653
654
655 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
656 {
657         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
658         
659         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
660
661         /* Iterate over all windows */
662         GList *win = priv->window_list;
663         while (win) {
664                 ModestWindow *window = MODEST_WINDOW (win->data);
665                 if (window) {
666                         /* This calls the vfunc, 
667                          * so each window can do its own thing: */
668                         modest_window_save_state (window);
669                 }       
670                 
671                 win = g_list_next (win);
672         }
673 }