X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-window-mgr.c;h=fb88abf2cb08f3584af8f5e9dbfe7660a67e792b;hp=aa654f420275b82ee4d92763f99937178a922c03;hb=f6d386ff93e929092ba105385a29d760aeba9ff7;hpb=1607d4b15dc3b82e6dcc07ed06aba900f4c22d17 diff --git a/src/widgets/modest-window-mgr.c b/src/widgets/modest-window-mgr.c index aa654f4..fb88abf 100644 --- a/src/widgets/modest-window-mgr.c +++ b/src/widgets/modest-window-mgr.c @@ -36,6 +36,7 @@ #include "widgets/modest-main-window.h" #include "widgets/modest-msg-edit-window.h" #include "widgets/modest-msg-view-window.h" +#include "modest-debug.h" /* 'private'/'protected' functions */ @@ -51,6 +52,9 @@ static gboolean on_modal_window_close (GtkWidget *widget, GdkEvent *event, gpointer user_data); +static void on_modal_dialog_destroy (GtkObject *object, + gpointer user_data); + static void on_modal_dialog_close (GtkDialog *dialog, gint arg1, gpointer user_data); @@ -60,14 +64,14 @@ static const gchar* get_show_toolbar_key (GType window_type, /* list my signals */ enum { - /* MY_SIGNAL_1, */ - /* MY_SIGNAL_2, */ - LAST_SIGNAL + WINDOW_LIST_EMPTY_SIGNAL, + NUM_SIGNALS }; typedef struct _ModestWindowMgrPrivate ModestWindowMgrPrivate; struct _ModestWindowMgrPrivate { GList *window_list; + guint banner_counter; ModestWindow *main_window; @@ -80,10 +84,17 @@ struct _ModestWindowMgrPrivate { GSList *preregistered_uids; GHashTable *destroy_handlers; GHashTable *viewer_handlers; + GSList *window_state_uids; guint closing_time; GSList *modal_handler_uids; + GtkWidget *cached_view; + GtkWidget *cached_editor; + guint idle_load_view_id; + guint idle_load_editor_id; + + ModestWindow *current_top; }; #define MODEST_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_WINDOW_MGR, \ @@ -92,7 +103,7 @@ struct _ModestWindowMgrPrivate { static GObjectClass *parent_class = NULL; /* uncomment the following if you have defined any signals */ -/* static guint signals[LAST_SIGNAL] = {0}; */ +static guint signals[NUM_SIGNALS] = {0}; GType modest_window_mgr_get_type (void) @@ -128,6 +139,59 @@ modest_window_mgr_class_init (ModestWindowMgrClass *klass) gobject_class->finalize = modest_window_mgr_finalize; g_type_class_add_private (gobject_class, sizeof(ModestWindowMgrPrivate)); + + + /** + * ModestWindowMgr::window-list-empty + * @self: the #ModestWindowMgr that emits the signal + * @user_data: user data set when the signal handler was connected + * + * Issued whenever the window list becomes empty + */ + signals[WINDOW_LIST_EMPTY_SIGNAL] = + g_signal_new ("window-list-empty", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ModestWindowMgrClass, window_list_empty), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static gboolean +idle_load_view (ModestWindowMgr *mgr) +{ + ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr); + + priv->cached_view = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL); + priv->idle_load_view_id = 0; + return FALSE; +} + +static gboolean +idle_load_editor (ModestWindowMgr *mgr) +{ + ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (mgr); + + priv->cached_editor = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL); + priv->idle_load_editor_id = 0; + return FALSE; +} + +static void +load_new_view (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + if ((priv->cached_view == NULL) && (priv->idle_load_view_id == 0)) + priv->idle_load_view_id = g_idle_add ((GSourceFunc) idle_load_view, self); +} + +static void +load_new_editor (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + if ((priv->cached_editor == NULL) && (priv->idle_load_editor_id == 0)) + priv->idle_load_editor_id = g_idle_add ((GSourceFunc) idle_load_editor, self); } static void @@ -137,8 +201,11 @@ modest_window_mgr_init (ModestWindowMgr *obj) priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj); priv->window_list = NULL; + priv->banner_counter = 0; priv->main_window = NULL; priv->fullscreen_mode = FALSE; + priv->current_top = NULL; + priv->window_state_uids = NULL; priv->modal_windows = g_queue_new (); priv->queue_lock = g_mutex_new (); @@ -153,6 +220,8 @@ modest_window_mgr_init (ModestWindowMgr *obj) priv->closing_time = 0; priv->modal_handler_uids = NULL; + priv->cached_view = NULL; + priv->cached_editor = NULL; } static void @@ -160,13 +229,35 @@ modest_window_mgr_finalize (GObject *obj) { ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE(obj); + if (priv->idle_load_view_id > 0) { + g_source_remove (priv->idle_load_view_id); + priv->idle_load_view_id = 0; + } + + if (priv->idle_load_editor_id > 0) { + g_source_remove (priv->idle_load_editor_id); + priv->idle_load_editor_id = 0; + } + + if (priv->cached_view) { + gtk_widget_destroy (priv->cached_view); + priv->cached_view = NULL; + } + if (priv->cached_editor) { + gtk_widget_destroy (priv->cached_editor); + priv->cached_editor = NULL; + } + + modest_signal_mgr_disconnect_all_and_destroy (priv->window_state_uids); + priv->window_state_uids = NULL; + if (priv->window_list) { GList *iter = priv->window_list; /* unregister pending windows */ while (iter) { - modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), - MODEST_WINDOW (iter->data)); + ModestWindow *window = (ModestWindow *) iter->data; iter = g_list_next (iter); + modest_window_mgr_unregister_window (MODEST_WINDOW_MGR (obj), window); } g_list_free (priv->window_list); priv->window_list = NULL; @@ -188,6 +279,7 @@ modest_window_mgr_finalize (GObject *obj) } modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids); + priv->modal_handler_uids = NULL; if (priv->modal_windows) { g_mutex_lock (priv->queue_lock); @@ -238,7 +330,7 @@ remove_uid (GSList *list, const gchar *uid) GSList *cursor = list, *start = list; if (!uid) - return FALSE; + return list; while (cursor) { GSList *next = g_slist_next (cursor); @@ -276,10 +368,10 @@ modest_window_mgr_register_header (ModestWindowMgr *self, TnyHeader *header, co uid = g_strdup (alt_uid); if (!has_uid (priv->preregistered_uids, uid)) { - g_debug ("registering new uid %s", uid); + MODEST_DEBUG_BLOCK(g_debug ("registering new uid %s", uid);); priv->preregistered_uids = append_uid (priv->preregistered_uids, uid); } else - g_debug ("already had uid %s", uid); + MODEST_DEBUG_BLOCK(g_debug ("already had uid %s", uid);); g_free (uid); } @@ -297,22 +389,49 @@ modest_window_mgr_unregister_header (ModestWindowMgr *self, TnyHeader *header) uid = modest_tny_folder_get_header_unique_id (header); if (!has_uid (priv->preregistered_uids, uid)) { - g_debug ("trying to unregister non-existing uid %s", uid); + MODEST_DEBUG_BLOCK(g_debug ("trying to unregister non-existing uid %s", uid);); priv->preregistered_uids = append_uid (priv->preregistered_uids, uid); } else - g_debug ("unregistering uid %s", uid); + MODEST_DEBUG_BLOCK(g_debug ("unregistering uid %s", uid);); if (has_uid (priv->preregistered_uids, uid)) { priv->preregistered_uids = remove_uid (priv->preregistered_uids, uid); if (has_uid (priv->preregistered_uids, uid)) g_debug ("BUG: uid %s NOT removed", uid); else - g_debug ("uid %s removed", uid); + MODEST_DEBUG_BLOCK(g_debug ("uid %s removed", uid);); } g_free (uid); } + +#define MODEST_WINDOW_HELP_ID_PARAM "help-id" + +void +modest_window_mgr_register_help_id (ModestWindowMgr *self, GtkWindow *win, const gchar* help_id) +{ + /* we don't need 'self', but for API consistency... */ + g_return_if_fail (self && MODEST_IS_WINDOW_MGR(self)); + + g_return_if_fail (win && GTK_IS_WINDOW(win)); + g_return_if_fail (help_id); + + g_object_set_data_full (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM, + g_strdup(help_id), g_free); +} + + +const gchar* +modest_window_mgr_get_help_id (ModestWindowMgr *self, GtkWindow *win) +{ + /* we don't need 'self', but for API consistency... */ + g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR (self), NULL); + g_return_val_if_fail (win, NULL); + + return g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM); +} + static gint compare_msguids (ModestWindow *win, const gchar *uid) @@ -341,19 +460,25 @@ void modest_window_mgr_close_all_windows (ModestWindowMgr *self) { ModestWindowMgrPrivate *priv = NULL; - GList *wins = NULL; gboolean ret_value = FALSE; g_return_if_fail (MODEST_IS_WINDOW_MGR (self)); priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); - /* delete-event handler already removes window_list item, */ - /* so no next its required on this loop */ - wins = priv->window_list; - while (wins) { - g_signal_emit_by_name (G_OBJECT (wins->data), "delete-event", NULL, &ret_value); + /* If there is a main window then try to close it, and it will + close the others if needed */ + if (priv->main_window) { + g_signal_emit_by_name (priv->main_window, "delete-event", NULL, &ret_value); + } else { + GList *wins = NULL, *next = NULL; + /* delete-event handler actually removes window_list item, */ wins = priv->window_list; + while (wins) { + next = g_list_next (wins); + g_signal_emit_by_name (G_OBJECT (wins->data), "delete-event", NULL, &ret_value); + wins = next; + } } } @@ -421,6 +546,64 @@ get_show_toolbar_key (GType window_type, return key; } +#ifndef MODEST_TOOLKIT_GTK +static void +on_window_is_topmost (GObject *gobject, + GParamSpec *arg1, + gpointer user_data) +{ + ModestWindowMgr *self; + ModestWindowMgrPrivate *priv; + ModestWindow *win = (ModestWindow *) gobject; + + g_return_if_fail (MODEST_IS_WINDOW_MGR (user_data)); + + self = MODEST_WINDOW_MGR (user_data); + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + if (hildon_window_get_is_topmost (HILDON_WINDOW (win))) + priv->current_top = win; +} + +#else +static gboolean +on_window_state_event (GtkWidget *widget, + GdkEventWindowState *event, + gpointer user_data) +{ + ModestWindowMgr *self; + ModestWindowMgrPrivate *priv; + + g_return_val_if_fail (MODEST_IS_WINDOW_MGR (user_data), FALSE); + + self = MODEST_WINDOW_MGR (user_data); + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + MODEST_DEBUG_BLOCK ( + if (event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) + g_print ("GDK_WINDOW_STATE_WITHDRAWN\n"); + if (event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) + g_print ("GDK_WINDOW_STATE_ICONIFIED\n"); + if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) + g_print ("GDK_WINDOW_STATE_MAXIMIZED\n"); + if (event->changed_mask & GDK_WINDOW_STATE_STICKY) + g_print ("GDK_WINDOW_STATE_STICKY\n"); + if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) + g_print ("GDK_WINDOW_STATE_FULLSCREEN\n"); + if (event->changed_mask & GDK_WINDOW_STATE_ABOVE) + g_print ("GDK_WINDOW_STATE_ABOVE\n"); + if (event->changed_mask & GDK_WINDOW_STATE_BELOW) + g_print ("GDK_WINDOW_STATE_BELOW\n"); + ); + if (event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN || + event->changed_mask & GDK_WINDOW_STATE_ABOVE) { + priv->current_top = MODEST_WINDOW (widget); + } + + return FALSE; +} +#endif + void modest_window_mgr_register_window (ModestWindowMgr *self, ModestWindow *window) @@ -437,8 +620,9 @@ modest_window_mgr_register_window (ModestWindowMgr *self, win = g_list_find (priv->window_list, window); if (win) { - g_warning ("%s: trying to re-register a window", - __FUNCTION__); + /* this is for the case we want to register the window and it was already + * registered. We leave silently. + */ return; } @@ -450,6 +634,8 @@ modest_window_mgr_register_window (ModestWindowMgr *self, return; } else { priv->main_window = window; + load_new_view (self); + load_new_editor (self); } } @@ -461,7 +647,7 @@ modest_window_mgr_register_window (ModestWindowMgr *self, if (!has_uid (priv->preregistered_uids, uid)) g_debug ("weird: no uid for window (%s)", uid); - g_debug ("registering window for %s", uid ? uid : ""); + MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid ? uid : "");); priv->preregistered_uids = remove_uid (priv->preregistered_uids, @@ -471,7 +657,7 @@ modest_window_mgr_register_window (ModestWindowMgr *self, const gchar *uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (window)); - g_debug ("registering window for %s", uid); + MODEST_DEBUG_BLOCK(g_debug ("registering window for %s", uid);); priv->preregistered_uids = remove_uid (priv->preregistered_uids, @@ -483,6 +669,24 @@ modest_window_mgr_register_window (ModestWindowMgr *self, g_object_ref (window); priv->window_list = g_list_prepend (priv->window_list, window); + /* Listen to window state changes. Unfortunately + window-state-event does not properly work for the Maemo + version, so we need to use is-topmost and the ifdef */ +#ifndef MODEST_TOOLKIT_GTK + priv->window_state_uids = + modest_signal_mgr_connect (priv->window_state_uids, + G_OBJECT (window), + "notify::is-topmost", + G_CALLBACK (on_window_is_topmost), + self); +#else + priv->window_state_uids = + modest_signal_mgr_connect (priv->window_state_uids, + G_OBJECT (window), + "window-state-event", + G_CALLBACK (on_window_state_event), + self); +#endif /* Listen to object destruction */ handler_id = g_malloc0 (sizeof (gint)); *handler_id = g_signal_connect (window, "delete-event", G_CALLBACK (on_window_destroy), self); @@ -507,12 +711,38 @@ modest_window_mgr_register_window (ModestWindowMgr *self, modest_window_show_toolbar (window, modest_conf_get_bool (modest_runtime_get_conf (), key, NULL)); } +static void +cancel_window_operations (ModestWindow *window) +{ + GSList* pending_ops = NULL; + + /* cancel open and receive operations */ + pending_ops = modest_mail_operation_queue_get_by_source (modest_runtime_get_mail_operation_queue (), + G_OBJECT (window)); + while (pending_ops != NULL) { + ModestMailOperationTypeOperation type; + GSList* tmp_list = NULL; + + type = modest_mail_operation_get_type_operation (MODEST_MAIL_OPERATION (pending_ops->data)); + if (type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || type == MODEST_MAIL_OPERATION_TYPE_OPEN) { + modest_mail_operation_cancel (pending_ops->data); + } + g_object_unref (G_OBJECT (pending_ops->data)); + tmp_list = pending_ops; + pending_ops = g_slist_next (pending_ops); + g_slist_free_1 (tmp_list); + } +} + + + static gboolean on_window_destroy (ModestWindow *window, GdkEvent *event, ModestWindowMgr *self) { gint dialog_response = GTK_RESPONSE_NONE; + gboolean no_propagate = FALSE; /* Specific stuff first */ if (MODEST_IS_MAIN_WINDOW (window)) { @@ -522,15 +752,19 @@ on_window_destroy (ModestWindow *window, /* If more than one window already opened */ if (g_list_length (priv->window_list) > 1) { + /* Present the window if it's not visible now */ + if (!gtk_window_has_toplevel_focus (GTK_WINDOW (window))) { + gtk_window_present (GTK_WINDOW (window)); + priv->current_top = window; + } /* Create the confirmation dialog MSG-NOT308 */ dialog_response = modest_platform_run_confirmation_dialog ( GTK_WINDOW (window), _("emev_nc_close_windows")); /* If the user wants to close all the windows */ if ((dialog_response == GTK_RESPONSE_OK) - || (dialog_response == GTK_RESPONSE_ACCEPT) - || (dialog_response == GTK_RESPONSE_YES)) - { + || (dialog_response == GTK_RESPONSE_ACCEPT) + || (dialog_response == GTK_RESPONSE_YES)) { GList *iter = priv->window_list; do { if (iter->data != window) { @@ -543,12 +777,22 @@ on_window_destroy (ModestWindow *window, iter = g_list_next (iter); } } while (iter); - } - else - { - return TRUE; - } + } else { + return TRUE; + } } + + /* Do not unregister it, just hide */ + gtk_widget_hide_all (GTK_WIDGET (window)); + + /* Cancel pending operations */ + cancel_window_operations (window); + + /* Fake the window system, make it think that there is no window */ + if (modest_window_mgr_num_windows (self) == 0) + g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0); + + no_propagate = TRUE; } else { if (MODEST_IS_MSG_EDIT_WINDOW (window)) { @@ -566,16 +810,17 @@ on_window_destroy (ModestWindow *window, modest_platform_run_confirmation_dialog (GTK_WINDOW (window), _("mcen_nc_no_email_message_modified_save_changes")); /* Save to drafts */ - if (response != GTK_RESPONSE_CANCEL) - modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window)); + if (response == GTK_RESPONSE_OK) + if (!modest_ui_actions_on_save_to_drafts (NULL, MODEST_MSG_EDIT_WINDOW (window))) + return TRUE; } } + /* Unregister window */ + modest_window_mgr_unregister_window (self, window); + no_propagate = TRUE; } - /* Unregister window */ - modest_window_mgr_unregister_window (self, window); - - return FALSE; + return no_propagate; } static void @@ -590,62 +835,6 @@ disconnect_msg_changed (gpointer key, g_signal_handler_disconnect (G_OBJECT (key), handler_id); } - - -/* interval before retrying to close the application */ -#define CLOSING_RETRY_INTERVAL 3000 -/* interval before cancel whatever is left in the queue, and closing anyway */ -#define MAX_WAIT_FOR_CLOSING 30 * 1000 - -static gboolean -on_quit_maybe (ModestWindowMgr *self) -{ - ModestWindowMgrPrivate *priv; - guint queue_num; - - priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); - - /* it seems, in the meantime some windows were - * created. in that case, stop 'on_quit_maybe' */ - if (priv->window_list) { - priv->closing_time = 0; - return FALSE; - } - - if (priv->closing_time >= MAX_WAIT_FOR_CLOSING) { - /* we waited long enough: cancel all remaining operations */ - g_debug ("%s: we waited long enough (%ds), cancelling queue and quiting", - __FUNCTION__, priv->closing_time/1000); - /* FIXME: below gives me a lot of: - * GLIB CRITICAL ** default - modest_mail_operation_cancel: - * assertion `priv->account' failed - * which means there is no account for the given operation - * so, we're not trying to be nice, we're just quiting. - */ - //modest_mail_operation_queue_cancel_all - // (modest_runtime_get_mail_operation_queue()); - } else { - - /* if there is anything left in our operation queue, - * wait another round - */ - queue_num = modest_mail_operation_queue_num_elements - (modest_runtime_get_mail_operation_queue()); - if (queue_num > 0) { - g_debug ("%s: waiting, there are still %d operation(s) queued", - __FUNCTION__, queue_num); - priv->closing_time += CLOSING_RETRY_INTERVAL; - return TRUE; - } - } - - /* so: no windows left, nothing in the queue: quit */ - priv->closing_time = 0; - gtk_main_quit (); - return FALSE; -} - - void modest_window_mgr_unregister_window (ModestWindowMgr *self, ModestWindow *window) @@ -680,9 +869,9 @@ modest_window_mgr_unregister_window (ModestWindowMgr *self, } /* Remove the viewer window handler from the hash table. The - HashTable could not exist if the main window was closeed + HashTable could not exist if the main window was closed when there were other windows remaining */ - if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewaer_handlers) { + if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) { tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window); /* If the viewer was created without a main window (for example when opening a message through D-Bus @@ -700,8 +889,34 @@ modest_window_mgr_unregister_window (ModestWindowMgr *self, priv->window_list = g_list_remove_link (priv->window_list, win); tmp = g_hash_table_lookup (priv->destroy_handlers, window); handler_id = *tmp; + g_hash_table_remove (priv->destroy_handlers, window); + /* cancel open and receive operations */ + cancel_window_operations (window); + + /* Check if it's the topmost window, and remove the window from the stack. + * This is needed for the cases there's no other topmost window that will + * replace it in topmost handler. + */ + if (window == priv->current_top) + priv->current_top = NULL; + + /* Disconnect the "window-state-event" handler, we won't need it anymore */ + if (priv->window_state_uids) { +#ifndef MODEST_TOOLKIT_GTK + priv->window_state_uids = + modest_signal_mgr_disconnect (priv->window_state_uids, + G_OBJECT (window), + "notify::is-topmost"); +#else + priv->window_state_uids = + modest_signal_mgr_disconnect (priv->window_state_uids, + G_OBJECT (window), + "window-state-event"); +#endif + } + /* Disconnect the "delete-event" handler, we won't need it anymore */ g_signal_handler_disconnect (window, handler_id); @@ -709,12 +924,13 @@ modest_window_mgr_unregister_window (ModestWindowMgr *self, modest_window_disconnect_signals (window); /* Destroy the window */ + g_object_unref (win->data); gtk_widget_destroy (win->data); + g_list_free (win); - /* If there are no more windows registered then exit program */ - if (priv->window_list == NULL) - g_timeout_add (CLOSING_RETRY_INTERVAL, - (GSourceFunc)on_quit_maybe, self); + /* If there are no more windows registered emit the signal */ + if (modest_window_mgr_num_windows (self) == 0) + g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0); } @@ -815,7 +1031,7 @@ modest_window_mgr_show_toolbars (ModestWindowMgr *self, } ModestWindow* -modest_window_mgr_get_main_window (ModestWindowMgr *self) +modest_window_mgr_get_main_window (ModestWindowMgr *self, gboolean create) { ModestWindowMgrPrivate *priv; @@ -823,16 +1039,30 @@ modest_window_mgr_get_main_window (ModestWindowMgr *self) priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); /* create the main window, if it hasn't been created yet */ - if (!priv->main_window) { + if (!priv->main_window && create) { /* modest_window_mgr_register_window will set priv->main_window */ modest_window_mgr_register_window (self, modest_main_window_new ()); - g_debug ("%s: created main window: %p\n", __FUNCTION__, priv->main_window); + MODEST_DEBUG_BLOCK( + g_debug ("%s: created main window: %p\n", __FUNCTION__, priv->main_window); + ); } return priv->main_window; } +gboolean +modest_window_mgr_main_window_exists (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv; + + g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE); + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + return priv->main_window != NULL; +} + + GtkWindow * modest_window_mgr_get_modal (ModestWindowMgr *self) { @@ -861,6 +1091,14 @@ modest_window_mgr_set_modal (ModestWindowMgr *self, g_mutex_unlock (priv->queue_lock); if (!old_modal) { + /* make us transient wrt the main window then */ + if (priv->current_top && ((GtkWindow *) priv->current_top != window)) { + gtk_window_set_transient_for (window, GTK_WINDOW(priv->current_top)); + } else { + ModestWindow *main_win = modest_window_mgr_get_main_window (self, FALSE); + if (GTK_WINDOW(main_win) != window) /* they should not be the same */ + gtk_window_set_transient_for (window, GTK_WINDOW(main_win)); + } gtk_window_set_modal (window, TRUE); } else { /* un-modalize the old one; the one on top should be the @@ -874,7 +1112,7 @@ modest_window_mgr_set_modal (ModestWindowMgr *self, g_queue_push_head (priv->modal_windows, window); g_mutex_unlock (priv->queue_lock); - if (GTK_IS_DIALOG (window)) + if (GTK_IS_DIALOG (window)) { /* Note that response is not always enough because it could be captured and removed easily by dialogs but works for most of situations */ @@ -884,13 +1122,25 @@ modest_window_mgr_set_modal (ModestWindowMgr *self, "response", G_CALLBACK (on_modal_dialog_close), self); - else + /* We need this as well because dialogs are often + destroyed with gtk_widget_destroy and this one will + prevent response from happening */ + priv->modal_handler_uids = + modest_signal_mgr_connect (priv->modal_handler_uids, + G_OBJECT (window), + "destroy", + G_CALLBACK (on_modal_dialog_destroy), + self); + } else { priv->modal_handler_uids = modest_signal_mgr_connect (priv->modal_handler_uids, G_OBJECT (window), "delete-event", G_CALLBACK (on_modal_window_close), self); + } + /* Destroy width parent */ + gtk_window_set_destroy_with_parent (window, TRUE); } @@ -984,8 +1234,15 @@ idle_top_modal (gpointer data) g_mutex_unlock (priv->queue_lock); /* Show it */ - if (topmost) + if (topmost) { + gdk_threads_enter (); gtk_window_present (topmost); + /* It seems that the window looses modality if some + other is shown on top of it after set_transient_for + and set_parent */ + gtk_window_set_modal (topmost, TRUE); + gdk_threads_leave (); + } return FALSE; } @@ -1012,12 +1269,17 @@ remove_modal_from_queue (GtkWidget *widget, g_mutex_unlock (priv->queue_lock); /* Disconnect handler */ - priv->modal_handler_uids = - modest_signal_mgr_disconnect (priv->modal_handler_uids, + priv->modal_handler_uids = + modest_signal_mgr_disconnect (priv->modal_handler_uids, G_OBJECT (widget), - GTK_IS_DIALOG (widget) ? - "response" : - "destroy-event"); + GTK_IS_DIALOG (widget) ? + "response" : + "delete-event"); + if (GTK_IS_DIALOG (widget)) + priv->modal_handler_uids = + modest_signal_mgr_disconnect (priv->modal_handler_uids, + G_OBJECT (widget), + "destroy"); /* Schedule the next one for being shown */ g_idle_add (idle_top_modal, self); @@ -1044,7 +1306,105 @@ on_modal_dialog_close (GtkDialog *dialog, { ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data); - /* Remove modal window from queue */ + /* Remove modal window from queue. Note that if "destroy" + signal was invoked before the response the window could be + already deleted */ remove_modal_from_queue (GTK_WIDGET (dialog), self); } +static void +on_modal_dialog_destroy (GtkObject *object, + gpointer user_data) +{ + ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data); + + /* Remove modal window from queue */ + remove_modal_from_queue (GTK_WIDGET (object), self); +} + +gint +modest_window_mgr_num_windows (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv; + gint num_windows = 0; + + g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), -1); + + priv = MODEST_WINDOW_MGR_GET_PRIVATE(self); + + if (priv->window_list) + num_windows = g_list_length (priv->window_list); + + /* Do not take into account the main window if it was hidden */ + if (priv->main_window && !GTK_WIDGET_VISIBLE (priv->main_window)) + num_windows--; + + return num_windows + priv->banner_counter; +} + +GtkWidget * +modest_window_mgr_get_msg_edit_window (ModestWindowMgr *self) +{ + GtkWidget *result; + ModestWindowMgrPrivate *priv; + + g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL); + + priv = MODEST_WINDOW_MGR_GET_PRIVATE(self); + + if (priv->cached_editor) { + result = priv->cached_editor; + priv->cached_editor = NULL; + load_new_editor (self); + } else { + result = g_object_new (MODEST_TYPE_MSG_EDIT_WINDOW, NULL); + } + + return result; +} + +GtkWidget * +modest_window_mgr_get_msg_view_window (ModestWindowMgr *self) +{ + GtkWidget *result; + ModestWindowMgrPrivate *priv; + + g_return_val_if_fail (self && MODEST_IS_WINDOW_MGR(self), NULL); + + priv = MODEST_WINDOW_MGR_GET_PRIVATE(self); + + if (priv->cached_view) { + result = priv->cached_view; + priv->cached_view = NULL; + load_new_view (self); + } else { + result = g_object_new (MODEST_TYPE_MSG_VIEW_WINDOW, NULL); + } + + return result; +} + +void +modest_window_mgr_register_banner (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv; + + g_return_if_fail (MODEST_IS_WINDOW_MGR (self)); + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + priv->banner_counter++; + +} + +void +modest_window_mgr_unregister_banner (ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv; + + g_return_if_fail (MODEST_IS_WINDOW_MGR (self)); + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + priv->banner_counter--; + if (modest_window_mgr_num_windows (self) == 0) + g_signal_emit (self, signals[WINDOW_LIST_EMPTY_SIGNAL], 0); +}