* Fixes NB#106248, do not allow launching a mailbox and folders windows at the same...
[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 gboolean
319 modest_hildon2_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
320                                                   ModestWindow **win)
321 {
322         ModestHildon2WindowMgrPrivate *priv = NULL;
323         gchar* uid = NULL;
324         gboolean has_header, has_window = FALSE;
325         GList *item = NULL;
326
327         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
328         g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
329         
330         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
331
332         has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
333         
334         uid = modest_tny_folder_get_header_unique_id (header);
335         
336         item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
337         if (item) {
338                 has_window = TRUE;
339                 if (win) {
340                         if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) && 
341                             (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
342                                 g_debug ("not a valid window!");
343                         else {
344                                 g_debug ("found a window");
345                                 *win = MODEST_WINDOW (item->data);
346                         }
347                 }
348         }
349         g_free (uid);
350         
351         return has_header || has_window;
352 }
353
354 static GList *
355 modest_hildon2_window_mgr_get_window_list (ModestWindowMgr *self)
356 {
357         ModestHildon2WindowMgrPrivate *priv;
358
359         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
360         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
361
362         return g_list_copy (priv->window_list);
363 }
364
365 static gboolean
366 modest_hildon2_window_mgr_register_window (ModestWindowMgr *self, 
367                                            ModestWindow *window,
368                                            ModestWindow *parent)
369 {
370         GList *win;
371         ModestHildon2WindowMgrPrivate *priv;
372         gint *handler_id;
373         HildonWindowStack *stack;
374         gboolean nested_msg = FALSE;
375         ModestWindow *current_top;
376
377         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
378         g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
379
380         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
381
382         stack = hildon_window_stack_get_default ();
383         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
384
385         win = g_list_find (priv->window_list, window);
386         if (win) {
387                 /* this is for the case we want to register the window
388                    and it was already registered */
389                 gtk_window_present (GTK_WINDOW (win));
390                 return FALSE;
391         }
392
393         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
394                 gtk_window_present (GTK_WINDOW (win));
395                 return FALSE;
396         }
397
398         if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
399                 gtk_window_present (GTK_WINDOW (win));
400                 return FALSE;
401         }
402
403         /* Mailboxes window can not replace folder windows */
404         if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
405                 gtk_window_present (GTK_WINDOW (current_top));
406                 return FALSE;
407         }
408
409         /* Trying to open a folders window and a mailboxes window at
410            the same time from the accounts window is not allowed */
411         if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
412             MODEST_IS_FOLDER_WINDOW (window) &&
413             MODEST_IS_ACCOUNTS_WINDOW (parent)) {
414                 gtk_window_present (GTK_WINDOW (win));
415                 return FALSE;
416         }
417
418         if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
419                 g_debug ("Trying to register a second header window is not allowed");
420                 gtk_window_present (GTK_WINDOW (current_top));
421                 return FALSE;
422         }
423
424         if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
425                 goto fail;
426
427         /* Add to list. Keep a reference to the window */
428         g_object_ref (window);
429         priv->window_list = g_list_prepend (priv->window_list, window);
430
431         nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
432                 MODEST_IS_MSG_VIEW_WINDOW (parent);
433
434         /* Close views if they're being shown. Nevertheless we must
435            allow nested messages */
436         if (!nested_msg &&
437             (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
438              MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
439                 gboolean retval;
440
441                 /* If the current view has modal dialogs then
442                    we fail to register the new view */
443                 if ((current_top != NULL) &&
444                     window_has_modals (MODEST_WINDOW (current_top))) {
445                         /* Window on top but it has opened dialogs */
446                         goto fail;
447                 }
448
449                 /* Close the current view */
450                 g_signal_emit_by_name (G_OBJECT (current_top), "delete-event", NULL, &retval);
451                 if (retval == TRUE) {
452                         /* Cancelled closing top window, then we fail to register */
453                         goto fail;
454                 }
455         }
456
457         /* Listen to object destruction */
458         handler_id = g_malloc0 (sizeof (gint));
459         *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
460         g_hash_table_insert (priv->destroy_handlers, window, handler_id);
461
462         /* Show toolbar always */
463         modest_window_show_toolbar (window, TRUE);
464
465         return TRUE;
466 fail:
467         /* Add to list. Keep a reference to the window */
468         priv->window_list = g_list_remove (priv->window_list, window);
469         g_object_unref (window);
470         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
471         if (current_top)
472                 gtk_window_present (GTK_WINDOW (current_top));
473         return FALSE;
474 }
475
476 static void
477 cancel_window_operations (ModestWindow *window)
478 {
479         GSList* pending_ops = NULL;
480
481         /* cancel open and receive operations */
482         pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (), 
483                                                                  G_OBJECT (window));
484         while (pending_ops != NULL) {
485                 ModestMailOperationTypeOperation type;
486                 GSList* tmp_list = NULL;
487
488                 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
489                 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
490                         modest_mail_operation_cancel (pending_ops->data);
491                 }
492                 g_object_unref (G_OBJECT (pending_ops->data));
493                 tmp_list = pending_ops;
494                 pending_ops = g_slist_next (pending_ops);
495                 g_slist_free_1 (tmp_list);
496         }
497 }
498
499 static gboolean
500 window_has_modals (ModestWindow *window)
501 {
502         GList *toplevels;
503         GList *node;
504         gboolean retvalue = FALSE;
505
506         /* First we fetch all toplevels */
507         toplevels = gtk_window_list_toplevels ();
508         for (node = toplevels; node != NULL; node = g_list_next (node)) {
509                 if (GTK_IS_WINDOW (node->data) &&
510                     gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (window) &&
511                     GTK_WIDGET_VISIBLE (node->data)) {
512                         retvalue = TRUE;
513                         break;
514                 }
515         }
516         g_list_free (toplevels);
517         return retvalue;
518 }
519
520 static gboolean
521 window_can_close (ModestWindow *window)
522 {
523         /* An editor can be always closed no matter the dialogs it has 
524          * on top. */
525         if (MODEST_IS_MSG_EDIT_WINDOW (window))
526                 return TRUE;
527
528         return !window_has_modals (window);
529 }
530
531 static gboolean
532 on_window_destroy (ModestWindow *window, 
533                    GdkEvent *event,
534                    ModestHildon2WindowMgr *self)
535 {
536         gboolean no_propagate = FALSE;
537
538         if (!window_can_close (window))
539                 return TRUE;
540
541         if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
542                 gboolean sent = FALSE;
543                 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
544                 /* Save currently edited message to Drafts if it was not sent */
545                 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
546                         ModestMsgEditWindow *edit_window;
547                         MsgData *data;
548
549                         edit_window = MODEST_MSG_EDIT_WINDOW (window);
550                         data = modest_msg_edit_window_get_msg_data (edit_window);
551
552                         if (data) {
553                                 gint parts_count;
554                                 guint64 parts_size, available_size, expected_size;
555
556                                 available_size = modest_utils_get_available_space (NULL);
557                                 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
558                                 expected_size = modest_tny_msg_estimate_size (data->plain_body,
559                                                                               data->html_body,
560                                                                               parts_count,
561                                                                               parts_size);
562                                 modest_msg_edit_window_free_msg_data (edit_window, data);
563                                 data = NULL;
564
565                                 /* If there is not enough space
566                                    available for saving the message
567                                    then show an error and close the
568                                    window without saving */
569                                 if (expected_size >= available_size) {
570                                         modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
571                                                                                 _("mail_in_ui_save_error"),
572                                                                                 FALSE);
573                                 } else {
574                                         if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
575                                                 return TRUE;
576                                 }
577                         } else {
578                                 g_warning ("Edit window without message data. This is probably a bug");
579                         }
580                 }
581         }
582
583         /* Unregister window */
584         modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
585         no_propagate = FALSE;
586
587         return no_propagate;
588 }
589
590 static void
591 modest_hildon2_window_mgr_unregister_window (ModestWindowMgr *self, 
592                                              ModestWindow *window)
593 {
594         GList *win;
595         ModestHildon2WindowMgrPrivate *priv;
596         gulong *tmp, handler_id;
597         guint num_windows;
598
599         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
600         g_return_if_fail (MODEST_IS_WINDOW (window));
601
602         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
603
604         win = g_list_find (priv->window_list, window);
605         if (!win) {
606                 g_warning ("Trying to unregister a window that has not being registered yet");
607                 return;
608         }
609
610         /* Remove the viewer window handler from the hash table. The
611            HashTable could not exist if the main window was closed
612            when there were other windows remaining */
613         if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
614                 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
615                 /* If the viewer was created without a main window
616                    (for example when opening a message through D-Bus
617                    the viewer handlers was not registered */
618                 if (tmp) {
619                         g_signal_handler_disconnect (window, *tmp);
620                         g_hash_table_remove (priv->viewer_handlers, window);
621                 }
622         }
623
624         /* Remove from list & hash table */
625         priv->window_list = g_list_remove_link (priv->window_list, win);
626         tmp = g_hash_table_lookup (priv->destroy_handlers, window);
627         handler_id = *tmp;
628
629         g_hash_table_remove (priv->destroy_handlers, window);
630
631         /* cancel open and receive operations */
632         cancel_window_operations (window);
633
634         /* Disconnect the "window-state-event" handler, we won't need it anymore */
635         if (priv->window_state_uids) {
636                 priv->window_state_uids = 
637                         modest_signal_mgr_disconnect (priv->window_state_uids, 
638                                                       G_OBJECT (window), 
639                                                       "notify::is-topmost");
640         }
641
642         /* Disconnect the "delete-event" handler, we won't need it anymore */
643         g_signal_handler_disconnect (window, handler_id);
644
645         /* Destroy the window */
646         g_object_unref (win->data);
647         g_list_free (win);
648
649         MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
650
651         /* We have to get the number of windows here in order not to
652            emit the signal too many times */
653         num_windows = modest_window_mgr_get_num_windows (self);
654
655         /* If there are no more windows registered emit the signal */
656         if (num_windows == 0)
657                 g_signal_emit_by_name (self, "window-list-empty");
658 }
659
660
661 static void
662 modest_hildon2_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
663                                                gboolean on)
664 {
665         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
666
667         return;
668 }
669
670 static gboolean
671 modest_hildon2_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
672 {
673         return FALSE;
674 }
675
676 static void 
677 modest_hildon2_window_mgr_show_toolbars (ModestWindowMgr *self,
678                                          GType window_type,
679                                          gboolean show_toolbars,
680                                          gboolean fullscreen)
681 {
682         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
683
684         return;
685 }
686
687 static ModestWindow*  
688 modest_hildon2_window_mgr_get_main_window (ModestWindowMgr *self, gboolean show)
689 {
690         ModestHildon2WindowMgrPrivate *priv;
691         ModestWindow *result;
692
693         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
694         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
695
696         /* TODO: make this return NULL always */
697
698         result = MODEST_WINDOW_MGR_CLASS (parent_class)->get_main_window (self, FALSE);
699         /* create the main window, if it hasn't been created yet */
700         if (!result && show) {
701                 /* modest_window_mgr_register_window will set priv->main_window */
702                 result = modest_main_window_new ();
703                 /* We have to remove all other windows */
704                 if (!modest_window_mgr_close_all_windows (self)) {
705                         gtk_widget_destroy (GTK_WIDGET (result));
706                         return NULL;
707                 }
708                 if (!modest_window_mgr_register_window (self, result, NULL)) {
709                         gtk_widget_destroy (GTK_WIDGET (result));
710                         return NULL;
711                 }
712                 MODEST_DEBUG_BLOCK(
713                         g_debug ("%s: created main window: %p\n", __FUNCTION__, result);
714                 );
715         }
716         if (show) {
717                 gtk_widget_show_all (GTK_WIDGET (result));
718                 gtk_window_present (GTK_WINDOW (result));
719         }
720         
721         return result;
722 }
723
724
725 static GtkWindow *
726 modest_hildon2_window_mgr_get_modal (ModestWindowMgr *self)
727 {
728         ModestHildon2WindowMgrPrivate *priv;
729         GList *toplevel_list;
730         GtkWidget *toplevel;
731         
732         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
733         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
734
735         toplevel = NULL;
736         toplevel_list = gtk_window_list_toplevels ();
737         while (toplevel_list) {
738                 if (gtk_window_is_active (toplevel_list->data)) {
739                         toplevel = toplevel_list->data;
740                         break;
741                 }
742                 toplevel_list = g_list_next (toplevel_list);
743         }
744
745         return NULL;
746 }
747
748
749 static void
750 modest_hildon2_window_mgr_set_modal (ModestWindowMgr *self, 
751                                      GtkWindow *window,
752                                      GtkWindow *parent)
753 {
754         g_return_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self));
755         g_return_if_fail (GTK_IS_WINDOW (window));
756
757         gtk_window_set_modal (window, TRUE);
758         gtk_window_set_transient_for (window, parent);
759         gtk_window_set_destroy_with_parent (window, TRUE);
760 }
761
762 static void
763 on_account_removed (TnyAccountStore *acc_store, 
764                     TnyAccount *account,
765                     gpointer user_data)
766 {
767         HildonWindowStack *stack;
768         ModestWindow *current_top;
769         gboolean has_accounts;
770
771         /* Ignore transport account removals */
772         if (TNY_IS_TRANSPORT_ACCOUNT (account))
773                 return;
774
775         stack = hildon_window_stack_get_default ();
776         current_top = (ModestWindow *) hildon_window_stack_peek (stack);
777         has_accounts = modest_account_mgr_has_accounts (modest_runtime_get_account_mgr (), TRUE);
778
779         /* if we're showing the header view of the currently deleted
780            account, or the outbox and we deleted the last account,
781            then close the window */
782         if (current_top && MODEST_IS_HEADER_WINDOW (current_top)) {
783                 ModestHeaderView *header_view;
784                 TnyFolder *folder;
785                 gboolean deleted = FALSE;
786
787                 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (current_top));
788                 folder = modest_header_view_get_folder (header_view);
789                 if (folder) {
790                         gboolean retval;
791
792                         /* Close if it's my account */
793                         if (!TNY_IS_MERGE_FOLDER (folder)) {
794                                 TnyAccount *my_account;
795
796                                 my_account = tny_folder_get_account (folder);
797                                 if (my_account) {
798                                         if (my_account == account) {
799                                                 g_signal_emit_by_name (G_OBJECT (current_top),
800                                                                        "delete-event",
801                                                                        NULL, &retval);
802                                                 deleted = TRUE;
803                                         }
804                                         g_object_unref (my_account);
805                                 }
806                         }
807
808                         /* Close if viewing outbox and no account left */
809                         if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_OUTBOX) {
810                                 if (!has_accounts) {
811                                         g_signal_emit_by_name (G_OBJECT (current_top),
812                                                                "delete-event",
813                                                                NULL, &retval);
814                                         deleted = TRUE;
815                                 }
816                         }
817                         g_object_unref (folder);
818
819                         if (deleted) {
820                                 current_top = (ModestWindow *) hildon_window_stack_peek (stack);
821                         }
822                 }
823         }
824 }
825
826 static ModestWindow *
827 modest_hildon2_window_mgr_show_initial_window (ModestWindowMgr *self)
828 {
829         ModestWindow *initial_window = NULL;
830         ModestHildon2WindowMgrPrivate *priv;
831
832         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
833
834         /* Connect to the account store "account-removed" signal". We
835            do this here because in the init the singletons are still
836            not initialized properly */
837         if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
838                                             priv->accounts_handler)) {
839                 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
840                                                            "account-removed",
841                                                            G_CALLBACK (on_account_removed),
842                                                            self);
843         }
844
845         /* Return accounts window */
846         initial_window = MODEST_WINDOW (modest_accounts_window_new ());
847         modest_window_mgr_register_window (self, initial_window, NULL);
848
849         return initial_window;
850 }
851
852
853 static ModestWindow *
854 modest_hildon2_window_mgr_get_current_top (ModestWindowMgr *self)
855 {
856         HildonWindowStack *stack;
857         stack = hildon_window_stack_get_default ();
858         return (ModestWindow *) hildon_window_stack_peek (stack);
859 }
860
861 static gint 
862 find_folder_window (gconstpointer a,
863                     gconstpointer b)
864 {
865         return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
866 }
867
868 ModestWindow *
869 modest_hildon2_window_mgr_get_folder_window (ModestHildon2WindowMgr *self)
870 {
871         ModestHildon2WindowMgrPrivate *priv;
872         GList *window;
873
874         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), NULL);
875
876         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
877
878         window = g_list_find_custom (priv->window_list,
879                                      NULL,
880                                      find_folder_window);
881
882         return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
883 }
884
885 static gboolean
886 modest_hildon2_window_mgr_screen_is_on (ModestWindowMgr *self)
887 {
888         ModestHildon2WindowMgrPrivate *priv = NULL;
889
890         g_return_val_if_fail (MODEST_IS_HILDON2_WINDOW_MGR (self), FALSE);
891
892         priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (self);
893         
894         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
895 }
896
897 static void 
898 osso_display_event_cb (osso_display_state_t state, 
899                        gpointer data)
900 {
901         ModestHildon2WindowMgrPrivate *priv = MODEST_HILDON2_WINDOW_MGR_GET_PRIVATE (data);
902
903         priv->display_state = state;
904
905         /* Stop blinking if the screen becomes on */
906         if (priv->display_state == OSSO_DISPLAY_ON)
907                 modest_platform_remove_new_mail_notifications (TRUE);
908 }
909