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