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