[evolution-data-server] Add EModule.



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]