[nautilus-actions] Define one test program for dynamic modules



commit 19bd842b47ade454292d6a739ddd10f697c98fd5
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sun Jan 16 01:22:49 2011 +0100

    Define one test program for dynamic modules

 ChangeLog                     |    6 +
 src/test/.gitignore           |    1 +
 src/test/Makefile.am          |   28 +++
 src/test/test-module-plugin.c |  280 ++++++++++++++++++++++++++
 src/test/test-module.c        |  447 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 762 insertions(+), 0 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 8f33df6..eb385e5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -25,6 +25,12 @@
 
 2011-01-15 Pierre Wieser <pwieser trychlos org>
 
+	* src/test/test-module.c:
+	* src/test/test-module-plugin.c: New files.
+
+	* src/test/.gitignore:
+	* src/test/Makefile.am: Updated accordingly.
+	 
 	* src/nact/nact-schemes-list.c: Remove gconf-client.h include.
 
 	* src/nact/base-iprefs.c
diff --git a/src/test/.gitignore b/src/test/.gitignore
index 8b89352..9fe4ee7 100644
--- a/src/test/.gitignore
+++ b/src/test/.gitignore
@@ -1,3 +1,4 @@
+test-module
 test-parse-uris
 test-reader
 test-virtuals
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 8d6d8d0..d297d48 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -38,6 +38,7 @@ AM_CPPFLAGS += \
 	-I $(top_srcdir)									\
 	-I $(top_srcdir)/src								\
 	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"			\
+	-DPKGLIBDIR=\""$(pkglibdir)"\"						\
 	-DG_LOG_DOMAIN=\"${NA_LOGDOMAIN_TEST}\"				\
 	$(NAUTILUS_ACTIONS_CFLAGS)							\
 	$(NULL)
@@ -65,6 +66,33 @@ test_iface_LDADD = \
 	$(NAUTILUS_ACTIONS_LIBS)							\
 	$(NULL)
 
+if NA_MAINTAINER_MODE
+noinst_PROGRAMS += test-module
+pkglib_LTLIBRARIES = libtest_module_plugin.la
+
+test_module_SOURCES = \
+	test-module.c										\
+	$(NULL)
+
+test_module_LDADD = \
+	$(NAUTILUS_ACTIONS_LIBS)							\
+	$(NULL)
+
+libtest_module_plugin_la_SOURCES = \
+	test-module-plugin.c								\
+	$(NULL)
+
+libtest_module_plugin_la_LIBADD = \
+	$(NAUTILUS_ACTIONS_LIBS)							\
+	$(NULL)
+
+libtest_module_plugin_la_LDFLAGS = \
+	-module 											\
+	-no-undefined										\
+	-avoid-version										\
+	$(NULL)
+endif
+
 test_parse_uris_SOURCES = \
 	test-parse-uris.c									\
 	$(NULL)
