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