1 /* Copyright (c) 2008, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
31 #include "modest-window.h"
32 #include "modest-gtk-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-window-mgr-priv.h"
38 #include "modest-conf.h"
39 #include "modest-defs.h"
40 #include "modest-signal-mgr.h"
41 #include "modest-runtime.h"
42 #include "modest-platform.h"
43 #include "modest-ui-actions.h"
44 #include "modest-debug.h"
45 #include "modest-tny-folder.h"
46 #include "modest-folder-window.h"
47 #include "modest-accounts-window.h"
48 #include "modest-utils.h"
49 #include "modest-tny-msg.h"
50 #include "modest-tny-account.h"
51 #include <modest-shell.h>
52 #include <tny-merge-folder.h>
54 /* 'private'/'protected' functions */
55 static void modest_gtk_window_mgr_class_init (ModestGtkWindowMgrClass *klass);
56 static void modest_gtk_window_mgr_instance_init (ModestGtkWindowMgr *obj);
57 static void modest_gtk_window_mgr_finalize (GObject *obj);
59 static gboolean on_window_destroy (ModestWindow *window,
61 ModestGtkWindowMgr *self);
63 static gboolean modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
65 ModestWindow *parent);
66 static void modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
67 ModestWindow *window);
68 static void modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
70 static gboolean modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self);
71 static void modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
73 gboolean show_toolbars,
75 static GtkWindow *modest_gtk_window_mgr_get_modal (ModestWindowMgr *self);
76 static void modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
79 static gboolean modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self,
82 static gboolean modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self,
85 static GList *modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self);
86 static gboolean modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self);
87 static gboolean modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self);
88 static gboolean window_has_modals (ModestWindow *window);
89 static ModestWindow *modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self);
90 static ModestWindow *modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self);
91 static gboolean modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self);
92 static void modest_gtk_window_mgr_create_caches (ModestWindowMgr *self);
93 static void on_account_removed (TnyAccountStore *acc_store,
96 static ModestWindow *modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self);
98 typedef struct _ModestGtkWindowMgrPrivate ModestGtkWindowMgrPrivate;
99 struct _ModestGtkWindowMgrPrivate {
102 GQueue *modal_windows;
104 gboolean fullscreen_mode;
106 GHashTable *destroy_handlers;
107 GHashTable *viewer_handlers;
108 GSList *window_state_uids;
112 GSList *modal_handler_uids;
113 ModestWindow *current_top;
115 gulong accounts_handler;
118 #define MODEST_GTK_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
119 MODEST_TYPE_GTK_WINDOW_MGR, \
120 ModestGtkWindowMgrPrivate))
122 static GObjectClass *parent_class = NULL;
125 modest_gtk_window_mgr_get_type (void)
127 static GType my_type = 0;
129 static const GTypeInfo my_info = {
130 sizeof(ModestGtkWindowMgrClass),
131 NULL, /* base init */
132 NULL, /* base finalize */
133 (GClassInitFunc) modest_gtk_window_mgr_class_init,
134 NULL, /* class finalize */
135 NULL, /* class data */
136 sizeof(ModestGtkWindowMgr),
138 (GInstanceInitFunc) modest_gtk_window_mgr_instance_init,
141 my_type = g_type_register_static (MODEST_TYPE_WINDOW_MGR,
142 "ModestGtkWindowMgr",
149 modest_gtk_window_mgr_class_init (ModestGtkWindowMgrClass *klass)
151 GObjectClass *gobject_class;
152 ModestWindowMgrClass *mgr_class;
154 gobject_class = (GObjectClass*) klass;
155 mgr_class = (ModestWindowMgrClass *) klass;
157 parent_class = g_type_class_peek_parent (klass);
158 gobject_class->finalize = modest_gtk_window_mgr_finalize;
159 mgr_class->register_window = modest_gtk_window_mgr_register_window;
160 mgr_class->unregister_window = modest_gtk_window_mgr_unregister_window;
161 mgr_class->set_fullscreen_mode = modest_gtk_window_mgr_set_fullscreen_mode;
162 mgr_class->get_fullscreen_mode = modest_gtk_window_mgr_get_fullscreen_mode;
163 mgr_class->show_toolbars = modest_gtk_window_mgr_show_toolbars;
164 mgr_class->get_modal = modest_gtk_window_mgr_get_modal;
165 mgr_class->set_modal = modest_gtk_window_mgr_set_modal;
166 mgr_class->find_registered_header = modest_gtk_window_mgr_find_registered_header;
167 mgr_class->find_registered_message_uid = modest_gtk_window_mgr_find_registered_message_uid;
168 mgr_class->get_window_list = modest_gtk_window_mgr_get_window_list;
169 mgr_class->close_all_windows = modest_gtk_window_mgr_close_all_windows;
170 mgr_class->close_all_but_initial = modest_gtk_window_mgr_close_all_but_initial;
171 mgr_class->show_initial_window = modest_gtk_window_mgr_show_initial_window;
172 mgr_class->get_current_top = modest_gtk_window_mgr_get_current_top;
173 mgr_class->screen_is_on = modest_gtk_window_mgr_screen_is_on;
174 mgr_class->create_caches = modest_gtk_window_mgr_create_caches;
175 mgr_class->get_folder_window = modest_gtk_window_mgr_get_folder_window;
177 g_type_class_add_private (gobject_class, sizeof(ModestGtkWindowMgrPrivate));
182 modest_gtk_window_mgr_instance_init (ModestGtkWindowMgr *obj)
184 ModestGtkWindowMgrPrivate *priv;
186 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
187 priv->window_list = NULL;
188 priv->fullscreen_mode = FALSE;
189 priv->window_state_uids = NULL;
191 priv->modal_windows = g_queue_new ();
192 priv->queue_lock = g_mutex_new ();
194 /* Could not initialize it from gconf, singletons are not
196 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
197 priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
199 priv->closing_time = 0;
201 priv->modal_handler_uids = NULL;
202 priv->shell = modest_shell_new ();
206 modest_gtk_window_mgr_finalize (GObject *obj)
208 ModestGtkWindowMgrPrivate *priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
209 ModestTnyAccountStore *acc_store;
211 modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids);
212 priv->window_state_uids = NULL;
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);
218 if (priv->window_list) {
219 GList *iter = priv->window_list;
220 /* unregister pending windows */
222 ModestWindow *window = (ModestWindow *) iter->data;
223 iter = g_list_next (iter);
224 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window);
226 g_list_free (priv->window_list);
227 priv->window_list = NULL;
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;
236 if (priv->viewer_handlers) {
237 g_hash_table_destroy (priv->viewer_handlers);
238 priv->viewer_handlers = NULL;
241 modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids);
242 priv->modal_handler_uids = NULL;
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);
250 g_mutex_free (priv->queue_lock);
252 G_OBJECT_CLASS(parent_class)->finalize (obj);
256 modest_gtk_window_mgr_new (void)
258 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_GTK_WINDOW_MGR, NULL));
262 modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self)
264 ModestGtkWindowMgrPrivate *priv = NULL;
265 gboolean ret_value = FALSE;
267 gboolean failed = FALSE;
269 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
270 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
272 while ((window = modest_shell_peek_window (MODEST_SHELL (priv->shell))) != NULL) {
273 ret_value = modest_shell_delete_window (MODEST_SHELL (priv->shell), window);
274 if (ret_value == TRUE) {
284 compare_msguids (ModestWindow *win,
287 const gchar *msg_uid;
289 if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
292 /* Get message uid from msg window */
293 if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
294 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
295 if (msg_uid && uid &&!strcmp (msg_uid, uid))
298 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
301 if (msg_uid && uid &&!strcmp (msg_uid, uid))
308 compare_headers (ModestWindow *win,
311 TnyHeader *my_header;
314 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
317 /* Get message uid from msg window */
318 my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
320 if (my_header == header)
322 g_object_unref (my_header);
329 modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
332 ModestGtkWindowMgrPrivate *priv = NULL;
334 gboolean has_header, has_window = FALSE;
337 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
338 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
340 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
342 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
344 uid = modest_tny_folder_get_header_unique_id (header);
346 item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
350 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
351 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
352 g_debug ("not a valid window!");
354 g_debug ("found a window");
355 *win = MODEST_WINDOW (item->data);
361 return has_header || has_window;
365 modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
368 ModestGtkWindowMgrPrivate *priv = NULL;
369 gboolean has_header, has_window = FALSE;
372 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
373 g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
375 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
377 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
379 item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
383 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
384 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
385 g_debug ("not a valid window!");
387 g_debug ("found a window");
388 *win = MODEST_WINDOW (item->data);
393 return has_header || has_window;
397 modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self)
399 ModestGtkWindowMgrPrivate *priv;
401 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
402 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
404 return g_list_copy (priv->window_list);
408 modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
409 ModestWindow *window,
410 ModestWindow *parent)
413 ModestGtkWindowMgrPrivate *priv;
415 gboolean nested_msg = FALSE;
416 ModestWindow *current_top;
418 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
419 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
421 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
423 /* Try to close active modal dialogs */
424 if (modest_window_mgr_get_num_windows (self) &&
425 !_modest_window_mgr_close_active_modals (self))
428 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
430 win = g_list_find (priv->window_list, window);
432 /* this is for the case we want to register the window
433 and it was already registered */
434 gtk_window_present (GTK_WINDOW (priv->shell));
438 /* Do not allow standalone editors or standalone viewers */
440 (MODEST_IS_MSG_VIEW_WINDOW (window) ||
441 MODEST_IS_MSG_EDIT_WINDOW (window)))
442 modest_window_mgr_show_initial_window (self);
444 if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
448 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
450 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
453 uid = modest_tny_folder_get_header_unique_id (header);
454 /* Embedded messages do not have uid */
456 if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
457 g_debug ("%s found another view window showing the same header", __FUNCTION__);
459 g_object_unref (header);
464 if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
465 g_debug ("%s found another view window showing the same header", __FUNCTION__);
466 g_object_unref (header);
471 g_object_unref (header);
474 /* Do not go backwards */
475 if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
476 MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
477 MODEST_IS_HEADER_WINDOW (current_top)) &&
478 (MODEST_IS_FOLDER_WINDOW (window) ||
479 MODEST_IS_ACCOUNTS_WINDOW (window) ||
480 MODEST_IS_MAILBOXES_WINDOW (window))) {
481 gtk_window_present (GTK_WINDOW (priv->shell));
485 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
488 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), shell);
491 gtk_window_present (GTK_WINDOW (priv->shell));
494 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
497 if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
498 gtk_window_present (GTK_WINDOW (priv->shell));
502 /* Mailboxes window can not replace folder windows */
503 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
504 gtk_window_present (GTK_WINDOW (priv->shell));
508 /* Trying to open a folders window and a mailboxes window at
509 the same time from the accounts window is not allowed */
510 if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
511 MODEST_IS_FOLDER_WINDOW (window) &&
512 MODEST_IS_ACCOUNTS_WINDOW (parent)) {
513 gtk_window_present (GTK_WINDOW (priv->shell));
517 if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
518 g_debug ("Trying to register a second header window is not allowed");
519 gtk_window_present (GTK_WINDOW (priv->shell));
523 if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
526 /* Add to list. Keep a reference to the window */
527 g_object_ref (window);
528 priv->window_list = g_list_prepend (priv->window_list, window);
530 nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
531 MODEST_IS_MSG_VIEW_WINDOW (parent);
533 /* Close views if they're being shown. Nevertheless we must
534 allow nested messages */
536 (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
537 MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
540 /* If the current view has modal dialogs then
541 we fail to register the new view */
542 if ((current_top != NULL) &&
543 window_has_modals (MODEST_WINDOW (current_top))) {
544 /* Window on top but it has opened dialogs */
548 /* Close the current view */
549 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
551 /* Cancelled closing top window, then we fail to register */
556 /* Listen to object destruction */
557 handler_id = g_malloc0 (sizeof (gint));
558 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
559 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
561 /* Show toolbar always */
562 modest_window_show_toolbar (window, TRUE);
564 modest_shell_add_window (MODEST_SHELL (priv->shell), window);
568 /* Add to list. Keep a reference to the window */
569 priv->window_list = g_list_remove (priv->window_list, window);
570 g_object_unref (window);
571 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
573 gtk_window_present (GTK_WINDOW (priv->shell));
578 cancel_window_operations (ModestWindow *window)
580 GSList* pending_ops = NULL;
582 /* cancel open and receive operations */
583 pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (),
585 while (pending_ops != NULL) {
586 ModestMailOperationTypeOperation type;
587 GSList* tmp_list = NULL;
589 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
590 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
591 type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
592 type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
593 modest_mail_operation_cancel (pending_ops->data);
595 g_object_unref (G_OBJECT (pending_ops->data));
596 tmp_list = pending_ops;
597 pending_ops = g_slist_next (pending_ops);
598 g_slist_free_1 (tmp_list);
603 window_has_modals (ModestWindow *window)
607 gboolean retvalue = FALSE;
609 /* First we fetch all toplevels */
610 toplevels = gtk_window_list_toplevels ();
611 for (node = toplevels; node != NULL; node = g_list_next (node)) {
612 if (GTK_IS_WINDOW (node->data) &&
613 gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (priv->shell) &&
614 GTK_WIDGET_VISIBLE (node->data)) {
619 g_list_free (toplevels);
624 on_window_destroy (ModestWindow *window,
626 ModestGtkWindowMgr *self)
628 gboolean no_propagate = FALSE;
630 /* Do not close the window if it has modals on top */
631 if (!MODEST_IS_MSG_EDIT_WINDOW (window) && window_has_modals (window))
634 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
635 gboolean sent = FALSE;
636 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
637 /* Save currently edited message to Drafts if it was not sent */
638 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
639 ModestMsgEditWindow *edit_window;
642 edit_window = MODEST_MSG_EDIT_WINDOW (window);
643 data = modest_msg_edit_window_get_msg_data (edit_window);
647 guint64 parts_size, available_size, expected_size;
649 available_size = modest_utils_get_available_space (NULL);
650 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
651 expected_size = modest_tny_msg_estimate_size (data->plain_body,
655 modest_msg_edit_window_free_msg_data (edit_window, data);
658 /* If there is not enough space
659 available for saving the message
660 then show an error and close the
661 window without saving */
662 if (expected_size >= available_size) {
663 modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
664 _("mail_in_ui_save_error"),
667 if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
671 g_warning ("Edit window without message data. This is probably a bug");
676 /* Unregister window */
677 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
678 no_propagate = FALSE;
684 modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
685 ModestWindow *window)
688 ModestGtkWindowMgrPrivate *priv;
689 gulong *tmp, handler_id;
692 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
693 g_return_if_fail (MODEST_IS_WINDOW (window));
695 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
697 win = g_list_find (priv->window_list, window);
699 g_debug ("Trying to unregister a window that has not being registered yet");
703 /* Remove the viewer window handler from the hash table. The
704 HashTable could not exist if the main window was closed
705 when there were other windows remaining */
706 if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
707 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
708 /* If the viewer was created without a main window
709 (for example when opening a message through D-Bus
710 the viewer handlers was not registered */
712 g_signal_handler_disconnect (window, *tmp);
713 g_hash_table_remove (priv->viewer_handlers, window);
717 /* Remove from list & hash table */
718 priv->window_list = g_list_remove_link (priv->window_list, win);
719 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
722 g_hash_table_remove (priv->destroy_handlers, window);
724 /* cancel open and receive operations */
725 cancel_window_operations (window);
727 /* Disconnect the "delete-event" handler, we won't need it anymore */
728 g_signal_handler_disconnect (window, handler_id);
730 /* Destroy the window */
731 g_object_unref (win->data);
734 MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
736 /* We have to get the number of windows here in order not to
737 emit the signal too many times */
738 num_windows = modest_window_mgr_get_num_windows (self);
740 /* If there are no more windows registered emit the signal */
741 if (num_windows == 0)
742 g_signal_emit_by_name (self, "window-list-empty");
747 modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
750 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
756 modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
762 modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
764 gboolean show_toolbars,
767 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
773 look_for_transient (gconstpointer a,
776 GtkWindow *win, *child;
781 child = (GtkWindow *) b;
782 win = (GtkWindow *) a;
784 if ((gtk_window_get_transient_for (win) == child) &&
785 GTK_WIDGET_VISIBLE (win))
792 modest_gtk_window_mgr_get_modal (ModestWindowMgr *self)
794 ModestGtkWindowMgrPrivate *priv;
795 GList *toplevel_list;
796 GtkWidget *current_top, *toplevel;
798 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
799 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
801 /* Get current top */
802 toplevel = priv->shell;
803 toplevel_list = gtk_window_list_toplevels ();
808 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
810 toplevel = (GtkWidget *) parent_link->data;
815 if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
816 return (GtkWindow *) toplevel;
823 modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
827 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
828 g_return_if_fail (GTK_IS_WINDOW (window));
830 gtk_window_set_modal (window, TRUE);
831 gtk_window_set_transient_for (window, parent);
832 gtk_window_set_destroy_with_parent (window, TRUE);
836 close_all_but_first (gpointer data)
840 HildonWindowStack *stack;
842 stack = hildon_window_stack_get_default ();
843 g_return_if_fail (stack);
845 num_windows = hildon_window_stack_size (stack);
847 for (i = 0; i < (num_windows - 1); i++) {
848 GtkWidget *current_top;
851 current_top = modest_shell_peek_window (MODEST_SHELL (priv->shell));
852 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
857 on_idle_close_all_but_first (gpointer data)
859 gdk_threads_enter ();
860 close_all_but_first (data);
861 gdk_threads_leave ();
867 on_account_removed (TnyAccountStore *acc_store,
871 ModestWindow *current_top;
873 /* Ignore transport account removals */
874 if (TNY_IS_TRANSPORT_ACCOUNT (account))
877 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
879 /* if we're showing the header view of the currently deleted
880 account, or the outbox and we deleted the last account,
881 then close the window */
883 (MODEST_IS_HEADER_WINDOW (current_top) ||
884 MODEST_IS_FOLDER_WINDOW (current_top))) {
885 const gchar *acc_name;
887 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
889 /* We emit it in an idle, because sometimes this
890 function could called when the account settings
891 dialog is about to close but still there. That
892 modal dialog would otherwise, prevent the
893 windows from being closed */
894 if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
895 g_idle_add (on_idle_close_all_but_first, NULL);
899 static ModestWindow *
900 modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self)
902 ModestWindow *initial_window = NULL;
903 ModestGtkWindowMgrPrivate *priv;
905 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
907 /* Connect to the account store "account-removed" signal". We
908 do this here because in the init the singletons are still
909 not initialized properly */
910 if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
911 priv->accounts_handler)) {
912 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
914 G_CALLBACK (on_account_removed),
918 /* Return accounts window */
919 initial_window = MODEST_WINDOW (modest_accounts_window_new ());
920 modest_window_mgr_register_window (self, initial_window, NULL);
922 return initial_window;
926 static ModestWindow *
927 modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self)
929 ModestWindow *initial_window = NULL;
930 ModestGtkWindowMgrPrivate *priv;
932 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
933 return (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
937 find_folder_window (gconstpointer a,
940 return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
943 static ModestWindow *
944 modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self)
946 ModestGtkWindowMgrPrivate *priv;
949 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
951 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
953 window = g_list_find_custom (priv->window_list,
957 return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
961 modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self)
963 ModestGtkWindowMgrPrivate *priv = NULL;
965 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
967 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
973 modest_gtk_window_mgr_create_caches (ModestWindowMgr *self)
975 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
977 modest_accounts_window_pre_create ();
979 MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
983 modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self)
987 /* Exit if there are no windows */
988 if (!modest_window_mgr_get_num_windows (self)) {
989 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
993 /* Close active modals */
994 if (!_modest_window_mgr_close_active_modals (self)) {
995 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
999 /* Close all but first */
1000 top = modest_window_mgr_get_current_top (self);
1001 if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1002 close_all_but_first (NULL);
1004 /* If some cannot be closed return */
1005 top = modest_window_mgr_get_current_top (self);
1006 if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1007 g_debug ("%s: could not close some windows", __FUNCTION__);