New show toolbar button in editor (fixes NB#152559).
[modest] / src / hildon2 / modest-hildon2-window-mgr.c
1 /* Copyright (c) 2008, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31 #include <hildon/hildon.h>
32 #include "modest-hildon2-window.h"
33 #include "modest-hildon2-window-mgr.h"
34 #include "modest-msg-edit-window.h"
35 #include "modest-mailboxes-window.h"
36 #include "modest-header-window.h"
37 #include "modest-main-window.h"
38 #include "modest-window-mgr-priv.h"
39 #include "modest-conf.h"
40 #include "modest-defs.h"
41 #include "modest-signal-mgr.h"
42 #include "modest-runtime.h"
43 #include "modest-platform.h"
44 #include "modest-ui-actions.h"
45 #include "modest-debug.h"
46 #include "modest-tny-folder.h"
47 #include "modest-folder-window.h"
48 #include "modest-accounts-window.h"
49 #include "modest-maemo-utils.h"
50 #include "modest-utils.h"
51 #include "modest-tny-msg.h"
52 #include "modest-tny-account.h"
53 #include <tny-merge-folder.h>
54
55 /* 'private'/'protected' functions */
56 static void modest_hildon2_window_mgr_class_init (ModestHildon2WindowMgrClass *klass);
57 static void modest_hildon2_window_mgr_instance_init (ModestHildon2WindowMgr *obj);
58 static void modest_hildon2_window_mgr_finalize   (GObject *obj);
59
60 static gboolean on_window_destroy        (ModestWindow *window,
61                                           GdkEvent *event,
62                                           ModestHildon2WindowMgr *self);
63
64 static gboolean modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
65                                                            ModestWindow *window,
66                                                            ModestWindow *parent);
67 static void modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
68                                                          ModestWindow *window);
69 static void modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
70                                                            gboolean on);
71 static gboolean modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self);
72 static void modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
73                                                      GType window_type,
74                                                      gboolean show_toolbars,
75                                                      gboolean fullscreen);
76 static ModestWindow* modest_hildon2_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show);
77 static GtkWindow *modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self);
78 static void modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
79                                                  GtkWindow *window,
80                                                  GtkWindow *parent);
81 static gboolean modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, 
82                                                                   TnyHeader *header,
83                                                                   ModestWindow **win);
84 static gboolean modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, 
85                                                                        const gchar *msg_uid,
86                                                                        ModestWindow **win);
87 static GList *modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self);
88 static gboolean modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self);
89 static gboolean modest_hildon2_window_mgr_close_all_but_initial (ModestWindowMgr *self);
90 static gboolean window_has_modals (ModestWindow *window);
91 static ModestWindow *modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self);
92 static ModestWindow *modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self);
93 static gboolean modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self);
94 static void modest_hildon2_window_mgr_create_caches (ModestWindowMgr *self);
95 static void osso_display_event_cb (osso_display_state_t state, 
96                                    gpointer data);
97 static void on_account_removed (TnyAccountStore *acc_store, 
98                                 TnyAccount *account,
99                                 gpointer user_data);
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_main_window = modest_hildon2_window_mgr_get_main_window;
170         mgr_class->get_modal = modest_hildon2_window_mgr_get_modal;
171         mgr_class->set_modal = modest_hildon2_window_mgr_set_modal;
172         mgr_class->find_registered_header = modest_hildon2_window_mgr_find_registered_header;
173         mgr_class->find_registered_message_uid = modest_hildon2_window_mgr_find_registered_message_uid;
174         mgr_class->get_window_list = modest_hildon2_window_mgr_get_window_list;
175         mgr_class->close_all_windows = modest_hildon2_window_mgr_close_all_windows;
176         mgr_class->close_all_but_initial = modest_hildon2_window_mgr_close_all_but_initial;
177         mgr_class->show_initial_window = modest_hildon2_window_mgr_show_initial_window;
178         mgr_class->get_current_top = modest_hildon2_window_mgr_get_current_top;
179         mgr_class->screen_is_on = modest_hildon2_window_mgr_screen_is_on;
180         mgr_class->create_caches = modest_hildon2_window_mgr_create_caches;
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         /* Do not unref priv->main_window because it does not hold a
268            new reference */
269
270         G_OBJECT_CLASS(parent_class)->finalize (obj);
271 }
272
273 ModestWindowMgr*
274 modest_hildon2_window_mgr_new (void)
275 {
276         return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_HILDON2_WINDOW_MGR, NULL));
277 }
278
279 static gboolean
280 modest_hildon2_window_mgr_close_all_windows (ModestWindowMgr *self)
281 {
282         ModestHildon2WindowMgrPrivate *priv = NULL;
283         gboolean ret_value = FALSE;
284         GtkWidget *window;
285         HildonWindowStack *stack;
286         gboolean failed = FALSE;
287
288         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
289         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
290
291         stack = hildon_window_stack_get_default ();
292
293         while ((window = hildon_window_stack_peek (stack)) != NULL) {
294                 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &ret_value);
295                 if (ret_value == TRUE) {
296                         failed = TRUE;
297                         break;
298                 }
299         }
300
301         return !failed;
302 }
303
304 static gint
305 compare_msguids (ModestWindow *win,
306                  const gchar *uid)
307 {
308         const gchar *msg_uid;
309
310         if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
311                 return 1;
312
313         /* Get message uid from msg window */
314         if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
315                 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
316                 if (msg_uid && uid &&!strcmp (msg_uid, uid))
317                         return 0;
318         } else {
319                 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
320         }
321
322         if (msg_uid && uid &&!strcmp (msg_uid, uid))
323                 return 0;
324         else
325                 return 1;
326 }
327
328 static gint
329 compare_headers (ModestWindow *win,
330                  TnyHeader *header)
331 {
332         TnyHeader *my_header;
333         gint result = 1;
334
335         if (!MODEST_IS_MSG_VIEW_WINDOW (win))
336                 return 1;
337
338         /* Get message uid from msg window */
339         my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
340         if (my_header) {
341                 if (my_header == header)
342                         result = 0;
343                 g_object_unref (my_header);
344         }
345         return result;
346 }
347
348
349 static gboolean
350 modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
351                                                   ModestWindow **win)
352 {
353         ModestHildon2WindowMgrPrivate *priv = NULL;
354         gchar* uid = NULL;
355         gboolean has_header, has_window = FALSE;
356         GList *item = NULL;
357
358         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
359         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
360         
361         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
362
363         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
364         
365         uid = modest_tny_folder_get_header_unique_id (header);
366         
367         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
368         if (item) {
369                 has_window = TRUE;
370                 if (win) {
371                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
372                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
373                                 g_debug ("not a valid window!");
374                         else {
375                                 g_debug ("found a window");
376                                 *win = MODEST_WINDOW (item->data);
377                         }
378                 }
379         }
380         g_free (uid);
381         
382         return has_header || has_window;
383 }
384
385 static gboolean
386 modest_hildon2_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
387                                                        ModestWindow **win)
388 {
389         ModestHildon2WindowMgrPrivate *priv = NULL;
390         gboolean has_header, has_window = FALSE;
391         GList *item = NULL;
392
393         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
394         g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
395         
396         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
397
398         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
399         
400         item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
401         if (item) {
402                 has_window = TRUE;
403                 if (win) {
404                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
405                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
406                                 g_debug ("not a valid window!");
407                         else {
408                                 g_debug ("found a window");
409                                 *win = MODEST_WINDOW (item->data);
410                         }
411                 }
412         }
413         
414         return has_header || has_window;
415 }
416
417 static GList *
418 modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self)
419 {
420         ModestHildon2WindowMgrPrivate *priv;
421
422         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
423         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
424
425         return g_list_copy (priv->window_list);
426 }
427
428 static gboolean
429 modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
430                                            ModestWindow *window,
431                                            ModestWindow *parent)
432 {
433         GList *win;
434         ModestHildon2WindowMgrPrivate *priv;
435         gint *handler_id;
436         HildonWindowStack *stack;
437         gboolean nested_msg = FALSE;
438         ModestWindow *current_top;
439         const gchar *acc_name;
440
441         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
442         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
443
444         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
445
446         /* Try to close active modal dialogs */
447         if (modest_window_mgr_get_num_windows (self) &&
448             !_modest_window_mgr_close_active_modals (self))
449                 return FALSE;
450
451         stack = hildon_window_stack_get_default ();
452         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
453
454         win = g_list_find (priv->window_list, window);
455         if (win) {
456                 /* this is for the case we want to register the window
457                    and it was already registered */
458                 gtk_window_present (GTK_WINDOW (window));
459                 return FALSE;
460         }
461
462         /* Do not allow standalone editors or standalone viewers */
463         if (!current_top &&
464             (MODEST_IS_MSG_VIEW_WINDOW (window) ||
465              MODEST_IS_MSG_EDIT_WINDOW (window)))
466                 modest_window_mgr_show_initial_window (self);
467
468         if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
469                 gchar *uid;
470                 TnyHeader *header;
471
472                 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
473                 
474                 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
475
476                 if (uid == NULL)
477                         uid = modest_tny_folder_get_header_unique_id (header);
478                 /* Embedded messages do not have uid */
479                 if (uid) {
480                         if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
481                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
482                                 g_free (uid);
483                                 g_object_unref (header);
484                                 return FALSE;
485                         }
486                         g_free (uid);
487                 } else if (header) {
488                         if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
489                                 g_debug ("%s found another view window showing the same header", __FUNCTION__);
490                                 g_object_unref (header);
491                                 return FALSE;
492                         }
493                 }
494                 if (header)
495                         g_object_unref (header);
496         }
497
498         /* Do not go backwards */
499         if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
500              MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
501              MODEST_IS_HEADER_WINDOW (current_top)) &&
502             (MODEST_IS_FOLDER_WINDOW (window) ||
503              MODEST_IS_ACCOUNTS_WINDOW (window) ||
504              MODEST_IS_MAILBOXES_WINDOW (window))) {
505                 gtk_window_present (GTK_WINDOW (current_top));
506                 return FALSE;
507         }
508
509         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
510                 gboolean retval;
511
512                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
513
514                 if (retval) {
515                         gtk_window_present (GTK_WINDOW (current_top));
516                         return FALSE;
517                 }
518                 current_top = (ModestWindow *) hildon_window_stack_peek (stack);
519         }
520
521         if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
522                 gtk_window_present (GTK_WINDOW (current_top));
523                 return FALSE;
524         }
525
526         /* Mailboxes window can not replace folder windows */
527         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
528                 gtk_window_present (GTK_WINDOW (current_top));
529                 return FALSE;
530         }
531
532         /* Trying to open a folders window and a mailboxes window at
533            the same time from the accounts window is not allowed */
534         if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
535             MODEST_IS_FOLDER_WINDOW (window) &&
536             MODEST_IS_ACCOUNTS_WINDOW (parent)) {
537                 gtk_window_present (GTK_WINDOW (window));
538                 return FALSE;
539         }
540
541         if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
542                 g_debug ("Trying to register a second header window is not allowed");
543                 gtk_window_present (GTK_WINDOW (current_top));
544                 return FALSE;
545         }
546
547         if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
548                 goto fail;
549
550         /* Add to list. Keep a reference to the window */
551         g_object_ref (window);
552         priv->window_list = g_list_prepend (priv->window_list, window);
553
554         nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
555                 MODEST_IS_MSG_VIEW_WINDOW (parent);
556
557         /* Close views if they're being shown. Nevertheless we must
558            allow nested messages */
559         if (!nested_msg &&
560             (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
561              MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
562                 gboolean retval;
563
564                 /* If the current view has modal dialogs then
565                    we fail to register the new view */
566                 if ((current_top != NULL) &&
567                     window_has_modals (MODEST_WINDOW (current_top))) {
568                         /* Window on top but it has opened dialogs */
569                         goto fail;
570                 }
571
572                 /* Close the current view */
573                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
574                 if (retval) {
575                         /* Cancelled closing top window, then we fail to register */
576                         goto fail;
577                 }
578         }
579
580         /* Listen to object destruction */
581         handler_id = g_malloc0 (sizeof (gint));
582         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
583         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
584
585         if (!MODEST_IS_MSG_EDIT_WINDOW (window) &&
586             !MODEST_IS_ACCOUNTS_WINDOW (window)) {
587                 acc_name = modest_window_get_active_account (window);
588
589                 if (acc_name) {
590                         modest_platform_remove_new_mail_notifications (FALSE, acc_name);
591                 }
592         }
593
594         /* Show toolbar always */
595         if (MODEST_MSG_EDIT_WINDOW (window)) {
596                 gboolean show_toolbar;
597                 show_toolbar = modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_EDIT_WINDOW_SHOW_TOOLBAR, NULL);
598                 modest_window_show_toolbar (window, show_toolbar);
599         } else {
600                 modest_window_show_toolbar (window, TRUE);
601         }
602
603         return TRUE;
604 fail:
605         /* Add to list. Keep a reference to the window */
606         priv->window_list = g_list_remove (priv->window_list, window);
607         g_object_unref (window);
608         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
609         if (current_top)
610                 gtk_window_present (GTK_WINDOW (current_top));
611         return FALSE;
612 }
613
614 static void
615 cancel_window_operations (ModestWindow *window)
616 {
617         GSList* pending_ops = NULL;
618
619         /* cancel open and receive operations */
620         pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (), 
621                                                                  G_OBJECT (window));
622         while (pending_ops != NULL) {
623                 ModestMailOperationTypeOperation type;
624                 GSList* tmp_list = NULL;
625
626                 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
627                 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
628                     type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
629                     type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
630                         modest_mail_operation_cancel (pending_ops->data);
631                 }
632                 g_object_unref (G_OBJECT (pending_ops->data));
633                 tmp_list = pending_ops;
634                 pending_ops = g_slist_next (pending_ops);
635                 g_slist_free_1 (tmp_list);
636         }
637 }
638
639 static gboolean
640 window_has_modals (ModestWindow *window)
641 {
642         GList *toplevels;
643         GList *node;
644         gboolean retvalue = FALSE;
645
646         /* First we fetch all toplevels */
647         toplevels = gtk_window_list_toplevels ();
648         for (node = toplevels; node != NULL; node = g_list_next (node)) {
649                 if (GTK_IS_WINDOW (node->data) &&
650                     gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (window) &&
651                     GTK_WIDGET_VISIBLE (node->data)) {
652                         retvalue = TRUE;
653                         break;
654                 }
655         }
656         g_list_free (toplevels);
657         return retvalue;
658 }
659
660 static gboolean
661 on_window_destroy (ModestWindow *window, 
662                    GdkEvent *event,
663                    ModestHildon2WindowMgr *self)
664 {
665         gboolean no_propagate = FALSE;
666
667         /* Do not close the window if it has modals on top */
668         if (!MODEST_IS_MSG_EDIT_WINDOW (window) && window_has_modals (window))
669                 return TRUE;
670
671         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
672                 gboolean sent = FALSE;
673                 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
674                 /* Save currently edited message to Drafts if it was not sent */
675                 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
676                         ModestMsgEditWindow *edit_window;
677                         MsgData *data;
678
679                         edit_window = MODEST_MSG_EDIT_WINDOW (window);
680                         data = modest_msg_edit_window_get_msg_data (edit_window);
681
682                         if (data) {
683                                 gint parts_count;
684                                 guint64 parts_size, available_size, expected_size;
685
686                                 available_size = modest_utils_get_available_space (NULL);
687                                 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
688                                 expected_size = modest_tny_msg_estimate_size (data->plain_body,
689                                                                               data->html_body,
690                                                                               parts_count,
691                                                                               parts_size);
692                                 modest_msg_edit_window_free_msg_data (edit_window, data);
693                                 data = NULL;
694
695                                 /* If there is not enough space
696                                    available for saving the message
697                                    then show an error and close the
698                                    window without saving */
699                                 if (expected_size >= available_size) {
700                                         modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
701                                                                                 _("mail_in_ui_save_error"),
702                                                                                 FALSE);
703                                 } else {
704                                         if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
705                                                 return TRUE;
706                                 }
707                         } else {
708                                 g_warning ("Edit window without message data. This is probably a bug");
709                         }
710                 }
711         }
712
713         /* Unregister window */
714         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
715         no_propagate = FALSE;
716
717         return no_propagate;
718 }
719
720 static void
721 modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
722                                              ModestWindow *window)
723 {
724         GList *win;
725         ModestHildon2WindowMgrPrivate *priv;
726         gulong *tmp, handler_id;
727         guint num_windows;
728
729         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
730         g_return_if_fail (MODEST_IS_WINDOW (window));
731
732         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
733
734         win = g_list_find (priv->window_list, window);
735         if (!win) {
736                 g_debug ("Trying to unregister a window that has not being registered yet");
737                 return;
738         }
739
740         /* Remove the viewer window handler from the hash table. The
741            HashTable could not exist if the main window was closed
742            when there were other windows remaining */
743         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
744                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
745                 /* If the viewer was created without a main window
746                    (for example when opening a message through D-Bus
747                    the viewer handlers was not registered */
748                 if (tmp) {
749                         g_signal_handler_disconnect (window, *tmp);
750                         g_hash_table_remove (priv->viewer_handlers, window);
751                 }
752         }
753
754         /* Remove from list & hash table */
755         priv->window_list = g_list_remove_link (priv->window_list, win);
756         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
757         handler_id = *tmp;
758
759         g_hash_table_remove (priv->destroy_handlers, window);
760
761         /* cancel open and receive operations */
762         cancel_window_operations (window);
763
764         /* Disconnect the "window-state-event" handler, we won't need it anymore */
765         if (priv->window_state_uids) {
766                 priv->window_state_uids = 
767                         modest_signal_mgr_disconnect (priv->window_state_uids, 
768                                                       G_OBJECT (window), 
769                                                       "notify::is-topmost");
770         }
771
772         /* Disconnect the "delete-event" handler, we won't need it anymore */
773         g_signal_handler_disconnect (window, handler_id);
774
775         /* Destroy the window */
776         g_object_unref (win->data);
777         g_list_free (win);
778
779         MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
780
781         /* We have to get the number of windows here in order not to
782            emit the signal too many times */
783         num_windows = modest_window_mgr_get_num_windows (self);
784
785         /* If there are no more windows registered emit the signal */
786         if (num_windows == 0)
787                 g_signal_emit_by_name (self, "window-list-empty");
788 }
789
790
791 static void
792 modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
793                                                gboolean on)
794 {
795         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
796
797         return;
798 }
799
800 static gboolean
801 modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
802 {
803         return FALSE;
804 }
805
806 static void 
807 modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
808                                          GType window_type,
809                                          gboolean show_toolbars,
810                                          gboolean fullscreen)
811 {
812         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
813
814         return;
815 }
816
817 static ModestWindow*  
818 modest_hildon2_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
819 {
820         ModestHildon2WindowMgrPrivate *priv;
821         ModestWindow *result;
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         /* TODO: make this return NULL always */
827
828         result = MODEST_WINDOW_MGR_CLASS (parent_class)->get_main_window (self, FALSE);
829         /* create the main window, if it hasn't been created yet */
830         if (!result && show) {
831                 /* modest_window_mgr_register_window will set priv->main_window */
832                 result = modest_main_window_new ();
833                 /* We have to remove all other windows */
834                 if (!modest_window_mgr_close_all_windows (self)) {
835                         gtk_widget_destroy (GTK_WIDGET (result));
836                         return NULL;
837                 }
838                 if (!modest_window_mgr_register_window (self, result, NULL)) {
839                         gtk_widget_destroy (GTK_WIDGET (result));
840                         return NULL;
841                 }
842                 MODEST_DEBUG_BLOCK(
843                         g_debug ("%s: created main window: %p\n", __FUNCTION__, result);
844                 );
845         }
846         if (show) {
847                 gtk_widget_show_all (GTK_WIDGET (result));
848                 gtk_window_present (GTK_WINDOW (result));
849         }
850
851         return result;
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
920 static void
921 close_all_but_first (gpointer data)
922 {
923         gint num_windows, i;
924         gboolean retval;
925         HildonWindowStack *stack;
926
927         stack = hildon_window_stack_get_default ();
928         g_return_if_fail (stack);
929
930         num_windows = hildon_window_stack_size (stack);
931
932         for (i = 0; i < (num_windows - 1); i++) {
933                 GtkWidget *current_top;
934
935                 /* Close window */
936                 current_top = hildon_window_stack_peek (stack);
937                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
938         }
939 }
940
941 static gboolean
942 on_idle_close_all_but_first (gpointer data)
943 {
944         gdk_threads_enter ();
945         close_all_but_first (data);
946         gdk_threads_leave ();
947
948         return FALSE;
949 }
950
951 static void
952 on_account_removed (TnyAccountStore *acc_store,
953                     TnyAccount *account,
954                     gpointer user_data)
955 {
956         HildonWindowStack *stack;
957         ModestWindow *current_top;
958
959         /* Ignore transport account removals */
960         if (TNY_IS_TRANSPORT_ACCOUNT (account))
961                 return;
962
963         stack = hildon_window_stack_get_default ();
964         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
965
966         /* if we're showing the header view of the currently deleted
967            account, or the outbox and we deleted the last account,
968            then close the window */
969         if (current_top &&
970             (MODEST_IS_HEADER_WINDOW (current_top) ||
971              MODEST_IS_FOLDER_WINDOW (current_top))) {
972                     const gchar *acc_name;
973
974                     acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
975
976                     /* We emit it in an idle, because sometimes this
977                        function could called when the account settings
978                        dialog is about to close but still there. That
979                        modal dialog would otherwise, prevent the
980                        windows from being closed */
981                     if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
982                             g_idle_add (on_idle_close_all_but_first, NULL);
983         }
984 }
985
986 static ModestWindow *
987 modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self)
988 {
989         ModestWindow *initial_window = NULL;
990         ModestHildon2WindowMgrPrivate *priv;
991
992         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
993
994         /* Connect to the account store "account-removed" signal". We
995            do this here because in the init the singletons are still
996            not initialized properly */
997         if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
998                                             priv->accounts_handler)) {
999                 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
1000                                                            "account-removed",
1001                                                            G_CALLBACK (on_account_removed),
1002                                                            self);
1003         }
1004
1005         /* Return accounts window */
1006         initial_window = MODEST_WINDOW (modest_accounts_window_new ());
1007         modest_window_mgr_register_window (self, initial_window, NULL);
1008
1009         return initial_window;
1010 }
1011
1012
1013 static ModestWindow *
1014 modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self)
1015 {
1016         HildonWindowStack *stack;
1017         stack = hildon_window_stack_get_default ();
1018         return (ModestWindow *) hildon_window_stack_peek (stack);
1019 }
1020
1021 static gint 
1022 find_folder_window (gconstpointer a,
1023                     gconstpointer b)
1024 {
1025         return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
1026 }
1027
1028 ModestWindow *
1029 modest_hildon2_window_mgr_get_folder_window (ModestHildon2WindowMgr *self)
1030 {
1031         ModestHildon2WindowMgrPrivate *priv;
1032         GList *window;
1033
1034         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
1035
1036         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
1037
1038         window = g_list_find_custom (priv->window_list,
1039                                      NULL,
1040                                      find_folder_window);
1041
1042         return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
1043 }
1044
1045 static gboolean
1046 modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self)
1047 {
1048         ModestHildon2WindowMgrPrivate *priv = NULL;
1049
1050         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
1051
1052         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
1053         
1054         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
1055 }
1056
1057 static void
1058 modest_hildon2_window_mgr_create_caches (ModestWindowMgr *self)
1059 {
1060         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
1061
1062         modest_accounts_window_pre_create ();
1063
1064         MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
1065 }
1066
1067 static void
1068 osso_display_event_cb (osso_display_state_t state,
1069                        gpointer data)
1070 {
1071         ModestHildon2WindowMgrPrivate *priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (data);
1072
1073         priv->display_state = state;
1074
1075         /* Stop blinking if the screen becomes on */
1076         if (priv->display_state == OSSO_DISPLAY_ON)
1077                 modest_platform_remove_new_mail_notifications (TRUE, NULL);
1078 }
1079
1080 static gboolean
1081 modest_hildon2_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1082 {
1083         ModestWindow *top;
1084
1085         /* Exit if there are no windows */
1086         if (!modest_window_mgr_get_num_windows (self)) {
1087                 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
1088                 return FALSE;
1089         }
1090
1091         /* Close active modals */
1092         if (!_modest_window_mgr_close_active_modals (self)) {
1093                 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
1094                 return FALSE;
1095         }
1096
1097         /* Close all but first */
1098         top = modest_window_mgr_get_current_top (self);
1099         if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1100                 close_all_but_first (NULL);
1101
1102         /* If some cannot be closed return */
1103         top = modest_window_mgr_get_current_top (self);
1104         if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1105                 g_debug ("%s: could not close some windows", __FUNCTION__);
1106                 return FALSE;
1107         }
1108
1109         return TRUE;
1110 }