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 shell_has_modals (ModestShell *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 ();
203 gtk_widget_show (priv->shell);
207 modest_gtk_window_mgr_finalize (GObject *obj)
209 ModestGtkWindowMgrPrivate *priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
210 ModestTnyAccountStore *acc_store;
212 modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids);
213 priv->window_state_uids = NULL;
215 acc_store = modest_runtime_get_account_store ();
216 if (acc_store && g_signal_handler_is_connected (acc_store, priv->accounts_handler))
217 g_signal_handler_disconnect (acc_store, priv->accounts_handler);
219 if (priv->window_list) {
220 GList *iter = priv->window_list;
221 /* unregister pending windows */
223 ModestWindow *window = (ModestWindow *) iter->data;
224 iter = g_list_next (iter);
225 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window);
227 g_list_free (priv->window_list);
228 priv->window_list = NULL;
231 /* Free the hash table with the handlers */
232 if (priv->destroy_handlers) {
233 g_hash_table_destroy (priv->destroy_handlers);
234 priv->destroy_handlers = NULL;
237 if (priv->viewer_handlers) {
238 g_hash_table_destroy (priv->viewer_handlers);
239 priv->viewer_handlers = NULL;
242 modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids);
243 priv->modal_handler_uids = NULL;
245 if (priv->modal_windows) {
246 g_mutex_lock (priv->queue_lock);
247 g_queue_free (priv->modal_windows);
248 priv->modal_windows = NULL;
249 g_mutex_unlock (priv->queue_lock);
251 g_mutex_free (priv->queue_lock);
253 G_OBJECT_CLASS(parent_class)->finalize (obj);
257 modest_gtk_window_mgr_new (void)
259 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_GTK_WINDOW_MGR, NULL));
263 modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self)
265 ModestGtkWindowMgrPrivate *priv = NULL;
266 gboolean ret_value = FALSE;
267 ModestWindow *window;
268 gboolean failed = FALSE;
270 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
271 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
273 while ((window = modest_shell_peek_window (MODEST_SHELL (priv->shell))) != NULL) {
274 ret_value = modest_shell_delete_window (MODEST_SHELL (priv->shell), window);
275 if (ret_value == TRUE) {
285 compare_msguids (ModestWindow *win,
288 const gchar *msg_uid;
290 if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
293 /* Get message uid from msg window */
294 if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
295 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
296 if (msg_uid && uid &&!strcmp (msg_uid, uid))
299 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
302 if (msg_uid && uid &&!strcmp (msg_uid, uid))
309 compare_headers (ModestWindow *win,
312 TnyHeader *my_header;
315 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
318 /* Get message uid from msg window */
319 my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
321 if (my_header == header)
323 g_object_unref (my_header);
330 modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
333 ModestGtkWindowMgrPrivate *priv = NULL;
335 gboolean has_header, has_window = FALSE;
338 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
339 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
341 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
343 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
345 uid = modest_tny_folder_get_header_unique_id (header);
347 item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
351 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
352 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
353 g_debug ("not a valid window!");
355 g_debug ("found a window");
356 *win = MODEST_WINDOW (item->data);
362 return has_header || has_window;
366 modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
369 ModestGtkWindowMgrPrivate *priv = NULL;
370 gboolean has_header, has_window = FALSE;
373 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
374 g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
376 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
378 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
380 item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
384 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
385 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
386 g_debug ("not a valid window!");
388 g_debug ("found a window");
389 *win = MODEST_WINDOW (item->data);
394 return has_header || has_window;
398 modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self)
400 ModestGtkWindowMgrPrivate *priv;
402 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
403 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
405 return g_list_copy (priv->window_list);
409 modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
410 ModestWindow *window,
411 ModestWindow *parent)
414 ModestGtkWindowMgrPrivate *priv;
416 gboolean nested_msg = FALSE;
417 ModestWindow *current_top;
419 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), 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), MODEST_WINDOW (window));
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 shell_has_modals (MODEST_SHELL (priv->shell))) {
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 shell_has_modals (ModestShell *shell)
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 (shell) &&
614 GTK_WIDGET_VISIBLE (node->data)) {
619 g_list_free (toplevels);
624 on_window_destroy (ModestWindow *window,
626 ModestGtkWindowMgr *self)
628 ModestGtkWindowMgrPrivate *priv;
629 gboolean no_propagate = FALSE;
631 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
633 /* Do not close the window if it has modals on top */
634 if (!MODEST_IS_MSG_EDIT_WINDOW (window) && shell_has_modals (MODEST_SHELL (priv->shell)))
637 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
638 gboolean sent = FALSE;
639 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
640 /* Save currently edited message to Drafts if it was not sent */
641 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
642 ModestMsgEditWindow *edit_window;
645 edit_window = MODEST_MSG_EDIT_WINDOW (window);
646 data = modest_msg_edit_window_get_msg_data (edit_window);
650 guint64 parts_size, available_size, expected_size;
652 available_size = modest_utils_get_available_space (NULL);
653 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
654 expected_size = modest_tny_msg_estimate_size (data->plain_body,
658 modest_msg_edit_window_free_msg_data (edit_window, data);
661 /* If there is not enough space
662 available for saving the message
663 then show an error and close the
664 window without saving */
665 if (expected_size >= available_size) {
666 modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
667 _("mail_in_ui_save_error"),
670 if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
674 g_warning ("Edit window without message data. This is probably a bug");
679 /* Unregister window */
680 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
681 no_propagate = FALSE;
687 modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
688 ModestWindow *window)
691 ModestGtkWindowMgrPrivate *priv;
692 gulong *tmp, handler_id;
695 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
696 g_return_if_fail (MODEST_IS_WINDOW (window));
698 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
700 win = g_list_find (priv->window_list, window);
702 g_debug ("Trying to unregister a window that has not being registered yet");
706 /* Remove the viewer window handler from the hash table. The
707 HashTable could not exist if the main window was closed
708 when there were other windows remaining */
709 if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
710 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
711 /* If the viewer was created without a main window
712 (for example when opening a message through D-Bus
713 the viewer handlers was not registered */
715 g_signal_handler_disconnect (window, *tmp);
716 g_hash_table_remove (priv->viewer_handlers, window);
720 /* Remove from list & hash table */
721 priv->window_list = g_list_remove_link (priv->window_list, win);
722 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
725 g_hash_table_remove (priv->destroy_handlers, window);
727 /* cancel open and receive operations */
728 cancel_window_operations (window);
730 /* Disconnect the "delete-event" handler, we won't need it anymore */
731 g_signal_handler_disconnect (window, handler_id);
733 /* Destroy the window */
734 g_object_unref (win->data);
737 MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
739 /* We have to get the number of windows here in order not to
740 emit the signal too many times */
741 num_windows = modest_window_mgr_get_num_windows (self);
743 /* If there are no more windows registered emit the signal */
744 if (num_windows == 0)
745 g_signal_emit_by_name (self, "window-list-empty");
750 modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
753 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
759 modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
765 modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
767 gboolean show_toolbars,
770 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
776 look_for_transient (gconstpointer a,
779 GtkWindow *win, *child;
784 child = (GtkWindow *) b;
785 win = (GtkWindow *) a;
787 if ((gtk_window_get_transient_for (win) == child) &&
788 GTK_WIDGET_VISIBLE (win))
795 modest_gtk_window_mgr_get_modal (ModestWindowMgr *self)
797 ModestGtkWindowMgrPrivate *priv;
798 GList *toplevel_list;
801 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
802 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
804 /* Get current top */
805 toplevel = priv->shell;
806 toplevel_list = gtk_window_list_toplevels ();
811 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
813 toplevel = (GtkWidget *) parent_link->data;
818 if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
819 return (GtkWindow *) toplevel;
826 modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
830 ModestGtkWindowMgrPrivate *priv;
832 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
833 g_return_if_fail (GTK_IS_WINDOW (window));
835 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
837 gtk_window_set_modal (window, TRUE);
839 if (GTK_IS_WINDOW (parent)) {
840 gtk_window_set_transient_for (window, parent);
842 gtk_window_set_transient_for (window, GTK_WINDOW (priv->shell));
844 gtk_window_set_destroy_with_parent (window, TRUE);
848 close_all_but_first (gpointer data)
852 ModestGtkWindowMgrPrivate *priv;
854 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(data);
855 num_windows = modest_shell_count_windows (MODEST_SHELL (priv->shell));
857 for (i = 0; i < (num_windows - 1); i++) {
858 ModestWindow *current_top;
861 current_top = modest_shell_peek_window (MODEST_SHELL (priv->shell));
862 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
867 on_idle_close_all_but_first (gpointer data)
869 gdk_threads_enter ();
870 close_all_but_first (data);
871 gdk_threads_leave ();
877 on_account_removed (TnyAccountStore *acc_store,
881 ModestWindow *current_top;
882 ModestGtkWindowMgrPrivate *priv;
884 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (user_data);
886 /* Ignore transport account removals */
887 if (TNY_IS_TRANSPORT_ACCOUNT (account))
890 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
892 /* if we're showing the header view of the currently deleted
893 account, or the outbox and we deleted the last account,
894 then close the window */
896 (MODEST_IS_HEADER_WINDOW (current_top) ||
897 MODEST_IS_FOLDER_WINDOW (current_top))) {
898 const gchar *acc_name;
900 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
902 /* We emit it in an idle, because sometimes this
903 function could called when the account settings
904 dialog is about to close but still there. That
905 modal dialog would otherwise, prevent the
906 windows from being closed */
907 if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
908 g_idle_add (on_idle_close_all_but_first, (gpointer) priv->shell);
912 static ModestWindow *
913 modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self)
915 ModestWindow *initial_window = NULL;
916 ModestGtkWindowMgrPrivate *priv;
918 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
920 /* Connect to the account store "account-removed" signal". We
921 do this here because in the init the singletons are still
922 not initialized properly */
923 if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
924 priv->accounts_handler)) {
925 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
927 G_CALLBACK (on_account_removed),
931 /* Return accounts window */
932 initial_window = MODEST_WINDOW (modest_accounts_window_new ());
933 modest_window_mgr_register_window (self, initial_window, NULL);
935 return initial_window;
939 static ModestWindow *
940 modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self)
942 ModestGtkWindowMgrPrivate *priv;
944 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
945 return (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
949 find_folder_window (gconstpointer a,
952 return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
955 static ModestWindow *
956 modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self)
958 ModestGtkWindowMgrPrivate *priv;
961 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
963 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
965 window = g_list_find_custom (priv->window_list,
969 return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
973 modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self)
975 ModestGtkWindowMgrPrivate *priv = NULL;
977 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
979 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
985 modest_gtk_window_mgr_create_caches (ModestWindowMgr *self)
987 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
989 modest_accounts_window_pre_create ();
991 MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
995 modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self)
998 ModestGtkWindowMgrPrivate *priv;
1000 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);
1002 /* Exit if there are no windows */
1003 if (!modest_window_mgr_get_num_windows (self)) {
1004 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
1008 /* Close active modals */
1009 if (!_modest_window_mgr_close_active_modals (self)) {
1010 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
1014 /* Close all but first */
1015 top = modest_window_mgr_get_current_top (self);
1016 if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1017 close_all_but_first ((gpointer) priv->shell);
1019 /* If some cannot be closed return */
1020 top = modest_window_mgr_get_current_top (self);
1021 if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1022 g_debug ("%s: could not close some windows", __FUNCTION__);
1030 modest_gtk_window_mgr_get_shell (ModestGtkWindowMgr *self)
1032 ModestGtkWindowMgrPrivate *priv;
1034 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);