Do ignore empty recipients when checking names
[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         gboolean no_windows, retval;
542
543         no_windows = (modest_window_mgr_get_num_windows (self) == 0);
544
545         retval = MODEST_WINDOW_MGR_GET_CLASS (self)->register_window (self, window, parent);
546
547         if  (no_windows) {
548                 /* If this is the first registered window then reset the
549                    status of the TnyDevice as it might be forced to be offline
550                    when modest is running in the background (see
551                    modest_tny_account_store_new()) */
552                 if (tny_device_is_forced (modest_runtime_get_device ()))
553                         tny_device_reset (modest_runtime_get_device ());
554
555                 /* Do also allow modest to shutdown when the
556                    application is closed */
557                 modest_runtime_set_allow_shutdown (TRUE);
558         }
559         return retval;
560 }
561
562 static gboolean
563 modest_window_mgr_register_window_default (ModestWindowMgr *self, 
564                                            ModestWindow *window,
565                                            ModestWindow *parent)
566 {
567         ModestWindowMgrPrivate *priv;
568
569         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
570         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
571
572         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
573
574         /* We set up the queue change handler */
575         if (priv->queue_change_handler == 0) {
576                 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
577                                                                "queue-changed",
578                                                                G_CALLBACK (modest_window_mgr_on_queue_changed),
579                                                                self);
580         }
581
582         /* Check that it's not a second main window */
583         if (MODEST_IS_MAIN_WINDOW (window)) {
584                 if (priv->main_window) {
585                         g_warning ("%s: trying to register a second main window",
586                                    __FUNCTION__);
587                         return FALSE;
588                 } else {
589                         priv->main_window = window;
590                 }
591         }
592
593         /* remove from the list of pre-registered uids */
594         if (MODEST_IS_MSG_VIEW_WINDOW(window)) {
595                 const gchar *uid = modest_msg_view_window_get_message_uid
596                         (MODEST_MSG_VIEW_WINDOW (window));
597
598                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "<none>"););
599
600                 if (has_uid (priv->preregistered_uids, uid)) {
601                         priv->preregistered_uids = 
602                                 remove_uid (priv->preregistered_uids,
603                                             modest_msg_view_window_get_message_uid
604                                             (MODEST_MSG_VIEW_WINDOW (window)));
605                 }
606         } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) {
607                 const gchar *uid = modest_msg_edit_window_get_message_uid
608                         (MODEST_MSG_EDIT_WINDOW (window));
609
610                 MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid););
611
612                 priv->preregistered_uids = 
613                         remove_uid (priv->preregistered_uids,
614                                     modest_msg_edit_window_get_message_uid
615                                     (MODEST_MSG_EDIT_WINDOW (window)));
616         }
617
618         return TRUE;
619 }
620
621 void 
622 modest_window_mgr_unregister_window (ModestWindowMgr *self, 
623                                      ModestWindow *window)
624 {
625         MODEST_WINDOW_MGR_GET_CLASS (self)->unregister_window (self, window);
626 }
627
628 static void 
629 modest_window_mgr_unregister_window_default (ModestWindowMgr *self, 
630                                              ModestWindow *window)
631 {
632         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
633         g_return_if_fail (MODEST_IS_WINDOW (window));
634
635         /* Save state */
636         modest_window_save_state (window);
637
638         /* Disconnect all the window signals */
639         modest_window_disconnect_signals (window);
640         
641         /* Destroy the window */
642         gtk_widget_destroy (GTK_WIDGET (window));
643 }
644
645
646
647 void
648 modest_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
649                                        gboolean on)
650 {
651         MODEST_WINDOW_MGR_GET_CLASS (self)->set_fullscreen_mode (self, on);
652 }
653
654 static void
655 modest_window_mgr_set_fullscreen_mode_default (ModestWindowMgr *self,
656                                                gboolean on)
657 {
658         return;
659 }
660
661 gboolean
662 modest_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
663 {
664         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_fullscreen_mode (self);
665 }
666
667 static gboolean
668 modest_window_mgr_get_fullscreen_mode_default (ModestWindowMgr *self)
669 {
670         return FALSE;
671 }
672
673 void 
674 modest_window_mgr_show_toolbars (ModestWindowMgr *self,
675                                  GType window_type,
676                                  gboolean show_toolbars,
677                                  gboolean fullscreen)
678 {
679         return MODEST_WINDOW_MGR_GET_CLASS (self)->show_toolbars (self, window_type, show_toolbars, fullscreen);
680 }
681
682 static void 
683 modest_window_mgr_show_toolbars_default (ModestWindowMgr *self,
684                                          GType window_type,
685                                          gboolean show_toolbars,
686                                          gboolean fullscreen)
687 {
688         return;
689 }
690
691 void
692 modest_window_mgr_set_main_window (ModestWindowMgr *self, ModestWindow *win)
693 {
694         ModestWindowMgrPrivate *priv;
695         
696         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
697
698         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
699         priv->main_window = win;
700 }
701
702 ModestWindow*  
703 modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
704 {
705         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_main_window (self, show);
706 }
707
708 static ModestWindow*  
709 modest_window_mgr_get_main_window_default (ModestWindowMgr *self, gboolean show)
710 {
711         ModestWindowMgrPrivate *priv;
712         
713         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL);
714
715         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
716         if (priv->main_window)
717                 return priv->main_window;
718
719         if (show) 
720                 return modest_main_window_new ();
721         else return NULL;
722 }
723
724
725 gboolean
726 modest_window_mgr_main_window_exists  (ModestWindowMgr *self)
727 {
728         ModestWindowMgrPrivate *priv;
729         
730         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
731         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
732
733         return priv->main_window != NULL;
734 }
735
736
737 GtkWindow *
738 modest_window_mgr_get_modal (ModestWindowMgr *self)
739 {
740         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_modal (self);
741 }
742
743 static GtkWindow *
744 modest_window_mgr_get_modal_default (ModestWindowMgr *self)
745 {
746         return NULL;
747 }
748
749
750 void
751 modest_window_mgr_set_modal (ModestWindowMgr *self, 
752                              GtkWindow *window,
753                              GtkWindow *parent)
754 {
755         MODEST_WINDOW_MGR_GET_CLASS (self)->set_modal (self, window, parent);
756 }
757
758 static void
759 modest_window_mgr_set_modal_default (ModestWindowMgr *self, 
760                                      GtkWindow *window,
761                                      GtkWindow *parent)
762 {
763         return;
764 }
765
766
767 static void
768 on_nonhibernating_window_hide(GtkWidget *widget, gpointer user_data)
769 {
770         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
771         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
772         
773         /* Forget this window,
774          * so hibernation will be allowed again if no windows are remembered: */
775         priv->windows_that_prevent_hibernation =
776                 g_slist_remove (priv->windows_that_prevent_hibernation, GTK_WINDOW(widget));
777 }
778
779 static void
780 on_nonhibernating_window_show(GtkWidget *widget, gpointer user_data)
781 {
782         ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data);
783         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
784         
785         GtkWindow *window = GTK_WINDOW (widget);
786         
787         priv->windows_that_prevent_hibernation = 
788                         g_slist_append (priv->windows_that_prevent_hibernation, window);
789         
790         /* Allow hibernation again when the window has been hidden: */
791         g_signal_connect (window, "hide", 
792                 G_CALLBACK (on_nonhibernating_window_hide), self);
793 }
794
795 void
796 modest_window_mgr_prevent_hibernation_while_window_is_shown (ModestWindowMgr *self,
797                                                                   GtkWindow *window)
798 {
799         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
800         
801         if (GTK_WIDGET_VISIBLE(window)) {
802                 on_nonhibernating_window_show (GTK_WIDGET (window), self);
803         } else {
804                 /* Wait for it to be shown: */
805                 g_signal_connect (window, "show", 
806                         G_CALLBACK (on_nonhibernating_window_show), self);      
807         }
808 }
809
810 gboolean
811 modest_window_mgr_get_hibernation_is_prevented (ModestWindowMgr *self)
812 {
813         g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE);
814         
815         ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
816         
817         /* Prevent hibernation if any open windows are currently 
818          * preventing hibernation: */
819         return (g_slist_length (priv->windows_that_prevent_hibernation) > 0);
820 }
821
822
823 void
824 modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self)
825 {
826         GList *window_list;
827         GList *node;
828         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
829         
830         /* Iterate over all windows */
831         window_list = modest_window_mgr_get_window_list (self);
832         node = window_list;
833         while (node) {
834                 ModestWindow *window = MODEST_WINDOW (node->data);
835                 if (window) {
836                         /* This calls the vfunc, 
837                          * so each window can do its own thing: */
838                         modest_window_save_state (window);
839                 }
840
841                 node = g_list_next (node);
842         }
843         g_list_free (window_list);
844 }
845
846 guint
847 modest_window_mgr_get_num_windows (ModestWindowMgr *self)
848 {
849         ModestWindowMgrPrivate *priv;
850         gint num_windows = 0;
851         GList *window_list;
852
853         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1);
854
855         priv =  MODEST_WINDOW_MGR_GET_PRIVATE(self);
856
857         window_list = modest_window_mgr_get_window_list (self);
858
859         if (window_list) {
860                 num_windows = g_list_length (window_list);
861                 g_list_free (window_list);
862         }
863
864         /* Do not take into account the main window if it was hidden */
865         if (num_windows && priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window))
866                 num_windows--;
867
868         return num_windows + priv->banner_counter;
869 }
870
871 GtkWidget *   
872 modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self)
873 {
874         GtkWidget *result;
875         ModestWindowMgrPrivate *priv;
876
877         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
878
879         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
880                 
881         if (priv->cached_editor) {
882                 result = priv->cached_editor;
883                 priv->cached_editor = NULL;
884                 load_new_editor (self);
885         } else {
886                 result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
887         }
888
889         return result;
890 }
891
892 GtkWidget *   
893 modest_window_mgr_get_msg_view_window (ModestWindowMgr *self)
894 {
895         GtkWidget *result;
896         ModestWindowMgrPrivate *priv;
897
898         g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL);
899         
900         priv = MODEST_WINDOW_MGR_GET_PRIVATE(self);
901
902         if (priv->cached_view) {
903                 result = priv->cached_view;
904                 priv->cached_view = NULL;
905                 load_new_view (self);
906         } else {
907                 result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
908         }
909
910         return result;
911 }
912
913 void
914 modest_window_mgr_register_banner (ModestWindowMgr *self)
915 {
916         ModestWindowMgrPrivate *priv;
917
918         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
919         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
920
921         priv->banner_counter++;
922 }
923
924 void
925 modest_window_mgr_unregister_banner (ModestWindowMgr *self)
926 {
927         ModestWindowMgrPrivate *priv;
928
929         g_return_if_fail (MODEST_IS_WINDOW_MGR (self));
930         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
931
932         priv->banner_counter--;
933         if (modest_window_mgr_get_num_windows (self) == 0)
934                 g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0);
935 }
936
937 ModestWindow *
938 modest_window_mgr_show_initial_window (ModestWindowMgr *self)
939 {
940         ModestWindow *window = NULL;
941
942         /* Call the children */
943         window = MODEST_WINDOW_MGR_GET_CLASS (self)->show_initial_window (self);
944
945         if (window) {
946                 ModestAccountMgr *mgr;
947
948                 /* Show the initial window */
949                 gtk_widget_show (GTK_WIDGET (window));
950
951                 /* If there are no accounts then show the account wizard */
952                 mgr = modest_runtime_get_account_mgr();
953                 if (!modest_account_mgr_has_accounts (mgr, TRUE)) {
954                         if (!modest_ui_actions_run_account_setup_wizard (window)) {
955                                 g_debug ("%s: couldn't show account setup wizard", __FUNCTION__);
956                         }
957                 }
958         }
959
960         return window;
961 }
962
963 static ModestWindow *
964 modest_window_mgr_show_initial_window_default (ModestWindowMgr *self)
965 {
966         /* By default it returns the main window creating it if
967            needed */
968         return modest_window_mgr_get_main_window (self, TRUE);
969 }
970
971
972 ModestWindow *
973 modest_window_mgr_get_current_top (ModestWindowMgr *self) 
974 {
975         return MODEST_WINDOW_MGR_GET_CLASS (self)->get_current_top (self);
976 }
977
978
979 static ModestWindow *
980 modest_window_mgr_get_current_top_default (ModestWindowMgr *self)
981 {
982         g_return_val_if_reached (NULL);
983 }
984
985 gboolean
986 modest_window_mgr_screen_is_on (ModestWindowMgr *self)
987 {
988         return MODEST_WINDOW_MGR_GET_CLASS (self)->screen_is_on (self);
989 }
990
991 static gboolean
992 modest_window_mgr_screen_is_on_default (ModestWindowMgr *self)
993 {
994         /* Default implementation is assuming screen is always on */
995
996         return TRUE;
997 }
998
999 void
1000 modest_window_mgr_create_caches (ModestWindowMgr *mgr)
1001 {
1002         MODEST_WINDOW_MGR_GET_CLASS (mgr)->create_caches (mgr);
1003 }
1004
1005 static void
1006 modest_window_mgr_create_caches_default (ModestWindowMgr *self)
1007 {
1008         load_new_editor (self);
1009         load_new_view (self);
1010 }
1011
1012 static gboolean
1013 tny_list_find (TnyList *list, GObject *item)
1014 {
1015         TnyIterator *iterator;
1016         gboolean found = FALSE;
1017
1018         for (iterator = tny_list_create_iterator (list);
1019              !tny_iterator_is_done (iterator) && !found;
1020              tny_iterator_next (iterator)) {
1021                 GObject *current = tny_iterator_get_current (iterator);
1022                 if (current == item)
1023                         found = TRUE;
1024                 g_object_unref (current);
1025         }
1026         g_object_unref (iterator);
1027         
1028         return found;
1029 }
1030
1031 static void
1032 modest_window_mgr_on_queue_changed (ModestMailOperationQueue *queue,
1033                                     ModestMailOperation *mail_op,
1034                                     ModestMailOperationQueueNotification type,
1035                                     ModestWindowMgr *self)
1036 {       
1037         ModestWindowMgrPrivate *priv;
1038
1039         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1040
1041         /* We register to track progress */
1042         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
1043                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1044                                                                G_OBJECT (mail_op),
1045                                                                "operation-started",
1046                                                                G_CALLBACK (on_mail_operation_started),
1047                                                                self);
1048                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1049                                                                G_OBJECT (mail_op),
1050                                                                "operation-finished",
1051                                                                G_CALLBACK (on_mail_operation_finished),
1052                                                                self);
1053         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
1054                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1055                                                                   G_OBJECT (mail_op),
1056                                                                   "operation-started");
1057                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1058                                                                   G_OBJECT (mail_op),
1059                                                                   "operation-finished");
1060                 if (tny_list_find  (priv->progress_operations, G_OBJECT (mail_op))) {
1061                         tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1062                         g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1063                 }
1064         }
1065 }
1066
1067 static void 
1068 on_mail_operation_started (ModestMailOperation *mail_op,
1069                            gpointer user_data)
1070 {
1071         ModestWindowMgr *self;
1072         ModestWindowMgrPrivate *priv;
1073         ModestMailOperationTypeOperation op_type;
1074
1075         self = MODEST_WINDOW_MGR (user_data);
1076         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1077
1078         /* First we check if the operation is a send receive operation,
1079          * If now, we don't handle this */
1080         op_type = modest_mail_operation_get_type_operation (mail_op);
1081         if (op_type != MODEST_MAIL_OPERATION_TYPE_SEND &&
1082             op_type != MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
1083                 return;
1084         }
1085
1086         if (!tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1087                 tny_list_prepend (priv->progress_operations, G_OBJECT (mail_op));
1088                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1089         }
1090 }
1091
1092 static void 
1093 on_mail_operation_finished (ModestMailOperation *mail_op,
1094                             gpointer user_data)
1095 {
1096         ModestWindowMgr *self;
1097         ModestWindowMgrPrivate *priv;
1098
1099         self = MODEST_WINDOW_MGR (user_data);
1100         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1101
1102         if (tny_list_find (priv->progress_operations, G_OBJECT (mail_op))) {
1103                 tny_list_remove (priv->progress_operations, G_OBJECT (mail_op));
1104                 g_signal_emit (self, signals[PROGRESS_LIST_CHANGED_SIGNAL], 0);
1105         }
1106 }
1107
1108 TnyList *
1109 modest_window_mgr_get_progress_operations (ModestWindowMgr *self)
1110 {
1111         ModestWindowMgrPrivate *priv;
1112
1113         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1114
1115         return tny_list_copy (priv->progress_operations);
1116 }
1117
1118 gboolean 
1119 modest_window_mgr_has_progress_operation (ModestWindowMgr *self)
1120 {
1121         ModestWindowMgrPrivate *priv;
1122
1123         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1124
1125         return tny_list_get_length (priv->progress_operations) > 0;
1126 }
1127
1128 gboolean 
1129 modest_window_mgr_has_progress_operation_on_account (ModestWindowMgr *self,
1130                                                      const gchar *account_name)
1131 {
1132         ModestWindowMgrPrivate *priv;
1133         gint account_ops = 0;
1134         TnyIterator *iterator;
1135
1136         priv = MODEST_WINDOW_MGR_GET_PRIVATE (self);
1137
1138         if (account_name == NULL)
1139                 return 0;
1140
1141         for (iterator = tny_list_create_iterator (priv->progress_operations);
1142              !tny_iterator_is_done (iterator);
1143              tny_iterator_next (iterator)) {
1144                 ModestMailOperation *mail_op; 
1145                 TnyAccount *account;
1146
1147                 mail_op= MODEST_MAIL_OPERATION (tny_iterator_get_current (iterator));
1148                 account = modest_mail_operation_get_account (mail_op);
1149
1150                 if (account != NULL) {
1151                         const gchar *current_name;
1152
1153                         current_name = tny_account_get_id (account);
1154                         if (current_name && strcmp (current_name, account_name) == 0)
1155                                 account_ops ++;
1156                         g_object_unref (account);
1157                 }
1158
1159                 g_object_unref (mail_op);
1160         }
1161         g_object_unref (iterator);
1162
1163         return account_ops;
1164 }
1165
1166 /* 'Protected method' must be only called by children */
1167 gboolean
1168 _modest_window_mgr_close_active_modals (ModestWindowMgr *self)
1169 {
1170         GtkWidget *modal;
1171
1172         /* Exit if there are no windows */
1173         if (!modest_window_mgr_get_num_windows (self)) {
1174                 g_warning ("%s: there are no windows to close", __FUNCTION__);
1175                 return FALSE;
1176         }
1177
1178         /* Check that there is no active modal dialog */
1179         modal = (GtkWidget *) modest_window_mgr_get_modal (self);
1180         while (modal && GTK_IS_DIALOG (modal)) {
1181                 GtkWidget *parent;
1182
1183 #if defined(MODEST_TOOLKIT_HILDON2) || defined(MODEST_TOOLKIT_HILDON)
1184 #include <hildon/hildon.h>
1185                 /* If it's a hildon note then don't try to close it as
1186                    this is the default behaviour of WM, delete event
1187                    is not issued for this kind of notes as we want the
1188                    user to always click on a button */
1189                 if (HILDON_IS_NOTE (modal)) {
1190                         gtk_window_present (GTK_WINDOW (modal));
1191                         return FALSE;
1192                 }
1193 #endif
1194
1195                 /* Get the parent */
1196                 parent = (GtkWidget *) gtk_window_get_transient_for (GTK_WINDOW (modal));
1197
1198                 /* Try to close it */
1199                 gtk_dialog_response (GTK_DIALOG (modal), GTK_RESPONSE_DELETE_EVENT);
1200
1201                 /* Maybe the dialog was not closed, because a close
1202                    confirmation dialog for example. Then ignore the
1203                    register process */
1204                 if (GTK_IS_WINDOW (modal)) {
1205                         gtk_window_present (GTK_WINDOW (modal));
1206                         return FALSE;
1207                 }
1208
1209                 /* Get next modal */
1210                 modal = parent;
1211         }
1212         return TRUE;
1213 }
1214
1215 gboolean
1216 modest_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1217 {
1218         return MODEST_WINDOW_MGR_GET_CLASS (self)->close_all_but_initial (self);
1219 }
1220
1221 static gboolean
1222 modest_window_mgr_close_all_but_initial_default (ModestWindowMgr *self)
1223 {
1224         /* Empty default implementation */
1225         return FALSE;
1226 }