diff options
-rw-r--r-- | e-util/Makefile.am | 4 | ||||
-rw-r--r-- | e-util/e-extensible.c | 112 | ||||
-rw-r--r-- | e-util/e-extensible.h | 57 | ||||
-rw-r--r-- | e-util/e-extension.c | 160 | ||||
-rw-r--r-- | 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 7384333452..99f873cbd8 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 0000000000..9960d31d9f --- /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 0000000000..a72ea71611 --- /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 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); +} diff --git a/e-util/e-extension.h b/e-util/e-extension.h new file mode 100644 index 0000000000..905ef412f3 --- /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 */ |