aboutsummaryrefslogtreecommitdiffstats
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/e-shell-module.c28
-rw-r--r--shell/e-shell-window-actions.c5
-rw-r--r--shell/e-shell-window-private.c1
-rw-r--r--shell/e-shell-window-private.h2
-rw-r--r--shell/e-shell-window.c9
-rw-r--r--shell/e-shell.c237
-rw-r--r--shell/e-shell.h12
-rw-r--r--shell/main.c165
8 files changed, 335 insertions, 124 deletions
diff --git a/shell/e-shell-module.c b/shell/e-shell-module.c
index 5ec13e00bc..11226557c2 100644
--- a/shell/e-shell-module.c
+++ b/shell/e-shell-module.c
@@ -44,7 +44,7 @@ struct _EShellModulePrivate {
GModule *module;
gchar *filename;
- EShell *shell;
+ gpointer shell; /* weak pointer */
gchar *config_dir;
gchar *data_dir;
@@ -82,7 +82,12 @@ shell_module_set_shell (EShellModule *shell_module,
EShell *shell)
{
g_return_if_fail (shell_module->priv->shell == NULL);
- shell_module->priv->shell = g_object_ref (shell);
+
+ shell_module->priv->shell = shell;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_module),
+ &shell_module->priv->shell);
}
static void
@@ -132,22 +137,6 @@ shell_module_get_property (GObject *object,
}
static void
-shell_module_dispose (GObject *object)
-{
- EShellModulePrivate *priv;
-
- priv = E_SHELL_MODULE_GET_PRIVATE (object);
-
- if (priv->shell != NULL) {
- g_object_unref (priv->shell);
- priv->shell = NULL;
- }
-
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
shell_module_finalize (GObject *object)
{
EShellModulePrivate *priv;
@@ -217,7 +206,6 @@ shell_module_class_init (EShellModuleClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->set_property = shell_module_set_property;
object_class->get_property = shell_module_get_property;
- object_class->dispose = shell_module_dispose;
object_class->finalize = shell_module_finalize;
type_module_class = G_TYPE_MODULE_CLASS (class);
@@ -420,7 +408,7 @@ e_shell_module_get_shell (EShellModule *shell_module)
{
g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), NULL);
- return shell_module->priv->shell;
+ return E_SHELL (shell_module->priv->shell);
}
/**
diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
index 50749a7698..a9ed7efb09 100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@ -853,9 +853,12 @@ action_new_window_cb (GtkAction *action,
EShellWindow *shell_window)
{
EShell *shell;
+ const gchar *view_name;
shell = e_shell_window_get_shell (shell_window);
- e_shell_create_shell_window (shell);
+ view_name = e_shell_window_get_active_view (shell_window);
+
+ e_shell_create_shell_window (shell, view_name);
}
/**
diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c
index 987c0ab9fb..53f7c28c64 100644
--- a/shell/e-shell-window-private.c
+++ b/shell/e-shell-window-private.c
@@ -420,7 +420,6 @@ e_shell_window_private_dispose (EShellWindow *shell_window)
priv->signal_handler_ids = NULL;
}
- DISPOSE (priv->shell);
DISPOSE (priv->ui_manager);
g_hash_table_remove_all (priv->loaded_views);
diff --git a/shell/e-shell-window-private.h b/shell/e-shell-window-private.h
index 3d0d913863..1f0bec799b 100644
--- a/shell/e-shell-window-private.h
+++ b/shell/e-shell-window-private.h
@@ -65,7 +65,7 @@ G_BEGIN_DECLS
struct _EShellWindowPrivate {
- EShell *shell;
+ gpointer shell; /* weak pointer */
/*** UI Management ***/
diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c
index 3272b524e7..82727fecdd 100644
--- a/shell/e-shell-window.c
+++ b/shell/e-shell-window.c
@@ -153,7 +153,12 @@ shell_window_set_shell (EShellWindow *shell_window,
gulong handler_id;
g_return_if_fail (shell_window->priv->shell == NULL);
- shell_window->priv->shell = g_object_ref (shell);
+
+ shell_window->priv->shell = shell;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_window),
+ &shell_window->priv->shell);
/* Need to disconnect these when the window is closing. */
@@ -435,7 +440,7 @@ e_shell_window_get_shell (EShellWindow *shell_window)
{
g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
- return shell_window->priv->shell;
+ return E_SHELL (shell_window->priv->shell);
}
/**
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;
}
/**
diff --git a/shell/e-shell.h b/shell/e-shell.h
index 1503ca776b..9e30550283 100644
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@ -28,6 +28,7 @@
#ifndef E_SHELL_H
#define E_SHELL_H
+#include <unique/unique.h>
#include <shell/e-shell-common.h>
#include <shell/e-shell-module.h>
#include <shell/e-shell-settings.h>
@@ -66,12 +67,12 @@ typedef enum _EShellLineStatus EShellLineStatus;
* functions below.
**/
struct _EShell {
- GObject parent;
+ UniqueApp parent;
EShellPrivate *priv;
};
struct _EShellClass {
- GObjectClass parent_class;
+ UniqueAppClass parent_class;
};
GType e_shell_get_type (void);
@@ -85,9 +86,10 @@ EShellModule * e_shell_get_module_by_name (EShell *shell,
EShellModule * e_shell_get_module_by_scheme (EShell *shell,
const gchar *scheme);
EShellSettings *e_shell_get_shell_settings (EShell *shell);
-GtkWidget * e_shell_create_shell_window (EShell *shell);
-gboolean e_shell_handle_uri (EShell *shell,
- const gchar *uri);
+GtkWidget * e_shell_create_shell_window (EShell *shell,
+ const gchar *view_name);
+guint e_shell_handle_uris (EShell *shell,
+ const gchar **uris);
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 0cf8c77d8c..670b24d1a2 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -23,6 +23,7 @@
#include <config.h>
#include <gtk/gtk.h>
+#include <gdk/gdkx.h> /* for copied UniqueApp code */
#include <glib/gstdio.h>
#ifdef G_OS_WIN32
@@ -101,8 +102,8 @@ static gboolean disable_eplugin = FALSE;
static gboolean disable_preview = FALSE;
static gboolean idle_cb (gchar **uris);
-static char *requested_view = NULL;
-static char *evolution_debug_log = NULL;
+static gchar *requested_view = NULL;
+static gchar *evolution_debug_log = NULL;
static gchar **remaining_args;
/* Defined in <e-shell.h> */
@@ -299,72 +300,38 @@ destroy_config (GConfClient *client)
#endif /* DEVELOPMENT */
-static void
-open_uris (gchar **uris)
-{
- EShell *shell;
- guint ii;
-
- g_return_if_fail (uris != NULL);
-
- shell = e_shell_get_default ();
-
- for (ii = 0; uris[ii] != NULL; ii++)
- if (!e_shell_handle_uri (shell, uris[ii]))
- g_warning ("Invalid URI: %s", uris[ii]);
-}
-
/* This is for doing stuff that requires the GTK+ loop to be running already. */
static gboolean
idle_cb (gchar **uris)
{
EShell *shell;
- GtkWidget *shell_window;
- const gchar *initial_view;
-
- g_return_val_if_fail (uris == NULL || g_strv_length (uris) > 0, FALSE);
+ guint ii;
#ifdef KILL_PROCESS_CMD
kill_old_dataserver ();
#endif
- if (uris != NULL) {
- open_uris (uris);
- return FALSE;
- }
-
shell = e_shell_get_default ();
- initial_view = e_shell_get_canonical_name (shell, requested_view);
- if (initial_view != NULL) {
- GConfClient *client;
- const gchar *key;
+ /* These calls do the right thing when there's another
+ * Evolution process running. */
+ if (uris != NULL && *uris != NULL)
+ e_shell_handle_uris (shell, uris);
+ else
+ e_shell_create_shell_window (shell, requested_view);
- client = gconf_client_get_default ();
- key = "/apps/evolution/shell/view_defaults/component_id";
- gconf_client_set_string (client, key, initial_view, NULL);
- g_object_unref (client);
+ if (unique_app_is_running (UNIQUE_APP (shell))) {
+ gtk_main_quit ();
+ return FALSE;
}
- shell_window = e_shell_create_shell_window (shell);
-
-#if 0 /* MBARNES */
- if (shell == NULL) {
- /*there is another instance but because we don't open any windows
- we must notify the startup was complete manually*/
- gdk_notify_startup_complete ();
- bonobo_main_quit ();
- }
-#endif
+ /* 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 */
- /* This must be done after Bonobo has created all the components. For
- * example the mail component makes the global variable `session` which
- * is being used by several EPlugins */
-
- if (!disable_eplugin) {
+ if (uris == NULL && !disable_eplugin)
e_plugin_load_plugins_with_missing_symbols ();
- }
return FALSE;
}
@@ -530,6 +497,84 @@ master_client_die_cb (GnomeClient *client,
e_shell_do_quit (shell);
}
+/* taken from nautilus */
+static guint32
+slowly_and_stupidly_obtain_timestamp (GdkDisplay *display)
+{
+ Display *xdisplay;
+ Window xwindow;
+ XEvent event;
+ XSetWindowAttributes attrs;
+ Atom atom_name;
+ Atom atom_type;
+ char *name;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ attrs.override_redirect = True;
+ attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
+
+ xwindow = XCreateWindow (
+ xdisplay, RootWindow (xdisplay, 0),
+ -100, -100, 1, 1,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attrs);
+
+ atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE);
+ g_assert (atom_name != None);
+
+ atom_type = XInternAtom (xdisplay, "STRING", TRUE);
+ g_assert (atom_type != None);
+
+ name = "Fake Window";
+ XChangeProperty (
+ xdisplay, xwindow, atom_name, atom_type,
+ 8, PropModeReplace, (unsigned char *) name,
+ strlen (name));
+
+ XWindowEvent (
+ xdisplay, xwindow, PropertyChangeMask, &event);
+
+ XDestroyWindow (xdisplay, xwindow);
+
+ return event.xproperty.time;
+}
+
+static gchar *
+pick_startup_id (void)
+{
+ GdkDisplay *display;
+ const gchar *startup_id;
+ gchar *id;
+
+ /* XXX This copies logic from unique_app_new(), which we can't use
+ * because we're subclassing UniqueApp. I already sent ebassi
+ * a patch to fix this. */
+
+ display = gdk_display_get_default ();
+
+ /* Try and get the startup notification ID from GDK, the
+ * environment or, if everything else failed, fake one. */
+ startup_id = gdk_x11_display_get_startup_notification_id (display);
+
+ if (!startup_id || startup_id[0] == '\0')
+ startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+
+ if (!startup_id || startup_id[0] == '\0') {
+ guint32 timestamp;
+
+ timestamp = slowly_and_stupidly_obtain_timestamp (display);
+ id = g_strdup_printf ("_TIME%lu", (gulong) timestamp);
+ } else
+ id = g_strdup (startup_id);
+
+ return id;
+}
+
static void
create_default_shell (void)
{
@@ -537,6 +582,7 @@ create_default_shell (void)
GConfClient *conf_client;
GnomeClient *master_client;
gboolean online_mode = TRUE;
+ gchar *startup_id;
GError *error = NULL;
conf_client = gconf_client_get_default ();
@@ -560,7 +606,16 @@ create_default_shell (void)
}
}
- shell = g_object_new (E_TYPE_SHELL, "online-mode", online_mode, NULL);
+ startup_id = pick_startup_id ();
+
+ shell = g_object_new (
+ E_TYPE_SHELL,
+ "name", "org.gnome.evolution",
+ "online-mode", online_mode,
+ "startup-id", startup_id,
+ NULL);
+
+ g_free (startup_id);
g_signal_connect (
shell, "window-destroyed",
@@ -718,6 +773,11 @@ main (int argc, char **argv)
gtk_main ();
+ /* Emit a warning if the shell is not finalized. */
+ g_object_unref (default_shell);
+ if (E_IS_SHELL (default_shell))
+ g_warning ("Shell not finalized on exit");
+
gtk_accel_map_save (e_get_accels_filename ());
e_icon_factory_shutdown ();
@@ -728,8 +788,5 @@ main (int argc, char **argv)
link_shutdown ();
#endif
- /* Indicates a clean shut down to the next session. */
- e_file_lock_destroy ();
-
return 0;
}