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