[evolution] Demonstrate extending the EExtension API.



commit 906f93a130d8d670c4b5213c2c2bf03c47c02337
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Mar 21 22:22:57 2010 -0400

    Demonstrate extending the EExtension API.
    
    Introduce e_extensible_list_extensions(), which provides extensible
    objects access to their own extensions, or a subset of them.
    
    Convert EShellBackend to an abstract EExtension subtype.  EShell will
    load its extensions with e_extensible_load_extensions(), and then obtain
    a list of EShellBackend extensions as follows:
    
        shell_backends = e_extensible_list_extensions (
                E_EXTENSIBLE (shell), E_TYPE_SHELL_BACKEND);
    
    Because EShellBackend is abstract, its GType is skipped while traversing
    the GType hierarchy to find EShell extensions.

 doc/reference/shell/eshell-sections.txt       |    1 +
 doc/reference/shell/tmpl/e-extensible.sgml    |   10 ++
 doc/reference/shell/tmpl/e-shell-backend.sgml |    5 -
 doc/reference/shell/tmpl/eshell-unused.sgml   |    6 +
 e-util/e-extensible.c                         |   46 ++++++++-
 e-util/e-extensible.h                         |    2 +
 shell/e-shell-backend.c                       |  148 ++++++-------------------
 shell/e-shell-backend.h                       |    5 +-
 shell/e-shell.c                               |   34 ++----
 9 files changed, 115 insertions(+), 142 deletions(-)
---
diff --git a/doc/reference/shell/eshell-sections.txt b/doc/reference/shell/eshell-sections.txt
index 776d08d..f25d7c7 100644
--- a/doc/reference/shell/eshell-sections.txt
+++ b/doc/reference/shell/eshell-sections.txt
@@ -445,6 +445,7 @@ e_dialog_combo_box_get
 <TITLE>Extensible</TITLE>
 EExtensible
 e_extensible_load_extensions
+e_extensible_list_extensions
 <SUBSECTION Standard>
 E_EXTENSIBLE
 E_IS_EXTENSIBLE
diff --git a/doc/reference/shell/tmpl/e-extensible.sgml b/doc/reference/shell/tmpl/e-extensible.sgml
index de8e8e1..80bf8f0 100644
--- a/doc/reference/shell/tmpl/e-extensible.sgml
+++ b/doc/reference/shell/tmpl/e-extensible.sgml
@@ -31,3 +31,13 @@ Extensible
 @extensible: 
 
 
+<!-- ##### FUNCTION e_extensible_list_extensions ##### -->
+<para>
+
+</para>
+
+ extensible: 
+ extension_type: 
+ Returns: 
+
+
diff --git a/doc/reference/shell/tmpl/e-shell-backend.sgml b/doc/reference/shell/tmpl/e-shell-backend.sgml
index 79456dc..76bf06c 100644
--- a/doc/reference/shell/tmpl/e-shell-backend.sgml
+++ b/doc/reference/shell/tmpl/e-shell-backend.sgml
@@ -31,11 +31,6 @@ EShellBackend
 @eshellbackend: the object which received the signal.
 @arg1: 
 
-<!-- ##### ARG EShellBackend:shell ##### -->
-<para>
-
-</para>
-
 <!-- ##### FUNCTION e_shell_backend_compare ##### -->
 <para>
 
diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml
index 8769407..ef0cb97 100644
--- a/doc/reference/shell/tmpl/eshell-unused.sgml
+++ b/doc/reference/shell/tmpl/eshell-unused.sgml
@@ -509,6 +509,12 @@ intelligent
 </para>
 
 
+<!-- ##### ARG EShellBackend:shell ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### ARG EShellContent:filter-action ##### -->
 <para>
 
diff --git a/e-util/e-extensible.c b/e-util/e-extensible.c
index a5e87c4..b718fc5 100644
--- a/e-util/e-extensible.c
+++ b/e-util/e-extensible.c
@@ -61,6 +61,9 @@
 #include <e-util/e-util.h>
 #include <e-util/e-extension.h>
 
+#define IS_AN_EXTENSION_TYPE(type) \
+	(g_type_is_a ((type), E_TYPE_EXTENSION))
+
 static GQuark extensible_quark;
 
 static GPtrArray *
@@ -133,7 +136,7 @@ e_extensible_get_type (void)
  * e_extensible_load_extensions:
  * @extensible: an #EExtensible
  *
