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-window-mgr-priv.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-utils.h"
48 #include "modest-tny-msg.h"
49 #include "modest-tny-account.h"
50 #include <modest-shell.h>
51 #include <tny-merge-folder.h>
53 /* 'private'/'protected' functions */
54 static void modest_gtk_window_mgr_class_init (ModestGtkWindowMgrClass *klass);
55 static void modest_gtk_window_mgr_instance_init (ModestGtkWindowMgr *obj);
56 static void modest_gtk_window_mgr_finalize (GObject *obj);
58 static gboolean on_window_destroy (ModestWindow *window,
60 ModestGtkWindowMgr *self);
62 static gboolean modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
64 ModestWindow *parent);
65 static void modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
66 ModestWindow *window);
67 static void modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
69 static gboolean modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self);
70 static void modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
72 gboolean show_toolbars,
74 static GtkWindow *modest_gtk_window_mgr_get_modal (ModestWindowMgr *self);
75 static void modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
78 static gboolean modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self,
81 static gboolean modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self,
84 static GList *modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self);
85 static gboolean modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self);
86 static gboolean modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self);
87 static gboolean shell_has_modals (ModestShell *window);
88 static ModestWindow *modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self);
89 static ModestWindow *modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self);
90 static gboolean modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self);
91 static void modest_gtk_window_mgr_create_caches (ModestWindowMgr *self);
92 static void on_account_removed (TnyAccountStore *acc_store,
95 static ModestWindow *modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self);
97 typedef struct _ModestGtkWindowMgrPrivate ModestGtkWindowMgrPrivate;
98 struct _ModestGtkWindowMgrPrivate {
101 GQueue *modal_windows;
103 gboolean fullscreen_mode;
105 GHashTable *destroy_handlers;
106 GHashTable *viewer_handlers;
107 GSList *window_state_uids;
111 GSList *modal_handler_uids;
112 ModestWindow *current_top;
114 gulong accounts_handler;
119 #define MODEST_GTK_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
120 MODEST_TYPE_GTK_WINDOW_MGR, \
121 ModestGtkWindowMgrPrivate))
123 static GObjectClass *parent_class = NULL;
126 modest_gtk_window_mgr_get_type (void)
128 static GType my_type = 0;
130 static const GTypeInfo my_info = {
131 sizeof(ModestGtkWindowMgrClass),
132 NULL, /* base init */
133 NULL, /* base finalize */
134 (GClassInitFunc) modest_gtk_window_mgr_class_init,
135 NULL, /* class finalize */
136 NULL, /* class data */
137 sizeof(ModestGtkWindowMgr),
139 (GInstanceInitFunc) modest_gtk_window_mgr_instance_init,
142 my_type = g_type_register_static (MODEST_TYPE_WINDOW_MGR,
143 "ModestGtkWindowMgr",
150 modest_gtk_window_mgr_class_init (ModestGtkWindowMgrClass *klass)
152 GObjectClass *gobject_class;
153 ModestWindowMgrClass *mgr_class;
155 gobject_class = (GObjectClass*) klass;
156 mgr_class = (ModestWindowMgrClass *) klass;
158 parent_class = g_type_class_peek_parent (klass);
159 gobject_class->finalize = modest_gtk_window_mgr_finalize;
160 mgr_class->register_window = modest_gtk_window_mgr_register_window;
161 mgr_class->unregister_window = modest_gtk_window_mgr_unregister_window;
162 mgr_class->set_fullscreen_mode = modest_gtk_window_mgr_set_fullscreen_mode;
163 mgr_class->get_fullscreen_mode = modest_gtk_window_mgr_get_fullscreen_mode;
164 mgr_class->show_toolbars = modest_gtk_window_mgr_show_toolbars;
165 mgr_class->get_modal = modest_gtk_window_mgr_get_modal;
166 mgr_class->set_modal = modest_gtk_window_mgr_set_modal;
167 mgr_class->find_registered_header = modest_gtk_window_mgr_find_registered_header;
168 mgr_class->find_registered_message_uid = modest_gtk_window_mgr_find_registered_message_uid;
169 mgr_class->get_window_list = modest_gtk_window_mgr_get_window_list;
170 mgr_class->close_all_windows = modest_gtk_window_mgr_close_all_windows;
171 mgr_class->close_all_but_initial = modest_gtk_window_mgr_close_all_but_initial;
172 mgr_class->show_initial_window = modest_gtk_window_mgr_show_initial_window;
173 mgr_class->get_current_top = modest_gtk_window_mgr_get_current_top;
174 mgr_class->screen_is_on = modest_gtk_window_mgr_screen_is_on;
175 mgr_class->create_caches = modest_gtk_window_mgr_create_caches;
176 mgr_class->get_folder_window = modest_gtk_window_mgr_get_folder_window;
178 g_type_class_add_private (gobject_class, sizeof(ModestGtkWindowMgrPrivate));
183 modest_gtk_window_mgr_instance_init (ModestGtkWindowMgr *obj)
185 ModestGtkWindowMgrPrivate *priv;
187 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
188 priv->window_list = NULL;
189 priv->fullscreen_mode = FALSE;
190 priv->window_state_uids = NULL;
192 priv->modal_windows = g_queue_new ();
193 priv->queue_lock = g_mutex_new ();
194 priv->fullscreen = FALSE;
196 /* Could not initialize it from gconf, singletons are not
198 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
199 priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
201 priv->closing_time = 0;
203 priv->modal_handler_uids = NULL;
204 priv->shell = modest_shell_new ();
205 gtk_widget_show (priv->shell);
209 modest_gtk_window_mgr_finalize (GObject *obj)
211 ModestGtkWindowMgrPrivate *priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
212 ModestTnyAccountStore *acc_store;
214 modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids);
215 priv->window_state_uids = NULL;
217 acc_store = modest_runtime_get_account_store ();
218 if (acc_store && g_signal_handler_is_connected (acc_store, priv->accounts_handler))
219 g_signal_handler_disconnect (acc_store, priv->accounts_handler);
221 if (priv->window_list) {
222 GList *iter = priv->window_list;
223 /* unregister pending windows */
225 ModestWindow *window = (ModestWindow *) iter->data;
226 iter = g_list_next (iter);
227 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window);
229 g_list_free (priv->window_list);
230 priv->window_list = NULL;
233 /* Free the hash table with the handlers */
234 if (priv->destroy_handlers) {
235 g_hash_table_destroy (priv->destroy_handlers);
236 priv->destroy_handlers = NULL;
239 if (priv->viewer_handlers) {
240 g_hash_table_destroy (priv->viewer_handlers);
241 priv->viewer_handlers = NULL;
244 modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids);
245 priv->modal_handler_uids = NULL;
247 if (priv->modal_windows) {
248 g_mutex_lock (priv->queue_lock);
249 g_queue_free (priv->modal_windows);
250 priv->modal_windows = NULL;
251 g_mutex_unlock (priv->queue_lock);
253 g_mutex_free (priv->queue_lock);
255 G_OBJECT_CLASS(parent_class)->finalize (obj);
259 modest_gtk_window_mgr_new (void)
261 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_GTK_WINDOW_MGR, NULL));
265 modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self)
267 ModestGtkWindowMgrPrivate *priv = NULL;
268 gboolean ret_value = FALSE;
269 ModestWindow *window;
270 gboolean failed = FALSE;
272 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
273 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
275 while ((window = modest_shell_peek_window (MODEST_SHELL (priv->shell))) != NULL) {
276 ret_value = modest_shell_delete_window (MODEST_SHELL (priv->shell), window);
277 if (ret_value == TRUE) {
287 compare_msguids (ModestWindow *win,
290 const gchar *msg_uid;
292 if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
295 /* Get message uid from msg window */
296 if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
297 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
298 if (msg_uid && uid &&!strcmp (msg_uid, uid))
301 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
304 if (msg_uid && uid &&!strcmp (msg_uid, uid))
311 compare_headers (ModestWindow *win,
314 TnyHeader *my_header;
317 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
320 /* Get message uid from msg window */
321 my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
323 if (my_header == header)
325 g_object_unref (my_header);
332 modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
335 ModestGtkWindowMgrPrivate *priv = NULL;
337 gboolean has_header, has_window = FALSE;
340 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
341 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
343 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
345 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
347 uid = modest_tny_folder_get_header_unique_id (header);
349 item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
353 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
354 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
355 g_debug ("not a valid window!");
357 g_debug ("found a window");
358 *win = MODEST_WINDOW (item->data);
364 return has_header || has_window;
368 modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
371 ModestGtkWindowMgrPrivate *priv = NULL;
372 gboolean has_header, has_window = FALSE;
375 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
376 g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
378 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
380 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
382 item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
386 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
387 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
388 g_debug ("not a valid window!");
390 g_debug ("found a window");
391 *win = MODEST_WINDOW (item->data);
396 return has_header || has_window;
400 modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self)
402 ModestGtkWindowMgrPrivate *priv;
404 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
405 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
407 return g_list_copy (priv->window_list);
411 modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
412 ModestWindow *window,
413 ModestWindow *parent)
416 ModestGtkWindowMgrPrivate *priv;
418 gboolean nested_msg = FALSE;
419 ModestWindow *current_top;
421 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
423 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
425 /* Try to close active modal dialogs */
426 if (modest_window_mgr_get_num_windows (self) &&
427 !_modest_window_mgr_close_active_modals (self))
430 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
432 win = g_list_find (priv->window_list, window);
434 /* this is for the case we want to register the window
435 and it was already registered */
436 gtk_window_present (GTK_WINDOW (priv->shell));
440 /* Do not allow standalone editors or standalone viewers */
442 (MODEST_IS_MSG_VIEW_WINDOW (window) ||
443 MODEST_IS_MSG_EDIT_WINDOW (window)))
444 modest_window_mgr_show_initial_window (self);
446 if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
450 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
452 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
455 uid = modest_tny_folder_get_header_unique_id (header);
456 /* Embedded messages do not have uid */
458 if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
459 g_debug ("%s found another view window showing the same header", __FUNCTION__);
461 g_object_unref (header);
466 if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
467 g_debug ("%s found another view window showing the same header", __FUNCTION__);
468 g_object_unref (header);
473 g_object_unref (header);
476 /* Do not go backwards */
477 if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
478 MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
479 MODEST_IS_HEADER_WINDOW (current_top)) &&
480 (MODEST_IS_FOLDER_WINDOW (window) ||
481 MODEST_IS_ACCOUNTS_WINDOW (window) ||
482 MODEST_IS_MAILBOXES_WINDOW (window))) {
483 gtk_window_present (GTK_WINDOW (priv->shell));
487 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
490 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), MODEST_WINDOW (window));
493 gtk_window_present (GTK_WINDOW (priv->shell));
496 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
499 if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
500 gtk_window_present (GTK_WINDOW (priv->shell));
504 /* Mailboxes window can not replace folder windows */
505 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
506 gtk_window_present (GTK_WINDOW (priv->shell));
510 /* Trying to open a folders window and a mailboxes window at
511 the same time from the accounts window is not allowed */
512 if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
513 MODEST_IS_FOLDER_WINDOW (window) &&
514 MODEST_IS_ACCOUNTS_WINDOW (parent)) {
515 gtk_window_present (GTK_WINDOW (priv->shell));
519 if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
520 g_debug ("Trying to register a second header window is not allowed");
521 gtk_window_present (GTK_WINDOW (priv->shell));
525 if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
528 /* Add to list. Keep a reference to the window */
529 g_object_ref (window);
530 priv->window_list = g_list_prepend (priv->window_list, window);
532 nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
533 MODEST_IS_MSG_VIEW_WINDOW (parent);
535 /* Close views if they're being shown. Nevertheless we must
536 allow nested messages */
538 (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
539 MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
542 /* If the current view has modal dialogs then
543 we fail to register the new view */
544 if ((current_top != NULL) &&
545 shell_has_modals (MODEST_SHELL (priv->shell))) {
546 /* Window on top but it has opened dialogs */
550 /* Close the current view */
551 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
553 /* Cancelled closing top window, then we fail to register */
558 /* Listen to object destruction */
559 handler_id = g_malloc0 (sizeof (gint));
560 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
561 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
563 /* Show toolbar always */
564 modest_window_show_toolbar (window, TRUE);
566 modest_shell_add_window (MODEST_SHELL (priv->shell), window);
570 /* Add to list. Keep a reference to the window */
571 priv->window_list = g_list_remove (priv->window_list, window);
572 g_object_unref (window);
573 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
575 gtk_window_present (GTK_WINDOW (priv->shell));
580 cancel_window_operations (ModestWindow *window)
582 GSList* pending_ops = NULL;
584 /* cancel open and receive operations */
585 pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (),
587 while (pending_ops != NULL) {
588 ModestMailOperationTypeOperation type;
589 GSList* tmp_list = NULL;
591 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
592 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
593 type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
594 type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
595 modest_mail_operation_cancel (pending_ops->data);
597 g_object_unref (G_OBJECT (pending_ops->data));
598 tmp_list = pending_ops;
599 pending_ops = g_slist_next (pending_ops);
600 g_slist_free_1 (tmp_list);
605 shell_has_modals (ModestShell *shell)
609 gboolean retvalue = FALSE;
611 /* First we fetch all toplevels */
612 toplevels = gtk_window_list_toplevels ();
613 for (node = toplevels; node != NULL; node = g_list_next (node)) {
614 if (GTK_IS_WINDOW (node->data) &&
615 gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (shell) &&
616 GTK_WIDGET_VISIBLE (node->data)) {
621 g_list_free (toplevels);
626 on_window_destroy (ModestWindow *window,
628 ModestGtkWindowMgr *self)
630 ModestGtkWindowMgrPrivate *priv;
631 gboolean no_propagate = FALSE;
633 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
635 /* Do not close the window if it has modals on top */
636 if (!MODEST_IS_MSG_EDIT_WINDOW (window) && shell_has_modals (MODEST_SHELL (priv->shell)))
639 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
640 gboolean sent = FALSE;
641 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
642 /* Save currently edited message to Drafts if it was not sent */
643 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
644 ModestMsgEditWindow *edit_window;
647 edit_window = MODEST_MSG_EDIT_WINDOW (window);
648 data = modest_msg_edit_window_get_msg_data (edit_window);
652 guint64 parts_size, available_size, expected_size;
654 available_size = modest_utils_get_available_space (NULL);
655 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
656 expected_size = modest_tny_msg_estimate_size (data->plain_body,
660 modest_msg_edit_window_free_msg_data (edit_window, data);
663 /* If there is not enough space
664 available for saving the message
665 then show an error and close the
666 window without saving */
667 if (expected_size >= available_size) {
668 modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
669 _("mail_in_ui_save_error"),
672 if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
676 g_warning ("Edit window without message data. This is probably a bug");
681 /* Unregister window */
682 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
683 no_propagate = FALSE;
689 modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
690 ModestWindow *window)
693 ModestGtkWindowMgrPrivate *priv;
694 gulong *tmp, handler_id;
697 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
698 g_return_if_fail (MODEST_IS_WINDOW (window));
700 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
702 win = g_list_find (priv->window_list, window);
704 g_debug ("Trying to unregister a window that has not being registered yet");
708 /* Remove the viewer window handler from the hash table. The
709 HashTable could not exist if the main window was closed
710 when there were other windows remaining */
711 if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
712 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
713 /* If the viewer was created without a main window
714 (for example when opening a message through D-Bus
715 the viewer handlers was not registered */
717 g_signal_handler_disconnect (window, *tmp);
718 g_hash_table_remove (priv->viewer_handlers, window);
722 /* Remove from list & hash table */
723 priv->window_list = g_list_remove_link (priv->window_list, win);
724 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
727 g_hash_table_remove (priv->destroy_handlers, window);
729 /* cancel open and receive operations */
730 cancel_window_operations (window);
732 /* Disconnect the "delete-event" handler, we won't need it anymore */
733 g_signal_handler_disconnect (window, handler_id);
735 /* Destroy the window */
736 g_object_unref (win->data);
739 MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
741 /* We have to get the number of windows here in order not to
742 emit the signal too many times */
743 num_windows = modest_window_mgr_get_num_windows (self);
745 /* If there are no more windows registered emit the signal */
746 if (num_windows == 0)
747 g_signal_emit_by_name (self, "window-list-empty");
752 modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
755 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
757 ModestGtkWindowMgrPrivate *priv = NULL;
758 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
760 priv->fullscreen = on;
763 gtk_window_fullscreen (GTK_WINDOW (priv->shell));
765 gtk_window_unfullscreen (GTK_WINDOW (priv->shell));
771 modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
773 ModestGtkWindowMgrPrivate *priv = NULL;
774 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
776 return priv->fullscreen;
780 modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
782 gboolean show_toolbars,
785 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
791 look_for_transient (gconstpointer a,
794 GtkWindow *win, *child;
799 child = (GtkWindow *) b;
800 win = (GtkWindow *) a;
802 if ((gtk_window_get_transient_for (win) == child) &&
803 GTK_WIDGET_VISIBLE (win))
810 modest_gtk_window_mgr_get_modal (ModestWindowMgr *self)
812 ModestGtkWindowMgrPrivate *priv;
813 GList *toplevel_list;
816 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
817 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
819 /* Get current top */
820 toplevel = priv->shell;
821 toplevel_list = gtk_window_list_toplevels ();
826 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
828 toplevel = (GtkWidget *) parent_link->data;
833 if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
834 return (GtkWindow *) toplevel;
841 modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
845 ModestGtkWindowMgrPrivate *priv;
847 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
848 g_return_if_fail (GTK_IS_WINDOW (window));
850 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
852 gtk_window_set_modal (window, TRUE);
854 if (GTK_IS_WINDOW (parent)) {
855 gtk_window_set_transient_for (window, parent);
857 gtk_window_set_transient_for (window, GTK_WINDOW (priv->shell));
859 gtk_window_set_destroy_with_parent (window, TRUE);
863 close_all_but_first (gpointer data)
867 ModestGtkWindowMgrPrivate *priv;
869 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(data);
870 num_windows = modest_shell_count_windows (MODEST_SHELL (priv->shell));
872 for (i = 0; i < (num_windows - 1); i++) {
873 ModestWindow *current_top;
876 current_top = modest_shell_peek_window (MODEST_SHELL (priv->shell));
877 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
882 on_idle_close_all_but_first (gpointer data)
884 gdk_threads_enter ();
885 close_all_but_first (data);
886 gdk_threads_leave ();
892 on_account_removed (TnyAccountStore *acc_store,
896 ModestWindow *current_top;
897 ModestGtkWindowMgrPrivate *priv;
899 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (user_data);
901 /* Ignore transport account removals */
902 if (TNY_IS_TRANSPORT_ACCOUNT (account))
905 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
907 /* if we're showing the header view of the currently deleted
908 account, or the outbox and we deleted the last account,
909 then close the window */
911 (MODEST_IS_HEADER_WINDOW (current_top) ||
912 MODEST_IS_FOLDER_WINDOW (current_top))) {
913 const gchar *acc_name;
915 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
917 /* We emit it in an idle, because sometimes this
918 function could called when the account settings
919 dialog is about to close but still there. That
920 modal dialog would otherwise, prevent the
921 windows from being closed */
922 if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
923 g_idle_add (on_idle_close_all_but_first, (gpointer) user_data);
927 static ModestWindow *
928 modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self)
930 ModestWindow *initial_window = NULL;
931 ModestGtkWindowMgrPrivate *priv;
933 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
935 /* Connect to the account store "account-removed" signal". We
936 do this here because in the init the singletons are still
937 not initialized properly */
938 if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
939 priv->accounts_handler)) {
940 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
942 G_CALLBACK (on_account_removed),
946 /* Return accounts window */
947 initial_window = MODEST_WINDOW (modest_accounts_window_new ());
948 modest_window_mgr_register_window (self, initial_window, NULL);
950 return initial_window;
954 static ModestWindow *
955 modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self)
957 ModestGtkWindowMgrPrivate *priv;
959 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
960 return (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
964 find_folder_window (gconstpointer a,
967 return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
970 static ModestWindow *
971 modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self)
973 ModestGtkWindowMgrPrivate *priv;
976 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
978 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
980 window = g_list_find_custom (priv->window_list,
984 return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
988 modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self)
990 ModestGtkWindowMgrPrivate *priv = NULL;
992 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
994 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
1000 modest_gtk_window_mgr_create_caches (ModestWindowMgr *self)
1002 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
1004 modest_accounts_window_pre_create ();
1006 MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
1010 modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1013 ModestGtkWindowMgrPrivate *priv;
1015 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);
1017 /* Exit if there are no windows */
1018 if (!modest_window_mgr_get_num_windows (self)) {
1019 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
1023 /* Close active modals */
1024 if (!_modest_window_mgr_close_active_modals (self)) {
1025 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
1029 /* Close all but first */
1030 top = modest_window_mgr_get_current_top (self);
1031 if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1032 close_all_but_first ((gpointer) priv->shell);
1034 /* If some cannot be closed return */
1035 top = modest_window_mgr_get_current_top (self);
1036 if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1037 g_debug ("%s: could not close some windows", __FUNCTION__);
1045 modest_gtk_window_mgr_get_shell (ModestGtkWindowMgr *self)
1047 ModestGtkWindowMgrPrivate *priv;
1049 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);