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;
120 #define MODEST_GTK_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
121 MODEST_TYPE_GTK_WINDOW_MGR, \
122 ModestGtkWindowMgrPrivate))
124 static GObjectClass *parent_class = NULL;
127 modest_gtk_window_mgr_get_type (void)
129 static GType my_type = 0;
131 static const GTypeInfo my_info = {
132 sizeof(ModestGtkWindowMgrClass),
133 NULL, /* base init */
134 NULL, /* base finalize */
135 (GClassInitFunc) modest_gtk_window_mgr_class_init,
136 NULL, /* class finalize */
137 NULL, /* class data */
138 sizeof(ModestGtkWindowMgr),
140 (GInstanceInitFunc) modest_gtk_window_mgr_instance_init,
143 my_type = g_type_register_static (MODEST_TYPE_WINDOW_MGR,
144 "ModestGtkWindowMgr",
151 modest_gtk_window_mgr_class_init (ModestGtkWindowMgrClass *klass)
153 GObjectClass *gobject_class;
154 ModestWindowMgrClass *mgr_class;
156 gobject_class = (GObjectClass*) klass;
157 mgr_class = (ModestWindowMgrClass *) klass;
159 parent_class = g_type_class_peek_parent (klass);
160 gobject_class->finalize = modest_gtk_window_mgr_finalize;
161 mgr_class->register_window = modest_gtk_window_mgr_register_window;
162 mgr_class->unregister_window = modest_gtk_window_mgr_unregister_window;
163 mgr_class->set_fullscreen_mode = modest_gtk_window_mgr_set_fullscreen_mode;
164 mgr_class->get_fullscreen_mode = modest_gtk_window_mgr_get_fullscreen_mode;
165 mgr_class->show_toolbars = modest_gtk_window_mgr_show_toolbars;
166 mgr_class->get_modal = modest_gtk_window_mgr_get_modal;
167 mgr_class->set_modal = modest_gtk_window_mgr_set_modal;
168 mgr_class->find_registered_header = modest_gtk_window_mgr_find_registered_header;
169 mgr_class->find_registered_message_uid = modest_gtk_window_mgr_find_registered_message_uid;
170 mgr_class->get_window_list = modest_gtk_window_mgr_get_window_list;
171 mgr_class->close_all_windows = modest_gtk_window_mgr_close_all_windows;
172 mgr_class->close_all_but_initial = modest_gtk_window_mgr_close_all_but_initial;
173 mgr_class->show_initial_window = modest_gtk_window_mgr_show_initial_window;
174 mgr_class->get_current_top = modest_gtk_window_mgr_get_current_top;
175 mgr_class->screen_is_on = modest_gtk_window_mgr_screen_is_on;
176 mgr_class->create_caches = modest_gtk_window_mgr_create_caches;
177 mgr_class->get_folder_window = modest_gtk_window_mgr_get_folder_window;
179 g_type_class_add_private (gobject_class, sizeof(ModestGtkWindowMgrPrivate));
184 modest_gtk_window_mgr_instance_init (ModestGtkWindowMgr *obj)
186 ModestGtkWindowMgrPrivate *priv;
188 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
189 priv->window_list = NULL;
190 priv->fullscreen_mode = FALSE;
191 priv->window_state_uids = NULL;
193 priv->modal_windows = g_queue_new ();
194 priv->queue_lock = g_mutex_new ();
195 priv->fullscreen = FALSE;
197 /* Could not initialize it from gconf, singletons are not
199 priv->destroy_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
200 priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
202 priv->closing_time = 0;
204 priv->modal_handler_uids = NULL;
205 priv->shell = modest_shell_new ();
206 gtk_widget_show (priv->shell);
210 modest_gtk_window_mgr_finalize (GObject *obj)
212 ModestGtkWindowMgrPrivate *priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(obj);
213 ModestTnyAccountStore *acc_store;
215 modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids);
216 priv->window_state_uids = NULL;
218 acc_store = modest_runtime_get_account_store ();
219 if (acc_store && g_signal_handler_is_connected (acc_store, priv->accounts_handler))
220 g_signal_handler_disconnect (acc_store, priv->accounts_handler);
222 if (priv->window_list) {
223 GList *iter = priv->window_list;
224 /* unregister pending windows */
226 ModestWindow *window = (ModestWindow *) iter->data;
227 iter = g_list_next (iter);
228 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window);
230 g_list_free (priv->window_list);
231 priv->window_list = NULL;
234 /* Free the hash table with the handlers */
235 if (priv->destroy_handlers) {
236 g_hash_table_destroy (priv->destroy_handlers);
237 priv->destroy_handlers = NULL;
240 if (priv->viewer_handlers) {
241 g_hash_table_destroy (priv->viewer_handlers);
242 priv->viewer_handlers = NULL;
245 modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids);
246 priv->modal_handler_uids = NULL;
248 if (priv->modal_windows) {
249 g_mutex_lock (priv->queue_lock);
250 g_queue_free (priv->modal_windows);
251 priv->modal_windows = NULL;
252 g_mutex_unlock (priv->queue_lock);
254 g_mutex_free (priv->queue_lock);
256 G_OBJECT_CLASS(parent_class)->finalize (obj);
260 modest_gtk_window_mgr_new (void)
262 return MODEST_WINDOW_MGR(g_object_new(MODEST_TYPE_GTK_WINDOW_MGR, NULL));
266 modest_gtk_window_mgr_close_all_windows (ModestWindowMgr *self)
268 ModestGtkWindowMgrPrivate *priv = NULL;
269 gboolean ret_value = FALSE;
270 ModestWindow *window;
271 gboolean failed = FALSE;
273 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
274 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
276 while ((window = modest_shell_peek_window (MODEST_SHELL (priv->shell))) != NULL) {
277 ret_value = modest_shell_delete_window (MODEST_SHELL (priv->shell), window);
278 if (ret_value == TRUE) {
288 compare_msguids (ModestWindow *win,
291 const gchar *msg_uid;
293 if ((!MODEST_IS_MSG_EDIT_WINDOW (win)) && (!MODEST_IS_MSG_VIEW_WINDOW (win)))
296 /* Get message uid from msg window */
297 if (MODEST_IS_MSG_EDIT_WINDOW (win)) {
298 msg_uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (win));
299 if (msg_uid && uid &&!strcmp (msg_uid, uid))
302 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (win));
305 if (msg_uid && uid &&!strcmp (msg_uid, uid))
312 compare_headers (ModestWindow *win,
315 TnyHeader *my_header;
318 if (!MODEST_IS_MSG_VIEW_WINDOW (win))
321 /* Get message uid from msg window */
322 my_header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
324 if (my_header == header)
326 g_object_unref (my_header);
333 modest_gtk_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *header,
336 ModestGtkWindowMgrPrivate *priv = NULL;
338 gboolean has_header, has_window = FALSE;
341 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
342 g_return_val_if_fail (TNY_IS_HEADER(header), FALSE);
344 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
346 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_header (self, header, win);
348 uid = modest_tny_folder_get_header_unique_id (header);
350 item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids);
354 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
355 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
356 g_debug ("not a valid window!");
358 g_debug ("found a window");
359 *win = MODEST_WINDOW (item->data);
365 return has_header || has_window;
369 modest_gtk_window_mgr_find_registered_message_uid (ModestWindowMgr *self, const gchar *msg_uid,
372 ModestGtkWindowMgrPrivate *priv = NULL;
373 gboolean has_header, has_window = FALSE;
376 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
377 g_return_val_if_fail (msg_uid && msg_uid[0] != '\0', FALSE);
379 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
381 has_header = MODEST_WINDOW_MGR_CLASS (parent_class)->find_registered_message_uid (self, msg_uid, win);
383 item = g_list_find_custom (priv->window_list, msg_uid, (GCompareFunc) compare_msguids);
387 if ((!MODEST_IS_MSG_VIEW_WINDOW(item->data)) &&
388 (!MODEST_IS_MSG_EDIT_WINDOW (item->data)))
389 g_debug ("not a valid window!");
391 g_debug ("found a window");
392 *win = MODEST_WINDOW (item->data);
397 return has_header || has_window;
401 modest_gtk_window_mgr_get_window_list (ModestWindowMgr *self)
403 ModestGtkWindowMgrPrivate *priv;
405 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
406 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
408 return g_list_copy (priv->window_list);
412 modest_gtk_window_mgr_register_window (ModestWindowMgr *self,
413 ModestWindow *window,
414 ModestWindow *parent)
417 ModestGtkWindowMgrPrivate *priv;
419 gboolean nested_msg = FALSE;
420 ModestWindow *current_top;
422 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
424 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
426 /* Try to close active modal dialogs */
427 if (modest_window_mgr_get_num_windows (self) &&
428 !_modest_window_mgr_close_active_modals (self))
431 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
433 win = g_list_find (priv->window_list, window);
435 /* this is for the case we want to register the window
436 and it was already registered */
437 gtk_window_present (GTK_WINDOW (priv->shell));
441 /* Do not allow standalone editors or standalone viewers */
443 (MODEST_IS_MSG_VIEW_WINDOW (window) ||
444 MODEST_IS_MSG_EDIT_WINDOW (window)))
445 modest_window_mgr_show_initial_window (self);
447 if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
451 uid = g_strdup (modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)));
453 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
456 uid = modest_tny_folder_get_header_unique_id (header);
457 /* Embedded messages do not have uid */
459 if (g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids)) {
460 g_debug ("%s found another view window showing the same header", __FUNCTION__);
462 g_object_unref (header);
467 if (g_list_find_custom (priv->window_list, header, (GCompareFunc) compare_headers)) {
468 g_debug ("%s found another view window showing the same header", __FUNCTION__);
469 g_object_unref (header);
474 g_object_unref (header);
477 /* Do not go backwards */
478 if ((MODEST_IS_MSG_VIEW_WINDOW (current_top) ||
479 MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
480 MODEST_IS_HEADER_WINDOW (current_top)) &&
481 (MODEST_IS_FOLDER_WINDOW (window) ||
482 MODEST_IS_ACCOUNTS_WINDOW (window) ||
483 MODEST_IS_MAILBOXES_WINDOW (window))) {
484 gtk_window_present (GTK_WINDOW (priv->shell));
488 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_FOLDER_WINDOW (window)) {
491 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), MODEST_WINDOW (window));
494 gtk_window_present (GTK_WINDOW (priv->shell));
497 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
500 if (MODEST_IS_MAILBOXES_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
501 gtk_window_present (GTK_WINDOW (priv->shell));
505 /* Mailboxes window can not replace folder windows */
506 if (MODEST_IS_FOLDER_WINDOW (current_top) && MODEST_IS_MAILBOXES_WINDOW (window)) {
507 gtk_window_present (GTK_WINDOW (priv->shell));
511 /* Trying to open a folders window and a mailboxes window at
512 the same time from the accounts window is not allowed */
513 if (MODEST_IS_MAILBOXES_WINDOW (current_top) &&
514 MODEST_IS_FOLDER_WINDOW (window) &&
515 MODEST_IS_ACCOUNTS_WINDOW (parent)) {
516 gtk_window_present (GTK_WINDOW (priv->shell));
520 if (MODEST_IS_HEADER_WINDOW (current_top) && MODEST_IS_HEADER_WINDOW (window)) {
521 g_debug ("Trying to register a second header window is not allowed");
522 gtk_window_present (GTK_WINDOW (priv->shell));
526 if (!MODEST_WINDOW_MGR_CLASS (parent_class)->register_window (self, window, parent))
529 /* Add to list. Keep a reference to the window */
530 g_object_ref (window);
531 priv->window_list = g_list_prepend (priv->window_list, window);
533 nested_msg = MODEST_IS_MSG_VIEW_WINDOW (window) &&
534 MODEST_IS_MSG_VIEW_WINDOW (parent);
536 /* Close views if they're being shown. Nevertheless we must
537 allow nested messages */
539 (MODEST_IS_MSG_EDIT_WINDOW (current_top) ||
540 MODEST_IS_MSG_VIEW_WINDOW (current_top))) {
543 /* If the current view has modal dialogs then
544 we fail to register the new view */
545 if ((current_top != NULL) &&
546 shell_has_modals (MODEST_SHELL (priv->shell))) {
547 /* Window on top but it has opened dialogs */
551 /* Close the current view */
552 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
554 /* Cancelled closing top window, then we fail to register */
559 /* Listen to object destruction */
560 handler_id = g_malloc0 (sizeof (gint));
561 *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self);
562 g_hash_table_insert (priv->destroy_handlers, window, handler_id);
564 /* Show toolbar always */
565 modest_window_show_toolbar (window, TRUE);
567 modest_shell_add_window (MODEST_SHELL (priv->shell), window);
571 /* Add to list. Keep a reference to the window */
572 priv->window_list = g_list_remove (priv->window_list, window);
573 g_object_unref (window);
574 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
576 gtk_window_present (GTK_WINDOW (priv->shell));
581 cancel_window_operations (ModestWindow *window)
583 GSList* pending_ops = NULL;
585 /* cancel open and receive operations */
586 pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (),
588 while (pending_ops != NULL) {
589 ModestMailOperationTypeOperation type;
590 GSList* tmp_list = NULL;
592 type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data));
593 if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
594 type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
595 type == MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE) {
596 modest_mail_operation_cancel (pending_ops->data);
598 g_object_unref (G_OBJECT (pending_ops->data));
599 tmp_list = pending_ops;
600 pending_ops = g_slist_next (pending_ops);
601 g_slist_free_1 (tmp_list);
606 shell_has_modals (ModestShell *shell)
610 gboolean retvalue = FALSE;
612 /* First we fetch all toplevels */
613 toplevels = gtk_window_list_toplevels ();
614 for (node = toplevels; node != NULL; node = g_list_next (node)) {
615 if (GTK_IS_WINDOW (node->data) &&
616 gtk_window_get_transient_for (GTK_WINDOW (node->data)) == GTK_WINDOW (shell) &&
617 GTK_WIDGET_VISIBLE (node->data)) {
622 g_list_free (toplevels);
627 on_window_destroy (ModestWindow *window,
629 ModestGtkWindowMgr *self)
631 ModestGtkWindowMgrPrivate *priv;
632 gboolean no_propagate = FALSE;
634 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
636 /* Do not close the window if it has modals on top */
637 if (!MODEST_IS_MSG_EDIT_WINDOW (window) && shell_has_modals (MODEST_SHELL (priv->shell)))
640 if (MODEST_IS_MSG_EDIT_WINDOW (window)) {
641 gboolean sent = FALSE;
642 sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window));
643 /* Save currently edited message to Drafts if it was not sent */
644 if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) {
645 ModestMsgEditWindow *edit_window;
648 edit_window = MODEST_MSG_EDIT_WINDOW (window);
649 data = modest_msg_edit_window_get_msg_data (edit_window);
653 guint64 parts_size, available_size, expected_size;
655 available_size = modest_utils_get_available_space (NULL);
656 modest_msg_edit_window_get_parts_size (edit_window, &parts_count, &parts_size);
657 expected_size = modest_tny_msg_estimate_size (data->plain_body,
661 modest_msg_edit_window_free_msg_data (edit_window, data);
664 /* If there is not enough space
665 available for saving the message
666 then show an error and close the
667 window without saving */
668 if (expected_size >= available_size) {
669 modest_platform_run_information_dialog (GTK_WINDOW (edit_window),
670 _("mail_in_ui_save_error"),
673 if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)))
677 g_warning ("Edit window without message data. This is probably a bug");
682 /* Unregister window */
683 modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (self), window);
684 no_propagate = FALSE;
690 modest_gtk_window_mgr_unregister_window (ModestWindowMgr *self,
691 ModestWindow *window)
694 ModestGtkWindowMgrPrivate *priv;
695 gulong *tmp, handler_id;
698 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
699 g_return_if_fail (MODEST_IS_WINDOW (window));
701 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
703 win = g_list_find (priv->window_list, window);
705 g_debug ("Trying to unregister a window that has not being registered yet");
709 /* Remove the viewer window handler from the hash table. The
710 HashTable could not exist if the main window was closed
711 when there were other windows remaining */
712 if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) {
713 tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window);
714 /* If the viewer was created without a main window
715 (for example when opening a message through D-Bus
716 the viewer handlers was not registered */
718 g_signal_handler_disconnect (window, *tmp);
719 g_hash_table_remove (priv->viewer_handlers, window);
723 /* Remove from list & hash table */
724 priv->window_list = g_list_remove_link (priv->window_list, win);
725 tmp = g_hash_table_lookup (priv->destroy_handlers, window);
728 g_hash_table_remove (priv->destroy_handlers, window);
730 /* cancel open and receive operations */
731 cancel_window_operations (window);
733 /* Disconnect the "delete-event" handler, we won't need it anymore */
734 g_signal_handler_disconnect (window, handler_id);
736 /* Destroy the window */
737 g_object_unref (win->data);
740 MODEST_WINDOW_MGR_CLASS (parent_class)->unregister_window (self, window);
742 /* We have to get the number of windows here in order not to
743 emit the signal too many times */
744 num_windows = modest_window_mgr_get_num_windows (self);
746 /* If there are no more windows registered emit the signal */
747 if (num_windows == 0)
748 g_signal_emit_by_name (self, "window-list-empty");
753 modest_gtk_window_mgr_set_fullscreen_mode (ModestWindowMgr *self,
756 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
758 ModestGtkWindowMgrPrivate *priv = NULL;
759 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
761 priv->fullscreen = on;
764 gtk_window_fullscreen (GTK_WINDOW (priv->shell));
766 gtk_window_unfullscreen (GTK_WINDOW (priv->shell));
772 modest_gtk_window_mgr_get_fullscreen_mode (ModestWindowMgr *self)
774 ModestGtkWindowMgrPrivate *priv = NULL;
775 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
777 return priv->fullscreen;
781 modest_gtk_window_mgr_show_toolbars (ModestWindowMgr *self,
783 gboolean show_toolbars,
786 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
792 look_for_transient (gconstpointer a,
795 GtkWindow *win, *child;
800 child = (GtkWindow *) b;
801 win = (GtkWindow *) a;
803 if ((gtk_window_get_transient_for (win) == child) &&
804 GTK_WIDGET_VISIBLE (win))
811 modest_gtk_window_mgr_get_modal (ModestWindowMgr *self)
813 ModestGtkWindowMgrPrivate *priv;
814 GList *toplevel_list;
817 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
818 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
820 /* Get current top */
821 toplevel = priv->shell;
822 toplevel_list = gtk_window_list_toplevels ();
827 parent_link = g_list_find_custom (toplevel_list, toplevel, look_for_transient);
829 toplevel = (GtkWidget *) parent_link->data;
834 if (toplevel && GTK_WIDGET_VISIBLE (toplevel) && gtk_window_get_modal ((GtkWindow *) toplevel))
835 return (GtkWindow *) toplevel;
842 modest_gtk_window_mgr_set_modal (ModestWindowMgr *self,
846 ModestGtkWindowMgrPrivate *priv;
848 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
849 g_return_if_fail (GTK_IS_WINDOW (window));
851 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
853 gtk_window_set_modal (window, TRUE);
855 if (GTK_IS_WINDOW (parent)) {
856 gtk_window_set_transient_for (window, parent);
858 gtk_window_set_transient_for (window, GTK_WINDOW (priv->shell));
860 gtk_window_set_destroy_with_parent (window, TRUE);
864 close_all_but_first (gpointer data)
868 ModestGtkWindowMgrPrivate *priv;
870 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(data);
871 num_windows = modest_shell_count_windows (MODEST_SHELL (priv->shell));
873 for (i = 0; i < (num_windows - 1); i++) {
874 ModestWindow *current_top;
877 current_top = modest_shell_peek_window (MODEST_SHELL (priv->shell));
878 retval = modest_shell_delete_window (MODEST_SHELL (priv->shell), current_top);
883 on_idle_close_all_but_first (gpointer data)
885 gdk_threads_enter ();
886 close_all_but_first (data);
887 gdk_threads_leave ();
893 on_account_removed (TnyAccountStore *acc_store,
897 ModestWindow *current_top;
898 ModestGtkWindowMgrPrivate *priv;
900 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (user_data);
902 /* Ignore transport account removals */
903 if (TNY_IS_TRANSPORT_ACCOUNT (account))
906 current_top = (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
908 /* if we're showing the header view of the currently deleted
909 account, or the outbox and we deleted the last account,
910 then close the window */
912 (MODEST_IS_HEADER_WINDOW (current_top) ||
913 MODEST_IS_FOLDER_WINDOW (current_top))) {
914 const gchar *acc_name;
916 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
918 /* We emit it in an idle, because sometimes this
919 function could called when the account settings
920 dialog is about to close but still there. That
921 modal dialog would otherwise, prevent the
922 windows from being closed */
923 if (!strcmp (acc_name, modest_window_get_active_account (current_top)))
924 g_idle_add (on_idle_close_all_but_first, (gpointer) user_data);
928 static ModestWindow *
929 modest_gtk_window_mgr_show_initial_window (ModestWindowMgr *self)
931 ModestWindow *initial_window = NULL;
932 ModestGtkWindowMgrPrivate *priv;
934 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
936 /* Connect to the account store "account-removed" signal". We
937 do this here because in the init the singletons are still
938 not initialized properly */
939 if (!g_signal_handler_is_connected (modest_runtime_get_account_store (),
940 priv->accounts_handler)) {
941 priv->accounts_handler = g_signal_connect (modest_runtime_get_account_store (),
943 G_CALLBACK (on_account_removed),
947 /* Return accounts window */
948 initial_window = MODEST_WINDOW (modest_accounts_window_new ());
949 modest_window_mgr_register_window (self, initial_window, NULL);
951 return initial_window;
955 static ModestWindow *
956 modest_gtk_window_mgr_get_current_top (ModestWindowMgr *self)
958 ModestGtkWindowMgrPrivate *priv;
960 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
961 return (ModestWindow *) modest_shell_peek_window (MODEST_SHELL (priv->shell));
965 find_folder_window (gconstpointer a,
968 return (MODEST_IS_FOLDER_WINDOW (a)) ? 0 : 1;
971 static ModestWindow *
972 modest_gtk_window_mgr_get_folder_window (ModestWindowMgr *self)
974 ModestGtkWindowMgrPrivate *priv;
977 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), NULL);
979 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
981 window = g_list_find_custom (priv->window_list,
985 return (window != NULL) ? MODEST_WINDOW (window->data) : NULL;
989 modest_gtk_window_mgr_screen_is_on (ModestWindowMgr *self)
991 ModestGtkWindowMgrPrivate *priv = NULL;
993 g_return_val_if_fail (MODEST_IS_GTK_WINDOW_MGR (self), FALSE);
995 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE (self);
1001 modest_gtk_window_mgr_create_caches (ModestWindowMgr *self)
1003 g_return_if_fail (MODEST_IS_GTK_WINDOW_MGR (self));
1005 modest_accounts_window_pre_create ();
1007 MODEST_WINDOW_MGR_CLASS(parent_class)->create_caches (self);
1011 modest_gtk_window_mgr_close_all_but_initial (ModestWindowMgr *self)
1014 ModestGtkWindowMgrPrivate *priv;
1016 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);
1018 /* Exit if there are no windows */
1019 if (!modest_window_mgr_get_num_windows (self)) {
1020 g_warning ("%s: unable to close, there are no windows", __FUNCTION__);
1024 /* Close active modals */
1025 if (!_modest_window_mgr_close_active_modals (self)) {
1026 g_debug ("%s: unable to close some dialogs", __FUNCTION__);
1030 /* Close all but first */
1031 top = modest_window_mgr_get_current_top (self);
1032 if (!MODEST_IS_ACCOUNTS_WINDOW (top))
1033 close_all_but_first ((gpointer) priv->shell);
1035 /* If some cannot be closed return */
1036 top = modest_window_mgr_get_current_top (self);
1037 if (!MODEST_IS_ACCOUNTS_WINDOW (top)) {
1038 g_debug ("%s: could not close some windows", __FUNCTION__);
1046 modest_gtk_window_mgr_get_shell (ModestGtkWindowMgr *self)
1048 ModestGtkWindowMgrPrivate *priv;
1050 priv = MODEST_GTK_WINDOW_MGR_GET_PRIVATE(self);