[evolution] Introduce a simple extension system for objects.



commit 84feab41bb9aae3362414ee818139a149a705903
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Mar 19 17:18:19 2010 -0400

    Introduce a simple extension system for objects.
    
    This introduces a simple means of extending Evolution objects.
    
    Any GObject subclass wishing to be extensible need only call
    
       g_type_add_interface_static (type, E_TYPE_EXTENSIBLE, NULL);
    
    when registering its GType, and then at some point during initialization
    call e_extensible_load_extensions() to load extensions for that subclass.
    
    Extensions are implemented by subclassing EExtension, setting the GType
    being extended in EExtensionClass, and making sure its own GType gets
    registered at startup.  This usually done while loading a GTypeModule.
    
    e_extension_get_extensible() provides extensions access to the object
    being extended.

 e-util/Makefile.am    |    4 +
 e-util/e-extensible.c |  112 ++++++++++++++++++++++++++++++++++
 e-util/e-extensible.h |   57 +++++++++++++++++
 e-util/e-extension.c  |  160 +++++++++++++++++++++++++++++++++++++++++++++++++
 e-util/e-extension.h  |   67 ++++++++++++++++++++
 5 files changed, 400 insertions(+), 0 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 7384333..99f873c 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -25,6 +25,8 @@ eutilinclude_HEADERS = 				\
 	e-dialog-utils.h			\
 	e-dialog-widgets.h			\
 	e-event.h				\
+	e-extensible.h				\
+	e-extension.h				\
 	e-file-utils.h				\
 	e-folder-map.h				\
 	e-html-utils.h				\
@@ -103,6 +105,8 @@ libeutil_la_SOURCES =				\
 	e-dialog-utils.c			\
 	e-dialog-widgets.c			\
 	e-event.c				\
+	e-extensible.c				\
+	e-extension.c				\
 	e-file-utils.c				\
 	e-folder-map.c				\
 	e-html-utils.c				\
