"Add to contacts" dialog must not be in edit mode
[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 GtkWindow *modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self);
77 static void modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
78                                                  GtkWindow *window,
79                                                  GtkWindow *parent);
80 static gboolean modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, 
81                                                                   TnyHeader *header,
82                                                                   ModestWindow **win);
83 static gboolean modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, 
84                                                                        const gchar *msg_uid,
85                                                                        ModestWindow **win);
86 static GList *modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self);
87 static gboolean modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self);
88 static gboolean modest_hildon2_window_mgr_close_all_but_initial (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_modal = modest_hildon2_window_mgr_get_modal;
169         mgr_class->set_modal = modest_hildon2_window_mgr_set_modal;
170         mgr_class->find_registered_header = modest_hildon2_window_mgr_find_registered_header;
171         mgr_class->find_registered_message_uid = modest_hildon2_window_mgr_find_registered_message_uid;
172         mgr_class->get_window_list = modest_hildon2_window_mgr_get_window_list;
173         mgr_class->close_all_windows = modest_hildon2_window_mgr_close_all_windows;
174         mgr_class->close_all_but_initial = modest_hildon2_window_mgr_close_all_but_initial;
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         G_OBJECT_CLASS(parent_class)->finalize (obj);
266 }
267
268 ModestWindowMgr*
269 modest_hildon2_window_mgr_new (void)
270 {
271         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_HILDON2_WINDOW_MGR, NULL));
272 }
273
274 static gboolean
275 modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self)
276 {
277         ModestHildon2WindowMgrPrivate *priv = NULL;
278         gboolean ret_value = FALSE;
279         GtkWidget *window;
280         HildonWindowStack *stack;
281         gboolean failed = FALSE;
282
283         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
284         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
285
286         stack = hildon_window_stack_get_default ();
287
288         while ((window = hildon_window_stack_peek (stack)) != NULL) {
289                 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &ret_value);
290                 if (ret_value == TRUE) {
291                         failed = TRUE;
292                         break;
293                 }
294         }
295
296         return !failed;
297 }
298
299 static gint
300 compare_msguids (ModestWindow *win,
301                  const gchar *uid)
302 {
303         const gchar *msg_uid;
304
305         if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
306                 return 1;
307
308         /* Get message uid from msg window */
309         if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
310                 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
311                 if (msg_uid && uid &&!strcmp (msg_uid, uid))
312                         return 0;
313         } else {
314                 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
315         }
316
317         if (msg_uid && uid &&!strcmp (msg_uid, uid))
318                 return 0;
319         else
320                 return 1;
321 }
322
323 static gint
324 compare_headers (ModestWindow *win,
325                  TnyHeader *header)
326 {
327         TnyHeader *my_header;
328         gint result = 1;
329
330         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
331                 return 1;
332
333         /* Get message uid from msg window */
334         my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
335         if (my_header) {
336                 if (my_header == header)
337                         result = 0;
338                 g_object_unref (my_header);
339         }
340         return result;
341 }
342
343
344 static gboolean
345 modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
346                                                   ModestWindow **win)
347 {
348         ModestHildon2WindowMgrPrivate *priv = NULL;
349         gchar* uid = NULL;
350         gboolean has_header, has_window = FALSE;
351         GList *item = NULL;
352
353         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
354         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
355         
356         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
357
358         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
359         
360         uid = modest_tny_folder_get_header_unique_id (header);
361         
362         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
363         if (item) {
364                 has_window = TRUE;
365                 if (win) {
366                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
367                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
368                                 g_debug ("not a valid window!");
369                         else {
370                                 g_debug ("found a window");
371                                 *win = MODEST_WINDOW (item->data);
372                         }
373                 }
374         }
375         g_free (uid);
376         
377         return has_header || has_window;
378 }
379
380 static gboolean
381 modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
382                                                        ModestWindow **win)
383 {
384         ModestHildon2WindowMgrPrivate *priv = NULL;
385         gboolean has_header, has_window = FALSE;
386         GList *item = NULL;
387
388         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
389         g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
390         
391         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
392
393         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
394         
395         item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
396         if (item) {
397                 has_window = TRUE;
398                 if (win) {
399                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
400                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
401                                 g_debug ("not a valid window!");
402                         else {
403                                 g_debug ("found a window");
404                                 *win = MODEST_WINDOW (item->data);
405                         }
406                 }
407         }
408         
409         return has_header || has_window;
410 }
411
412 static GList *
413 modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self)
414 {
415         ModestHildon2WindowMgrPrivate *priv;
416
417         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
418         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
419
420         return g_list_copy (priv->window_list);
421 }
422
423 static gboolean
424 modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
425                                            ModestWindow *window,
426                                            ModestWindow *parent)
427 {
428         GList *win;
429         ModestHildon2WindowMgrPrivate *priv;
430         gint *handler_id;
431         HildonWindowStack *stack;
432         gboolean nested_msg = FALSE;
433         ModestWindow *current_top;
434
435         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
436         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
437
438         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
439
440         /* Try to close active modal dialogs */
441         if (modest_window_mgr_get_num_windows (self) &&
442             !_modest_window_mgr_close_active_modals (self))
443                 return FALSE;
444
445         stack = hildon_window_stack_get_default ();
446         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
447
448         win = g_list_find (priv->window_list, window);
449         if (win) {
450                 /* this is for the case we want to register the window
451                    and it was already registered */
452                 gtk_window_present (GTK_WINDOW (window));
453                 return FALSE;
454         }
455
456         /* Do not allow standalone editors or standalone viewers */
457         if (!current_top &&
458             (MODEST_IS_MSG_VIEW_WINDOW (window) ||
459              MODEST_IS_MSG_EDIT_WINDOW (window)))
460                 modest_window_mgr_show_initial_window (self);
461
462         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
463                 gchar *uid;
464                 TnyHeader *header;
465
466                 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
467                 
468                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
469
470                 if (uid == NULL)
471                         uid = modest_tny_folder_get_header_unique_id (header);
472                 /* Embedded messages do not have uid */
473                 if (uid) {
474                         if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
475                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
476                                 g_free (uid);
477                                 g_object_unref (header);
478                                 return FALSE;
479                         }
480                         g_free (uid);
481                 } else if (header) {
482                         if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
483                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
484                                 g_object_unref (header);
485                                 return FALSE;
486                         }
487                 }
488                 if (header)
489                         g_object_unref (header);
490         }
491
492         /* Do not go backwards */
493         if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
494              MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
495              MODEST_IS_HEADER_WINDOW (current_top)) &&
496             (MODEST_IS_FOLDER_WINDOW (window) ||
497              MODEST_IS_ACCOUNTS_WINDOW (window) ||
498              MODEST_IS_MAILBOXES_WINDOW (window))) {
499                 gtk_window_present (GTK_WINDOW (current_top));
500                 return FALSE;
501         }
502
503         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
504                 gboolean retval;
505
506                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
507
508                 if (retval) {
509                         gtk_window_present (GTK_WINDOW (current_top));
510                         return FALSE;
511                 }
512                 current_top = (ModestWindow *) hildon_window_stack_peek (stack);
513         }
514
515         if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
516                 gtk_window_present (GTK_WINDOW (current_top));
517                 return FALSE;
518         }
519
520         /* Mailboxes window can not replace folder windows */
521         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
522                 gtk_window_present (GTK_WINDOW (current_top));
523                 return FALSE;
524         }
525
526         /* Trying to open a folders window and a mailboxes window at
527            the same time from the accounts window is not allowed */
528         if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
529             MODEST_IS_FOLDER_WINDOW (window) &&
530             MODEST_IS_ACCOUNTS_WINDOW (parent)) {
531                 gtk_window_present (GTK_WINDOW (window));
532                 return FALSE;
533         }
534
535         if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
536                 g_debug ("Trying to register a second header window is not allowed");
537                 gtk_window_present (GTK_WINDOW (current_top));
538                 return FALSE;
539         }
540
541         if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
542                 goto fail;
543
544         /* Add to list. Keep a reference to the window */
545         g_object_ref (window);
546         priv->window_list = g_list_prepend (priv->window_list, window);
547
548         nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
549                 MODEST_IS_MSG_VIEW_WINDOW (parent);
550
551         /* Close views if they're being shown. Nevertheless we must
552            allow nested messages */
553         if (!nested_msg &&
554             (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
555              MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
556                 gboolean retval;
557
558                 /* If the current view has modal dialogs then
559                    we fail to register the new view */
560                 if ((current_top != NULL) &&
561                     window_has_modals (MODEST_WINDOW (current_top))) {
562                         /* Window on top but it has opened dialogs */
563                         goto fail;
564                 }
565
566                 /* Close the current view */
567                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
568                 if (retval) {
569                         /* Cancelled closing top window, then we fail to register */
570                         goto fail;
571                 }
572         }
573
574         /* Listen to object destruction */
575         handler_id = g_malloc0 (sizeof (gint));
576         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
577         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
578
579         /* Show toolbar always */
580         modest_window_show_toolbar (window, TRUE);
581
582         return TRUE;
583 fail:
584         /* Add to list. Keep a reference to the window */
585         priv->window_list = g_list_remove (priv->window_list, window);
586         g_object_unref (window);
587         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
588         if (current_top)
589                 gtk_window_present (GTK_WINDOW (current_top));
590         return FALSE;
591 }
592
593 static void
594 cancel_window_operations (ModestWindow *window)
595 {
596         GSList* pending_ops = NULL;
597
598         /* cancel open and receive operations */
599         pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (), 
600                                                                  G_OBJECT (window));
601         while (pending_ops != NULL) {
602                 ModestMailOperationTypeOperation type;
603                 GSList* tmp_list = NULL;
604
605                 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
606                 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
607                     type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
608                     type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
609                         modest_mail_operation_cancel (pending_ops->data);
610                 }
611                 g_object_unref (G_OBJECT (pending_ops->data));
612                 tmp_list = pending_ops;
613                 pending_ops = g_slist_next (pending_ops);
614                 g_slist_free_1 (tmp_list);
615         }
616 }
617
618 static gboolean
619 window_has_modals (ModestWindow *window)
620 {
621         GList *toplevels;
622         GList *node;
623         gboolean retvalue = FALSE;
624
625         /* First we fetch all toplevels */
626         toplevels = gtk_window_list_toplevels ();
627         for (node = toplevels; node != NULL; node = g_list_next (node)) {
628                 if (GTK_IS_WINDOW (node->data) &&
629                     gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (window) &&
630                     GTK_WIDGET_VISIBLE (node->data)) {
631                         retvalue = TRUE;
632                         break;
633                 }
634         }
635         g_list_free (toplevels);
636         return retvalue;
637 }
638
639 static gboolean
640 on_window_destroy (ModestWindow *window, 
641                    GdkEvent *event,
642                    ModestHildon2WindowMgr *self)
643 {
644         gboolean no_propagate = FALSE;
645
646         /* Do not close the window if it has modals on top */
647         if (!MODEST_IS_MSG_EDIT_WINDOW (window) && window_has_modals (window))
648                 return TRUE;
649
650         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
651                 gboolean sent = FALSE;
652                 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
653                 /* Save currently edited message to Drafts if it was not sent */
654                 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
655                         ModestMsgEditWindow *edit_window;
656                         MsgData *data;
657
658                         edit_window = MODEST_MSG_EDIT_WINDOW (window);
659                         data = modest_msg_edit_window_get_msg_data (edit_window);
660
661                         if (data) {
662                                 gint parts_count;
663                                 guint64 parts_size, available_size, expected_size;
664
665                                 available_size = modest_utils_get_available_space (NULL);
666                                 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
667                                 expected_size = modest_tny_msg_estimate_size (data->plain_body,
668                                                                               data->html_body,
669                                                                               parts_count,
670                                                                               parts_size);
671                                 modest_msg_edit_window_free_msg_data (edit_window, data);
672                                 data = NULL;
673
674                                 /* If there is not enough space
675                                    available for saving the message
676                                    then show an error and close the
677                                    window without saving */
678                                 if (expected_size >= available_size) {
679                                         modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
680                                                                                 _("mail_in_ui_save_error"),
681                                                                                 FALSE);
682                                 } else {
683                                         if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
684                                                 return TRUE;
685                                 }
686                         } else {
687                                 g_warning ("Edit window without message data. This is probably a bug");
688                         }
689                 }
690         }
691
692         /* Unregister window */
693         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
694         no_propagate = FALSE;
695
696         return no_propagate;
697 }
698
699 static void
700 modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
701                                              ModestWindow *window)
702 {
703         GList *win;
704         ModestHildon2WindowMgrPrivate *priv;
705         gulong *tmp, handler_id;
706         guint num_windows;
707
708         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
709         g_return_if_fail (MODEST_IS_WINDOW (window));
710
711         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
712
713         win = g_list_find (priv->window_list, window);
714         if (!win) {
715                 g_debug ("Trying to unregister a window that has not being registered yet");
716                 return;
717         }
718
719         /* Remove the viewer window handler from the hash table. The
720            HashTable could not exist if the main window was closed
721            when there were other windows remaining */
722         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
723                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
724                 /* If the viewer was created without a main window
725                    (for example when opening a message through D-Bus
726                    the viewer handlers was not registered */
727                 if (tmp) {
728                         g_signal_handler_disconnect (window, *tmp);
729                         g_hash_table_remove (priv->viewer_handlers, window);
730                 }
731         }
732
733         /* Remove from list & hash table */
734         priv->window_list = g_list_remove_link (priv->window_list, win);
735         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
736         handler_id = *tmp;
737
738         g_hash_table_remove (priv->destroy_handlers, window);
739
740         /* cancel open and receive operations */
741         cancel_window_operations (window);
742
743         /* Disconnect the "window-state-event" handler, we won't need it anymore */
744         if (priv->window_state_uids) {
745                 priv->window_state_uids = 
746                         modest_signal_mgr_disconnect (priv->window_state_uids, 
747                                                       G_OBJECT (window), 
748                                                       "notify::is-topmost");
749         }
750
751         /* Disconnect the "delete-event" handler, we won't need it anymore */
752         g_signal_handler_disconnect (window, handler_id);
753
754         /* Destroy the window */
755         g_object_unref (win->data);
756         g_list_free (win);
757
758         MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
759
760         /* We have to get the number of windows here in order not to
761            emit the signal too many times */
762         num_windows = modest_window_mgr_get_num_windows (self);
763
764         /* If there are no more windows registered emit the signal */
765         if (num_windows == 0)
766                 g_signal_emit_by_name (self, "window-list-empty");
767 }
768
769
770 static void
771 modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
772                                                gboolean on)
773 {
774         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
775
776         return;
777 }
778
779 static gboolean
780 modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
781 {
782         return FALSE;
783 }
784
785 static void 
786 modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
787                                          GType window_type,
788                                          gboolean show_toolbars,
789                                          gboolean fullscreen)
790 {
791         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
792
793         return;
794 }
795
796 static gint
797 look_for_transient (gconstpointer a,
798                     gconstpointer b)
799 {
800         GtkWindow *win, *child;
801
802         if (a == b)
803                 return 1;
804
805         child = (GtkWindow *) b;
806         win = (GtkWindow *) a;
807
808         if ((gtk_window_get_transient_for (win) == child) &&
809             GTK_WIDGET_VISIBLE (win))
810                 return 0;
811         else
812                 return 1;
813 }
814
815 static GtkWindow *
816 modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self)
817 {
818         ModestHildon2WindowMgrPrivate *priv;
819         GList *toplevel_list;
820         GtkWidget *current_top, *toplevel;
821         HildonWindowStack *stack;
822
823         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
824         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
825
826         /* Get current top */
827         stack = hildon_window_stack_get_default ();
828         current_top = hildon_window_stack_peek (stack);
829         toplevel = current_top;
830         toplevel_list = gtk_window_list_toplevels ();
831
832         while (toplevel) {
833                 GList *parent_link;
834
835                 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
836                 if (parent_link)
837                         toplevel = (GtkWidget *) parent_link->data;
838                 else
839                         break;
840         }
841
842         if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
843                 return (GtkWindow *) toplevel;
844         else
845                 return NULL;
846 }
847
848
849 static void
850 modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
851                                      GtkWindow *window,
852                                      GtkWindow *parent)
853 {
854         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
855         g_return_if_fail (GTK_IS_WINDOW (window));
856
857         gtk_window_set_modal (window, TRUE);
858         gtk_window_set_transient_for (window, parent);
859         gtk_window_set_destroy_with_parent (window, TRUE);
860 }
861
862 static void
863 close_all_but_first (gpointer data)
864 {
865         gint num_windows, i;
866         gboolean retval;
867         HildonWindowStack *stack;
868
869         stack = hildon_window_stack_get_default ();
870         g_return_if_fail (stack);
871
872         num_windows = hildon_window_stack_size (stack);
873
874         for (i = 0; i < (num_windows - 1); i++) {
875                 GtkWidget *current_top;
876
877                 /* Close window */
878                 current_top = hildon_window_stack_peek (stack);
879                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
880         }
881 }
882
883 static gboolean
884 on_idle_close_all_but_first (gpointer data)
885 {
886         gdk_threads_enter ();
887         close_all_but_first (data);
888         gdk_threads_leave ();
889
890         return FALSE;
891 }
892
893 static void
894 on_account_removed (TnyAccountStore *acc_store,
895                     TnyAccount *account,
896                     gpointer user_data)
897 {
898         HildonWindowStack *stack;
899         ModestWindow *current_top;
900
901         /* Ignore transport account removals */
902         if (TNY_IS_TRANSPORT_ACCOUNT (account))
903                 return;
904
905         stack = hildon_window_stack_get_default ();
906         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
907
908         /* if we're showing the header view of the currently deleted
909            account, or the outbox and we deleted the last account,
910            then close the window */
911         if (current_top &&
912             (MODEST_IS_HEADER_WINDOW (current_top) ||
913              MODEST_IS_FOLDER_WINDOW (current_top))) {
914                     const gchar *acc_name;
915
916                     acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
917
918                     /* We emit it in an idle, because sometimes this
919                        function could called when the account settings
920                        dialog is about to close but still there. That
921                        modal dialog would otherwise, prevent the
922                        windows from being closed */
923                     if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
924                             g_idle_add (on_idle_close_all_but_first, NULL);
925         }
926 }
927
928 static ModestWindow *
929 modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self)
930 {
931         ModestWindow *initial_window = NULL;
932         ModestHildon2WindowMgrPrivate *priv;
933
934         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
935
936         /* Connect to the account store "account-removed" signal". We
937            do this here because in the init the singletons are still
938            not initialized properly */
939         if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
940                                             priv->accounts_handler)) {
941                 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
942                                                            "account-removed",
943                                                            G_CALLBACK (on_account_removed),
944                                                            self);
945         }
946
947         /* Return accounts window */
948         initial_window = MODEST_WINDOW (modest_accounts_window_new ());
949         modest_window_mgr_register_window (self, initial_window, NULL);
950
951         return initial_window;
952 }
953
954
955 static ModestWindow *
956 modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self)
957 {
958         HildonWindowStack *stack;
959         stack = hildon_window_stack_get_default ();
960         return (ModestWindow *) hildon_window_stack_peek (stack);
961 }
962
963 static gint 
964 find_folder_window (gconstpointer a,
965                     gconstpointer b)
966 {
967         return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
968 }
969
970 ModestWindow *
971 modest_hildon2_window_mgr_get_folder_window (ModestHildon2WindowMgr *self)
972 {
973         ModestHildon2WindowMgrPrivate *priv;
974         GList *window;
975
976         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
977
978         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
979
980         window = g_list_find_custom (priv->window_list,
981                                      NULL,
982                                      find_folder_window);
983
984         return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
985 }
986
987 static gboolean
988 modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self)
989 {
990         ModestHildon2WindowMgrPrivate *priv = NULL;
991
992         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
993
994         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
995         
996         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
997 }
998
999 static void
1000 modest_hildon2_window_mgr_create_caches (ModestWindowMgr *self)
1001 {
1002         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
1003
1004         modest_accounts_window_pre_create ();
1005
1006         MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
1007 }
1008
1009 static void
1010 osso_display_event_cb (osso_display_state_t state,
1011                        gpointer data)
1012 {
1013         ModestHildon2WindowMgrPrivate *priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (data);
1014
1015         priv->display_state = state;
1016
1017         /* Stop blinking if the screen becomes on */
1018         if (priv->display_state == OSSO_DISPLAY_ON)
1019                 modest_platform_remove_new_mail_notifications (TRUE);
1020 }
1021
1022 static gboolean
1023 modest_hildon2_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1024 {
1025         ModestWindow *top;
1026
1027         /* Exit if there are no windows */
1028         if (!modest_window_mgr_get_num_windows (self)) {
1029                 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
1030                 return FALSE;
1031         }
1032
1033         /* Close active modals */
1034         if (!_modest_window_mgr_close_active_modals (self)) {
1035                 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
1036                 return FALSE;
1037         }
1038
1039         /* Close all but first */
1040         top = modest_window_mgr_get_current_top (self);
1041         if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1042                 close_all_but_first (NULL);
1043
1044         /* If some cannot be closed return */
1045         top = modest_window_mgr_get_current_top (self);
1046         if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1047                 g_debug ("%s: could not close some windows", __FUNCTION__);
1048                 return FALSE;
1049         }
1050
1051         return TRUE;
1052 }