[evolution] Bug 603468 - Improve handling of --quit option



commit 51d0fc6863be998af5056605281cc0ebc2abfe00
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Jun 12 14:28:07 2010 -0400

    Bug 603468 - Improve handling of --quit option

 addressbook/gui/contact-editor/eab-editor.c |   11 ++-
 doc/reference/shell/tmpl/e-shell.sgml       |    2 +
 glib-gen.mak                                |   42 ++++++++++
 mail/e-mail-backend.c                       |    5 +
 shell/Makefile.am                           |   13 +++-
 shell/e-shell-window-actions.c              |    2 +-
 shell/e-shell.c                             |  116 ++++++++++++++-------------
 shell/e-shell.h                             |   33 +++++++-
 shell/main.c                                |   16 +++-
 9 files changed, 170 insertions(+), 70 deletions(-)
---
diff --git a/addressbook/gui/contact-editor/eab-editor.c b/addressbook/gui/contact-editor/eab-editor.c
index 17ac1c3..f53ecc3 100644
--- a/addressbook/gui/contact-editor/eab-editor.c
+++ b/addressbook/gui/contact-editor/eab-editor.c
@@ -57,11 +57,16 @@ static gpointer parent_class;
 static guint signals[LAST_SIGNAL];
 
 static void
-eab_editor_quit_requested_cb (EABEditor *editor,
-                              EShell *shell)
+eab_editor_quit_requested_cb (EShell *shell,
+                              EShellQuitReason reason,
+                              EABEditor *editor)
 {
 	GtkWindow *window;
 
+	/* Quit immediately if another Evolution process asked us to. */
+	if (reason == E_SHELL_QUIT_REMOTE_REQUEST)
+		return;
+
 	window = eab_editor_get_window (editor);
 
 	eab_editor_raise (editor);
@@ -78,7 +83,7 @@ eab_editor_set_shell (EABEditor *editor,
 
 	editor->priv->shell = g_object_ref (shell);
 
-	g_signal_connect_swapped (
+	g_signal_connect (
 		shell, "quit-requested",
 		G_CALLBACK (eab_editor_quit_requested_cb), editor);
 }
diff --git a/doc/reference/shell/tmpl/e-shell.sgml b/doc/reference/shell/tmpl/e-shell.sgml
index 2287392..5505f3e 100644
--- a/doc/reference/shell/tmpl/e-shell.sgml
+++ b/doc/reference/shell/tmpl/e-shell.sgml
@@ -73,6 +73,7 @@ EShell
 </para>
 
 @eshell: the object which received the signal.
+ Param2: 
 
 <!-- ##### SIGNAL EShell::send-receive ##### -->
 <para>
@@ -339,6 +340,7 @@ EShell
 </para>
 
 @shell: 
+ reason: 
 @Returns: 
 
 
diff --git a/glib-gen.mak b/glib-gen.mak
new file mode 100644
index 0000000..7aae596
--- /dev/null
+++ b/glib-gen.mak
@@ -0,0 +1,42 @@
+# these are the variables your Makefile.am should set
+# the example is based on the colorbalance interface
+
+#glib_enum_headers=$(colorbalance_headers)
+#glib_enum_define=GST_COLOR_BALANCE
+#glib_enum_prefix=gst_color_balance
+
+# these are all the rules generating the relevant files
+%-marshal.h: %-marshal.list
+	glib-genmarshal --header --prefix=$(glib_enum_prefix)_marshal $^ > $*-marshal.h.tmp
+	mv $*-marshal.h.tmp $*-marshal.h
+
+%-marshal.c: %-marshal.list
+	echo "#include \"$*-marshal.h\"" >> $*-marshal.c.tmp
+	glib-genmarshal --body --prefix=$(glib_enum_prefix)_marshal $^ >> $*-marshal.c.tmp
+	mv $*-marshal.c.tmp $*-marshal.c
+
+%-enumtypes.h: $(glib_enum_headers)
+	glib-mkenums \
+	--fhead "#ifndef __$(glib_enum_define)_ENUM_TYPES_H__\n#define __$(glib_enum_define)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+	--fprod "/* enumerations from \"@filename \" */\n" \
+	--vhead "GType @enum_name _get_type (void);\n#define E_TYPE_ ENUMSHORT@ (@enum_name _get_type())\n"         \
+	--ftail "G_END_DECLS\n\n#endif /* __$(glib_enum_define)_ENUM_TYPES_H__ */" \
+	$^ > $@
+
+%-enumtypes.c: $(glib_enum_headers)
+	@if test "x$(glib_enum_headers)" == "x"; then echo "ERROR: glib_enum_headers is empty, please fix Makefile"; exit 1; fi
+	glib-mkenums \
+	--fhead "#include <$*.h>\n#include \"$*-enumtypes.h\"" \
+	--fprod "\n/* enumerations from \"@filename \" */" \
+	--vhead "GType\n enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G Type@Value values[] = {"     \
+	--vprod "      { @VALUENAME@, \"@VALUENAME \", \"@VALUENAME \" }," \
+	--vtail "      { 0, NULL, NULL }\n    };\n    etype = g_ type@_register_static (\"@EnumName \", values);\n  }\n  return etype;\n}\n" \
+	$^ > $@
+
+# a hack rule to make sure .Plo files exist because they get include'd
+# from Makefile's
+.deps/%-marshal.Plo:
+	touch $@
+
+.deps/%-enumtypes.Plo:
+	touch $@
diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c
index 7f62c46..a0453a9 100644
--- a/mail/e-mail-backend.c
+++ b/mail/e-mail-backend.c
@@ -260,6 +260,7 @@ mail_backend_prepare_for_quit_cb (EShell *shell,
 
 static void
 mail_backend_quit_requested_cb (EShell *shell,
+                                EShellQuitReason reason,
                                 EShellBackend *shell_backend)
 {
 	CamelFolder *folder;
@@ -272,6 +273,10 @@ mail_backend_quit_requested_cb (EShell *shell,
 	if (!e_shell_get_online (shell))
 		return;
 
+	/* Or if another Evolution process asked us to. */
+	if (reason == E_SHELL_QUIT_REMOTE_REQUEST)
+		return;
+
 	/* In express mode, don't raise mail request in non mail window. */
 	if (e_shell_get_express_mode(shell) &&
 		strcmp(e_shell_window_get_active_view((EShellWindow *)window), "mail") != 0)
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 567059e..2f044e4 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -6,15 +6,23 @@ endif
 bin_PROGRAMS = evolution
 
 # Shell library
-privsolib_LTLIBRARIES =	libeshell.la
+privsolib_LTLIBRARIES = libeshell.la
 
 eshellincludedir = $(privincludedir)/shell
 
+include $(top_srcdir)/glib-gen.mak
+glib_enum_headers=e-shell.h
+glib_enum_define=E_SHELL
+glib_enum_prefix=e_shell
+
+ENUM_GENERATED = e-shell-enumtypes.h e-shell-enumtypes.c
+
 eshellinclude_HEADERS = 			\
 	e-shell.h				\
 	e-shell-backend.h			\
 	e-shell-common.h			\
 	e-shell-content.h			\
+	e-shell-enumtypes.h			\
 	e-shell-searchbar.h			\
 	e-shell-settings.h			\
 	e-shell-sidebar.h			\
@@ -58,6 +66,7 @@ libeshell_la_SOURCES =				\
 	e-shell.c				\
 	e-shell-backend.c			\
 	e-shell-content.c			\
+	e-shell-enumtypes.c			\
 	e-shell-meego.c				\
 	e-shell-meego.h				\
 	e-shell-searchbar.c			\
@@ -217,7 +226,7 @@ evolution.pure: evolution
 
 endif
 
-BUILT_SOURCES = $(error_DATA)
+BUILT_SOURCES = $(error_DATA) $(ENUM_GENERATED)
 CLEANFILES = $(BUILT_SOURCES)
 
 DISTCLEANFILES = $(schema_DATA)
diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
index 606f125..480b99d 100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@ -1012,7 +1012,7 @@ action_quit_cb (GtkAction *action,
 	EShell *shell;
 
 	shell = e_shell_window_get_shell (shell_window);
-	e_shell_quit (shell);
+	e_shell_quit (shell, E_SHELL_QUIT_ACTION);
 }
 
 /**
diff --git a/shell/e-shell.c b/shell/e-shell.c
index f82931c..21bf16e 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -38,6 +38,7 @@
 #include "widgets/misc/e-preferences-window.h"
 
 #include "e-shell-backend.h"
+#include "e-shell-enumtypes.h"
 #include "e-shell-window.h"
 #include "e-shell-utils.h"
 
@@ -65,6 +66,7 @@ struct _EShellPrivate {
 	gchar *startup_view;
 
 	guint auto_reconnect	: 1;
+	guint modules_loaded	: 1;
 	guint network_available	: 1;
 	guint online		: 1;
 	guint quit_cancelled	: 1;
@@ -145,7 +147,7 @@ shell_window_delete_event_cb (EShell *shell,
 		return FALSE;
 
 	/* Otherwise we initiate application quit. */
-	e_shell_quit (shell);
+	e_shell_quit (shell, E_SHELL_QUIT_LAST_WINDOW);
 
 	return TRUE;
 }
@@ -311,15 +313,6 @@ shell_ready_for_quit (EShell *shell,
 	/* Finalize the activity. */
 	g_object_ref (activity);
 
-	/* This handles a strange corner case where --quit is given on
-	 * the command-line but no other Evolution process is running.
-	 * We bring all the shell backends up and then immediately run
-	 * the shutdown procedure, which gets us here.  But because no
-	 * windows have been shown yet, the usual "main loop ends when
-	 * the last window is destroyed" trick won't work. */
-	if (e_shell_get_watched_windows (shell) == NULL)
-		gtk_main_quit ();
-
 	/* 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
@@ -362,7 +355,8 @@ shell_prepare_for_quit (EShell *shell)
 }
 
 static gboolean
-shell_request_quit (EShell *shell)
+shell_request_quit (EShell *shell,
+                    EShellQuitReason reason)
 {
 	/* Are preparations already in progress? */
 	if (shell->priv->preparing_for_quit != NULL)
@@ -370,28 +364,11 @@ shell_request_quit (EShell *shell)
 
 	/* Give the application a chance to cancel quit. */
 	shell->priv->quit_cancelled = FALSE;
-	g_signal_emit (shell, signals[QUIT_REQUESTED], 0);
+	g_signal_emit (shell, signals[QUIT_REQUESTED], 0, reason);
 
 	return !shell->priv->quit_cancelled;
 }
 
-static void
-shell_load_modules (EShell *shell)
-{
-	const gchar *module_directory;
-	GList *modules = NULL;
-
-	/* Load all shared library modules. */
-
-	module_directory = e_shell_get_module_directory (shell);
-	g_return_if_fail (module_directory != NULL);
-
-	modules = e_module_load_all_in_directory (module_directory);
-
-	g_list_foreach (modules, (GFunc) g_type_module_unuse, NULL);
-	g_list_free (modules);
-}
-
 /* Helper for shell_add_backend() */
 static void
 shell_split_and_insert_items (GHashTable *hash_table,
@@ -443,12 +420,13 @@ static void
 shell_sm_quit_requested_cb (EShell *shell,
                             EggSMClient *sm_client)
 {
+	EShellQuitReason reason = E_SHELL_QUIT_SESSION_REQUEST;
 	gboolean will_quit;
 
 	/* If preparations are already in progress then we have already
 	 * committed ourselves to quitting, and can answer 'yes'. */
 	if (shell->priv->preparing_for_quit == NULL)
-		will_quit = shell_request_quit (shell);
+		will_quit = shell_request_quit (shell, reason);
 	else
 		will_quit = TRUE;
 
@@ -675,34 +653,14 @@ shell_finalize (GObject *object)
 static void
 shell_constructed (GObject *object)
 {
-	EShellPrivate *priv;
-	GList *list;
-
-	priv = E_SHELL_GET_PRIVATE (object);
-
 	/* The first EShell instance is the default. */
 	if (default_shell == NULL) {
 		default_shell = object;
 		g_object_add_weak_pointer (object, &default_shell);
 	}
 
-	/* 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;
-
-	e_file_lock_create ();
-
-	shell_load_modules (E_SHELL (object));
-
-	/* Process shell backends. */
-	list = g_list_sort (
-		e_extensible_list_extensions (
-		E_EXTENSIBLE (object), E_TYPE_SHELL_BACKEND),
-		(GCompareFunc) e_shell_backend_compare);
-	g_list_foreach (list, (GFunc) shell_process_backend, object);
-	priv->loaded_backends = list;
+	if (!unique_app_is_running (UNIQUE_APP (object)))
+		e_file_lock_create ();
 }
 
 static UniqueResponse
@@ -753,7 +711,7 @@ shell_message_handle_close (EShell *shell,
 {
 	UniqueResponse response;
 
-	if (e_shell_quit (shell))
+	if (e_shell_quit (shell, E_SHELL_QUIT_REMOTE_REQUEST))
 		response = UNIQUE_RESPONSE_OK;
 	else
 		response = UNIQUE_RESPONSE_CANCEL;
@@ -1070,6 +1028,7 @@ e_shell_class_init (EShellClass *class)
 	/**
 	 * EShell::quit-requested
 	 * @shell: the #EShell which emitted the signal
+	 * @reason: the reason for quitting
 	 *
 	 * Emitted when the user elects to quit the application, before
 	 * #EShell::prepare-for-quit.
@@ -1086,8 +1045,9 @@ e_shell_class_init (EShellClass *class)
 		G_SIGNAL_RUN_FIRST,
 		G_STRUCT_OFFSET (EShellClass, quit_requested),
 		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
+		g_cclosure_marshal_VOID__ENUM,
+		G_TYPE_NONE, 1,
+		E_TYPE_SHELL_QUIT_REASON);
 
 	/**
 	 * EShell::send-receive
@@ -1245,6 +1205,46 @@ e_shell_get_default (void)
 }
 
 /**
+ * e_shell_load_modules:
+ * @shell: an #EShell
+ *
+ * Loads all installed modules and performs some internal bookkeeping.
+ * This function should be called after creating the #EShell instance
+ * but before initiating migration or starting the main loop.
+ **/
+void
+e_shell_load_modules (EShell *shell)
+{
+	const gchar *module_directory;
+	GList *list;
+
+	g_return_if_fail (E_IS_SHELL (shell));
+
+	if (shell->priv->modules_loaded)
+		return;
+
+	/* Load all shared library modules. */
+
+	module_directory = e_shell_get_module_directory (shell);
+	g_return_if_fail (module_directory != NULL);
+
+	list = e_module_load_all_in_directory (module_directory);
+	g_list_foreach (list, (GFunc) g_type_module_unuse, NULL);
+	g_list_free (list);
+
+	/* Process shell backends. */
+
+	list = g_list_sort (
+		e_extensible_list_extensions (
+		E_EXTENSIBLE (shell), E_TYPE_SHELL_BACKEND),
+		(GCompareFunc) e_shell_backend_compare);
+	g_list_foreach (list, (GFunc) shell_process_backend, shell);
+	shell->priv->loaded_backends = list;
+
+	shell->priv->modules_loaded = TRUE;
+}
+
+/**
  * e_shell_get_shell_backends:
  * @shell: an #EShell
  *
@@ -1846,6 +1846,7 @@ e_shell_event (EShell *shell,
 /**
  * e_shell_quit:
  * @shell: an #EShell
+ * @reason: the reason for quitting
  *
  * Requests an application shutdown.  This happens in two phases: the
  * first is synchronous, the second is asynchronous.
@@ -1866,7 +1867,8 @@ e_shell_event (EShell *shell,
  * Returns: %TRUE if shutdown is underway, %FALSE if it was cancelled
  **/
 gboolean
-e_shell_quit (EShell *shell)
+e_shell_quit (EShell *shell,
+              EShellQuitReason reason)
 {
 	UniqueApp *app;
 	UniqueResponse response;
@@ -1878,7 +1880,7 @@ e_shell_quit (EShell *shell)
 	if (unique_app_is_running (app))
 		goto unique;
 
-	if (!shell_request_quit (shell))
+	if (!shell_request_quit (shell, reason))
 		return FALSE;
 
 	shell_prepare_for_quit (shell);
diff --git a/shell/e-shell.h b/shell/e-shell.h
index f1d76b9..6962ff6 100644
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@ -57,6 +57,32 @@ typedef struct _EShellClass EShellClass;
 typedef struct _EShellPrivate EShellPrivate;
 
 /**
+ * EShellQuitReason:
+ *
+ * @E_SHELL_QUIT_ACTION:
+ *   @E_SHELL_WINDOW_ACTION_QUIT was activated.
+ * @E_SHELL_QUIT_LAST_WINDOW:
+ *   The last watched window has been destroyed.
+ * @E_SHELL_QUIT_OPTION:
+ *   The program was invoked with --quit.  Extensions will never
+ *   see this value because they are not loaded when --quit is given.
+ * @E_SHELL_QUIT_REMOTE_REQUEST:
+ *   Another Evolution process requested we quit.
+ * @E_SHELL_QUIT_SESSION_REQUEST:
+ *   The desktop session requested we quit.
+ *
+ * These values are passed in the #EShell::quit-requested signal to
+ * indicate why the shell is requesting to shut down.
+ **/
+typedef enum {
+	E_SHELL_QUIT_ACTION,
+	E_SHELL_QUIT_LAST_WINDOW,
+	E_SHELL_QUIT_OPTION,
+	E_SHELL_QUIT_REMOTE_REQUEST,
+	E_SHELL_QUIT_SESSION_REQUEST
+} EShellQuitReason;
+
+/**
  * EShell:
  *
  * Contains only private data that should be read and manipulated using the
@@ -78,7 +104,8 @@ struct _EShellClass {
 						 EActivity *activity);
 	void		(*prepare_for_quit)	(EShell *shell,
 						 EActivity *activity);
-	void		(*quit_requested)	(EShell *shell);
+	void		(*quit_requested)	(EShell *shell,
+						 EShellQuitReason reason);
 	void		(*send_receive)		(EShell *shell,
 						 GtkWindow *parent);
 	void		(*window_created)	(EShell *shell,
@@ -88,6 +115,7 @@ struct _EShellClass {
 
 GType		e_shell_get_type		(void);
 EShell *	e_shell_get_default		(void);
+void		e_shell_load_modules		(EShell *shell);
 GList *		e_shell_get_shell_backends	(EShell *shell);
 const gchar *	e_shell_get_canonical_name	(EShell *shell,
 						 const gchar *name);
@@ -122,7 +150,8 @@ GtkWidget *	e_shell_get_preferences_window	(EShell *shell);
 void		e_shell_event			(EShell *shell,
 						 const gchar *event_name,
 						 gpointer event_data);
-gboolean	e_shell_quit			(EShell *shell);
+gboolean	e_shell_quit			(EShell *shell,
+						 EShellQuitReason reason);
 void		e_shell_cancel_quit		(EShell *shell);
 
 void		e_shell_adapt_window_size	(EShell    *shell,
diff --git a/shell/main.c b/shell/main.c
index cac04dd..7e58d97 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -232,9 +232,7 @@ idle_cb (gchar **uris)
 
 	/* These calls do the right thing when another Evolution
 	 * process is running. */
-	if (quit)
-		e_shell_quit (shell);
-	else if (uris != NULL && *uris != NULL) {
+	if (uris != NULL && *uris != NULL) {
 		if (e_shell_handle_uris (shell, uris, import_uris) == 0)
 			gtk_main_quit ();
 	} else {
@@ -578,6 +576,13 @@ main (gint argc, gchar **argv)
 
 	shell = create_default_shell ();
 
+	if (quit) {
+		e_shell_quit (shell, E_SHELL_QUIT_OPTION);
+		goto exit;
+	}
+
+	e_shell_load_modules (shell);
+
 	if (!disable_eplugin) {
 		/* Register built-in plugin hook types. */
 		es_event_hook_get_type ();
@@ -593,9 +598,9 @@ main (gint argc, gchar **argv)
 	}
 
 	if (requested_view)
-		e_shell_set_startup_view(shell, requested_view);
+		e_shell_set_startup_view (shell, requested_view);
 	else if (express_mode)
-		e_shell_set_startup_view(shell, "mail");
+		e_shell_set_startup_view (shell, "mail");
 
 	/* Attempt migration -after- loading all modules and plugins,
 	 * as both shell backends and certain plugins hook into this. */
@@ -608,6 +613,7 @@ main (gint argc, gchar **argv)
 
 	gtk_main ();
 
+exit:
 	/* Drop what should be the last reference to the shell.
 	 * That will cause e_shell_get_default() to henceforth
 	 * return NULL.  Use that to check for reference leaks. */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]