Refactored the code that closes the active dialogs
[modest] / src / hildon2 / modest-hildon2-window-mgr.c
1 /* Copyright (c) 2008, 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 <hildon/hildon.h>
32 #include "modest-hildon2-window.h"
33 #include "modest-hildon2-window-mgr.h"
34 #include "modest-msg-edit-window.h"
35 #include "modest-mailboxes-window.h"
36 #include "modest-header-window.h"
37 #include "modest-main-window.h"
38 #include "modest-window-mgr-priv.h"
39 #include "modest-conf.h"
40 #include "modest-defs.h"
41 #include "modest-signal-mgr.h"
42 #include "modest-runtime.h"
43 #include "modest-platform.h"
44 #include "modest-ui-actions.h"
45 #include "modest-debug.h"
46 #include "modest-tny-folder.h"
47 #include "modest-folder-window.h"
48 #include "modest-accounts-window.h"
49 #include "modest-maemo-utils.h"
50 #include "modest-utils.h"
51 #include "modest-tny-msg.h"
52 #include "modest-tny-account.h"
53 #include <tny-merge-folder.h>
54
55 /* 'private'/'protected' functions */
56 static void modest_hildon2_window_mgr_class_init (ModestHildon2WindowMgrClass *klass);
57 static void modest_hildon2_window_mgr_instance_init (ModestHildon2WindowMgr *obj);
58 static void modest_hildon2_window_mgr_finalize   (GObject *obj);
59
60 static gboolean on_window_destroy        (ModestWindow *window,
61                                           GdkEvent *event,
62                                           ModestHildon2WindowMgr *self);
63
64 static gboolean modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
65                                                            ModestWindow *window,
66                                                            ModestWindow *parent);
67 static void modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
68                                                          ModestWindow *window);
69 static void modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
70                                                            gboolean on);
71 static gboolean modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self);
72 static void modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
73                                                      GType window_type,
74                                                      gboolean show_toolbars,
75                                                      gboolean fullscreen);
76 static ModestWindow* modest_hildon2_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show);
77 static GtkWindow *modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self);
78 static void modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
79                                                  GtkWindow *window,
80                                                  GtkWindow *parent);
81 static gboolean modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, 
82                                                                   TnyHeader *header,
83                                                                   ModestWindow **win);
84 static gboolean modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, 
85                                                                        const gchar *msg_uid,
86                                                                        ModestWindow **win);
87 static GList *modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self);
88 static gboolean modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self);
89 static gboolean window_has_modals (ModestWindow *window);
90 static ModestWindow *modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self);
91 static ModestWindow *modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self);
92 static gboolean modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self);
93 static void modest_hildon2_window_mgr_create_caches (ModestWindowMgr *self);
94 static void osso_display_event_cb (osso_display_state_t state, 
95                                    gpointer data);
96 static void on_account_removed (TnyAccountStore *acc_store, 
97                                 TnyAccount *account,
98                                 gpointer user_data);
99
100 typedef struct _ModestHildon2WindowMgrPrivate ModestHildon2WindowMgrPrivate;
101 struct _ModestHildon2WindowMgrPrivate {
102         GList        *window_list;
103         GMutex       *queue_lock;
104         GQueue       *modal_windows;
105
106         gboolean     fullscreen_mode;
107
108         GHashTable   *destroy_handlers;
109         GHashTable   *viewer_handlers;
110         GSList       *window_state_uids;
111
112         guint        closing_time;
113
114         GSList       *modal_handler_uids;
115         ModestWindow *current_top;
116
117         gulong        accounts_handler;
118
119         /* Display state */
120         osso_display_state_t display_state;
121 };
122 #define MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
123                                                                                    MODEST_TYPE_HILDON2_WINDOW_MGR, \
124                                                                                    ModestHildon2WindowMgrPrivate))
125 /* globals */
126 static GObjectClass *parent_class = NULL;
127
128 GType
129 modest_hildon2_window_mgr_get_type (void)
130 {
131         static GType my_type = 0;
132         if (!my_type) {
133                 static const GTypeInfo my_info = {
134                         sizeof(ModestHildon2WindowMgrClass),
135                         NULL,           /* base init */
136                         NULL,           /* base finalize */
137                         (GClassInitFunc) modest_hildon2_window_mgr_class_init,
138                         NULL,           /* class finalize */
139                         NULL,           /* class data */
140                         sizeof(ModestHildon2WindowMgr),
141                         1,              /* n_preallocs */
142                         (GInstanceInitFunc) modest_hildon2_window_mgr_instance_init,
143                         NULL
144                 };
145                 my_type = g_type_register_static (MODEST_TYPE_WINDOW_MGR,
146                                                   "ModestHildon2WindowMgr",
147                                                   &my_info, 0);
148         }
149         return my_type;
150 }
151
152 static void
153 modest_hildon2_window_mgr_class_init (ModestHildon2WindowMgrClass *klass)
154 {
155         GObjectClass *gobject_class;
156         ModestWindowMgrClass *mgr_class;
157
158         gobject_class = (GObjectClass*) klass;
159         mgr_class = (ModestWindowMgrClass *) klass;
160
161         parent_class            = g_type_class_peek_parent (klass);
162         gobject_class->finalize = modest_hildon2_window_mgr_finalize;
163         mgr_class->register_window = modest_hildon2_window_mgr_register_window;
164         mgr_class->unregister_window = modest_hildon2_window_mgr_unregister_window;
165         mgr_class->set_fullscreen_mode = modest_hildon2_window_mgr_set_fullscreen_mode;
166         mgr_class->get_fullscreen_mode = modest_hildon2_window_mgr_get_fullscreen_mode;
167         mgr_class->show_toolbars = modest_hildon2_window_mgr_show_toolbars;
168         mgr_class->get_main_window = modest_hildon2_window_mgr_get_main_window;
169         mgr_class->get_modal = modest_hildon2_window_mgr_get_modal;
170         mgr_class->set_modal = modest_hildon2_window_mgr_set_modal;
171         mgr_class->find_registered_header = modest_hildon2_window_mgr_find_registered_header;
172         mgr_class->find_registered_message_uid = modest_hildon2_window_mgr_find_registered_message_uid;
173         mgr_class->get_window_list = modest_hildon2_window_mgr_get_window_list;
174         mgr_class->close_all_windows = modest_hildon2_window_mgr_close_all_windows;
175         mgr_class->show_initial_window = modest_hildon2_window_mgr_show_initial_window;
176         mgr_class->get_current_top = modest_hildon2_window_mgr_get_current_top;
177         mgr_class->screen_is_on = modest_hildon2_window_mgr_screen_is_on;
178         mgr_class->create_caches = modest_hildon2_window_mgr_create_caches;
179
180         g_type_class_add_private (gobject_class, sizeof(ModestHildon2WindowMgrPrivate));
181
182 }
183
184 static void
185 modest_hildon2_window_mgr_instance_init (ModestHildon2WindowMgr *obj)
186 {
187         ModestHildon2WindowMgrPrivate *priv;
188
189         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE(obj);
190         priv->window_list = NULL;
191         priv->fullscreen_mode = FALSE;
192         priv->window_state_uids = NULL;
193
194         priv->modal_windows = g_queue_new ();
195         priv->queue_lock = g_mutex_new ();
196
197         /* Could not initialize it from gconf, singletons are not
198            ready yet */
199         priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
200         priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
201
202         priv->closing_time = 0;
203
204         priv->modal_handler_uids = NULL;
205         priv->display_state = OSSO_DISPLAY_ON;
206
207         /* Listen for changes in the screen, we don't want to show a
208            led pattern when the display is on for example */
209         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
210                                       osso_display_event_cb,
211                                       obj); 
212
213 }
214
215 static void
216 modest_hildon2_window_mgr_finalize (GObject *obj)
217 {
218         ModestHildon2WindowMgrPrivate *priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE(obj);
219         ModestTnyAccountStore *acc_store;
220
221         modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids);
222         priv->window_state_uids = NULL;
223
224         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
225                                       NULL, NULL);
226
227         acc_store = modest_runtime_get_account_store ();
228         if (acc_store && g_signal_handler_is_connected (acc_store, priv->accounts_handler))
229                 g_signal_handler_disconnect (acc_store, priv->accounts_handler);
230
231         if (priv->window_list) {
232                 GList *iter = priv->window_list;
233                 /* unregister pending windows */
234                 while (iter) {
235                         ModestWindow *window = (ModestWindow *) iter->data;
236                         iter = g_list_next (iter);
237                         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window);
238                 }
239                 g_list_free (priv->window_list);
240                 priv->window_list = NULL;
241         }
242
243         /* Free the hash table with the handlers */
244         if (priv->destroy_handlers) {
245                 g_hash_table_destroy (priv->destroy_handlers);
246                 priv->destroy_handlers = NULL;
247         }
248
249         if (priv->viewer_handlers) {
250                 g_hash_table_destroy (priv->viewer_handlers);
251                 priv->viewer_handlers = NULL;
252         }
253
254         modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids);
255         priv->modal_handler_uids = NULL;
256
257         if (priv->modal_windows) {
258                 g_mutex_lock (priv->queue_lock);
259                 g_queue_free (priv->modal_windows);
260                 priv->modal_windows = NULL;
261                 g_mutex_unlock (priv->queue_lock);
262         }
263         g_mutex_free (priv->queue_lock);
264
265         /* Do not unref priv->main_window because it does not hold a
266            new reference */
267
268         G_OBJECT_CLASS(parent_class)->finalize (obj);
269 }
270
271 ModestWindowMgr*
272 modest_hildon2_window_mgr_new (void)
273 {
274         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_HILDON2_WINDOW_MGR, NULL));
275 }
276
277 static gboolean
278 modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self)
279 {
280         ModestHildon2WindowMgrPrivate *priv = NULL;
281         gboolean ret_value = FALSE;
282         GtkWidget *window;
283         HildonWindowStack *stack;
284         gboolean failed = FALSE;
285
286         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
287         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
288
289         stack = hildon_window_stack_get_default ();
290
291         while ((window = hildon_window_stack_peek (stack)) != NULL) {
292                 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &ret_value);
293                 if (ret_value == TRUE) {
294                         failed = TRUE;
295                         break;
296                 }
297         }
298
299         return !failed;
300 }
301
302 static gint
303 compare_msguids (ModestWindow *win,
304                  const gchar *uid)
305 {
306         const gchar *msg_uid;
307
308         if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
309                 return 1;
310
311         /* Get message uid from msg window */
312         if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
313                 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
314                 if (msg_uid && uid &&!strcmp (msg_uid, uid))
315                         return 0;
316         } else {
317                 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
318         }
319
320         if (msg_uid && uid &&!strcmp (msg_uid, uid))
321                 return 0;
322         else
323                 return 1;
324 }
325
326 static gint
327 compare_headers (ModestWindow *win,
328                  TnyHeader *header)
329 {
330         TnyHeader *my_header;
331         gint result = 1;
332
333         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
334                 return 1;
335
336         /* Get message uid from msg window */
337         my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
338         if (my_header) {
339                 if (my_header == header)
340                         result = 0;
341                 g_object_unref (my_header);
342         }
343         return result;
344 }
345
346
347 static gboolean
348 modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
349                                                   ModestWindow **win)
350 {
351         ModestHildon2WindowMgrPrivate *priv = NULL;
352         gchar* uid = NULL;
353         gboolean has_header, has_window = FALSE;
354         GList *item = NULL;
355
356         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
357         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
358         
359         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
360
361         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
362         
363         uid = modest_tny_folder_get_header_unique_id (header);
364         
365         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
366         if (item) {
367                 has_window = TRUE;
368                 if (win) {
369                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
370                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
371                                 g_debug ("not a valid window!");
372                         else {
373                                 g_debug ("found a window");
374                                 *win = MODEST_WINDOW (item->data);
375                         }
376                 }
377         }
378         g_free (uid);
379         
380         return has_header || has_window;
381 }
382
383 static gboolean
384 modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
385                                                        ModestWindow **win)
386 {
387         ModestHildon2WindowMgrPrivate *priv = NULL;
388         gboolean has_header, has_window = FALSE;
389         GList *item = NULL;
390
391         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
392         g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
393         
394         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
395
396         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
397         
398         item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
399         if (item) {
400                 has_window = TRUE;
401                 if (win) {
402                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
403                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
404                                 g_debug ("not a valid window!");
405                         else {
406                                 g_debug ("found a window");
407                                 *win = MODEST_WINDOW (item->data);
408                         }
409                 }
410         }
411         
412         return has_header || has_window;
413 }
414
415 static GList *
416 modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self)
417 {
418         ModestHildon2WindowMgrPrivate *priv;
419
420         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
421         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
422
423         return g_list_copy (priv->window_list);
424 }
425
426 static gboolean
427 modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
428                                            ModestWindow *window,
429                                            ModestWindow *parent)
430 {
431         GList *win;
432         ModestHildon2WindowMgrPrivate *priv;
433         gint *handler_id;
434         HildonWindowStack *stack;
435         gboolean nested_msg = FALSE;
436         ModestWindow *current_top;
437
438         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
439         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
440
441         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
442
443         /* Try to close active modal dialogs */
444         if (modest_window_mgr_get_num_windows (self) &&
445             !_modest_window_mgr_close_active_modals (self))
446                 return FALSE;
447
448         stack = hildon_window_stack_get_default ();
449         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
450
451         win = g_list_find (priv->window_list, window);
452         if (win) {
453                 /* this is for the case we want to register the window
454                    and it was already registered */
455                 gtk_window_present (GTK_WINDOW (window));
456                 return FALSE;
457         }
458
459         /* Do not allow standalone editors or standalone viewers */
460         if (!current_top &&
461             (MODEST_IS_MSG_VIEW_WINDOW (window) ||
462              MODEST_IS_MSG_EDIT_WINDOW (window)))
463                 modest_window_mgr_show_initial_window (self);
464
465         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
466                 gchar *uid;
467                 TnyHeader *header;
468
469                 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
470                 
471                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
472
473                 if (uid == NULL)
474                         uid = modest_tny_folder_get_header_unique_id (header);
475                 /* Embedded messages do not have uid */
476                 if (uid) {
477                         if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
478                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
479                                 g_free (uid);
480                                 g_object_unref (header);
481                                 return FALSE;
482                         }
483                         g_free (uid);
484                 } else if (header) {
485                         if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
486                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
487                                 g_object_unref (header);
488                                 return FALSE;
489                         }
490                 }
491                 if (header)
492                         g_object_unref (header);
493         }
494
495         /* Do not go backwards */
496         if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
497              MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
498              MODEST_IS_HEADER_WINDOW (current_top)) &&
499             (MODEST_IS_FOLDER_WINDOW (window) ||
500              MODEST_IS_ACCOUNTS_WINDOW (window) ||
501              MODEST_IS_MAILBOXES_WINDOW (window))) {
502                 gtk_window_present (GTK_WINDOW (current_top));
503                 return FALSE;
504         }
505
506         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
507                 gboolean retval;
508
509                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
510
511                 if (retval) {
512                         gtk_window_present (GTK_WINDOW (current_top));
513                         return FALSE;
514                 }
515                 current_top = (ModestWindow *) hildon_window_stack_peek (stack);
516         }
517
518         if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
519                 gtk_window_present (GTK_WINDOW (current_top));
520                 return FALSE;
521         }
522
523         /* Mailboxes window can not replace folder windows */
524         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
525                 gtk_window_present (GTK_WINDOW (current_top));
526                 return FALSE;
527         }
528
529         /* Trying to open a folders window and a mailboxes window at
530            the same time from the accounts window is not allowed */
531         if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
532             MODEST_IS_FOLDER_WINDOW (window) &&
533             MODEST_IS_ACCOUNTS_WINDOW (parent)) {
534                 gtk_window_present (GTK_WINDOW (window));
535                 return FALSE;
536         }
537
538         if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
539                 g_debug ("Trying to register a second header window is not allowed");
540                 gtk_window_present (GTK_WINDOW (current_top));
541                 return FALSE;
542         }
543
544         if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
545                 goto fail;
546
547         /* Add to list. Keep a reference to the window */
548         g_object_ref (window);
549         priv->window_list = g_list_prepend (priv->window_list, window);
550
551         nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
552                 MODEST_IS_MSG_VIEW_WINDOW (parent);
553
554         /* Close views if they're being shown. Nevertheless we must
555            allow nested messages */
556         if (!nested_msg &&
557             (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
558              MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
559                 gboolean retval;
560
561                 /* If the current view has modal dialogs then
562                    we fail to register the new view */
563                 if ((current_top != NULL) &&
564                     window_has_modals (MODEST_WINDOW (current_top))) {
565                         /* Window on top but it has opened dialogs */
566                         goto fail;
567                 }
568
569                 /* Close the current view */
570                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
571                 if (retval) {
572                         /* Cancelled closing top window, then we fail to register */
573                         goto fail;
574                 }
575         }
576
577         /* Listen to object destruction */
578         handler_id = g_malloc0 (sizeof (gint));
579         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
580         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
581
582         /* Show toolbar always */
583         modest_window_show_toolbar (window, TRUE);
584
585         return TRUE;
586 fail:
587         /* Add to list. Keep a reference to the window */
588         priv->window_list = g_list_remove (priv->window_list, window);
589         g_object_unref (window);
590         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
591         if (current_top)
592                 gtk_window_present (GTK_WINDOW (current_top));
593         return FALSE;
594 }
595
596 static void
597 cancel_window_operations (ModestWindow *window)
598 {
599         GSList* pending_ops = NULL;
600
601         /* cancel open and receive operations */
602         pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (), 
603                                                                  G_OBJECT (window));
604         while (pending_ops != NULL) {
605                 ModestMailOperationTypeOperation type;
606                 GSList* tmp_list = NULL;
607
608                 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
609                 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
610                     type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
611                     type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
612                         modest_mail_operation_cancel (pending_ops->data);
613                 }
614                 g_object_unref (G_OBJECT (pending_ops->data));
615                 tmp_list = pending_ops;
616                 pending_ops = g_slist_next (pending_ops);
617                 g_slist_free_1 (tmp_list);
618         }
619 }
620
621 static gboolean
622 window_has_modals (ModestWindow *window)
623 {
624         GList *toplevels;
625         GList *node;
626         gboolean retvalue = FALSE;
627
628         /* First we fetch all toplevels */
629         toplevels = gtk_window_list_toplevels ();
630         for (node = toplevels; node != NULL; node = g_list_next (node)) {
631                 if (GTK_IS_WINDOW (node->data) &&
632                     gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (window) &&
633                     GTK_WIDGET_VISIBLE (node->data)) {
634                         retvalue = TRUE;
635                         break;
636                 }
637         }
638         g_list_free (toplevels);
639         return retvalue;
640 }
641
642 static gboolean
643 on_window_destroy (ModestWindow *window, 
644                    GdkEvent *event,
645                    ModestHildon2WindowMgr *self)
646 {
647         gboolean no_propagate = FALSE;
648
649         /* Do not close the window if it has modals on top */
650         if (!MODEST_IS_MSG_EDIT_WINDOW (window) && window_has_modals (window))
651                 return TRUE;
652
653         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
654                 gboolean sent = FALSE;
655                 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
656                 /* Save currently edited message to Drafts if it was not sent */
657                 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
658                         ModestMsgEditWindow *edit_window;
659                         MsgData *data;
660
661                         edit_window = MODEST_MSG_EDIT_WINDOW (window);
662                         data = modest_msg_edit_window_get_msg_data (edit_window);
663
664                         if (data) {
665                                 gint parts_count;
666                                 guint64 parts_size, available_size, expected_size;
667
668                                 available_size = modest_utils_get_available_space (NULL);
669                                 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
670                                 expected_size = modest_tny_msg_estimate_size (data->plain_body,
671                                                                               data->html_body,
672                                                                               parts_count,
673                                                                               parts_size);
674                                 modest_msg_edit_window_free_msg_data (edit_window, data);
675                                 data = NULL;
676
677                                 /* If there is not enough space
678                                    available for saving the message
679                                    then show an error and close the
680                                    window without saving */
681                                 if (expected_size >= available_size) {
682                                         modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
683                                                                                 _("mail_in_ui_save_error"),
684                                                                                 FALSE);
685                                 } else {
686                                         if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
687                                                 return TRUE;
688                                 }
689                         } else {
690                                 g_warning ("Edit window without message data. This is probably a bug");
691                         }
692                 }
693         }
694
695         /* Unregister window */
696         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
697         no_propagate = FALSE;
698
699         return no_propagate;
700 }
701
702 static void
703 modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
704                                              ModestWindow *window)
705 {
706         GList *win;
707         ModestHildon2WindowMgrPrivate *priv;
708         gulong *tmp, handler_id;
709         guint num_windows;
710
711         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
712         g_return_if_fail (MODEST_IS_WINDOW (window));
713
714         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
715
716         win = g_list_find (priv->window_list, window);
717         if (!win) {
718                 g_debug ("Trying to unregister a window that has not being registered yet");
719                 return;
720         }
721
722         /* Remove the viewer window handler from the hash table. The
723            HashTable could not exist if the main window was closed
724            when there were other windows remaining */
725         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
726                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
727                 /* If the viewer was created without a main window
728                    (for example when opening a message through D-Bus
729                    the viewer handlers was not registered */
730                 if (tmp) {
731                         g_signal_handler_disconnect (window, *tmp);
732                         g_hash_table_remove (priv->viewer_handlers, window);
733                 }
734         }
735
736         /* Remove from list & hash table */
737         priv->window_list = g_list_remove_link (priv->window_list, win);
738         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
739         handler_id = *tmp;
740
741         g_hash_table_remove (priv->destroy_handlers, window);
742
743         /* cancel open and receive operations */
744         cancel_window_operations (window);
745
746         /* Disconnect the "window-state-event" handler, we won't need it anymore */
747         if (priv->window_state_uids) {
748                 priv->window_state_uids = 
749                         modest_signal_mgr_disconnect (priv->window_state_uids, 
750                                                       G_OBJECT (window), 
751                                                       "notify::is-topmost");
752         }
753
754         /* Disconnect the "delete-event" handler, we won't need it anymore */
755         g_signal_handler_disconnect (window, handler_id);
756
757         /* Destroy the window */
758         g_object_unref (win->data);
759         g_list_free (win);
760
761         MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
762
763         /* We have to get the number of windows here in order not to
764            emit the signal too many times */
765         num_windows = modest_window_mgr_get_num_windows (self);
766
767         /* If there are no more windows registered emit the signal */
768         if (num_windows == 0)
769                 g_signal_emit_by_name (self, "window-list-empty");
770 }
771
772
773 static void
774 modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
775                                                gboolean on)
776 {
777         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
778
779         return;
780 }
781
782 static gboolean
783 modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
784 {
785         return FALSE;
786 }
787
788 static void 
789 modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
790                                          GType window_type,
791                                          gboolean show_toolbars,
792                                          gboolean fullscreen)
793 {
794         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
795
796         return;
797 }
798
799 static ModestWindow*  
800 modest_hildon2_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
801 {
802         ModestHildon2WindowMgrPrivate *priv;
803         ModestWindow *result;
804
805         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
806         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
807
808         /* TODO: make this return NULL always */
809
810         result = MODEST_WINDOW_MGR_CLASS (parent_class)->get_main_window (self, FALSE);
811         /* create the main window, if it hasn't been created yet */
812         if (!result && show) {
813                 /* modest_window_mgr_register_window will set priv->main_window */
814                 result = modest_main_window_new ();
815                 /* We have to remove all other windows */
816                 if (!modest_window_mgr_close_all_windows (self)) {
817                         gtk_widget_destroy (GTK_WIDGET (result));
818                         return NULL;
819                 }
820                 if (!modest_window_mgr_register_window (self, result, NULL)) {
821                         gtk_widget_destroy (GTK_WIDGET (result));
822                         return NULL;
823                 }
824                 MODEST_DEBUG_BLOCK(
825                         g_debug ("%s: created main window: %p\n", __FUNCTION__, result);
826                 );
827         }
828         if (show) {
829                 gtk_widget_show_all (GTK_WIDGET (result));
830                 gtk_window_present (GTK_WINDOW (result));
831         }
832
833         return result;
834 }
835
836 static gint
837 look_for_transient (gconstpointer a,
838                     gconstpointer b)
839 {
840         GtkWindow *win, *child;
841
842         if (a == b)
843                 return 1;
844
845         child = (GtkWindow *) b;
846         win = (GtkWindow *) a;
847
848         if ((gtk_window_get_transient_for (win) == child) &&
849             GTK_WIDGET_VISIBLE (win))
850                 return 0;
851         else
852                 return 1;
853 }
854
855 static GtkWindow *
856 modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self)
857 {
858         ModestHildon2WindowMgrPrivate *priv;
859         GList *toplevel_list;
860         GtkWidget *current_top, *toplevel;
861         HildonWindowStack *stack;
862
863         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
864         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
865
866         /* Get current top */
867         stack = hildon_window_stack_get_default ();
868         current_top = hildon_window_stack_peek (stack);
869         toplevel = current_top;
870         toplevel_list = gtk_window_list_toplevels ();
871
872         while (toplevel) {
873                 GList *parent_link;
874
875                 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
876                 if (parent_link)
877                         toplevel = (GtkWidget *) parent_link->data;
878                 else
879                         break;
880         }
881
882         if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
883                 return (GtkWindow *) toplevel;
884         else
885                 return NULL;
886 }
887
888
889 static void
890 modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
891                                      GtkWindow *window,
892                                      GtkWindow *parent)
893 {
894         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
895         g_return_if_fail (GTK_IS_WINDOW (window));
896
897         gtk_window_set_modal (window, TRUE);
898         gtk_window_set_transient_for (window, parent);
899         gtk_window_set_destroy_with_parent (window, TRUE);
900 }
901
902 static gboolean
903 on_idle_close_all_but_first (gpointer data)
904 {
905         gint num_windows, i;
906         gboolean retval;
907         HildonWindowStack *stack;
908
909         stack = hildon_window_stack_get_default ();
910         g_return_val_if_fail (stack, FALSE);
911
912         num_windows = hildon_window_stack_size (stack);
913
914         for (i = 0; i < (num_windows - 1); i++) {
915                 GtkWidget *current_top;
916
917                 /* Close window */
918                 current_top = hildon_window_stack_peek (stack);
919                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
920         }
921         return FALSE;
922 }
923
924 static void
925 on_account_removed (TnyAccountStore *acc_store,
926                     TnyAccount *account,
927                     gpointer user_data)
928 {
929         HildonWindowStack *stack;
930         ModestWindow *current_top;
931
932         /* Ignore transport account removals */
933         if (TNY_IS_TRANSPORT_ACCOUNT (account))
934                 return;
935
936         stack = hildon_window_stack_get_default ();
937         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
938
939         /* if we're showing the header view of the currently deleted
940            account, or the outbox and we deleted the last account,
941            then close the window */
942         if (current_top &&
943             (MODEST_IS_HEADER_WINDOW (current_top) ||
944              MODEST_IS_FOLDER_WINDOW (current_top))) {
945                     const gchar *acc_name;
946
947                     acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
948
949                     /* We emit it in an idle, because sometimes this
950                        function could called when the account settings
951                        dialog is about to close but still there. That
952                        modal dialog would otherwise, prevent the
953                        windows from being closed */
954                     if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
955                             g_idle_add (on_idle_close_all_but_first, NULL);
956         }
957 }
958
959 static ModestWindow *
960 modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self)
961 {
962         ModestWindow *initial_window = NULL;
963         ModestHildon2WindowMgrPrivate *priv;
964
965         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
966
967         /* Connect to the account store "account-removed" signal". We
968            do this here because in the init the singletons are still
969            not initialized properly */
970         if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
971                                             priv->accounts_handler)) {
972                 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
973                                                            "account-removed",
974                                                            G_CALLBACK (on_account_removed),
975                                                            self);
976         }
977
978         /* Return accounts window */
979         initial_window = MODEST_WINDOW (modest_accounts_window_new ());
980         modest_window_mgr_register_window (self, initial_window, NULL);
981
982         return initial_window;
983 }
984
985
986 static ModestWindow *
987 modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self)
988 {
989         HildonWindowStack *stack;
990         stack = hildon_window_stack_get_default ();
991         return (ModestWindow *) hildon_window_stack_peek (stack);
992 }
993
994 static gint 
995 find_folder_window (gconstpointer a,
996                     gconstpointer b)
997 {
998         return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
999 }
1000
1001 ModestWindow *
1002 modest_hildon2_window_mgr_get_folder_window (ModestHildon2WindowMgr *self)
1003 {
1004         ModestHildon2WindowMgrPrivate *priv;
1005         GList *window;
1006
1007         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
1008
1009         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
1010
1011         window = g_list_find_custom (priv->window_list,
1012                                      NULL,
1013                                      find_folder_window);
1014
1015         return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
1016 }
1017
1018 static gboolean
1019 modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self)
1020 {
1021         ModestHildon2WindowMgrPrivate *priv = NULL;
1022
1023         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
1024
1025         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
1026         
1027         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
1028 }
1029
1030 static void
1031 modest_hildon2_window_mgr_create_caches (ModestWindowMgr *self)
1032 {
1033         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
1034
1035         modest_accounts_window_pre_create ();
1036
1037         MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
1038         
1039 }
1040
1041 static void 
1042 osso_display_event_cb (osso_display_state_t state, 
1043                        gpointer data)
1044 {
1045         ModestHildon2WindowMgrPrivate *priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (data);
1046
1047         priv->display_state = state;
1048
1049         /* Stop blinking if the screen becomes on */
1050         if (priv->display_state == OSSO_DISPLAY_ON)
1051                 modest_platform_remove_new_mail_notifications (TRUE);
1052 }