From 70fce0bbb0712dc70a15c481c0b65d68a98a4ff7 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 28 Jan 2009 22:28:57 +0000 Subject: When invoking Evolution with URIs on the command-line (e.g. mailto:), terminate after all the windows for those URIs have been closed. svn path=/branches/kill-bonobo/; revision=37157 --- shell/e-shell-window-private.c | 2 + shell/e-shell-window.c | 19 +++-- shell/e-shell.c | 167 +++++++++++++++++++++++---------------- shell/e-shell.h | 6 +- shell/main.c | 15 ++-- shell/test/e-test-shell-module.c | 11 ++- 6 files changed, 128 insertions(+), 92 deletions(-) (limited to 'shell') diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c index 53f7c28c64..02aac6cf10 100644 --- a/shell/e-shell-window-private.c +++ b/shell/e-shell-window-private.c @@ -340,6 +340,8 @@ e_shell_window_private_constructed (EShellWindow *shell_window) shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); + e_shell_watch_window (shell, GTK_WINDOW (shell_window)); + /* Create the switcher actions before we set the initial * shell view, because the shell view relies on them for * default settings during construction. */ diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c index 82727fecdd..ecc30cb9b5 100644 --- a/shell/e-shell-window.c +++ b/shell/e-shell-window.c @@ -132,17 +132,22 @@ static void shell_window_update_close_action_cb (EShellWindow *shell_window) { EShell *shell; - GList *shell_windows; - gboolean sensitive; + GList *watched_windows; + gint n_shell_windows = 0; shell = e_shell_window_get_shell (shell_window); - shell_windows = e_shell_get_shell_windows (shell); - g_return_if_fail (shell_windows != NULL); + watched_windows = e_shell_get_watched_windows (shell); - /* Disable Close Window if there's only one window. + /* Count the shell windows. */ + while (watched_windows != NULL) { + if (E_IS_SHELL_WINDOW (watched_windows->data)) + n_shell_windows++; + watched_windows = g_list_next (watched_windows); + } + + /* Disable Close Window if there's only one shell window. * Helps prevent users from accidentally quitting. */ - sensitive = (g_list_length (shell_windows) > 1); - gtk_action_set_sensitive (ACTION (CLOSE), sensitive); + gtk_action_set_sensitive (ACTION (CLOSE), n_shell_windows > 1); } static void diff --git a/shell/e-shell.c b/shell/e-shell.c index 160d637d54..e2d7761965 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -38,7 +38,7 @@ ((obj), E_TYPE_SHELL, EShellPrivate)) struct _EShellPrivate { - GList *active_windows; + GList *watched_windows; EShellSettings *settings; /* Shell Modules */ @@ -101,12 +101,21 @@ shell_parse_debug_string (EShell *shell) e_shell_settings_enable_debug (shell->priv->settings); } +static void +shell_notify_online_mode_cb (EShell *shell) +{ + gboolean online; + + online = e_shell_get_online_mode (shell); + e_passwords_set_online (online); +} + static gboolean shell_window_delete_event_cb (EShell *shell, - EShellWindow *shell_window) + GtkWindow *window) { /* If other windows are open we can safely close this one. */ - if (g_list_length (shell->priv->active_windows) > 1) + if (g_list_length (shell->priv->watched_windows) > 1) return FALSE; /* Otherwise we initiate application shutdown. */ @@ -116,16 +125,16 @@ shell_window_delete_event_cb (EShell *shell, static gboolean shell_window_focus_in_event_cb (EShell *shell, GdkEventFocus *event, - EShellWindow *shell_window) + GtkWindow *window) { GList *list, *link; - /* Keep the active windows list sorted by most recently focused, + /* Keep the watched windows list sorted by most recently focused, * so the first item in the list should always be the currently - * focused shell window. */ + * focused window. */ - list = shell->priv->active_windows; - link = g_list_find (list, shell_window); + list = shell->priv->watched_windows; + link = g_list_find (list, window); g_return_val_if_fail (link != NULL, FALSE); if (link != list) { @@ -133,29 +142,20 @@ shell_window_focus_in_event_cb (EShell *shell, list = g_list_concat (link, list); } - shell->priv->active_windows = list; + shell->priv->watched_windows = list; return FALSE; } -static void -shell_notify_online_mode_cb (EShell *shell) -{ - gboolean online; - - online = e_shell_get_online_mode (shell); - e_passwords_set_online (online); -} - static void shell_window_weak_notify_cb (EShell *shell, GObject *where_the_object_was) { - GList *active_windows; + GList *list; - active_windows = shell->priv->active_windows; - active_windows = g_list_remove (active_windows, where_the_object_was); - shell->priv->active_windows = active_windows; + list = shell->priv->watched_windows; + list = g_list_remove (list, where_the_object_was); + shell->priv->watched_windows = list; g_signal_emit (shell, signals[WINDOW_DESTROYED], 0); } @@ -380,7 +380,7 @@ shell_shutdown_timeout (EShell *shell) * the act of destroying a shell window will modify the active * windows list, which would otherwise derail the iteration. */ if (proceed) { - list = g_list_copy (shell->priv->active_windows); + list = g_list_copy (shell->priv->watched_windows); g_list_foreach (list, (GFunc) gtk_widget_destroy, NULL); g_list_free (list); @@ -748,9 +748,9 @@ shell_class_init (EShellClass *class) /** * EShell::window-created * @shell: the #EShell which emitted the signal - * @shell_window: the newly created #EShellWindow + * @window: the newly created #GtkWindow * - * Emitted when a new #EShellWindow is created. + * Emitted when @shell begins watching a newly created window. **/ signals[WINDOW_CREATED] = g_signal_new ( "window-created", @@ -759,7 +759,7 @@ shell_class_init (EShellClass *class) 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - E_TYPE_SHELL_WINDOW); + GTK_TYPE_WINDOW); /** * EShell::window-destroyed @@ -896,6 +896,9 @@ e_shell_get_type (void) * * Returns the #EShell created by main(). * + * Try to obtain the #EShell from elsewhere if you can. This function + * is intended as a temporary workaround for when that proves difficult. + * * Returns: the #EShell singleton **/ EShell * @@ -924,26 +927,6 @@ e_shell_get_shell_modules (EShell *shell) return shell->priv->loaded_modules; } -/** - * e_shell_get_shell_windows: - * @shell: an #EShell - * - * Returns a list of active #EShellWindow instances that were created by - * e_shell_create_shell_window(). The list is sorted by the most recently - * focused window, such that the first instance is the currently focused - * window. (Useful for choosing a parent for a transient window.) The - * list is owned by @shell and should not be modified or freed. - * - * Returns: a list of active #EShellWindow instances - **/ -GList * -e_shell_get_shell_windows (EShell *shell) -{ - g_return_val_if_fail (E_IS_SHELL (shell), NULL); - - return shell->priv->active_windows; -} - /** * e_shell_get_canonical_name: * @shell: an #EShell @@ -1052,7 +1035,6 @@ GtkWidget * e_shell_create_shell_window (EShell *shell, const gchar *view_name) { - GList *active_windows; GtkWidget *shell_window; UniqueMessageData *data; UniqueApp *app; @@ -1085,25 +1067,6 @@ e_shell_create_shell_window (EShell *shell, } shell_window = e_shell_window_new (shell, shell->priv->safe_mode); - unique_app_watch_window (app, GTK_WINDOW (shell_window)); - - active_windows = shell->priv->active_windows; - active_windows = g_list_prepend (active_windows, shell_window); - shell->priv->active_windows = active_windows; - - g_signal_connect_swapped ( - shell_window, "delete-event", - G_CALLBACK (shell_window_delete_event_cb), shell); - - g_signal_connect_swapped ( - shell_window, "focus-in-event", - G_CALLBACK (shell_window_focus_in_event_cb), shell); - - g_object_weak_ref ( - G_OBJECT (shell_window), (GWeakNotify) - shell_window_weak_notify_cb, shell); - - g_signal_emit (shell, signals[WINDOW_CREATED], 0, shell_window); gtk_widget_show (shell_window); @@ -1135,7 +1098,7 @@ unique: /* Send a message to the other Evolution process. */ **/ guint e_shell_handle_uris (EShell *shell, - const gchar **uris) + gchar **uris) { UniqueApp *app; UniqueMessageData *data; @@ -1163,17 +1126,81 @@ e_shell_handle_uris (EShell *shell, unique: /* Send a message to the other Evolution process. */ - /* XXX Do something with UniqueResponse? - * XXX set_uris() should take a "const" URI list. */ + /* XXX Do something with UniqueResponse? */ data = unique_message_data_new (); - unique_message_data_set_uris (data, (gchar **) uris); + unique_message_data_set_uris (data, uris); unique_app_send_message (app, UNIQUE_OPEN, data); unique_message_data_free (data); return 0; } +/** + * e_shell_watch_window: + * @shell: an #EShell + * @window: a #GtkWindow + * + * Makes @shell "watch" a newly created toplevel window, and emits the + * #EShell::window-created signal. All #EShellWindows should be + * watched, along with any editor or viewer windows that may be shown in + * response to e_shell_handle_uris(). When the last watched window is + * closed, Evolution terminates. + **/ +void +e_shell_watch_window (EShell *shell, + GtkWindow *window) +{ + GList *list; + + g_return_if_fail (E_IS_SHELL (shell)); + g_return_if_fail (GTK_IS_WINDOW (window)); + + list = shell->priv->watched_windows; + + /* Ignore duplicates. */ + if (g_list_find (list, window) != NULL) + return; + + list = g_list_prepend (list, window); + shell->priv->watched_windows = list; + + unique_app_watch_window (UNIQUE_APP (shell), window); + + g_signal_connect_swapped ( + window, "delete-event", + G_CALLBACK (shell_window_delete_event_cb), shell); + + g_signal_connect_swapped ( + window, "focus-in-event", + G_CALLBACK (shell_window_focus_in_event_cb), shell); + + g_object_weak_ref ( + G_OBJECT (window), (GWeakNotify) + shell_window_weak_notify_cb, shell); + + g_signal_emit (shell, signals[WINDOW_CREATED], 0, window); +} + +/** + * e_shell_get_watched_windows: + * @shell: an #EShell + * + * Returns a list of windows being watched by @shell. The list is sorted + * by the most recently focused window, such that the first instance is the + * currently focused window. (Useful for choosing a parent for a transient + * window.) The list is owned by @shell and should not be modified or freed. + * + * Returns: a list of watched windows + **/ +GList * +e_shell_get_watched_windows (EShell *shell) +{ + g_return_val_if_fail (E_IS_SHELL (shell), NULL); + + return shell->priv->watched_windows; +} + /** * e_shell_send_receive: * @shell: an #EShell diff --git a/shell/e-shell.h b/shell/e-shell.h index 9e30550283..3f23779ee7 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -78,7 +78,6 @@ struct _EShellClass { GType e_shell_get_type (void); EShell * e_shell_get_default (void); GList * e_shell_get_shell_modules (EShell *shell); -GList * e_shell_get_shell_windows (EShell *shell); const gchar * e_shell_get_canonical_name (EShell *shell, const gchar *name); EShellModule * e_shell_get_module_by_name (EShell *shell, @@ -89,7 +88,10 @@ EShellSettings *e_shell_get_shell_settings (EShell *shell); GtkWidget * e_shell_create_shell_window (EShell *shell, const gchar *view_name); guint e_shell_handle_uris (EShell *shell, - const gchar **uris); + gchar **uris); +void e_shell_watch_window (EShell *shell, + GtkWindow *window); +GList * e_shell_get_watched_windows (EShell *shell); void e_shell_send_receive (EShell *shell, GtkWindow *parent); gboolean e_shell_get_network_available (EShell *shell); diff --git a/shell/main.c b/shell/main.c index 670b24d1a2..ce1b467754 100644 --- a/shell/main.c +++ b/shell/main.c @@ -306,7 +306,6 @@ static gboolean idle_cb (gchar **uris) { EShell *shell; - guint ii; #ifdef KILL_PROCESS_CMD kill_old_dataserver (); @@ -314,23 +313,21 @@ idle_cb (gchar **uris) shell = e_shell_get_default (); - /* These calls do the right thing when there's another - * Evolution process running. */ + /* These calls do the right thing when another Evolution + * process is running. */ if (uris != NULL && *uris != NULL) e_shell_handle_uris (shell, uris); else e_shell_create_shell_window (shell, requested_view); - if (unique_app_is_running (UNIQUE_APP (shell))) { + /* If another Evolution process is running, we're done. */ + if (unique_app_is_running (UNIQUE_APP (shell))) gtk_main_quit (); - return FALSE; - } /* This must be done after EShell has loaded all the modules. * For example the mail module makes the global variable `session` * which is being used by several EPlugins */ - - if (uris == NULL && !disable_eplugin) + else if (uris == NULL && !disable_eplugin) e_plugin_load_plugins_with_missing_symbols (); return FALSE; @@ -471,7 +468,7 @@ set_paths (void) static void shell_window_destroyed_cb (EShell *shell) { - if (e_shell_get_shell_windows (shell) == NULL) + if (e_shell_get_watched_windows (shell) == NULL) gtk_main_quit (); } diff --git a/shell/test/e-test-shell-module.c b/shell/test/e-test-shell-module.c index fc489fa3b0..a7d2389fb7 100644 --- a/shell/test/e-test-shell-module.c +++ b/shell/test/e-test-shell-module.c @@ -115,20 +115,23 @@ test_module_send_receive_cb (EShellModule *shell_module, static void test_module_window_created_cb (EShellModule *shell_module, - EShellWindow *shell_window) + GtkWindow *window) { const gchar *module_name; - g_debug ("%s (window=%p)", G_STRFUNC, shell_window); + g_debug ("%s (%s)", G_STRFUNC, G_OBJECT_TYPE_NAME (window)); + + if (!E_IS_SHELL_WINDOW (window)) + return; module_name = G_TYPE_MODULE (shell_module)->name; e_shell_window_register_new_item_actions ( - shell_window, module_name, + E_SHELL_WINDOW (window), module_name, item_entries, G_N_ELEMENTS (item_entries)); e_shell_window_register_new_source_actions ( - shell_window, module_name, + E_SHELL_WINDOW (window), module_name, source_entries, G_N_ELEMENTS (source_entries)); } -- cgit