ca27a2c41e9bc1a6c2b520acaa5ae41e46accf10
[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_yes_no_dialog (GTK_WINDOW (window),
431                                                                            _("mcen_nc_no_email_message_modified_save_changes"));
432                                 /* Save to drafts */
433                                 if (response != GTK_RESPONSE_NO)                                
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                 /* FIXME: do we ever need to do this here? */
500                 if (gtk_main_level() > 0)
501                         gtk_main_quit ();
502         }
503 }
504
505 void
506 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
507                                        gboolean on)
508 {
509         ModestWindowMgrPrivate *priv;
510         GList *win = NULL;
511
512         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
513
514         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
515
516         /* If there is no change do nothing */
517         if (priv->fullscreen_mode == on)
518                 return;
519
520         priv->fullscreen_mode = on;
521
522         /* Update windows */
523         win = priv->window_list;
524         while (win) {
525                 if (on) {
526                         gtk_window_fullscreen (GTK_WINDOW (win->data));
527                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
528                                                     priv->show_toolbars_fullscreen);
529                 } else {
530                         gtk_window_unfullscreen (GTK_WINDOW (win->data));
531                         modest_window_show_toolbar (MODEST_WINDOW (win->data), 
532                                                     priv->show_toolbars);
533                 }
534                 win = g_list_next (win);
535         }
536 }
537
538 gboolean
539 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
540 {
541         ModestWindowMgrPrivate *priv;
542
543         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
544
545         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
546
547         return priv->fullscreen_mode;
548 }
549
550 void 
551 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
552                                  gboolean show_toolbars,
553                                  gboolean fullscreen)
554 {
555         ModestWindowMgrPrivate *priv;
556
557         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
558
559         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
560
561         /* If nothing changes then return. Otherwise cache it, do not
562            save to GConf for the moment, it will be done when all
563            windows become unregistered in order to avoid unnecessary
564            ModestConf calls */
565         if (fullscreen) {
566                 if (priv->show_toolbars_fullscreen == show_toolbars)
567                         return;
568                 else
569                         priv->show_toolbars_fullscreen = show_toolbars;
570         } else {
571                 if (priv->show_toolbars == show_toolbars)
572                         return;
573                 else
574                         priv->show_toolbars = show_toolbars;
575         }
576
577         /* Apply now if the view mode is the right one */
578         if ((fullscreen && priv->fullscreen_mode) ||
579             (!fullscreen && !priv->fullscreen_mode)) {
580
581                 GList *win = priv->window_list;
582
583                 while (win) {
584                         modest_window_show_toolbar (MODEST_WINDOW (win->data),
585                                                     show_toolbars);
586                         win = g_list_next (win);
587                 }
588         }
589 }
590
591 ModestWindow*  
592 modest_window_mgr_get_main_window (ModestWindowMgr *self)
593 {
594         ModestWindowMgrPrivate *priv;
595
596         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
597
598         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
599
600         return priv->main_window;
601 }
602
603 static void
604 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
605 {
606         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
607         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
608         
609         /* Forget this window,
610          * so hibernation will be allowed again if no windows are remembered: */
611         priv->windows_that_prevent_hibernation =
612                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
613 }
614
615 static void
616 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
617 {
618         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
619         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
620         
621         GtkWindow *window = GTK_WINDOW (widget);
622         
623         priv->windows_that_prevent_hibernation = 
624                         g_slist_append (priv->windows_that_prevent_hibernation, window);
625         
626         /* Allow hibernation again when the window has been hidden: */
627         g_signal_connect (window, "hide", 
628                 G_CALLBACK (on_nonhibernating_window_hide), self);
629 }
630
631 void modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
632                                                                   GtkWindow *window)
633 {
634         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
635         
636         if (GTK_WIDGET_VISIBLE(window)) {
637                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
638         } else {
639                 /* Wait for it to be shown: */
640                 g_signal_connect (window, "show", 
641                         G_CALLBACK (on_nonhibernating_window_show), self);      
642         }
643 }
644
645 gboolean modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
646 {
647         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
648         
649         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
650         
651         /* Prevent hibernation if any open windows are currently 
652          * preventing hibernation: */
653         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
654 }
655
656
657 void modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
658 {
659         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
660         
661         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
662
663         /* Iterate over all windows */
664         GList *win = priv->window_list;
665         while (win) {
666                 ModestWindow *window = MODEST_WINDOW (win->data);
667                 if (window) {
668                         /* This calls the vfunc, 
669                          * so each window can do its own thing: */
670                         modest_window_save_state (window);
671                 }       
672                 
673                 win = g_list_next (win);
674         }
675 }