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