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