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