- * Creates an instance of all registered subtypes of #EExtension which
+ * Creates an instance of all instantiable subtypes of #EExtension which
  * target the class of @extensible.  The lifetimes of these newly created
  * #EExtension objects are bound to @extensible such that they are finalized
  * when @extensible is finalized.
@@ -159,3 +162,44 @@ e_extensible_load_extensions (EExtensible *extensible)
 		E_TYPE_EXTENSION, (ETypeFunc)
 		extensible_load_extension, extensible);
 }
+
+/**
+ * e_extensible_list_extensions:
+ * @extensible: an #EExtensible
+ * @extension_type: the type of extensions to list
+ *
+ * Returns a list of #EExtension objects bound to @extensible whose
+ * types are ancestors of @extension_type.  For a complete list of
+ * extension objects bound to @extensible, pass %E_TYPE_EXTENSION.
+ *
+ * The list itself should be freed with g_list_free().  The extension
+ * objects are owned by @extensible and should not be unreferenced.
+ *
+ * Returns: a list of extension objects derived from @extension_type
+ **/
+GList *
+e_extensible_list_extensions (EExtensible *extensible,
+                              GType extension_type)
+{
+	GPtrArray *extensions;
+	GList *list = NULL;
+	guint ii;
+
+	g_return_val_if_fail (E_IS_EXTENSIBLE (extensible), NULL);
+	g_return_val_if_fail (IS_AN_EXTENSION_TYPE (extension_type), NULL);
+
+	e_extensible_load_extensions (extensible);
+
+	extensions = extensible_get_extensions (extensible);
+	g_return_val_if_fail (extensions != NULL, NULL);
+
+	for (ii = 0; ii < extensions->len; ii++) {
+		GObject *object;
+
+		object = g_ptr_array_index (extensions, ii);
+		if (g_type_is_a (G_OBJECT_TYPE (object), extension_type))
+			list = g_list_prepend (list, object);
+	}
+
+	return g_list_reverse (list);
+}
diff --git a/e-util/e-extensible.h b/e-util/e-extensible.h
index a72ea71..6dd6294 100644
--- a/e-util/e-extensible.h
+++ b/e-util/e-extensible.h
@@ -51,6 +51,8 @@ struct _EExtensibleInterface {
 
 GType		e_extensible_get_type		(void);
 void		e_extensible_load_extensions	(EExtensible *extensible);
+GList *		e_extensible_list_extensions	(EExtensible *extensible,
+						 GType extension_type);
 
 G_END_DECLS
 
diff --git a/shell/e-shell-backend.c b/shell/e-shell-backend.c
index ed35471..570e58d 100644
--- a/shell/e-shell-backend.c
+++ b/shell/e-shell-backend.c
@@ -43,8 +43,6 @@
 
 struct _EShellBackendPrivate {
 
-	gpointer shell;  /* weak pointer */
-
 	/* We keep a reference to corresponding EShellView subclass
 	 * since it keeps a reference back to us.  This ensures the
 	 * subclass is not finalized before we are, otherwise it
@@ -58,63 +56,38 @@ struct _EShellBackendPrivate {
 };
 
 enum {
-	PROP_0,
-	PROP_SHELL
-};
-
-enum {
 	ACTIVITY_ADDED,
 	LAST_SIGNAL
 };
 
-static gpointer parent_class;
 static guint signals[LAST_SIGNAL];
 
-static void
-shell_backend_set_shell (EShellBackend *shell_backend,
-                         EShell *shell)
-{
-	g_return_if_fail (shell_backend->priv->shell == NULL);
-
-	shell_backend->priv->shell = shell;
+G_DEFINE_ABSTRACT_TYPE (EShellBackend, e_shell_backend, E_TYPE_EXTENSION)
 
-	g_object_add_weak_pointer (
-		G_OBJECT (shell_backend),
-		&shell_backend->priv->shell);
-}
-
-static void
-shell_backend_set_property (GObject *object,
-                            guint property_id,
-                            const GValue *value,
-                            GParamSpec *pspec)
+static GObject *
+shell_backend_constructor (GType type,
+                           guint n_construct_properties,
+                           GObjectConstructParam *construct_properties)
 {
-	switch (property_id) {
-		case PROP_SHELL:
-			shell_backend_set_shell (
-				E_SHELL_BACKEND (object),
-				g_value_get_object (value));
-			return;
-	}
+	EShellBackendPrivate *priv;
+	EShellBackendClass *class;
+	EShellViewClass *shell_view_class;
+	GObject *object;
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
+	/* Chain up to parent's construct() method. */
+	object = G_OBJECT_CLASS (e_shell_backend_parent_class)->constructor (
+		type, n_construct_properties, construct_properties);
 
-static void
-shell_backend_get_property (GObject *object,
-                            guint property_id,
-                            GValue *value,
-                            GParamSpec *pspec)
-{
-	switch (property_id) {
-		case PROP_SHELL:
-			g_value_set_object (
-				value, e_shell_backend_get_shell (
-				E_SHELL_BACKEND (object)));
-			return;
-	}
+	class = E_SHELL_BACKEND_GET_CLASS (object);
+	priv = E_SHELL_BACKEND_GET_PRIVATE (object);
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	/* Install a reference to ourselves in the
+	 * corresponding EShellViewClass structure. */
+	shell_view_class = g_type_class_ref (class->shell_view_type);
+	shell_view_class->shell_backend = g_object_ref (object);
+	priv->shell_view_class = shell_view_class;
+
+	return object;
 }
 
 static void
@@ -124,19 +97,13 @@ shell_backend_dispose (GObject *object)
 
 	priv = E_SHELL_BACKEND_GET_PRIVATE (object);
 
-	if (priv->shell != NULL) {
-		g_object_remove_weak_pointer (
-			G_OBJECT (priv->shell), &priv->shell);
-		priv->shell = NULL;
-	}
-
 	if (priv->shell_view_class != NULL) {
 		g_type_class_unref (priv->shell_view_class);
 		priv->shell_view_class = NULL;
 	}
 
 	/* Chain up to parent's dispose() method. */
-	G_OBJECT_CLASS (parent_class)->dispose (object);
+	G_OBJECT_CLASS (e_shell_backend_parent_class)->dispose (object);
 }
 
 static void
@@ -150,7 +117,7 @@ shell_backend_finalize (GObject *object)
 	g_free (priv->data_dir);
 
 	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	G_OBJECT_CLASS (e_shell_backend_parent_class)->finalize (object);
 }
 
 static const gchar *
