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