[evolution-data-server] Add EModule.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Add EModule.
- Date: Mon, 26 Sep 2011 13:47:00 +0000 (UTC)
commit e512211da51071b88d418d7698e59b06b4f6ad38
Author: Matthew Barnes <mbarnes redhat com>
Date: Wed Sep 7 16:24:07 2011 -0400
Add EModule.
Copied from Evolution's libeutil.
docs/reference/libebackend/libebackend-docs.xml | 1 +
.../reference/libebackend/libebackend-sections.txt | 22 ++
docs/reference/libebackend/libebackend.types | 2 +
docs/reference/libebackend/tmpl/e-module.sgml | 79 +++++
libebackend/Makefile.am | 2 +
libebackend/e-module.c | 364 ++++++++++++++++++++
libebackend/e-module.h | 91 +++++
7 files changed, 561 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/libebackend/libebackend-docs.xml b/docs/reference/libebackend/libebackend-docs.xml
index acbdff2..8fcf57c 100644
--- a/docs/reference/libebackend/libebackend-docs.xml
+++ b/docs/reference/libebackend/libebackend-docs.xml
@@ -10,6 +10,7 @@
<chapter>
<title>Evolution-Data-Server Manual: Backend Utilities (libebackend)</title>
+ <xi:include href="xml/e-module.xml"/>
<xi:include href="xml/e-file-cache.xml"/>
<xi:include href="xml/e-dbhash.xml"/>
<xi:include href="xml/e-db3-utils.xml"/>
diff --git a/docs/reference/libebackend/libebackend-sections.txt b/docs/reference/libebackend/libebackend-sections.txt
index 0154510..0ef3e13 100644
--- a/docs/reference/libebackend/libebackend-sections.txt
+++ b/docs/reference/libebackend/libebackend-sections.txt
@@ -50,6 +50,28 @@ e_db3_utils_upgrade_format
</SECTION>
<SECTION>
+<FILE>e-module</FILE>
+<TITLE>EModule</TITLE>
+EModule
+e_module_new
+e_module_get_filename
+e_module_load_all_in_directory
+ETypeFunc
+e_type_traverse
+<SUBSECTION Standard>
+E_MODULE
+E_IS_MODULE
+E_TYPE_MODULE
+E_MODULE_CLASS
+E_IS_MODULE_CLASS
+E_MODULE_GET_CLASS
+EModuleClass
+<SUBSECTION Private>
+EModulePrivate
+e_module_get_type
+</SECTION>
+
+<SECTION>
<FILE>e-offline-listener</FILE>
<TITLE>EOfflineListener</TITLE>
EOfflineListenerState
diff --git a/docs/reference/libebackend/libebackend.types b/docs/reference/libebackend/libebackend.types
index 2e4baa0..4a0207b 100644
--- a/docs/reference/libebackend/libebackend.types
+++ b/docs/reference/libebackend/libebackend.types
@@ -1,5 +1,7 @@
#include <libebackend/e-file-cache.h>
+#include <libebackend/e-module.h>
#include <libebackend/e-offline-listener.h>
e_file_cache_get_type
+e_module_get_type
e_offline_listener_get_type
diff --git a/docs/reference/libebackend/tmpl/e-module.sgml b/docs/reference/libebackend/tmpl/e-module.sgml
new file mode 100644
index 0000000..e74099b
--- /dev/null
+++ b/docs/reference/libebackend/tmpl/e-module.sgml
@@ -0,0 +1,79 @@
+<!-- ##### SECTION Title ##### -->
+EModule
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT EModule ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG EModule:filename ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION e_module_new ##### -->
+<para>
+
+</para>
+
+ filename:
+ Returns:
+
+
+<!-- ##### FUNCTION e_module_get_filename ##### -->
+<para>
+
+</para>
+
+ module:
+ Returns:
+
+
+<!-- ##### FUNCTION e_module_load_all_in_directory ##### -->
+<para>
+
+</para>
+
+ dirname:
+ Returns:
+
+
+<!-- ##### USER_FUNCTION ETypeFunc ##### -->
+<para>
+
+</para>
+
+ type:
+ user_data:
+
+
+<!-- ##### FUNCTION e_type_traverse ##### -->
+<para>
+
+</para>
+
+ parent_type:
+ func:
+ user_data:
+
+
diff --git a/libebackend/Makefile.am b/libebackend/Makefile.am
index 91d4518..604fffd 100644
--- a/libebackend/Makefile.am
+++ b/libebackend/Makefile.am
@@ -12,6 +12,7 @@ libebackend_1_2_la_SOURCES = \
e-offline-listener.c \
e-dbhash.c \
e-db3-utils.c \
+ e-module.c \
e-sqlite3-vfs.c \
e-file-cache.c
@@ -30,6 +31,7 @@ libebackendinclude_HEADERS = \
e-offline-listener.h \
e-db3-utils.h \
e-dbhash.h \
+ e-module.h \
e-sqlite3-vfs.h \
e-file-cache.h
diff --git a/libebackend/e-module.c b/libebackend/e-module.c
new file mode 100644
index 0000000..6d10d9a
--- /dev/null
+++ b/libebackend/e-module.c
@@ -0,0 +1,364 @@
+/*
+ * e-module.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/>
+ *
+ */
+
+/**
+ * SECTION: e-module
+ * @short_description: a module loader
+ * @include: libebackend/e-module.h
+ **/
+
+#include "e-module.h"
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+/* This is the symbol we call when loading a module. */
+#define LOAD_SYMBOL "e_module_load"
+
+/* This is the symbol we call when unloading a module. */
+#define UNLOAD_SYMBOL "e_module_unload"
+
+struct _EModulePrivate {
+ GModule *module;
+ gchar *filename;
+
+ void (*load) (GTypeModule *type_module);
+ void (*unload) (GTypeModule *type_module);
+};
+
+enum {
+ PROP_0,
+ PROP_FILENAME
+};
+
+G_DEFINE_TYPE (
+ EModule,
+ e_module,
+ G_TYPE_TYPE_MODULE)
+
+static void
+module_set_filename (EModule *module,
+ const gchar *filename)
+{
+ g_return_if_fail (module->priv->filename == NULL);
+
+ module->priv->filename = g_strdup (filename);
+}
+
+static void
+module_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILENAME:
+ module_set_filename (
+ E_MODULE (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+module_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILENAME:
+ g_value_set_string (
+ value, e_module_get_filename (
+ E_MODULE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+module_finalize (GObject *object)
+{
+ EModulePrivate *priv;
+
+ priv = E_MODULE (object)->priv;
+
+ g_free (priv->filename);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_module_parent_class)->finalize (object);
+}
+
+static gboolean
+module_load (GTypeModule *type_module)
+{
+ EModulePrivate *priv;
+ gpointer symbol;
+
+ priv = E_MODULE (type_module)->priv;
+
+ g_return_val_if_fail (priv->filename != NULL, FALSE);
+ priv->module = g_module_open (priv->filename, 0);
+
+ if (priv->module == NULL)
+ goto fail;
+
+ if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol))
+ goto fail;
+
+ priv->load = symbol;
+
+ if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol))
+ goto fail;
+
+ priv->unload = symbol;
+
+ priv->load (type_module);
+
+ /* XXX This is a Band-Aid for a design flaw in EExtension. If the
+ * "extensible_type" member of EExtensionClass is set to a GType
+ * that hasn't already been registered, then when the extension's
+ * module is unloaded the GType registration that was triggered
+ * by setting "extensible_type" will be invalidated and cause
+ * Evolution to malfunction when the module is loaded again.
+ *
+ * Extension modules get loaded and unloaded repeatedly by
+ * e_extensible_load_extensions(), which temporarily references
+ * all extension classes and picks out the ones it needs for a
+ * given EExtensible instance based on the "extensible_type"
+ * class member.
+ *
+ * Making the module resident prevents the aforementioned GType
+ * registration from being invalidated when the extension class
+ * is unreferenced.
+ */
+ g_module_make_resident (priv->module);
+
+ return TRUE;
+
+fail:
+ g_warning ("%s", g_module_error ());
+
+ if (priv->module != NULL)
+ g_module_close (priv->module);
+
+ return FALSE;
+}
+
+static void
+module_unload (GTypeModule *type_module)
+{
+ EModulePrivate *priv;
+
+ priv = E_MODULE (type_module)->priv;
+
+ priv->unload (type_module);
+
+ g_module_close (priv->module);
+ priv->module = NULL;
+
+ priv->load = NULL;
+ priv->unload = NULL;
+}
+
+static void
+e_module_class_init (EModuleClass *class)
+{
+ GObjectClass *object_class;
+ GTypeModuleClass *type_module_class;
+
+ g_type_class_add_private (class, sizeof (EModulePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = module_set_property;
+ object_class->get_property = module_get_property;
+ object_class->finalize = module_finalize;
+
+ type_module_class = G_TYPE_MODULE_CLASS (class);
+ type_module_class->load = module_load;
+ type_module_class->unload = module_unload;
+
+ /**
+ * EModule:filename
+ *
+ * The filename of the module.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_FILENAME,
+ g_param_spec_string (
+ "filename",
+ "Filename",
+ "The filename of the module",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_module_init (EModule *module)
+{
+ module->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ module, E_TYPE_MODULE, EModulePrivate);
+}
+
+/**
+ * e_module_new:
+ * @filename: filename of the shared library module
+ *
+ * Creates a new #EModule that will load the specific shared library
+ * when in use.
+ *
+ * Returns: a new #EModule for @filename
+ *
+ * Since: 3.4
+ **/
+EModule *
+e_module_new (const gchar *filename)
+{
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ return g_object_new (E_TYPE_MODULE, "filename", filename, NULL);
+}
+
+/**
+ * e_module_get_filename:
+ * @module: an #EModule
+ *
+ * Returns the filename of the shared library for @module. The
+ * string is owned by @module and should not be modified or freed.
+ *
+ * Returns: the filename for @module
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_module_get_filename (EModule *module)
+{
+ g_return_val_if_fail (E_IS_MODULE (module), NULL);
+
+ return module->priv->filename;
+}
+
+/**
+ * e_module_load_all_in_directory:
+ * @dirname: pathname for a directory containing modules to load
+ *
+ * Loads all the modules in the specified directory into memory. If
+ * you want to unload them (enabling on-demand loading) you must call
+ * g_type_module_unuse() on all the modules. Free the returned list
+ * with g_list_free().
+ *
+ * Returns: a list of #EModules loaded from @dirname
+ *
+ * Since: 3.4
+ **/
+GList *
+e_module_load_all_in_directory (const gchar *dirname)
+{
+ GDir *dir;
+ const gchar *basename;
+ GList *loaded_modules = NULL;
+ GError *error = NULL;
+
+ g_return_val_if_fail (dirname != NULL, NULL);
+
+ if (!g_module_supported ())
+ return NULL;
+
+ dir = g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ EModule *module;
+ gchar *filename;
+
+ if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX))
+ continue;
+
+ filename = g_build_filename (dirname, basename, NULL);
+
+ module = e_module_new (filename);
+
+ if (!g_type_module_use (G_TYPE_MODULE (module))) {
+ g_printerr ("Failed to load module: %s\n", filename);
+ g_object_unref (module);
+ g_free (filename);
+ continue;
+ }
+
+ g_free (filename);
+
+ loaded_modules = g_list_prepend (loaded_modules, module);
+ }
+
+ g_dir_close (dir);
+
+ return loaded_modules;
+}
+
+/**
+ * e_type_traverse:
+ * @parent_type: the root #GType to traverse from
+ * @func: the function to call for each visited #GType
+ * @user_data: user data to pass to the function
+ *
+ * Calls @func for all instantiable subtypes of @parent_type.
+ *
+ * This is often useful for extending functionality by way of #EModule.
+ * A module may register a subtype of @parent_type in its e_module_load()
+ * function. Then later on the application will call e_type_traverse()
+ * to instantiate all registered subtypes of @parent_type.
+ *
+ * Since: 3.4
+ **/
+void
+e_type_traverse (GType parent_type,
+ ETypeFunc func,
+ gpointer user_data)
+{
+ GType *children;
+ guint n_children, ii;
+
+ g_return_if_fail (func != NULL);
+
+ children = g_type_children (parent_type, &n_children);
+
+ for (ii = 0; ii < n_children; ii++) {
+ GType type = children[ii];
+
+ /* Recurse over the child's children. */
+ e_type_traverse (type, func, user_data);
+
+ /* Skip abstract types. */
+ if (G_TYPE_IS_ABSTRACT (type))
+ continue;
+
+ func (type, user_data);
+ }
+
+ g_free (children);
+}
+
diff --git a/libebackend/e-module.h b/libebackend/e-module.h
new file mode 100644
index 0000000..2700ac1
--- /dev/null
+++ b/libebackend/e-module.h
@@ -0,0 +1,91 @@
+/*
+ * e-module.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_MODULE_H
+#define E_MODULE_H
+
+#include <gmodule.h>
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MODULE \
+ (e_module_get_type ())
+#define E_MODULE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MODULE, EModule))
+#define E_MODULE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MODULE, EModuleClass))
+#define E_IS_MODULE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MODULE))
+#define E_IS_MODULE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MODULE))
+#define E_MODULE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MODULE, EModuleClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EModule EModule;
+typedef struct _EModuleClass EModuleClass;
+typedef struct _EModulePrivate EModulePrivate;
+
+/**
+ * EModule:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _EModule {
+ GTypeModule parent;
+ EModulePrivate *priv;
+};
+
+struct _EModuleClass {
+ GTypeModuleClass parent_class;
+};
+
+GType e_module_get_type (void) G_GNUC_CONST;
+EModule * e_module_new (const gchar *filename);
+const gchar * e_module_get_filename (EModule *module);
+GList * e_module_load_all_in_directory (const gchar *dirname);
+
+/* This is here for lack of a better place for it. */
+
+/**
+ * ETypeFunc:
+ * @type: a #GType
+ * @user_data: user data passed to e_type_traverse()
+ *
+ * Specifies the type of functions passed to e_type_traverse().
+ *
+ * Since: 3.4
+ **/
+typedef void (*ETypeFunc) (GType type,
+ gpointer user_data);
+void e_type_traverse (GType parent_type,
+ ETypeFunc func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* E_MODULE_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]