diff --git a/e-util/e-extensible.c b/e-util/e-extensible.c
new file mode 100644
index 0000000..9960d31
--- /dev/null
+++ b/e-util/e-extensible.c
@@ -0,0 +1,112 @@
+/*
+ * e-extensible.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-extensible.h"
+
+#include <e-util/e-util.h>
+#include <e-util/e-extension.h>
+
+static GQuark extensible_quark;
+
+static GPtrArray *
+extensible_get_extensions (EExtensible *extensible)
+{
+	return g_object_get_qdata (G_OBJECT (extensible), extensible_quark);
+}
+
+static void
+extensible_load_extension (GType extension_type,
+                           EExtensible *extensible)
+{
+	EExtensionClass *extension_class;
+	GType extensible_type;
+	GPtrArray *extensions;
+	EExtension *extension;
+
+	extensible_type = G_OBJECT_TYPE (extensible);
+	extension_class = g_type_class_ref (extension_type);
+
+	/* Only load extensions that extend the given extensible object. */
+	if (!g_type_is_a (extensible_type, extension_class->extensible_type))
+		goto exit;
+
+	extension = g_object_new (
+		extension_type, "extensible", extensible, NULL);
+
+	extensions = extensible_get_extensions (extensible);
+	g_ptr_array_add (extensions, extension);
+
+exit:
+	g_type_class_unref (extension_class);
+}
+
+static void
+extensible_interface_init (EExtensibleInterface *interface)
+{
+	extensible_quark = g_quark_from_static_string ("e-extensible-quark");
+}
+
+GType
+e_extensible_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EExtensibleInterface),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) extensible_interface_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			0,     /* instance_size */
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_INTERFACE, "EExtensible", &type_info, 0);
+
+		g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+	}
+
+	return type;
+}
+
+void
+e_extensible_load_extensions (EExtensible *extensible)
+{
+	GPtrArray *extensions;
+
+	g_return_if_fail (E_IS_EXTENSIBLE (extensible));
+
+	if (extensible_get_extensions (extensible) != NULL)
+		return;
+
+	extensions = g_ptr_array_new_with_free_func (
+		(GDestroyNotify) g_object_unref);
+
+	g_object_set_qdata_full (
+		G_OBJECT (extensible), extensible_quark,
+		extensions, (GDestroyNotify) g_ptr_array_unref);
+
+	e_type_traverse (
+		E_TYPE_EXTENSION, (ETypeFunc)
+		extensible_load_extension, extensible);
+}
diff --git a/e-util/e-extensible.h b/e-util/e-extensible.h
new file mode 100644
index 0000000..a72ea71
--- /dev/null
+++ b/e-util/e-extensible.h
@@ -0,0 +1,57 @@
+/*
+ * e-extensible.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_EXTENSIBLE_H
+#define E_EXTENSIBLE_H
+
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EXTENSIBLE \
+	(e_extensible_get_type ())
+#define E_EXTENSIBLE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_EXTENSIBLE, EExtensible))
+#define E_EXTENSIBLE_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_EXTENSIBLE, EExtensibleInterface))
+#define E_IS_EXTENSIBLE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_EXTENSIBLE))
+#define E_IS_EXTENSIBLE_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_EXTENSIBLE))
+#define E_EXTENSIBLE_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_EXTENSIBLE, EExtensibleInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _EExtensible EExtensible;
+typedef struct _EExtensibleInterface EExtensibleInterface;
+
+struct _EExtensibleInterface {
+	GTypeInterface parent_interface;
+};
+
+GType		e_extensible_get_type		(void);
+void		e_extensible_load_extensions	(EExtensible *extensible);
+
+G_END_DECLS
+
+#endif /* E_EXTENSIBLE_H */
diff --git a/e-util/e-extension.c b/e-util/e-extension.c
new file mode 100644
index 0000000..05687b6
--- /dev/null
+++ b/e-util/e-extension.c
@@ -0,0 +1,160 @@
+/*
+ * e-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-extension.h"
+
+#define E_EXTENSION_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_EXTENSION, EExtensionPrivate))
+
+struct _EExtensionPrivate {
+	gpointer extensible;  /* weak pointer */
+};
+
+enum {
+	PROP_0,
+	PROP_EXTENSIBLE
+};
+
+G_DEFINE_ABSTRACT_TYPE (EExtension, e_extension, G_TYPE_OBJECT)
+
+static void
+extension_set_extensible (EExtension *extension,
+                          EExtensible *extensible)
+{
+	EExtensionClass *class;
+	GType extensible_type;
+
+	g_return_if_fail (E_IS_EXTENSIBLE (extensible));
+	g_return_if_fail (extension->priv->extensible == NULL);
+
+	class = E_EXTENSION_GET_CLASS (extension);
+	extensible_type = G_OBJECT_TYPE (extensible);
+
+	/* Verify the EExtensible object is the type we want. */
+	if (!g_type_is_a (extensible_type, class->extensible_type)) {
+		g_warning ("%s is meant to extend %s but was given an %s",
+			G_OBJECT_TYPE_NAME (extension),
+			g_type_name (class->extensible_type),
+			g_type_name (extensible_type));
+		return;
+	}
+
+	extension->priv->extensible = extensible;
+
+	g_object_add_weak_pointer (
+		G_OBJECT (extensible), &extension->priv->extensible);
+}
+
+static void
+extension_set_property (GObject *object,
+                        guint property_id,
+                        const GValue *value,
+                        GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_EXTENSIBLE:
+			extension_set_extensible (
+				E_EXTENSION (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+extension_get_property (GObject *object,
+                        guint property_id,
+                        GValue *value,
+                        GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_EXTENSIBLE:
+			g_value_set_object (
+				value, e_extension_get_extensible (
+				E_EXTENSION (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+extension_constructed (GObject *object)
+{
+	/* This allows subclasses to chain up safely since GObject
+	 * does not implement this method, and we might want to do
+	 * something here in the future. */
+}
+
+static void
+extension_dispose (GObject *object)
+{
+	EExtensionPrivate *priv;
+
+	priv = E_EXTENSION_GET_PRIVATE (object);
+
+	if (priv->extensible != NULL) {
+		g_object_remove_weak_pointer (
+			G_OBJECT (priv->extensible), &priv->extensible);
+		priv->extensible = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_extension_parent_class)->dispose (object);
+}
+
+static void
+e_extension_class_init (EExtensionClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (EExtensionPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = extension_set_property;
+	object_class->get_property = extension_get_property;
+	object_class->constructed = extension_constructed;
+	object_class->dispose = extension_dispose;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_EXTENSIBLE,
+		g_param_spec_object (
+			"extensible",
+			"Extensible Object",
+			"The object being extended",
+			E_TYPE_EXTENSIBLE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_extension_init (EExtension *extension)
+{
+	extension->priv = E_EXTENSION_GET_PRIVATE (extension);
+}
+
+EExtensible *
+e_extension_get_extensible (EExtension *extension)
+{
+	g_return_val_if_fail (E_IS_EXTENSION (extension), NULL);
+
+	return E_EXTENSIBLE (extension->priv->extensible);
+}
diff --git a/e-util/e-extension.h b/e-util/e-extension.h
new file mode 100644
index 0000000..905ef41
--- /dev/null
+++ b/e-util/e-extension.h
@@ -0,0 +1,67 @@
+/*
+ * e-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_EXTENSION_H
+#define E_EXTENSION_H
+
+#include <glib-object.h>
+#include <e-util/e-extensible.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EXTENSION \
+	(e_extension_get_type ())
+#define E_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_EXTENSION, EExtension))
+#define E_EXTENSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_EXTENSION, EExtensionClass))
+#define E_IS_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_EXTENSION))
+#define E_IS_EXTENSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_EXTENSION))
+#define E_EXTENSION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_EXTENSION, EExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EExtension EExtension;
+typedef struct _EExtensionClass EExtensionClass;
+typedef struct _EExtensionPrivate EExtensionPrivate;
+
+struct _EExtension {
+	GObject parent;
+	EExtensionPrivate *priv;
+};
+
+struct _EExtensionClass {
+	GObjectClass parent_class;
+
+	/* The type to extend. */
+	GType extensible_type;
+};
+
+GType		e_extension_get_type		(void);
+EExtensible *	e_extension_get_extensible	(EExtension *extension);
+
+G_END_DECLS
+
+#endif /* E_EXTENSION_H */



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