Fixes leak 19/26
[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 "modest-debug.h"
40 #include <tny-simple-list.h>
41
42
43 /* 'private'/'protected' functions */
44 static void modest_window_mgr_class_init (ModestWindowMgrClass *klass);
45 static void modest_window_mgr_init       (ModestWindowMgr *obj);
46 static void modest_window_mgr_finalize   (GObject *obj);
47
48 static gboolean modest_window_mgr_register_window_default (ModestWindowMgr *self, 
49                                                            ModestWindow *window,
50                                                            ModestWindow *parent);
51 static void modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
52                                                          ModestWindow *window);
53 static void modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
54                                                            gboolean on);
55 static gboolean modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self);
56 static void modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
57                                                      GType window_type,
58                                                      gboolean show_toolbars,
59                                                      gboolean fullscreen);
60 static ModestWindow* modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show);
61 static GtkWindow *modest_window_mgr_get_modal_default (ModestWindowMgr *self);
62 static void modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
63                                                  GtkWindow *window,
64                                                  GtkWindow *parent);
65 static gboolean modest_window_mgr_close_all_windows_default (ModestWindowMgr *self);
66 static gboolean modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, 
67                                                                   TnyHeader *header,
68                                                                   ModestWindow **win);
69 static GList *modest_window_mgr_get_window_list_default (ModestWindowMgr *self);
70 static ModestWindow *modest_window_mgr_show_initial_window_default (ModestWindowMgr *self);
71 static ModestWindow *modest_window_mgr_get_current_top_default (ModestWindowMgr *self);
72 static gboolean modest_window_mgr_screen_is_on_default (ModestWindowMgr *self);
73 static void modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
74                                                 ModestMailOperation *mail_op,
75                                                 ModestMailOperationQueueNotification type,
76                                                 ModestWindowMgr *self);
77 static void on_mail_operation_started (ModestMailOperation *mail_op,
78                                        gpointer user_data);
79 static void on_mail_operation_finished (ModestMailOperation *mail_op,
80                                         gpointer user_data);
81
82 /* list my signals  */
83 enum {
84         WINDOW_LIST_EMPTY_SIGNAL,
85         PROGRESS_LIST_CHANGED_SIGNAL,
86         NUM_SIGNALS
87 };
88
89 typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate;
90 struct _ModestWindowMgrPrivate {
91         guint         banner_counter;
92
93         ModestWindow *main_window;
94
95         GSList       *windows_that_prevent_hibernation;
96         GSList       *preregistered_uids;
97         
98         guint        closing_time;
99
100         GtkWidget    *cached_view;
101         GtkWidget    *cached_editor;
102         guint        idle_load_view_id;
103         guint        idle_load_editor_id;
104
105         guint        queue_change_handler;
106         TnyList      *progress_operations;
107         GSList       *sighandlers;
108 };
109
110 #define MODEST_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
111                                                MODEST_TYPE_WINDOW_MGR, \
112                                                ModestWindowMgrPrivate))
113 /* globals */
114 static GObjectClass *parent_class = NULL;
115
116 /* uncomment the following if you have defined any signals */
117 static guint signals[NUM_SIGNALS] = {0};
118
119 GType
120 modest_window_mgr_get_type (void)
121 {
122         static GType my_type = 0;
123         if (!my_type) {
124                 static const GTypeInfo my_info = {
125                         sizeof(ModestWindowMgrClass),
126                         NULL,           /* base init */
127                         NULL,           /* base finalize */
128                         (GClassInitFunc) modest_window_mgr_class_init,
129                         NULL,           /* class finalize */
130                         NULL,           /* class data */
131                         sizeof(ModestWindowMgr),
132                         1,              /* n_preallocs */
133                         (GInstanceInitFunc) modest_window_mgr_init,
134                         NULL
135                 };
136                 my_type = g_type_register_static (G_TYPE_OBJECT,
137                                                   "ModestWindowMgr",
138                                                   &my_info, 0);
139         }
140         return my_type;
141 }
142
143 static void
144 modest_window_mgr_class_init (ModestWindowMgrClass *klass)
145 {
146         GObjectClass *gobject_class;
147         ModestWindowMgrClass *mgr_class;
148
149         gobject_class = (GObjectClass*) klass;
150         mgr_class = (ModestWindowMgrClass *) klass;
151
152         parent_class            = g_type_class_peek_parent (klass);
153         gobject_class->finalize = modest_window_mgr_finalize;
154         mgr_class->register_window = modest_window_mgr_register_window_default;
155         mgr_class->unregister_window = modest_window_mgr_unregister_window_default;
156         mgr_class->set_fullscreen_mode = modest_window_mgr_set_fullscreen_mode_default;
157         mgr_class->get_fullscreen_mode = modest_window_mgr_get_fullscreen_mode_default;
158         mgr_class->show_toolbars = modest_window_mgr_show_toolbars_default;
159         mgr_class->get_main_window = modest_window_mgr_get_main_window_default;
160         mgr_class->get_modal = modest_window_mgr_get_modal_default;
161         mgr_class->set_modal = modest_window_mgr_set_modal_default;
162         mgr_class->close_all_windows = modest_window_mgr_close_all_windows_default;
163         mgr_class->find_registered_header = modest_window_mgr_find_registered_header_default;
164         mgr_class->get_window_list = modest_window_mgr_get_window_list_default;
165         mgr_class->show_initial_window = modest_window_mgr_show_initial_window_default;
166         mgr_class->get_current_top = modest_window_mgr_get_current_top_default;
167         mgr_class->screen_is_on = modest_window_mgr_screen_is_on_default;
168
169         g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate));
170
171
172         /**
173          * ModestWindowMgr::window-list-empty
174          * @self: the #ModestWindowMgr that emits the signal
175          * @user_data: user data set when the signal handler was connected
176          *
177          * Issued whenever the window list becomes empty
178          */
179         signals[WINDOW_LIST_EMPTY_SIGNAL] =
180                 g_signal_new ("window-list-empty",
181                               G_TYPE_FROM_CLASS (gobject_class),
182                               G_SIGNAL_RUN_FIRST,
183                               G_STRUCT_OFFSET (ModestWindowMgrClass, window_list_empty),
184                               NULL, NULL,
185                               g_cclosure_marshal_VOID__VOID,
186                               G_TYPE_NONE, 0);
187
188         /**
189          * ModestWindowMgr::progress-list-changed
190          * @self: the #ModestWindowMgr that emits the signal
191          * @user_data: user data set when the signal handler was connected
192          *
193          * Issued whenever the progress mail operations list becomes changed
194          */
195         signals[PROGRESS_LIST_CHANGED_SIGNAL] =
196                 g_signal_new ("progress-list-changed",
197                               G_TYPE_FROM_CLASS (gobject_class),
198                               G_SIGNAL_RUN_FIRST,
199                               G_STRUCT_OFFSET (ModestWindowMgrClass, progress_list_changed),
200                               NULL, NULL,
201                               g_cclosure_marshal_VOID__VOID,
202                               G_TYPE_NONE, 0);
203 }
204
205 static gboolean
206 idle_load_view (ModestWindowMgr *mgr)
207 {
208         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
209         
210         priv->cached_view = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
211         priv->idle_load_view_id = 0;
212         return FALSE;
213 }
214
215 static gboolean
216 idle_load_editor (ModestWindowMgr *mgr)
217 {
218         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr);
219         
220         priv->cached_editor = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
221         priv->idle_load_editor_id = 0;
222         return FALSE;
223 }
224
225 static void
226 load_new_view (ModestWindowMgr *self)
227 {
228         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
229         if ((priv->cached_view == NULL) && (priv->idle_load_view_id == 0))
230                 priv->idle_load_view_id = g_idle_add ((GSourceFunc) idle_load_view, self);
231 }
232
233 static void
234 load_new_editor (ModestWindowMgr *self)
235 {
236         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
237         if ((priv->cached_editor == NULL) && (priv->idle_load_editor_id == 0))
238                 priv->idle_load_editor_id = g_idle_add ((GSourceFunc) idle_load_editor, self);
239 }
240
241 static void
242 modest_window_mgr_init (ModestWindowMgr *obj)
243 {
244         ModestWindowMgrPrivate *priv;
245
246         priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
247         priv->banner_counter = 0;
248         priv->main_window = NULL;
249
250         priv->preregistered_uids = NULL;
251
252         priv->closing_time = 0;
253
254         priv->cached_view = NULL;
255         priv->cached_editor = NULL;
256
257         priv->windows_that_prevent_hibernation = NULL;
258
259         priv->queue_change_handler = 0;
260         priv->progress_operations = TNY_LIST (tny_simple_list_new ());
261 }
262
263 static void
264 modest_window_mgr_finalize (GObject *obj)
265 {
266         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj);
267
268         if (priv->idle_load_view_id > 0) {
269                 g_source_remove (priv->idle_load_view_id);
270                 priv->idle_load_view_id = 0;
271         }
272         
273         if (priv->idle_load_editor_id > 0) {
274                 g_source_remove (priv->idle_load_editor_id);
275                 priv->idle_load_editor_id = 0;
276         }
277         
278         if (priv->cached_view) {
279                 gtk_widget_destroy (priv->cached_view);
280                 priv->cached_view = NULL;
281         }
282         if (priv->cached_editor) {
283                 gtk_widget_destroy (priv->cached_editor);
284                 priv->cached_editor = NULL;
285         }
286
287         if (priv->windows_that_prevent_hibernation) {
288                 g_slist_free (priv->windows_that_prevent_hibernation);
289                 priv->cached_editor = NULL;
290         }
291
292         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
293         priv->sighandlers = NULL;
294
295         if (priv->queue_change_handler > 0) {
296                 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
297                                              priv->queue_change_handler);
298                 priv->queue_change_handler = 0;
299         }
300
301         if (priv->progress_operations) {
302                 g_object_unref (priv->progress_operations);
303                 priv->progress_operations = NULL;
304         }
305
306         g_slist_foreach (priv->preregistered_uids, (GFunc)g_free, NULL);
307         g_slist_free (priv->preregistered_uids);
308
309         G_OBJECT_CLASS(parent_class)->finalize (obj);
310 }
311
312 ModestWindowMgr*
313 modest_window_mgr_new (void)
314 {
315         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_WINDOW_MGR, NULL));
316 }
317
318
319
320
321 /* do we have uid? */
322 static gboolean
323 has_uid (GSList *list, const gchar *uid)
324 {
325         GSList *cursor = list;
326
327         if (!uid)
328                 return FALSE;
329         
330         while (cursor) {
331                 if (cursor->data && strcmp (cursor->data, uid) == 0)
332                         return TRUE;
333                 cursor = g_slist_next (cursor);
334         }
335         return FALSE;
336 }
337
338
339 /* remove all from the list have have uid = uid */
340 static GSList*
341 remove_uid (GSList *list, const gchar *uid)
342 {
343         GSList *cursor = list, *start = list;
344         
345         if (!uid)
346                 return list;
347         
348         while (cursor) {
349                 GSList *next = g_slist_next (cursor);
350                 if (cursor->data && strcmp (cursor->data, uid) == 0) {
351                         g_free (cursor->data);
352                         start = g_slist_delete_link (start, cursor);
353                 }
354                 cursor = next;
355         }
356         return start;
357 }
358
359
360 static GSList *
361 append_uid (GSList *list, const gchar *uid)
362 {
363         return g_slist_append (list, g_strdup(uid));
364 }
365
366
367
368 void 
369 modest_window_mgr_register_header (ModestWindowMgr *self,  TnyHeader *header, const gchar *alt_uid)
370 {
371         ModestWindowMgrPrivate *priv;
372         gchar* uid;
373         
374         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
375         g_return_if_fail (TNY_IS_HEADER(header));
376                 
377         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
378         uid = modest_tny_folder_get_header_unique_id (header);
379
380         if (uid == NULL)
381                 uid = g_strdup (alt_uid);
382         
383         if (!has_uid (priv->preregistered_uids, uid)) {
384                 MODEST_DEBUG_BLOCK(g_debug ("registering new uid %s", uid););
385                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
386         } else
387                 MODEST_DEBUG_BLOCK(g_debug ("already had uid %s", uid););
388         
389         g_free (uid);
390 }
391
392 void 
393 modest_window_mgr_unregister_header (ModestWindowMgr *self,  TnyHeader *header)
394 {
395         ModestWindowMgrPrivate *priv;
396         gchar* uid;
397         
398         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
399         g_return_if_fail (TNY_IS_HEADER(header));
400                 
401         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
402         uid = modest_tny_folder_get_header_unique_id (header);
403
404         if (!has_uid (priv->preregistered_uids, uid)) {
405                 MODEST_DEBUG_BLOCK(g_debug ("trying to unregister non-existing uid %s", uid););
406                 priv->preregistered_uids = append_uid (priv->preregistered_uids, uid);
407         } else
408                 MODEST_DEBUG_BLOCK(g_debug ("unregistering uid %s", uid););
409         
410         if (has_uid (priv->preregistered_uids, uid)) {
411                 priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid);
412                 if (has_uid (priv->preregistered_uids, uid))
413                         g_debug ("BUG: uid %s NOT removed", uid);
414                 else
415                         MODEST_DEBUG_BLOCK(g_debug ("uid %s removed", uid););
416         }
417                 
418         g_free (uid);
419 }
420
421
422 #define MODEST_WINDOW_HELP_ID_PARAM "help-id"
423
424 void
425 modest_window_mgr_register_help_id (ModestWindowMgr *self, GtkWindow *win, const gchar* help_id)
426 {
427         /* we don't need 'self', but for API consistency... */
428         g_return_if_fail (self && MODEST_IS_WINDOW_MGR(self));
429
430         g_return_if_fail (win && GTK_IS_WINDOW(win));
431         g_return_if_fail (help_id);
432         
433         g_object_set_data_full (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM,
434                                 g_strdup(help_id), g_free);
435 }
436
437
438 const gchar*
439 modest_window_mgr_get_help_id (ModestWindowMgr *self, GtkWindow *win)
440 {
441         /* we don't need 'self', but for API consistency... */
442         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR (self), NULL);
443         g_return_val_if_fail (win, NULL);
444
445         return g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM);
446 }
447
448 gboolean
449 modest_window_mgr_close_all_windows (ModestWindowMgr *self)
450 {
451         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_windows (self);
452 }
453
454 static gboolean
455 modest_window_mgr_close_all_windows_default (ModestWindowMgr *self)
456 {
457         return TRUE;
458 }
459
460
461 gboolean
462 modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
463                                                   ModestWindow **win)
464 {
465         return MODEST_WINDOW_MGR_GET_CLASS (self)->find_registered_header (self, header, win);
466 }
467
468 static gboolean
469 modest_window_mgr_find_registered_header_default (ModestWindowMgr *self, TnyHeader *header,
470                                                   ModestWindow **win)
471 {
472         ModestWindowMgrPrivate *priv = NULL;
473         gchar* uid = NULL;
474         gboolean has_header = FALSE;
475
476         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
477         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
478
479         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
480
481         uid = modest_tny_folder_get_header_unique_id (header);
482
483         if (win)
484                 *win = NULL;
485
486         has_header = has_uid (priv->preregistered_uids, uid);
487         g_free (uid);
488
489         return has_header;
490 }
491
492 GList *
493 modest_window_mgr_get_window_list (ModestWindowMgr *self)
494 {
495         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_window_list (self);
496 }
497
498 static GList *
499 modest_window_mgr_get_window_list_default (ModestWindowMgr *self)
500 {
501         return NULL;
502 }
503
504 gboolean
505 modest_window_mgr_register_window (ModestWindowMgr *self, 
506                                    ModestWindow *window,
507                                    ModestWindow *parent)
508 {
509         return MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
510 }
511
512 static gboolean
513 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
514                                            ModestWindow *window,
515                                            ModestWindow *parent)
516 {
517         ModestWindowMgrPrivate *priv;
518
519         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
520         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
521
522         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
523
524         /* We set up the queue change handler */
525         if (priv->queue_change_handler == 0) {
526                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
527                                                                "queue-changed",
528                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
529                                                                self);
530         }
531
532         /* Check that it's not a second main window */
533         if (MODEST_IS_MAIN_WINDOW (window)) {
534                 if (priv->main_window) {
535                         g_warning ("%s: trying to register a second main window",
536                                    __FUNCTION__);
537                         return FALSE;
538                 } else {
539                         priv->main_window = window;
540                         load_new_view (self);
541                         load_new_editor (self);
542                 }
543         }
544
545         /* remove from the list of pre-registered uids */
546         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
547                 const gchar *uid = modest_msg_view_window_get_message_uid
548                         (MODEST_MSG_VIEW_WINDOW (window));
549
550                 if (!has_uid (priv->preregistered_uids, uid)) 
551                         g_debug ("weird: no uid for window (%s)", uid);
552                 
553                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
554                 
555                 priv->preregistered_uids = 
556                         remove_uid (priv->preregistered_uids,
557                                     modest_msg_view_window_get_message_uid
558                                     (MODEST_MSG_VIEW_WINDOW (window)));
559         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
560                 const gchar *uid = modest_msg_edit_window_get_message_uid
561                         (MODEST_MSG_EDIT_WINDOW (window));
562                 
563                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
564
565                 priv->preregistered_uids = 
566                         remove_uid (priv->preregistered_uids,
567                                     modest_msg_edit_window_get_message_uid
568                                     (MODEST_MSG_EDIT_WINDOW (window)));
569         }
570
571         return TRUE;
572 }
573
574 void 
575 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
576                                      ModestWindow *window)
577 {
578         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
579 }
580
581 static void 
582 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
583                                              ModestWindow *window)
584 {
585         ModestWindowMgrPrivate *priv;
586
587         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
588         g_return_if_fail (MODEST_IS_WINDOW (window));
589
590         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
591
592         /* Save state */
593         modest_window_save_state (window);
594
595         /* Disconnect all the window signals */
596         modest_window_disconnect_signals (window);
597         
598         /* Destroy the window */
599         gtk_widget_destroy (GTK_WIDGET (window));
600 }
601
602
603
604 void
605 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
606                                        gboolean on)
607 {
608         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
609 }
610
611 static void
612 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
613                                                gboolean on)
614 {
615         return;
616 }
617
618 gboolean
619 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
620 {
621         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
622 }
623
624 static gboolean
625 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
626 {
627         return FALSE;
628 }
629
630 void 
631 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
632                                  GType window_type,
633                                  gboolean show_toolbars,
634                                  gboolean fullscreen)
635 {
636         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
637 }
638
639 static void 
640 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
641                                          GType window_type,
642                                          gboolean show_toolbars,
643                                          gboolean fullscreen)
644 {
645         return;
646 }
647
648 void
649 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
650 {
651         ModestWindowMgrPrivate *priv;
652         
653         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
654
655         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
656         priv->main_window = win;
657 }
658
659 ModestWindow*  
660 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
661 {
662         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
663 }
664
665 static ModestWindow*  
666 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
667 {
668         ModestWindowMgrPrivate *priv;
669         
670         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
671
672         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
673         if (priv->main_window)
674                 return priv->main_window;
675
676         if (show) 
677                 return modest_main_window_new ();
678         else return NULL;
679 }
680
681
682 gboolean
683 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
684 {
685         ModestWindowMgrPrivate *priv;
686         
687         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
688         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
689
690         return priv->main_window != NULL;
691 }
692
693
694 GtkWindow *
695 modest_window_mgr_get_modal (ModestWindowMgr *self)
696 {
697         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
698 }
699
700 static GtkWindow *
701 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
702 {
703         return NULL;
704 }
705
706
707 void
708 modest_window_mgr_set_modal (ModestWindowMgr *self, 
709                              GtkWindow *window,
710                              GtkWindow *parent)
711 {
712         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
713 }
714
715 static void
716 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
717                                      GtkWindow *window,
718                                      GtkWindow *parent)
719 {
720         return;
721 }
722
723
724 static void
725 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
726 {
727         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
728         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
729         
730         /* Forget this window,
731          * so hibernation will be allowed again if no windows are remembered: */
732         priv->windows_that_prevent_hibernation =
733                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
734 }
735
736 static void
737 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
738 {
739         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
740         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
741         
742         GtkWindow *window = GTK_WINDOW (widget);
743         
744         priv->windows_that_prevent_hibernation = 
745                         g_slist_append (priv->windows_that_prevent_hibernation, window);
746         
747         /* Allow hibernation again when the window has been hidden: */
748         g_signal_connect (window, "hide", 
749                 G_CALLBACK (on_nonhibernating_window_hide), self);
750 }
751
752 void
753 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
754                                                                   GtkWindow *window)
755 {
756         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
757         
758         if (GTK_WIDGET_VISIBLE(window)) {
759                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
760         } else {
761                 /* Wait for it to be shown: */
762                 g_signal_connect (window, "show", 
763                         G_CALLBACK (on_nonhibernating_window_show), self);      
764         }
765 }
766
767 gboolean
768 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
769 {
770         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
771         
772         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
773         
774         /* Prevent hibernation if any open windows are currently 
775          * preventing hibernation: */
776         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
777 }
778
779
780 void
781 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
782 {
783         GList *window_list;
784         GList *node;
785         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
786         
787         /* Iterate over all windows */
788         window_list = modest_window_mgr_get_window_list (self);
789         node = window_list;
790         while (node) {
791                 ModestWindow *window = MODEST_WINDOW (node->data);
792                 if (window) {
793                         /* This calls the vfunc, 
794                          * so each window can do its own thing: */
795                         modest_window_save_state (window);
796                 }
797
798                 node = g_list_next (node);
799         }
800         g_list_free (window_list);
801 }
802
803 guint
804 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
805 {
806         ModestWindowMgrPrivate *priv;
807         gint num_windows = 0;
808         GList *window_list;
809
810         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
811
812         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
813
814         window_list = modest_window_mgr_get_window_list (self);
815
816         if (window_list) {
817                 num_windows = g_list_length (window_list);
818                 g_list_free (window_list);
819         }
820
821         /* Do not take into account the main window if it was hidden */
822         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
823                 num_windows--;
824
825         return num_windows + priv->banner_counter;
826 }
827
828 GtkWidget *   
829 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
830 {
831         GtkWidget *result;
832         ModestWindowMgrPrivate *priv;
833
834         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
835
836         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
837                 
838         if (priv->cached_editor) {
839                 result = priv->cached_editor;
840                 priv->cached_editor = NULL;
841                 load_new_editor (self);
842         } else {
843                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
844         }
845
846         return result;
847 }
848
849 GtkWidget *   
850 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
851 {
852         GtkWidget *result;
853         ModestWindowMgrPrivate *priv;
854
855         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
856         
857         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
858
859         if (priv->cached_view) {
860                 result = priv->cached_view;
861                 priv->cached_view = NULL;
862                 load_new_view (self);
863         } else {
864                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
865         }
866
867         return result;
868 }
869
870 void
871 modest_window_mgr_register_banner (ModestWindowMgr *self)
872 {
873         ModestWindowMgrPrivate *priv;
874
875         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
876         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
877
878         priv->banner_counter++;
879 }
880
881 void
882 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
883 {
884         ModestWindowMgrPrivate *priv;
885
886         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
887         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
888
889         priv->banner_counter--;
890         if (modest_window_mgr_get_num_windows (self) == 0)
891                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
892 }
893
894 ModestWindow *
895 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
896 {
897         ModestWindow *window = NULL;
898
899         /* Call the children */
900         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
901
902         if (window) {
903                 ModestAccountMgr *mgr;
904
905                 /* Show the initial window */
906                 gtk_widget_show (GTK_WIDGET (window));
907
908                 /* If there are no accounts then show the account wizard */
909                 mgr = modest_runtime_get_account_mgr();
910                 if (!modest_account_mgr_has_accounts (mgr, TRUE))
911                         modest_ui_actions_run_account_setup_wizard (window);
912         }
913
914         return window;
915 }
916
917 static ModestWindow *
918 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
919 {
920         /* By default it returns the main window creating it if
921            needed */
922         return modest_window_mgr_get_main_window (self, TRUE);
923 }
924
925
926 ModestWindow *
927 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
928 {
929         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
930 }
931
932
933 static ModestWindow *
934 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
935 {
936         g_return_val_if_reached (NULL);
937 }
938
939 gboolean
940 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
941 {
942         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
943 }
944
945 static gboolean
946 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
947 {
948         /* Default implementation is assuming screen is always on */
949
950         return TRUE;
951 }
952
953 static gboolean
954 tny_list_find (TnyList *list, GObject *item)
955 {
956         TnyIterator *iterator;
957         gboolean found = FALSE;
958
959         for (iterator = tny_list_create_iterator (list);
960              !tny_iterator_is_done (iterator) && !found;
961              tny_iterator_next (iterator)) {
962                 GObject *current = tny_iterator_get_current (iterator);
963                 if (current == item)
964                         found = TRUE;
965                 g_object_unref (current);
966         }
967         g_object_unref (iterator);
968         
969         return found;
970 }
971
972 static void
973 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
974                                     ModestMailOperation *mail_op,
975                                     ModestMailOperationQueueNotification type,
976                                     ModestWindowMgr *self)
977 {       
978         ModestWindowMgrPrivate *priv;
979
980         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
981
982         /* We register to track progress */
983         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
984                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
985                                                                G_OBJECT (mail_op),
986                                                                "operation-started",
987                                                                G_CALLBACK (on_mail_operation_started),
988                                                                self);
989                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
990                                                                G_OBJECT (mail_op),
991                                                                "operation-finished",
992                                                                G_CALLBACK (on_mail_operation_finished),
993                                                                self);
994         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
995                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
996                                                                   G_OBJECT (mail_op),
997                                                                   "operation-started");
998                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
999                                                                   G_OBJECT (mail_op),
1000                                                                   "operation-finished");
1001                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
1002                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1003                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1004                 }
1005         }
1006 }
1007
1008 static void 
1009 on_mail_operation_started (ModestMailOperation *mail_op,
1010                            gpointer user_data)
1011 {
1012         ModestWindowMgr *self;
1013         ModestWindowMgrPrivate *priv;
1014         ModestMailOperationTypeOperation op_type;
1015
1016         self = MODEST_WINDOW_MGR (user_data);
1017         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1018
1019         /* First we check if the operation is a send receive operation,
1020          * If now, we don't handle this */
1021         op_type = modest_mail_operation_get_type_operation (mail_op);
1022         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1023             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1024                 return;
1025         }
1026
1027         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1028                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1029                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1030         }
1031 }
1032
1033 static void 
1034 on_mail_operation_finished (ModestMailOperation *mail_op,
1035                             gpointer user_data)
1036 {
1037         ModestWindowMgr *self;
1038         ModestWindowMgrPrivate *priv;
1039
1040         self = MODEST_WINDOW_MGR (user_data);
1041         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1042
1043         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1044                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1045                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1046         }
1047 }
1048
1049 TnyList *
1050 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1051 {
1052         ModestWindowMgrPrivate *priv;
1053
1054         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1055
1056         return tny_list_copy (priv->progress_operations);
1057 }
1058
1059 gboolean 
1060 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1061 {
1062         ModestWindowMgrPrivate *priv;
1063
1064         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1065
1066         return tny_list_get_length (priv->progress_operations) > 0;
1067 }
1068
1069 gboolean 
1070 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1071                                                      const gchar *account_name)
1072 {
1073         ModestWindowMgrPrivate *priv;
1074         gint account_ops = 0;
1075         TnyIterator *iterator;
1076
1077         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1078
1079         if (account_name == NULL)
1080                 return 0;
1081
1082         for (iterator = tny_list_create_iterator (priv->progress_operations);
1083              !tny_iterator_is_done (iterator);
1084              tny_iterator_next (iterator)) {
1085                 ModestMailOperation *mail_op; 
1086                 TnyAccount *account;
1087
1088                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1089                 account = modest_mail_operation_get_account (mail_op);
1090
1091                 if (account != NULL) {
1092                         const gchar *current_name;
1093
1094                         current_name = tny_account_get_id (account);
1095                         if (current_name && strcmp (current_name, account_name) == 0)
1096                                 account_ops ++;
1097                         g_object_unref (account);
1098                 }
1099
1100                 g_object_unref (mail_op);
1101         }
1102         g_object_unref (iterator);
1103
1104         return account_ops;
1105 }