@@ -195,39 +162,25 @@ shell_backend_get_data_dir (EShellBackend *shell_backend)
 }
 
 static void
-shell_backend_class_init (EShellBackendClass *class)
+e_shell_backend_class_init (EShellBackendClass *class)
 {
 	GObjectClass *object_class;
+	EExtensionClass *extension_class;
 
-	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (EShellBackendPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
-	object_class->set_property = shell_backend_set_property;
-	object_class->get_property = shell_backend_get_property;
+	object_class->constructor = shell_backend_constructor;
 	object_class->dispose = shell_backend_dispose;
 	object_class->finalize = shell_backend_finalize;
 
+	extension_class = E_EXTENSION_CLASS (class);
+	extension_class->extensible_type = E_TYPE_SHELL;
+
 	class->get_config_dir = shell_backend_get_config_dir;
 	class->get_data_dir = shell_backend_get_data_dir;
 
 	/**
-	 * EShellBackend:shell
-	 *
-	 * The #EShell singleton.
-	 **/
-	g_object_class_install_property (
-		object_class,
-		PROP_SHELL,
-		g_param_spec_object (
-			"shell",
-			_("Shell"),
-			_("The EShell singleton"),
-			E_TYPE_SHELL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT_ONLY));
-
-	/**
 	 * EShellBackend::activity-added
 	 * @shell_backend: the #EShellBackend that emitted the signal
 	 * @activity: an #EActivity
@@ -245,44 +198,9 @@ shell_backend_class_init (EShellBackendClass *class)
 }
 
 static void
-shell_backend_init (EShellBackend *shell_backend,
-                    EShellBackendClass *class)
+e_shell_backend_init (EShellBackend *shell_backend)
 {
-	EShellViewClass *shell_view_class;
-
 	shell_backend->priv = E_SHELL_BACKEND_GET_PRIVATE (shell_backend);
-
-	/* Install a reference to ourselves in the corresponding
-	 * EShellViewClass structure, */
-	shell_view_class = g_type_class_ref (class->shell_view_type);
-	shell_view_class->shell_backend = g_object_ref (shell_backend);
-	shell_backend->priv->shell_view_class = shell_view_class;
-}
-
-GType
-e_shell_backend_get_type (void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0)) {
-		const GTypeInfo type_info = {
-			sizeof (EShellBackendClass),
-			(GBaseInitFunc) NULL,
-			(GBaseFinalizeFunc) NULL,
-			(GClassInitFunc) shell_backend_class_init,
-			(GClassFinalizeFunc) NULL,
-			NULL,  /* class_data */
-			sizeof (EShellBackend),
-			0,     /* n_preallocs */
-			(GInstanceInitFunc) shell_backend_init,
-			NULL   /* value_table */
-		};
-
-		type = g_type_register_static (
-			G_TYPE_OBJECT, "EShellBackend", &type_info, 0);
-	}
-
-	return type;
 }
 
 /**
@@ -364,9 +282,13 @@ e_shell_backend_get_data_dir (EShellBackend *shell_backend)
 EShell *
 e_shell_backend_get_shell (EShellBackend *shell_backend)
 {
+	EExtensible *extensible;
+
 	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
 
-	return E_SHELL (shell_backend->priv->shell);
+	extensible = e_extension_get_extensible (E_EXTENSION (shell_backend));
+
+	return E_SHELL (extensible);
 }
 
 /**
diff --git a/shell/e-shell-backend.h b/shell/e-shell-backend.h
index df4abc8..055a2a3 100644
--- a/shell/e-shell-backend.h
+++ b/shell/e-shell-backend.h
@@ -24,6 +24,7 @@
 
 #include <shell/e-shell-common.h>
 #include <e-util/e-activity.h>
+#include <e-util/e-extension.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SHELL_BACKEND \
@@ -60,7 +61,7 @@ typedef struct _EShellBackendPrivate EShellBackendPrivate;
  * functions below.
  **/
 struct _EShellBackend {
-	GObject parent;
+	EExtension parent;
 	EShellBackendPrivate *priv;
 };
 
