aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-extension.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2010-03-20 05:18:19 +0800
committerMichael Meeks <michael.meeks@novell.com>2010-04-07 19:08:59 +0800
commit3fb2b21c08556d04770fb585ca303c4044e3c9bc (patch)
tree66fe4b4cdf90092147d508a02f7075863cee9662 /e-util/e-extension.c
parent4cc6bd4673115dff52a403d31e9613deea402d0e (diff)
downloadgsoc2013-evolution-3fb2b21c08556d04770fb585ca303c4044e3c9bc.tar.gz
gsoc2013-evolution-3fb2b21c08556d04770fb585ca303c4044e3c9bc.tar.zst
gsoc2013-evolution-3fb2b21c08556d04770fb585ca303c4044e3c9bc.zip
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.
Diffstat (limited to 'e-util/e-extension.c')
-rw-r--r--e-util/e-extension.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/e-util/e-extension.c b/e-util/e-extension.c
new file mode 100644
index 0000000000..05687b64ba
--- /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);
+}