aboutsummaryrefslogtreecommitdiffstats
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/Makefile.am2
-rw-r--r--shell/e-shell-backend.c61
-rw-r--r--shell/e-shell-backend.h12
-rw-r--r--shell/e-shell.c160
-rw-r--r--shell/e-shell.h4
-rw-r--r--shell/main.c142
6 files changed, 107 insertions, 274 deletions
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 8df302be77..878642ec21 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -3,7 +3,6 @@ SUBDIRS = . test
endif
AM_CPPFLAGS = \
- -I$(top_srcdir)/e-util \
-I$(top_srcdir)/widgets \
-I$(top_srcdir)/widgets/menus \
-I$(top_srcdir)/widgets/misc \
@@ -99,6 +98,7 @@ libeshell_la_LDFLAGS = $(NO_UNDEFINED)
libeshell_la_LIBADD = \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/filter/libfilter.la \
+ $(top_builddir)/smclient/libeggsmclient.la \
$(top_builddir)/widgets/misc/libemiscwidgets.la \
$(top_builddir)/widgets/menus/libmenus.la \
$(SHELL_LIBS)
diff --git a/shell/e-shell-backend.c b/shell/e-shell-backend.c
index 9ee2edb4dc..c996d8ab01 100644
--- a/shell/e-shell-backend.c
+++ b/shell/e-shell-backend.c
@@ -370,67 +370,6 @@ e_shell_backend_start (EShellBackend *shell_backend)
}
/**
- * e_shell_backend_is_busy:
- * @shell_backend: an #EShellBackend
- *
- * Returns %TRUE if @shell_backend is busy and cannot be shutdown at
- * present. Each backend must define what "busy" means to them and
- * determine an appropriate response.
- *
- * XXX This function is likely to change or disappear. I'm toying with
- * the idea of just having it check whether there are any unfinished
- * #EActivity<!-- -->'s left, so we have a consistent and easily
- * testable definition of what "busy" means.
- *
- * Returns: %TRUE if the backend is busy
- **/
-gboolean
-e_shell_backend_is_busy (EShellBackend *shell_backend)
-{
- EShellBackendClass *class;
-
- g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
-
- class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
-
- if (class->is_busy == NULL)
- return FALSE;
-
- return class->is_busy (shell_backend);
-}
-
-/**
- * e_shell_backend_shutdown:
- * @shell_backend: an #EShellBackend
- *
- * Alerts @shell_backend to begin shutdown procedures. If the backend is
- * busy and cannot immediately shut down, the function returns %FALSE.
- * A %TRUE response implies @shell_backend has successfully shut down.
- *
- * XXX This function is likely to change or disappear. I'm toying with
- * the idea of just having it check whether there are any unfinished
- * #EActivity<!-- -->'s left, so we have a consistent and easily
- * testable definition of what "busy" means.
- *
- * Returns: %TRUE if the backend has shut down, %FALSE if the backend is
- * busy and cannot immediately shut down
- */
-gboolean
-e_shell_backend_shutdown (EShellBackend *shell_backend)
-{
- EShellBackendClass *class;
-
- g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE);
-
- class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
-
- if (class->shutdown == NULL)
- return TRUE;
-
- return class->shutdown (shell_backend);
-}
-
-/**
* e_shell_migrate:
* @shell_backend: an #EShellBackend
* @major: major part of version to migrate from
diff --git a/shell/e-shell-backend.h b/shell/e-shell-backend.h
index 0d4e02f9bb..8b7e24034f 100644
--- a/shell/e-shell-backend.h
+++ b/shell/e-shell-backend.h
@@ -91,14 +91,6 @@ struct _EShellBackend {
* corresponding #EShellView subclass. It allows the
* backend to delay initialization steps that consume
* significant resources until they are actually needed.
- * @is_busy: Method for querying whether the backend has operations
- * in progress that cannot be cancelled or finished
- * immediately. Returning %TRUE prevents the application
- * from shutting down.
- * @shutdown: Method for notifying the backend to begin shutting
- * down. Returning %FALSE indicates there are still
- * unfinished operations and the #EShell should check
- * back shortly.
* @migrate: Method for notifying the backend to migrate data and
* settings from the given version. Returns %TRUE if the
* migration was successful or if no action was necessary.
@@ -119,8 +111,6 @@ struct _EShellBackendClass {
/* Methods */
void (*start) (EShellBackend *shell_backend);
- gboolean (*is_busy) (EShellBackend *shell_backend);
- gboolean (*shutdown) (EShellBackend *shell_backend);
gboolean (*migrate) (EShellBackend *shell_backend,
gint major,
gint minor,
@@ -138,8 +128,6 @@ struct _EShell *e_shell_backend_get_shell (EShellBackend *shell_backend);
void e_shell_backend_add_activity (EShellBackend *shell_backend,
EActivity *activity);
void e_shell_backend_start (EShellBackend *shell_backend);
-gboolean e_shell_backend_is_busy (EShellBackend *shell_backend);
-gboolean e_shell_backend_shutdown (EShellBackend *shell_backend);
gboolean e_shell_backend_migrate (EShellBackend *shell_backend,
gint major,
gint minor,
diff --git a/shell/e-shell.c b/shell/e-shell.c
index c9e8d46317..35908e0855 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -50,6 +50,7 @@ struct _EShellPrivate {
GHashTable *backends_by_scheme;
gpointer preparing_for_line_change; /* weak pointer */
+ gpointer preparing_for_shutdown; /* weak pointer */
guint auto_reconnect : 1;
guint network_available : 1;
@@ -69,6 +70,7 @@ enum {
HANDLE_URI,
PREPARE_FOR_OFFLINE,
PREPARE_FOR_ONLINE,
+ PREPARE_FOR_SHUTDOWN,
SEND_RECEIVE,
WINDOW_CREATED,
WINDOW_DESTROYED,
@@ -122,7 +124,9 @@ shell_window_delete_event_cb (EShell *shell,
return FALSE;
/* Otherwise we initiate application shutdown. */
- return !e_shell_quit (shell);
+ e_shell_quit (shell);
+
+ return TRUE;
}
static gboolean
@@ -272,6 +276,40 @@ shell_prepare_for_online (EShell *shell)
}
static void
+shell_ready_for_shutdown (EShell *shell,
+ EActivity *activity,
+ gboolean is_last_ref)
+{
+ GList *list;
+
+ if (!is_last_ref)
+ return;
+
+ /* Increment the reference count so we can safely emit
+ * a signal without triggering the toggle reference. */
+ g_object_ref (activity);
+
+ e_activity_complete (activity);
+
+ g_object_remove_toggle_ref (
+ G_OBJECT (activity), (GToggleNotify)
+ shell_ready_for_shutdown, shell);
+
+ /* Finalize the activity. */
+ g_object_ref (activity);
+
+ g_message ("Shutdown preparations complete.");
+
+ /* Destroy all watched windows. Note, we iterate over a -copy-
+ * of the watched windows list because the act of destroying a
+ * watched window will modify the watched windows list, which
+ * would derail the iteration. */
+ list = g_list_copy (e_shell_get_watched_windows (shell));
+ g_list_foreach (list, (GFunc) gtk_widget_destroy, NULL);
+ g_list_free (list);
+}
+
+static void
shell_load_modules (EShell *shell)
{
GList *modules;
@@ -358,54 +396,6 @@ shell_create_backends (EShell *shell)
g_free (children);
}
-static gboolean
-shell_shutdown_timeout (EShell *shell)
-{
- GList *list, *iter;
- gboolean proceed = TRUE;
- static guint source_id = 0;
- static guint message_timer = 1;
-
- /* Module list is read-only; do not free. */
- list = e_shell_get_shell_backends (shell);
-
- /* Any backend can defer shutdown if it's still busy. */
- for (iter = list; proceed && iter != NULL; iter = iter->next) {
- EShellBackend *shell_backend = iter->data;
- proceed = e_shell_backend_shutdown (shell_backend);
-
- /* Emit a message every few seconds to indicate
- * which backend(s) we're still waiting on. */
- if (proceed || message_timer == 0)
- continue;
-
- g_message (
- _("Waiting for the \"%s\" backend to finish..."),
- E_SHELL_BACKEND_GET_CLASS (shell_backend)->name);
- }
-
- message_timer = (message_timer + 1) % 10;
-
- /* If we're go for shutdown, destroy all shell windows. Note,
- * we iterate over a /copy/ of the active windows list because
- * 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->watched_windows);
- g_list_foreach (list, (GFunc) gtk_widget_destroy, NULL);
- g_list_free (list);
-
- /* If a backend is still busy, try again after a short delay. */
- } else if (source_id == 0)
- source_id = g_timeout_add (
- SHUTDOWN_TIMEOUT, (GSourceFunc)
- shell_shutdown_timeout, shell);
-
- /* Return TRUE to repeat the timeout, FALSE to stop it. This
- * may seem backwards if the function was called directly. */
- return !proceed;
-}
-
static void
shell_set_property (GObject *object,
guint property_id,
@@ -761,6 +751,31 @@ shell_class_init (EShellClass *class)
E_TYPE_ACTIVITY);
/**
+ * EShell::prepare-for-shutdown
+ * @shell: the #EShell which emitted the signal
+ * @activity: the #EActivity for shutdown preparations
+ *
+ * Emitted when the user elects to quit the application. An
+ * #EShellBackend should listen for this signal and make
+ * preparations for shutting down.
+ *
+ * If preparations for shutting down cannot immediately be completed
+ * (such as when there are uncompleted network operations), the
+ * #EShellBackend should reference the @activity until preparations
+ * are complete, and then unreference the @activity. This will
+ * delay Evolution from actually shutting down until all backends
+ * have unreferenced @activity.
+ **/
+ signals[PREPARE_FOR_SHUTDOWN] = g_signal_new (
+ "prepare-for-shutdown",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_ACTIVITY);
+
+ /**
* EShell::send-receive
* @shell: the #EShell which emitted the signal
* @parent: a parent #GtkWindow
@@ -1411,23 +1426,38 @@ e_shell_event (EShell *shell,
g_signal_emit (shell, signals[EVENT], detail, event_data);
}
-gboolean
-e_shell_is_busy (EShell *shell)
+void
+e_shell_quit (EShell *shell)
{
- /* FIXME */
- return FALSE;
-}
+ GList *list, *iter;
-gboolean
-e_shell_do_quit (EShell *shell)
-{
- /* FIXME */
- return TRUE;
-}
+ g_return_if_fail (E_IS_SHELL (shell));
-gboolean
-e_shell_quit (EShell *shell)
-{
- /* FIXME */
- return TRUE;
+ /* Are preparations already in progress? */
+ if (shell->priv->preparing_for_shutdown != NULL)
+ return;
+
+ g_message ("Preparing for shutdown...");
+
+ shell->priv->preparing_for_shutdown =
+ e_activity_new (_("Preparing to shut down..."));
+
+ g_object_add_toggle_ref (
+ G_OBJECT (shell->priv->preparing_for_shutdown),
+ (GToggleNotify) shell_ready_for_shutdown, shell);
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell->priv->preparing_for_shutdown),
+ &shell->priv->preparing_for_shutdown);
+
+ g_signal_emit (
+ shell, signals[PREPARE_FOR_SHUTDOWN], 0,
+ shell->priv->preparing_for_shutdown);
+
+ g_object_unref (shell->priv->preparing_for_shutdown);
+
+ /* Desensitize all watched windows to prevent user action. */
+ list = e_shell_get_watched_windows (shell);
+ for (iter = list; iter != NULL; iter = iter->next)
+ gtk_widget_set_sensitive (GTK_WIDGET (iter->data), FALSE);
}
diff --git a/shell/e-shell.h b/shell/e-shell.h
index 1d0b9ab705..3b414e641c 100644
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@ -104,9 +104,7 @@ GtkWidget * e_shell_get_preferences_window (EShell *shell);
void e_shell_event (EShell *shell,
const gchar *event_name,
gpointer event_data);
-gboolean e_shell_is_busy (EShell *shell);
-gboolean e_shell_do_quit (EShell *shell);
-gboolean e_shell_quit (EShell *shell);
+void e_shell_quit (EShell *shell);
G_END_DECLS
diff --git a/shell/main.c b/shell/main.c
index b921dd87ec..bbd9319176 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -58,7 +58,6 @@
#include <glib/gi18n.h>
#include <libgnome/gnome-sound.h>
#include <libgnomeui/gnome-ui-init.h>
-#include <libgnomeui/gnome-client.h>
#include <bonobo/bonobo-exception.h>
@@ -427,8 +426,7 @@ static void
set_paths (void)
{
/* Set PATH to include the Evolution executable's folder
- * and the lib/evolution/$(BASE_VERSION)/components folder.
- */
+ * and the lib/evolution/$(BASE_VERSION)/components folder. */
wchar_t exe_filename[MAX_PATH];
wchar_t *p;
gchar *exe_folder_utf8;
@@ -449,18 +447,16 @@ set_paths (void)
*p = L'\0';
top_folder_utf8 = g_utf16_to_utf8 (exe_filename, -1, NULL, NULL, NULL);
- components_folder_utf8 =
- g_strconcat (top_folder_utf8,
- "/lib/evolution/" BASE_VERSION "/components",
- NULL);
-
- path = g_build_path (";",
- exe_folder_utf8,
- components_folder_utf8,
- g_getenv ("PATH"),
- NULL);
+ components_folder_utf8 = g_strconcat (
+ top_folder_utf8, "/lib/evolution/"
+ BASE_VERSION "/components", NULL);
+
+ path = g_build_path (
+ ";", exe_folder_utf8,
+ components_folder_utf8, g_getenv ("PATH"), NULL);
if (!g_setenv ("PATH", path, TRUE))
- g_warning ("Could not set PATH for Evolution and its child processes");
+ g_warning ("Could not set PATH for Evolution "
+ "and its child processes");
g_free (path);
g_free (exe_folder_utf8);
@@ -477,118 +473,15 @@ shell_window_destroyed_cb (EShell *shell)
gtk_main_quit ();
}
-static gint
-master_client_save_yourself_cb (GnomeClient *client,
- GnomeSaveStyle save_style,
- gint shutdown,
- GnomeInteractStyle interact_style,
- gint fast,
- gpointer user_data)
-{
- EShell *shell = user_data;
-
- return !e_shell_is_busy (shell);
-}
-
-static void
-master_client_die_cb (GnomeClient *client,
- gpointer user_data)
-{
- EShell *shell = user_data;
-
- 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;
- const gchar *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, (guchar *) 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)
{
EShell *shell;
GConfClient *conf_client;
- GnomeClient *master_client;
gboolean online = TRUE;
- gchar *startup_id;
GError *error = NULL;
conf_client = gconf_client_get_default ();
- master_client = gnome_master_client ();
if (start_online)
online = TRUE;
@@ -608,31 +501,16 @@ create_default_shell (void)
}
}
- startup_id = pick_startup_id ();
-
shell = g_object_new (
E_TYPE_SHELL,
"name", "org.gnome.evolution",
"online", online,
- "startup-id", startup_id,
NULL);
- g_free (startup_id);
-
g_signal_connect (
shell, "window-destroyed",
G_CALLBACK (shell_window_destroyed_cb), NULL);
- if (master_client != NULL) {
- g_signal_connect (
- master_client, "save_yourself",
- G_CALLBACK (master_client_save_yourself_cb), shell);
-
- g_signal_connect (
- master_client, "die",
- G_CALLBACK (master_client_die_cb), shell);
- }
-
g_object_unref (conf_client);
/* EShell keeps its own reference to the first instance for use