aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-shell.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@src.gnome.org>2009-01-29 01:19:34 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2009-01-29 01:19:34 +0800
commit533d59e2cd30ba79a99a71907ffdda65505e633a (patch)
treeba6f611ce6a1bb9d3dfb98a6a6a670cf99a55b9d /shell/e-shell.c
parent3e339d5ecc63d912840c6f885460c58f60eb85e0 (diff)
downloadgsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar.gz
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar.bz2
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar.lz
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar.xz
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.tar.zst
gsoc2013-evolution-533d59e2cd30ba79a99a71907ffdda65505e633a.zip
Add unique-1.0 requirement (blessed external dependency).
Make EShell a subclass of UniqueApp and handle single-instance negotiation. When another Evolution process is running: - Running "evolution" will simply present the existing windows. - Running "evolution -c <view>" will open a shell window set to <view>. - Running "evolution <uri>" will open an appropriate window for <uri>. The second process will then terminate immediately. svn path=/branches/kill-bonobo/; revision=37147
Diffstat (limited to 'shell/e-shell.c')
-rw-r--r--shell/e-shell.c237
1 files changed, 197 insertions, 40 deletions
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 02c9627448..160d637d54 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -316,6 +316,37 @@ shell_query_module (EShell *shell,
modules_by_scheme, string, shell_module);
}
+static void
+shell_load_modules (EShell *shell)
+{
+ GDir *dir;
+ const gchar *dirname;
+ const gchar *basename;
+ GError *error = NULL;
+
+ dirname = EVOLUTION_MODULEDIR;
+
+ dir = g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ g_critical ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ gchar *filename;
+
+ if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX))
+ continue;
+
+ filename = g_build_filename (dirname, basename, NULL);
+ shell_query_module (shell, filename);
+ g_free (filename);
+ }
+
+ g_dir_close (dir);
+}
+
static gboolean
shell_shutdown_timeout (EShell *shell)
{
@@ -448,6 +479,10 @@ shell_finalize (GObject *object)
g_hash_table_destroy (priv->modules_by_name);
g_hash_table_destroy (priv->modules_by_scheme);
+ /* Indicates a clean shut down to the next session. */
+ if (!unique_app_is_running (UNIQUE_APP (object)))
+ e_file_lock_destroy ();
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -455,42 +490,94 @@ shell_finalize (GObject *object)
static void
shell_constructed (GObject *object)
{
- GDir *dir;
- EShell *shell;
- const gchar *dirname;
- const gchar *basename;
- GError *error = NULL;
+ /* UniqueApp will have by this point determined whether we're
+ * the only Evolution process running. If so, proceed normally.
+ * Otherwise we just issue commands to the other process. */
+ if (unique_app_is_running (UNIQUE_APP (object)))
+ return;
- shell = E_SHELL (object);
- dirname = EVOLUTION_MODULEDIR;
+ e_file_lock_create ();
- dir = g_dir_open (dirname, 0, &error);
- if (dir == NULL) {
- g_critical ("%s", error->message);
- g_error_free (error);
- return;
- }
+ shell_load_modules (E_SHELL (object));
+ e_shell_migrate_attempt (E_SHELL (object));
+}
- while ((basename = g_dir_read_name (dir)) != NULL) {
- gchar *filename;
+static gboolean
+shell_message_handle_new (EShell *shell,
+ UniqueMessageData *data)
+{
+ gchar *view_name;
- if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX))
- continue;
+ view_name = unique_message_data_get_text (data);
+ e_shell_create_shell_window (shell, view_name);
+ g_free (view_name);
- filename = g_build_filename (dirname, basename, NULL);
- shell_query_module (shell, filename);
- g_free (filename);
- }
+ return TRUE;
+}
- g_dir_close (dir);
+static gboolean
+shell_message_handle_open (EShell *shell,
+ UniqueMessageData *data)
+{
+ gchar **uris;
+
+ uris = unique_message_data_get_uris (data);
+ e_shell_handle_uris (shell, uris);
+ g_strfreev (uris);
+
+ return TRUE;
+}
+
+static gboolean
+shell_message_handle_close (EShell *shell,
+ UniqueMessageData *data)
+{
+ e_shell_quit (shell);
+
+ return TRUE;
+}
+
+static UniqueResponse
+shell_message_received (UniqueApp *app,
+ gint command,
+ UniqueMessageData *data,
+ guint time_)
+{
+ EShell *shell = E_SHELL (app);
+
+ switch (command) {
+ case UNIQUE_ACTIVATE:
+ break; /* use the default behavior */
+
+ case UNIQUE_NEW:
+ if (shell_message_handle_new (shell, data))
+ return UNIQUE_RESPONSE_OK;
+ break;
+
+ case UNIQUE_OPEN:
+ if (shell_message_handle_open (shell, data))
+ return UNIQUE_RESPONSE_OK;
+ break;
+
+ case UNIQUE_CLOSE:
+ if (shell_message_handle_close (shell, data))
+ return UNIQUE_RESPONSE_OK;
+ break;
+
+ default:
+ break;
+ }
- e_shell_migrate_attempt (shell);
+ /* Chain up to parent's message_received() method. */
+ return UNIQUE_APP_CLASS (parent_class)->
+ message_received (app, command, data, time_);
}
static void
shell_class_init (EShellClass *class)
{
GObjectClass *object_class;
+ UniqueAppClass *unique_app_class;
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EShellPrivate));
@@ -502,6 +589,9 @@ shell_class_init (EShellClass *class)
object_class->finalize = shell_finalize;
object_class->constructed = shell_constructed;
+ unique_app_class = UNIQUE_APP_CLASS (class);
+ unique_app_class->message_received = shell_message_received;
+
/**
* EShell:network-available
*
@@ -748,8 +838,6 @@ shell_init (EShell *shell)
e_shell_dbus_initialize (shell);
#endif
- e_file_lock_create ();
-
shell_parse_debug_string (shell);
g_signal_connect (
@@ -797,7 +885,7 @@ e_shell_get_type (void)
};
type = g_type_register_static (
- G_TYPE_OBJECT, "EShell", &type_info, 0);
+ UNIQUE_TYPE_APP, "EShell", &type_info, 0);
}
return type;
@@ -864,8 +952,6 @@ e_shell_get_shell_windows (EShell *shell)
* Returns the canonical name for the #EShellModule whose name or alias
* is @name.
*
- * XXX Not sure this function is worth keeping around.
- *
* Returns: the canonical #EShellModule name
**/
const gchar *
@@ -954,6 +1040,7 @@ e_shell_get_shell_settings (EShell *shell)
/**
* e_shell_create_shell_window:
* @shell: an #EShell
+ * @view_name: name of the initial shell view, or %NULL
*
* Creates a new #EShellWindow and emits the #EShell::window-created
* signal. Use this function instead of e_shell_window_new() so that
@@ -962,14 +1049,43 @@ e_shell_get_shell_settings (EShell *shell)
* Returns: a new #EShellWindow
**/
GtkWidget *
-e_shell_create_shell_window (EShell *shell)
+e_shell_create_shell_window (EShell *shell,
+ const gchar *view_name)
{
GList *active_windows;
GtkWidget *shell_window;
+ UniqueMessageData *data;
+ UniqueApp *app;
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ app = UNIQUE_APP (shell);
+
+ if (unique_app_is_running (app))
+ goto unique;
+
+ view_name = e_shell_get_canonical_name (shell, view_name);
+
+ /* EShellWindow initializes its active view from a GConf key,
+ * so set the key ahead of time to control the intial view. */
+ if (view_name != NULL) {
+ GConfClient *client;
+ const gchar *key;
+ GError *error = NULL;
+
+ client = gconf_client_get_default ();
+ key = "/apps/evolution/shell/view_defaults/component_id";
+ gconf_client_set_string (client, key, view_name, &error);
+ g_object_unref (client);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+
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);
@@ -992,29 +1108,70 @@ e_shell_create_shell_window (EShell *shell)
gtk_widget_show (shell_window);
return shell_window;
+
+unique: /* Send a message to the other Evolution process. */
+
+ /* XXX Do something with UniqueResponse? */
+
+ if (view_name != NULL) {
+ data = unique_message_data_new ();
+ unique_message_data_set_text (data, view_name, -1);
+ unique_app_send_message (app, UNIQUE_NEW, data);
+ unique_message_data_free (data);
+ } else
+ unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
+
+ return NULL;
}
/**
- * e_shell_handle_uri:
+ * e_shell_handle_uris:
* @shell: an #EShell
- * @uri: the URI to be handled
+ * @uris: %NULL-terminated list of URIs
*
- * Emits the #EShell::handle-uri signal.
+ * Emits the #EShell::handle-uri signal for each URI.
*
- * Returns: %TRUE if the URI was handled, %FALSE otherwise
+ * Returns: the number of URIs successfully handled
**/
-gboolean
-e_shell_handle_uri (EShell *shell,
- const gchar *uri)
+guint
+e_shell_handle_uris (EShell *shell,
+ const gchar **uris)
{
- gboolean handled;
+ UniqueApp *app;
+ UniqueMessageData *data;
+ guint n_handled = 0;
+ gint ii;
g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
- g_return_val_if_fail (uri != NULL, FALSE);
+ g_return_val_if_fail (uris != NULL, FALSE);
+
+ app = UNIQUE_APP (shell);
+
+ if (unique_app_is_running (app))
+ goto unique;
+
+ for (ii = 0; uris[ii] != NULL; ii++) {
+ gboolean handled;
+
+ g_signal_emit (
+ shell, signals[HANDLE_URI],
+ 0, uris[ii], &handled);
+ n_handled += handled ? 1 : 0;
+ }
+
+ return n_handled;
+
+unique: /* Send a message to the other Evolution process. */
+
+ /* XXX Do something with UniqueResponse?
+ * XXX set_uris() should take a "const" URI list. */
- g_signal_emit (shell, signals[HANDLE_URI], 0, uri, &handled);
+ data = unique_message_data_new ();
+ unique_message_data_set_uris (data, (gchar **) uris);
+ unique_app_send_message (app, UNIQUE_OPEN, data);
+ unique_message_data_free (data);
- return handled;
+ return 0;
}
/**