X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-window-mgr.c;h=3b94951ecaad1e91c47a6bfbaf0aa266b2f3a122;hp=fa3258608549c129e5871a108d5c6695357170cf;hb=d4537d8a01b0789310de9a11d3344147ee9691c0;hpb=aab537f6ce755830767baa7260d7879449ceeb38 diff --git a/src/widgets/modest-window-mgr.c b/src/widgets/modest-window-mgr.c index fa32586..3b94951 100644 --- a/src/widgets/modest-window-mgr.c +++ b/src/widgets/modest-window-mgr.c @@ -47,6 +47,14 @@ static gboolean on_window_destroy (ModestWindow *window, GdkEvent *event, ModestWindowMgr *self); +static gboolean on_modal_window_close (GtkWidget *widget, + GdkEvent *event, + gpointer user_data); + +static void on_modal_dialog_close (GtkDialog *dialog, + gint arg1, + gpointer user_data); + static const gchar* get_show_toolbar_key (GType window_type, gboolean fullscreen); @@ -62,7 +70,9 @@ struct _ModestWindowMgrPrivate { GList *window_list; ModestWindow *main_window; - GtkDialog *easysetup_dialog; + + GMutex *queue_lock; + GQueue *modal_windows; gboolean fullscreen_mode; @@ -72,6 +82,8 @@ struct _ModestWindowMgrPrivate { GHashTable *viewer_handlers; guint closing_time; + + GSList *modal_handler_uids; }; #define MODEST_WINDOW_MGR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_WINDOW_MGR, \ @@ -127,7 +139,9 @@ modest_window_mgr_init (ModestWindowMgr *obj) priv->window_list = NULL; priv->main_window = NULL; priv->fullscreen_mode = FALSE; - priv->easysetup_dialog = NULL; + + priv->modal_windows = g_queue_new (); + priv->queue_lock = g_mutex_new (); priv->preregistered_uids = NULL; @@ -137,6 +151,8 @@ modest_window_mgr_init (ModestWindowMgr *obj) priv->viewer_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); priv->closing_time = 0; + + priv->modal_handler_uids = NULL; } static void @@ -171,12 +187,15 @@ modest_window_mgr_finalize (GObject *obj) priv->viewer_handlers = NULL; } - if (priv->easysetup_dialog) { - g_warning ("%s: forgot to destroy an easysetup dialog somewhere", - __FUNCTION__); - gtk_widget_destroy (GTK_WIDGET(priv->easysetup_dialog)); - priv->easysetup_dialog = NULL; + modest_signal_mgr_disconnect_all_and_destroy (priv->modal_handler_uids); + + if (priv->modal_windows) { + g_mutex_lock (priv->queue_lock); + g_queue_free (priv->modal_windows); + priv->modal_windows = NULL; + g_mutex_unlock (priv->queue_lock); } + g_mutex_free (priv->queue_lock); /* Do not unref priv->main_window because it does not hold a new reference */ @@ -242,7 +261,7 @@ append_uid (GSList *list, const gchar *uid) void -modest_window_mgr_register_header (ModestWindowMgr *self, TnyHeader *header) +modest_window_mgr_register_header (ModestWindowMgr *self, TnyHeader *header, const gchar *alt_uid) { ModestWindowMgrPrivate *priv; gchar* uid; @@ -253,13 +272,15 @@ modest_window_mgr_register_header (ModestWindowMgr *self, TnyHeader *header) priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); uid = modest_tny_folder_get_header_unique_id (header); - + if (uid == NULL) + uid = g_strdup (alt_uid); + if (!has_uid (priv->preregistered_uids, uid)) { g_debug ("registering new uid %s", uid); priv->preregistered_uids = append_uid (priv->preregistered_uids, uid); } else g_debug ("already had uid %s", uid); - + g_free (uid); } @@ -274,13 +295,13 @@ modest_window_mgr_unregister_header (ModestWindowMgr *self, TnyHeader *header) priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); 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); priv->preregistered_uids = append_uid (priv->preregistered_uids, uid); } else 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)) @@ -288,10 +309,72 @@ modest_window_mgr_unregister_header (ModestWindowMgr *self, TnyHeader *header) else 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) +{ + const gchar* help_id = NULL; + + /* 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); + g_return_val_if_fail (GTK_IS_WINDOW(win), NULL); + + if (MODEST_IS_MAIN_WINDOW (win)) { + GtkWidget *folder_view; + TnyFolderStore *folder_store; + + /* Get selected folder */ + folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win), + MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW); + folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view)); + + /* Switch help_id */ + if (folder_store && TNY_IS_FOLDER (folder_store)) { + help_id = modest_tny_folder_get_help_id (TNY_FOLDER (folder_store)); + if (!help_id) + g_warning ("%s: BUG: did not get a valid help_id", __FUNCTION__); + } + if (folder_store) + g_object_unref (folder_store); + } + + if (!help_id) + help_id = g_object_get_data (G_OBJECT(win), MODEST_WINDOW_HELP_ID_PARAM); + + return help_id; +} + + + + + + + + + + static gint compare_msguids (ModestWindow *win, const gchar *uid) @@ -316,14 +399,13 @@ compare_msguids (ModestWindow *win, return 1; } - 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); @@ -356,9 +438,9 @@ modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *head if (win) *win = NULL; - + has_header = has_uid (priv->preregistered_uids, uid); - + item = g_list_find_custom (priv->window_list, uid, (GCompareFunc) compare_msguids); if (item) { has_window = TRUE; @@ -372,8 +454,8 @@ modest_window_mgr_find_registered_header (ModestWindowMgr *self, TnyHeader *head } } } - g_free (uid); + return has_header || has_window; } @@ -437,17 +519,16 @@ modest_window_mgr_register_window (ModestWindowMgr *self, if (MODEST_IS_MSG_VIEW_WINDOW(window)) { const gchar *uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window)); - + if (!has_uid (priv->preregistered_uids, uid)) g_debug ("weird: no uid for window (%s)", uid); g_debug ("registering window for %s", uid ? uid : ""); - + priv->preregistered_uids = remove_uid (priv->preregistered_uids, modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window))); - } else if (MODEST_IS_MSG_EDIT_WINDOW(window)) { const gchar *uid = modest_msg_edit_window_get_message_uid (MODEST_MSG_EDIT_WINDOW (window)); @@ -493,6 +574,8 @@ on_window_destroy (ModestWindow *window, GdkEvent *event, ModestWindowMgr *self) { + gint dialog_response = GTK_RESPONSE_NONE; + /* Specific stuff first */ if (MODEST_IS_MAIN_WINDOW (window)) { ModestWindowMgrPrivate *priv; @@ -501,21 +584,32 @@ on_window_destroy (ModestWindow *window, /* If more than one window already opened */ if (g_list_length (priv->window_list) > 1) { + /* 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 (modest_main_window_close_all (MODEST_MAIN_WINDOW (window))) { - GList *iter = priv->window_list; - do { - if (iter->data != window) { - GList *tmp = iter->next; - on_window_destroy (MODEST_WINDOW (iter->data), - event, - self); - iter = tmp; - } else { - iter = g_list_next (iter); - } - } while (iter); - } + if ((dialog_response == GTK_RESPONSE_OK) + || (dialog_response == GTK_RESPONSE_ACCEPT) + || (dialog_response == GTK_RESPONSE_YES)) + { + GList *iter = priv->window_list; + do { + if (iter->data != window) { + GList *tmp = iter->next; + on_window_destroy (MODEST_WINDOW (iter->data), + event, + self); + iter = tmp; + } else { + iter = g_list_next (iter); + } + } while (iter); + } + else + { + return TRUE; + } } } else { @@ -525,6 +619,10 @@ on_window_destroy (ModestWindow *window, sent = modest_msg_edit_window_get_sent (MODEST_MSG_EDIT_WINDOW (window)); /* Save currently edited message to Drafts if it was not sent */ if (!sent && modest_msg_edit_window_is_modified (MODEST_MSG_EDIT_WINDOW (window))) { + + /* Raise the window if it's minimized */ + if (!gtk_window_has_toplevel_focus (GTK_WINDOW (window))) + gtk_window_present (GTK_WINDOW (window)); response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), @@ -547,10 +645,11 @@ disconnect_msg_changed (gpointer key, gpointer value, gpointer user_data) { - gulong *handler_id; - - handler_id = (gulong *) value; - g_signal_handler_disconnect (G_OBJECT (key), *handler_id); + guint handler_id; + handler_id = GPOINTER_TO_UINT(value); + + if (key && G_IS_OBJECT(key)) + g_signal_handler_disconnect (G_OBJECT (key), handler_id); } @@ -647,8 +746,13 @@ modest_window_mgr_unregister_window (ModestWindowMgr *self, when there were other windows remaining */ if (MODEST_IS_MSG_VIEW_WINDOW (window) && priv->viewer_handlers) { tmp = (gulong *) g_hash_table_lookup (priv->viewer_handlers, window); - g_signal_handler_disconnect (window, *tmp); - g_hash_table_remove (priv->viewer_handlers, window); + /* If the viewer was created without a main window + (for example when opening a message through D-Bus + the viewer handlers was not registered */ + if (tmp) { + g_signal_handler_disconnect (window, *tmp); + g_hash_table_remove (priv->viewer_handlers, window); + } } /* Save state */ @@ -773,7 +877,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; @@ -781,7 +885,7 @@ 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); @@ -791,27 +895,76 @@ modest_window_mgr_get_main_window (ModestWindowMgr *self) } -GtkDialog* -modest_window_mgr_get_easysetup_dialog (ModestWindowMgr *self) +gboolean +modest_window_mgr_main_window_exists (ModestWindowMgr *self) { ModestWindowMgrPrivate *priv; - g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL); + g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), FALSE); priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); - return priv->easysetup_dialog; + return priv->main_window != NULL; } -GtkDialog* -modest_window_mgr_set_easysetup_dialog (ModestWindowMgr *self, GtkDialog *dialog) +GtkWindow * +modest_window_mgr_get_modal (ModestWindowMgr *self) { ModestWindowMgrPrivate *priv; g_return_val_if_fail (MODEST_IS_WINDOW_MGR (self), NULL); priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); - return priv->easysetup_dialog = dialog; + return g_queue_peek_head (priv->modal_windows); +} + + +void +modest_window_mgr_set_modal (ModestWindowMgr *self, + GtkWindow *window) +{ + GtkWindow *old_modal; + ModestWindowMgrPrivate *priv; + + g_return_if_fail (MODEST_IS_WINDOW_MGR (self)); + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + g_mutex_lock (priv->queue_lock); + old_modal = g_queue_peek_head (priv->modal_windows); + g_mutex_unlock (priv->queue_lock); + + if (!old_modal) { + gtk_window_set_modal (window, TRUE); + } else { + /* un-modalize the old one; the one on top should be the + * modal one */ + gtk_window_set_transient_for (window, GTK_WINDOW(old_modal)); + gtk_window_set_modal (window, TRUE); + } + + /* this will be the new modal window */ + g_mutex_lock (priv->queue_lock); + g_queue_push_head (priv->modal_windows, window); + g_mutex_unlock (priv->queue_lock); + + 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 */ + priv->modal_handler_uids = + modest_signal_mgr_connect (priv->modal_handler_uids, + G_OBJECT (window), + "response", + G_CALLBACK (on_modal_dialog_close), + 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); } @@ -891,3 +1044,81 @@ modest_window_mgr_save_state_for_all_windows (ModestWindowMgr *self) win = g_list_next (win); } } + +static gboolean +idle_top_modal (gpointer data) +{ + ModestWindowMgr *self = MODEST_WINDOW_MGR (data); + ModestWindowMgrPrivate *priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + GtkWindow *topmost; + + /* Get the top modal */ + g_mutex_lock (priv->queue_lock); + topmost = (GtkWindow *) g_queue_peek_head (priv->modal_windows); + g_mutex_unlock (priv->queue_lock); + + /* Show it */ + if (topmost) + gtk_window_present (topmost); + + return FALSE; +} + +static void +remove_modal_from_queue (GtkWidget *widget, + ModestWindowMgr *self) +{ + ModestWindowMgrPrivate *priv; + GList *item = NULL; + + priv = MODEST_WINDOW_MGR_GET_PRIVATE (self); + + /* Remove from queue. We don't use remove, because we want to + exit if the widget does not belong to the queue */ + g_mutex_lock (priv->queue_lock); + item = g_queue_find (priv->modal_windows, widget); + if (!item) { + g_warning ("Trying to remove a modal window that is not registered"); + g_mutex_unlock (priv->queue_lock); + return; + } + g_queue_unlink (priv->modal_windows, item); + g_mutex_unlock (priv->queue_lock); + + /* Disconnect handler */ + priv->modal_handler_uids = + modest_signal_mgr_disconnect (priv->modal_handler_uids, + G_OBJECT (widget), + GTK_IS_DIALOG (widget) ? + "response" : + "destroy-event"); + + /* Schedule the next one for being shown */ + g_idle_add (idle_top_modal, self); +} + +static gboolean +on_modal_window_close (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data); + + /* Remove modal window from queue */ + remove_modal_from_queue (widget, self); + + /* Continue */ + return FALSE; +} + +static void +on_modal_dialog_close (GtkDialog *dialog, + gint arg1, + gpointer user_data) +{ + ModestWindowMgr *self = MODEST_WINDOW_MGR (user_data); + + /* Remove modal window from queue */ + remove_modal_from_queue (GTK_WIDGET (dialog), self); +} +