Added progress hint support in folder window.
[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
488         return has_header;
489 }
490
491 GList *
492 modest_window_mgr_get_window_list (ModestWindowMgr *self)
493 {
494         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_window_list (self);
495 }
496
497 static GList *
498 modest_window_mgr_get_window_list_default (ModestWindowMgr *self)
499 {
500         return NULL;
501 }
502
503 gboolean
504 modest_window_mgr_register_window (ModestWindowMgr *self, 
505                                    ModestWindow *window,
506                                    ModestWindow *parent)
507 {
508         return MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
509 }
510
511 static gboolean
512 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
513                                            ModestWindow *window,
514                                            ModestWindow *parent)
515 {
516         ModestWindowMgrPrivate *priv;
517
518         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
519         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
520
521         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
522
523         /* We set up the queue change handler */
524         if (priv->queue_change_handler == 0) {
525                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
526                                                                "queue-changed",
527                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
528                                                                self);
529         }
530
531         /* Check that it's not a second main window */
532         if (MODEST_IS_MAIN_WINDOW (window)) {
533                 if (priv->main_window) {
534                         g_warning ("%s: trying to register a second main window",
535                                    __FUNCTION__);
536                         return FALSE;
537                 } else {
538                         priv->main_window = window;
539                         load_new_view (self);
540                         load_new_editor (self);
541                 }
542         }
543
544         /* remove from the list of pre-registered uids */
545         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
546                 const gchar *uid = modest_msg_view_window_get_message_uid
547                         (MODEST_MSG_VIEW_WINDOW (window));
548
549                 if (!has_uid (priv->preregistered_uids, uid)) 
550                         g_debug ("weird: no uid for window (%s)", uid);
551                 
552                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
553                 
554                 priv->preregistered_uids = 
555                         remove_uid (priv->preregistered_uids,
556                                     modest_msg_view_window_get_message_uid
557                                     (MODEST_MSG_VIEW_WINDOW (window)));
558         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
559                 const gchar *uid = modest_msg_edit_window_get_message_uid
560                         (MODEST_MSG_EDIT_WINDOW (window));
561                 
562                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
563
564                 priv->preregistered_uids = 
565                         remove_uid (priv->preregistered_uids,
566                                     modest_msg_edit_window_get_message_uid
567                                     (MODEST_MSG_EDIT_WINDOW (window)));
568         }
569
570         return TRUE;
571 }
572
573 void 
574 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
575                                      ModestWindow *window)
576 {
577         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
578 }
579
580 static void 
581 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
582                                              ModestWindow *window)
583 {
584         ModestWindowMgrPrivate *priv;
585
586         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
587         g_return_if_fail (MODEST_IS_WINDOW (window));
588
589         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
590
591         /* Save state */
592         modest_window_save_state (window);
593
594         /* Disconnect all the window signals */
595         modest_window_disconnect_signals (window);
596         
597         /* Destroy the window */
598         gtk_widget_destroy (GTK_WIDGET (window));
599 }
600
601
602
603 void
604 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
605                                        gboolean on)
606 {
607         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
608 }
609
610 static void
611 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
612                                                gboolean on)
613 {
614         return;
615 }
616
617 gboolean
618 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
619 {
620         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
621 }
622
623 static gboolean
624 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
625 {
626         return FALSE;
627 }
628
629 void 
630 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
631                                  GType window_type,
632                                  gboolean show_toolbars,
633                                  gboolean fullscreen)
634 {
635         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
636 }
637
638 static void 
639 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
640                                          GType window_type,
641                                          gboolean show_toolbars,
642                                          gboolean fullscreen)
643 {
644         return;
645 }
646
647 void
648 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
649 {
650         ModestWindowMgrPrivate *priv;
651         
652         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
653
654         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
655         priv->main_window = win;
656 }
657
658 ModestWindow*  
659 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
660 {
661         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
662 }
663
664 static ModestWindow*  
665 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
666 {
667         ModestWindowMgrPrivate *priv;
668         
669         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
670
671         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
672         if (priv->main_window)
673                 return priv->main_window;
674
675         if (show) 
676                 return modest_main_window_new ();
677         else return NULL;
678 }
679
680
681 gboolean
682 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
683 {
684         ModestWindowMgrPrivate *priv;
685         
686         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
687         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
688
689         return priv->main_window != NULL;
690 }
691
692
693 GtkWindow *
694 modest_window_mgr_get_modal (ModestWindowMgr *self)
695 {
696         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
697 }
698
699 static GtkWindow *
700 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
701 {
702         return NULL;
703 }
704
705
706 void
707 modest_window_mgr_set_modal (ModestWindowMgr *self, 
708                              GtkWindow *window,
709                              GtkWindow *parent)
710 {
711         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
712 }
713
714 static void
715 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
716                                      GtkWindow *window,
717                                      GtkWindow *parent)
718 {
719         return;
720 }
721
722
723 static void
724 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
725 {
726         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
727         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
728         
729         /* Forget this window,
730          * so hibernation will be allowed again if no windows are remembered: */
731         priv->windows_that_prevent_hibernation =
732                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
733 }
734
735 static void
736 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
737 {
738         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
739         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
740         
741         GtkWindow *window = GTK_WINDOW (widget);
742         
743         priv->windows_that_prevent_hibernation = 
744                         g_slist_append (priv->windows_that_prevent_hibernation, window);
745         
746         /* Allow hibernation again when the window has been hidden: */
747         g_signal_connect (window, "hide", 
748                 G_CALLBACK (on_nonhibernating_window_hide), self);
749 }
750
751 void
752 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
753                                                                   GtkWindow *window)
754 {
755         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
756         
757         if (GTK_WIDGET_VISIBLE(window)) {
758                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
759         } else {
760                 /* Wait for it to be shown: */
761                 g_signal_connect (window, "show", 
762                         G_CALLBACK (on_nonhibernating_window_show), self);      
763         }
764 }
765
766 gboolean
767 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
768 {
769         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
770         
771         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
772         
773         /* Prevent hibernation if any open windows are currently 
774          * preventing hibernation: */
775         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
776 }
777
778
779 void
780 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
781 {
782         GList *window_list;
783         GList *node;
784         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
785         
786         /* Iterate over all windows */
787         window_list = modest_window_mgr_get_window_list (self);
788         node = window_list;
789         while (node) {
790                 ModestWindow *window = MODEST_WINDOW (node->data);
791                 if (window) {
792                         /* This calls the vfunc, 
793                          * so each window can do its own thing: */
794                         modest_window_save_state (window);
795                 }
796
797                 node = g_list_next (node);
798         }
799         g_list_free (window_list);
800 }
801
802 guint
803 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
804 {
805         ModestWindowMgrPrivate *priv;
806         gint num_windows = 0;
807         GList *window_list;
808
809         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
810
811         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
812
813         window_list = modest_window_mgr_get_window_list (self);
814
815         if (window_list) {
816                 num_windows = g_list_length (window_list);
817                 g_list_free (window_list);
818         }
819
820         /* Do not take into account the main window if it was hidden */
821         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
822                 num_windows--;
823
824         return num_windows + priv->banner_counter;
825 }
826
827 GtkWidget *   
828 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
829 {
830         GtkWidget *result;
831         ModestWindowMgrPrivate *priv;
832
833         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
834
835         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
836                 
837         if (priv->cached_editor) {
838                 result = priv->cached_editor;
839                 priv->cached_editor = NULL;
840                 load_new_editor (self);
841         } else {
842                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
843         }
844
845         return result;
846 }
847
848 GtkWidget *   
849 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
850 {
851         GtkWidget *result;
852         ModestWindowMgrPrivate *priv;
853
854         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
855         
856         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
857
858         if (priv->cached_view) {
859                 result = priv->cached_view;
860                 priv->cached_view = NULL;
861                 load_new_view (self);
862         } else {
863                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
864         }
865
866         return result;
867 }
868
869 void
870 modest_window_mgr_register_banner (ModestWindowMgr *self)
871 {
872         ModestWindowMgrPrivate *priv;
873
874         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
875         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
876
877         priv->banner_counter++;
878 }
879
880 void
881 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
882 {
883         ModestWindowMgrPrivate *priv;
884
885         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
886         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
887
888         priv->banner_counter--;
889         if (modest_window_mgr_get_num_windows (self) == 0)
890                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
891 }
892
893 ModestWindow *
894 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
895 {
896         ModestWindow *window = NULL;
897
898         /* Call the children */
899         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
900
901         if (window) {
902                 ModestAccountMgr *mgr;
903
904                 /* Show the initial window */
905                 gtk_widget_show (GTK_WIDGET (window));
906
907                 /* If there are no accounts then show the account wizard */
908                 mgr = modest_runtime_get_account_mgr();
909                 if (!modest_account_mgr_has_accounts (mgr, TRUE))
910                         modest_ui_actions_run_account_setup_wizard (window);
911         }
912
913         return window;
914 }
915
916 static ModestWindow *
917 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
918 {
919         /* By default it returns the main window creating it if
920            needed */
921         return modest_window_mgr_get_main_window (self, TRUE);
922 }
923
924
925 ModestWindow *
926 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
927 {
928         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
929 }
930
931
932 static ModestWindow *
933 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
934 {
935         g_return_val_if_reached (NULL);
936 }
937
938 gboolean
939 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
940 {
941         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
942 }
943
944 static gboolean
945 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
946 {
947         /* Default implementation is assuming screen is always on */
948
949         return TRUE;
950 }
951
952 static gboolean
953 tny_list_find (TnyList *list, GObject *item)
954 {
955         TnyIterator *iterator;
956         gboolean found = FALSE;
957
958         for (iterator = tny_list_create_iterator (list);
959              !tny_iterator_is_done (iterator) && !found;
960              tny_iterator_next (iterator)) {
961                 GObject *current = tny_iterator_get_current (iterator);
962                 if (current == item)
963                         found = TRUE;
964                 g_object_unref (current);
965         }
966         g_object_unref (iterator);
967         
968         return found;
969 }
970
971 static void
972 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
973                                     ModestMailOperation *mail_op,
974                                     ModestMailOperationQueueNotification type,
975                                     ModestWindowMgr *self)
976 {       
977         ModestWindowMgrPrivate *priv;
978
979         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
980
981         /* We register to track progress */
982         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
983                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
984                                                                G_OBJECT (mail_op),
985                                                                "operation-started",
986                                                                G_CALLBACK (on_mail_operation_started),
987                                                                self);
988                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
989                                                                G_OBJECT (mail_op),
990                                                                "operation-finished",
991                                                                G_CALLBACK (on_mail_operation_finished),
992                                                                self);
993         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
994                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
995                                                                   G_OBJECT (mail_op),
996                                                                   "operation-started");
997                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
998                                                                   G_OBJECT (mail_op),
999                                                                   "operation-finished");
1000                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
1001                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1002                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1003                 }
1004         }
1005 }
1006
1007 static void 
1008 on_mail_operation_started (ModestMailOperation *mail_op,
1009                            gpointer user_data)
1010 {
1011         ModestWindowMgr *self;
1012         ModestWindowMgrPrivate *priv;
1013         ModestMailOperationTypeOperation op_type;
1014
1015         self = MODEST_WINDOW_MGR (user_data);
1016         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1017
1018         /* First we check if the operation is a send receive operation,
1019          * If now, we don't handle this */
1020         op_type = modest_mail_operation_get_type_operation (mail_op);
1021         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1022             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1023                 return;
1024         }
1025
1026         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1027                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1028                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1029         }
1030 }
1031
1032 static void 
1033 on_mail_operation_finished (ModestMailOperation *mail_op,
1034                             gpointer user_data)
1035 {
1036         ModestWindowMgr *self;
1037         ModestWindowMgrPrivate *priv;
1038
1039         self = MODEST_WINDOW_MGR (user_data);
1040         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1041
1042         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1043                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1044                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1045         }
1046 }
1047
1048 TnyList *
1049 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1050 {
1051         ModestWindowMgrPrivate *priv;
1052
1053         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1054
1055         return tny_list_copy (priv->progress_operations);
1056 }
1057
1058 gboolean 
1059 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1060 {
1061         ModestWindowMgrPrivate *priv;
1062
1063         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1064
1065         return tny_list_get_length (priv->progress_operations) > 0;
1066 }
1067
1068 gboolean 
1069 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1070                                                      const gchar *account_name)
1071 {
1072         ModestWindowMgrPrivate *priv;
1073         gint account_ops = 0;
1074         TnyIterator *iterator;
1075
1076         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1077
1078         if (account_name == NULL)
1079                 return 0;
1080
1081         for (iterator = tny_list_create_iterator (priv->progress_operations);
1082              !tny_iterator_is_done (iterator);
1083              tny_iterator_next (iterator)) {
1084                 ModestMailOperation *mail_op; 
1085                 TnyAccount *account;
1086
1087                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1088                 account = modest_mail_operation_get_account (mail_op);
1089
1090                 if (account != NULL) {
1091                         const gchar *current_name;
1092
1093                         current_name = tny_account_get_id (account);
1094                         if (current_name && strcmp (current_name, account_name) == 0)
1095                                 account_ops ++;
1096                         g_object_unref (account);
1097                 }
1098
1099                 g_object_unref (mail_op);
1100         }
1101         g_object_unref (iterator);
1102
1103         return account_ops;
1104 }