@@ -94,7 +95,7 @@ struct _EShellBackend {
  * #EShellBackendClass contains a number of important settings for subclasses.
  **/
 struct _EShellBackendClass {
-	GObjectClass parent_class;
+	EExtensionClass parent_class;
 
 	GType shell_view_type;
 
diff --git a/shell/e-shell.c b/shell/e-shell.c
index c9dfd15..f877bca 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -52,7 +52,7 @@ struct _EShellPrivate {
 	GtkWidget *preferences_window;
 
 	/* Shell Backends */
-	GList *loaded_backends;
+	GList *loaded_backends;              /* not referenced */
 	GHashTable *backends_by_name;
 	GHashTable *backends_by_scheme;
 
@@ -407,23 +407,14 @@ shell_split_and_insert_items (GHashTable *hash_table,
 }
 
 static void
-shell_add_backend (GType type,
-                   EShell *shell)
+shell_process_backend (EShellBackend *shell_backend,
+                       EShell *shell)
 {
 	EShellBackendClass *class;
-	EShellBackend *shell_backend;
 	GHashTable *backends_by_name;
 	GHashTable *backends_by_scheme;
 	const gchar *string;
 
-	shell_backend = g_object_new (type, "shell", shell, NULL);
-
-	shell->priv->loaded_backends = g_list_insert_sorted (
-		shell->priv->loaded_backends, shell_backend,
-		(GCompareFunc) e_shell_backend_compare);
-
-	/* Bookkeeping */
-
 	class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
 	backends_by_name = shell->priv->backends_by_name;
 	backends_by_scheme = shell->priv->backends_by_scheme;
@@ -601,10 +592,6 @@ shell_dispose (GObject *object)
 		priv->preferences_window = NULL;
 	}
 
-	g_list_foreach (priv->loaded_backends, (GFunc) g_object_unref, NULL);
-	g_list_free (priv->loaded_backends);
-	priv->loaded_backends = NULL;
-
 	if (priv->preparing_for_line_change != NULL) {
 		g_object_remove_weak_pointer (
 			G_OBJECT (priv->preparing_for_line_change),
@@ -629,6 +616,8 @@ shell_finalize (GObject *object)
 	if (!unique_app_is_running (UNIQUE_APP (object)))
 		e_file_lock_destroy ();
 
+	g_list_free (priv->loaded_backends);
+
 	g_free (priv->geometry);
 	g_free (priv->module_directory);
 
@@ -640,6 +629,7 @@ static void
 shell_constructed (GObject *object)
 {
 	EShellPrivate *priv;
+	GList *list;
 
 	priv = E_SHELL_GET_PRIVATE (object);
 
@@ -659,11 +649,13 @@ shell_constructed (GObject *object)
 
 	shell_load_modules (E_SHELL (object));
 
-	e_type_traverse (
-		E_TYPE_SHELL_BACKEND, (ETypeFunc)
-		shell_add_backend, object);
-
-	e_extensible_load_extensions (E_EXTENSIBLE (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;
 }
 
 static UniqueResponse



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