diff --git a/src/test/test-module-plugin.c b/src/test/test-module-plugin.c
new file mode 100755
index 0000000..c9f59c5
--- /dev/null
+++ b/src/test/test-module-plugin.c
@@ -0,0 +1,280 @@
+/*
+ * Nautilus-Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib-object.h>
+#include <gmodule.h>
+
+/* this is a plugin, i.e. a dynamically loaded resource
+ */
+
+G_MODULE_EXPORT const gchar *g_module_check_init( GModule *module );
+G_MODULE_EXPORT void         g_module_unload( GModule *module );
+
+#if 0
+/* this is first version
+ * the module is loaded, the function called, and then the module is unloaded
+ * note that we do not define any GType here, so do not provide any sort of
+ * GInterface implementation
+ *
+	(process:23911): NA-test-DEBUG: in g_module_check_init: module=0xf97f20
+	(process:23911): NA-test-DEBUG: say_hello: module=0xf97f20
+	(process:23911): NA-test-DEBUG: in g_module_unload: module=0xf97f20
+ *
+ */
+
+G_MODULE_EXPORT void         say_hello( GModule *module );
+
+/* automatically called when the module is loaded
+ */
+G_MODULE_EXPORT const gchar *
+g_module_check_init( GModule *module )
+{
+	const gchar *error;
+
+	error = NULL;
+	g_debug( "in g_module_check_init: module=%p", ( void * ) module );
+
+	return( error );
+}
+
+/* automatically called when the module is unloaded
+ */
+G_MODULE_EXPORT void
+g_module_unload( GModule *module )
+{
+	g_debug( "in g_module_unload: module=%p", ( void * ) module );
+}
+
+/* a function dynamically called from the program
+ */
+G_MODULE_EXPORT void
+say_hello( GModule *module )
+{
+	g_debug( "say_hello: module=%p", ( void * ) module );
+}
+#endif
+
+/* version 2
+ * define the module as a GTypeModule-derived one
+ */
+#define TEST_MODULE_PLUGIN_TYPE                 ( na_module_plugin_get_type())
+#define TEST_MODULE_PLUGIN( object )            ( G_TYPE_CHECK_INSTANCE_CAST( object, TEST_MODULE_PLUGIN_TYPE, NAModulePlugin ))
+#define TEST_MODULE_PLUGIN_CLASS( klass )       ( G_TYPE_CHECK_CLASS_CAST( klass, TEST_MODULE_PLUGIN_TYPE, NAModulePluginClass ))
+#define TEST_IS_MODULE_PLUGIN( object )         ( G_TYPE_CHECK_INSTANCE_TYPE( object, TEST_MODULE_PLUGIN_TYPE ))
+#define TEST_IS_MODULE_PLUGIN_CLASS( klass )    ( G_TYPE_CHECK_CLASS_TYPE(( klass ), TEST_MODULE_PLUGIN_TYPE ))
+#define TEST_MODULE_PLUGIN_GET_CLASS( object )  ( G_TYPE_INSTANCE_GET_CLASS(( object ), TEST_MODULE_PLUGIN_TYPE, NAModulePluginClass ))
+
+typedef struct _NAModulePluginPrivate           NAModulePluginPrivate;
+typedef struct _NAModulePluginClassPrivate      NAModulePluginClassPrivate;
+
+typedef struct {
+	GObject                parent;
+	NAModulePluginPrivate *private;
+}
+	NAModulePlugin;
+
+typedef struct {
+	GObjectClass                parent;
+	NAModulePluginClassPrivate *private;
+}
+	NAModulePluginClass;
+
+GType na_module_plugin_get_type( void );
+
+/* private instance data
+ */
+struct _NAModulePluginPrivate {
+	gboolean dispose_has_run;
+};
+
+/* private class data
+ */
+struct _NAModulePluginClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static GType             st_module_type = 0;
+static GTypeModuleClass *st_parent_class = NULL;
+
+static void           na_module_plugin_register_type( GTypeModule *module );
+static void class_init( NAModulePluginClass *klass );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *object );
+static void instance_finalize( GObject *object );
+
+G_MODULE_EXPORT void plugin_init( GTypeModule *module );
+
+GType
+na_module_plugin_get_type( void )
+{
+	return( st_module_type );
+}
+
+static void
+na_module_plugin_register_type( GTypeModule *module )
+{
+	static const gchar *thisfn = "na_module_plugin_register_type";
+
+	static GTypeInfo info = {
+		sizeof( NAModulePluginClass ),
+		NULL,
+		NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAModulePlugin ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	/*static const GInterfaceInfo iio_provider_iface_info = {
+		( GInterfaceInitFunc ) iio_provider_iface_init,
+		NULL,
+		NULL
+	};*/
+
+	g_debug( "%s", thisfn );
+
+	st_module_type = g_type_module_register_type( module, G_TYPE_OBJECT, "NAModulePlugin", &info, 0 );
+
+	/*g_type_module_add_interface( module, st_module_type, NA_IIO_PROVIDER_TYPE, &iio_provider_iface_info );*/
+}
+
+static void
+class_init( NAModulePluginClass *klass )
+{
+	static const gchar *thisfn = "na_module_plugin_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NAModulePluginClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_module_plugin_instance_init";
+	NAModulePlugin *self;
+
+	g_return_if_fail( TEST_IS_MODULE_PLUGIN( instance ));
+
+	g_debug( "%s: instance=%p (%s), klass=%p",
+			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
+
+	self = TEST_MODULE_PLUGIN( instance );
+
+	self->private = g_new0( NAModulePluginPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_module_plugin_instance_dispose";
+	NAModulePlugin *self;
+
+	g_return_if_fail( TEST_IS_MODULE_PLUGIN( object ));
+
+	self = TEST_MODULE_PLUGIN( object );
+
+	if( !self->private->dispose_has_run ){
+
+		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_test_module_plugin_instance_finalize";
+	NAModulePlugin *self;
+
+	g_return_if_fail( TEST_IS_MODULE_PLUGIN( object ));
+
+	g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+
+	self = TEST_MODULE_PLUGIN( object );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/* automatically called when the module is loaded
+ * this is very less useful in this version as we need a GTypeModule to register
+ * our dynamic types
+ */
+G_MODULE_EXPORT const gchar *
+g_module_check_init( GModule *module )
+{
+	g_debug( "in g_module_check_init: module=%p", ( void * ) module );
+	return( NULL );
+}
+
+/* automatically called when the module is unloaded
+ */
+G_MODULE_EXPORT void
+g_module_unload( GModule *module )
+{
+	g_debug( "in g_module_unload: module=%p", ( void * ) module );
+}
+
+/* module is actually a NAModule, but we do not care of that
+ * registering the type - but do not yet allocate an object
+ */
+G_MODULE_EXPORT void
+plugin_init( GTypeModule *module )
+{
+	g_debug( "plugin_init: module=%p", ( void * ) module );
+
+	na_module_plugin_register_type( module );
+}
diff --git a/src/test/test-module.c b/src/test/test-module.c
new file mode 100755
index 0000000..943f0a2
--- /dev/null
+++ b/src/test/test-module.c
@@ -0,0 +1,447 @@
+/*
+ * Nautilus-Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* this is a module to test how to use the GLib dynamic-loading functions
+ * it tries to load, then unload, a test-module-plugin.so plugin
+ *
+ * more specifically, I am interested on releasing allocated resources
+ */
+
+#include <stdlib.h>
+
+#include <glib-object.h>
+#include <gmodule.h>
+
+#define PLUGIN_NAME								"test_module_plugin"
+
+
+#if 0
+/* this is first version
+ */
+static GModule *load_plugin( void );
+static void     call_plugin_fn( GModule *module );
+static void     unload_plugin( GModule *module );
+
+int
+main( int argc, char **argv )
+{
+	GModule *module;
+
+	g_type_init();
+
+	/* dynamically load the module */
+	module = load_plugin();
+
+	if( module ){
+		/* call a function in the module */
+		call_plugin_fn( module );
+
+		/* unload the module */
+		unload_plugin( module );
+	}
+
+	return( 0 );
+}
+
+static GModule *
+load_plugin( void )
+{
+	gchar *module_path;
+	GModule *module;
+
+	module = NULL;
+
+	if( g_module_supported()){
+
+		module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
+		module = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
+		if( !module ){
+			g_printerr( "%s: %s\n", module_path, g_module_error());
+		}
+		g_free( module_path );
+	}
+
+	return( module );
+}
+
+static void
+call_plugin_fn( GModule *module )
+{
+	typedef void ( *PluginFn )( GModule *module );
+	PluginFn plugin_fn;
+
+	if( !g_module_symbol( module, "say_hello", ( gpointer * ) &plugin_fn )){
+		g_printerr( "%s\n", g_module_error());
+		return;
+	}
+	if( !plugin_fn ){
+		g_printerr( "%s\n", g_module_error());
+		return;
+	}
+	plugin_fn( module );
+}
+
+static void
+unload_plugin( GModule *module )
+{
+	if( !g_module_close( module )){
+		g_printerr( "%s\n", g_module_error());
+	}
+}
+#endif
+
+/* version 2
+ * Having the plugin register dynamic GTypes require a GTypeModule
+ * This GTtypeModule is provided by the program as a GTypeModule-derived object
+ * NAModule embeds the GModule
+ *
+ * Result:
+ *
+ * - the main program (the loader) should define a GTypeModule derived class
+ *
+ * - the GTypeModule derived class (here NAModule) embeds a GModule pointer
+ *
+ * - when loading plugins:
+ *
+ *   > allocate a new GTypeModule derived object for each module
+ *     setup the path here
+ *
+ *   > g_type_module_use() it
+ *     this triggers the on_load() virtual method on GTypeModule derived class
+ *       in on_load_derived(), g_module_open() the plugin and check the API
+ *
+ *       on_load_derived() may return FALSE
+ *       while dynamic types have not been registered, we are always safe to unref
+ *       the allocated GTypeModule derived object
+ *       setup the GModule pointer on the loaded library
+ *
+ *     so, if g_module_use() returns FALSE, just unref the object
+ *
+ *     so, g_module_use() cannot be called from instance_init or
+ *     instance_constructed (which have no return value)
+ *
+ * At the end, it is impossible to release the GTypeModule objects.
+ * But we can safely unuse their loaded libraries.
+ *
+ * The main program does not known which GType or GInterface the plugin
+ * declares.
+ * Nautilus defines a get_types() API, and then allocates an object for each
+ * returned type. It is then easy to check if the object implements a given
+ * interface.
+ * Nautilus never release these objects.
+ * We may also ask the plugin to just allocate itself its own management object,
+ * returning it to the program (returning a pointer is possible because we are
+ * in the same process).
+ */
+
+#define NA_MODULE_TYPE                  ( na_module_get_type())
+#define NA_MODULE( object )             ( G_TYPE_CHECK_INSTANCE_CAST( object, NA_MODULE_TYPE, NAModule ))
+#define NA_MODULE_CLASS( klass )        ( G_TYPE_CHECK_CLASS_CAST( klass, NA_MODULE_TYPE, NAModuleClass ))
+#define NA_IS_MODULE( object )          ( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_MODULE_TYPE ))
+#define NA_IS_MODULE_CLASS( klass )     ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_MODULE_TYPE ))
+#define NA_MODULE_GET_CLASS( object )   ( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_MODULE_TYPE, NAModuleClass ))
+
+typedef struct _NAModulePrivate         NAModulePrivate;
+typedef struct _NAModuleClassPrivate    NAModuleClassPrivate;
+
+typedef struct {
+	/*< private >*/
+	GTypeModule      parent;
+	NAModulePrivate *private;
+}
+	NAModule;
+
+typedef struct {
+	/*< private >*/
+	GTypeModuleClass      parent;
+	NAModuleClassPrivate *private;
+}
+	NAModuleClass;
+
+GType    na_module_get_type               ( void );
+
+/* private class data
+ */
+struct _NAModuleClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct _NAModulePrivate {
+	gboolean  dispose_has_run;
+	GModule  *plugin;
+};
+
+static GTypeModuleClass *st_parent_class = NULL;
+
+static GType     register_type( void );
+static void      class_init( NAModuleClass *klass );
+static void      instance_init( GTypeInstance *instance, gpointer klass );
+static void      instance_dispose( GObject *object );
+static void      instance_finalize( GObject *object );
+
+static NAModule *load_plugin( void );
+static gboolean  on_module_load( GTypeModule *module );
+static void      call_plugin_fn( NAModule *module );
+static void      on_unload_plugin( GTypeModule *module );
+
+GType
+na_module_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_module_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NAModuleClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAModule ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_TYPE_MODULE, "NAModule", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( NAModuleClass *klass )
+{
+	static const gchar *thisfn = "na_module_class_init";
+	GObjectClass *object_class;
+	GTypeModuleClass *module_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	module_class = G_TYPE_MODULE_CLASS( klass );
+	module_class->load = on_module_load;
+	module_class->unload = on_unload_plugin;
+
+	klass->private = g_new0( NAModuleClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_module_instance_init";
+	NAModule *self;
+
+	g_return_if_fail( NA_IS_MODULE( instance ));
+
+	g_debug( "%s: instance=%p (%s), klass=%p",
+			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
+
+	self = NA_MODULE( instance );
+
+	self->private = g_new0( NAModulePrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_module_instance_dispose";
+	NAModule *self;
+
+	g_return_if_fail( NA_IS_MODULE( object ));
+
+	self = NA_MODULE( object );
+
+	if( !self->private->dispose_has_run ){
+
+		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+
+		self->private->dispose_has_run = TRUE;
+
+		/* should trigger unload of the plugin */
+		/* refused by GLib
+		 * GLib-GObject-WARNING **: gtypemodule.c:111: unsolicitated invocation of g_object_dispose() on GTypeModule
+		 */
+		/*g_type_module_unuse( G_TYPE_MODULE( self ));*/
+
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_module_instance_finalize";
+	NAModule *self;
+
+	g_return_if_fail( NA_IS_MODULE( object ));
+
+	g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+
+	self = NA_MODULE( object );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+int
+main( int argc, char **argv )
+{
+	NAModule *module;
+
+	g_type_init();
+
+	/* dynamically load the module */
+	module = load_plugin();
+
+	if( module ){
+		/* call a function in the module */
+		call_plugin_fn( module );
+
+		/* try to just unref the NAModule */
+		/* not ok */
+		/*g_object_unref( module );*/
+
+		/* try to unload the plugin */
+		g_type_module_unuse( G_TYPE_MODULE( module ));
+		/* then unref the object */
+		/* not ok
+		 * it happens that releasing the GTypeModule after having registered a GType or a
+		 * GInterface is impossible
+		 * see http://git.gnome.org/browse/glib/tree/gobject/gtypemodule.c
+		 * and http://library.gnome.org/devel/gobject/unstable/GTypeModule.html#g-type-module-unuse
+		 */
+		/*g_object_unref( module );*/
+	}
+
+	return( 0 );
+}
+
+static NAModule *
+load_plugin( void )
+{
+	NAModule *module;
+
+	module = NULL;
+
+	if( g_module_supported()){
+
+		module = g_object_new( NA_MODULE_TYPE, NULL );
+		g_debug( "test_module_load_plugin: module=%p", ( void * ) module );
+
+		if( !g_type_module_use( G_TYPE_MODULE( module ))){
+			g_object_unref( module );
+		}
+	}
+
+	return( module );
+}
+
+static gboolean
+on_module_load( GTypeModule *module )
+{
+	gboolean ok;
+	gchar *module_path;
+	NAModule *na_module = NA_MODULE( module );
+
+	g_debug( "test_module_on_module_load" );
+
+	ok = TRUE;
+	module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
+
+	g_debug( "test_module_on_module_load: opening the library" );
+	na_module->private->plugin = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
+
+	if( !na_module->private->plugin ){
+		g_printerr( "%s: %s\n", module_path, g_module_error());
+		ok = FALSE;
+	}
+
+	g_free( module_path );
+
+	return( ok );
+}
+
+static void
+call_plugin_fn( NAModule *module )
+{
+	typedef void ( *PluginInit )( NAModule *module );
+	PluginInit plugin_fn;
+
+	if( !g_module_symbol( module->private->plugin, "plugin_init", ( gpointer * ) &plugin_fn )){
+		g_printerr( "%s\n", g_module_error());
+		return;
+	}
+	if( !plugin_fn ){
+		g_printerr( "%s\n", g_module_error());
+		return;
+	}
+	plugin_fn( module );
+}
+
+static void
+on_unload_plugin( GTypeModule *module )
+{
+	g_debug( "test_module_on_unload_plugin" );
+	if( !g_module_close( NA_MODULE( module )->private->plugin )){
+		g_printerr( "%s\n", g_module_error());
+	}
+}



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