Define new 'pivot-prop-loadable' property
[nautilus-actions.git] / src / test / test-module.c
blob943f0a21c95c887e7ed8fce2a73d58d16c05eea8
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 /* this is a module to test how to use the GLib dynamic-loading functions
36 * it tries to load, then unload, a test-module-plugin.so plugin
38 * more specifically, I am interested on releasing allocated resources
41 #include <stdlib.h>
43 #include <glib-object.h>
44 #include <gmodule.h>
46 #define PLUGIN_NAME "test_module_plugin"
49 #if 0
50 /* this is first version
52 static GModule *load_plugin( void );
53 static void call_plugin_fn( GModule *module );
54 static void unload_plugin( GModule *module );
56 int
57 main( int argc, char **argv )
59 GModule *module;
61 g_type_init();
63 /* dynamically load the module */
64 module = load_plugin();
66 if( module ){
67 /* call a function in the module */
68 call_plugin_fn( module );
70 /* unload the module */
71 unload_plugin( module );
74 return( 0 );
77 static GModule *
78 load_plugin( void )
80 gchar *module_path;
81 GModule *module;
83 module = NULL;
85 if( g_module_supported()){
87 module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
88 module = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
89 if( !module ){
90 g_printerr( "%s: %s\n", module_path, g_module_error());
92 g_free( module_path );
95 return( module );
98 static void
99 call_plugin_fn( GModule *module )
101 typedef void ( *PluginFn )( GModule *module );
102 PluginFn plugin_fn;
104 if( !g_module_symbol( module, "say_hello", ( gpointer * ) &plugin_fn )){
105 g_printerr( "%s\n", g_module_error());
106 return;
108 if( !plugin_fn ){
109 g_printerr( "%s\n", g_module_error());
110 return;
112 plugin_fn( module );
115 static void
116 unload_plugin( GModule *module )
118 if( !g_module_close( module )){
119 g_printerr( "%s\n", g_module_error());
122 #endif
124 /* version 2
125 * Having the plugin register dynamic GTypes require a GTypeModule
126 * This GTtypeModule is provided by the program as a GTypeModule-derived object
127 * NAModule embeds the GModule
129 * Result:
131 * - the main program (the loader) should define a GTypeModule derived class
133 * - the GTypeModule derived class (here NAModule) embeds a GModule pointer
135 * - when loading plugins:
137 * > allocate a new GTypeModule derived object for each module
138 * setup the path here
140 * > g_type_module_use() it
141 * this triggers the on_load() virtual method on GTypeModule derived class
142 * in on_load_derived(), g_module_open() the plugin and check the API
144 * on_load_derived() may return FALSE
145 * while dynamic types have not been registered, we are always safe to unref
146 * the allocated GTypeModule derived object
147 * setup the GModule pointer on the loaded library
149 * so, if g_module_use() returns FALSE, just unref the object
151 * so, g_module_use() cannot be called from instance_init or
152 * instance_constructed (which have no return value)
154 * At the end, it is impossible to release the GTypeModule objects.
155 * But we can safely unuse their loaded libraries.
157 * The main program does not known which GType or GInterface the plugin
158 * declares.
159 * Nautilus defines a get_types() API, and then allocates an object for each
160 * returned type. It is then easy to check if the object implements a given
161 * interface.
162 * Nautilus never release these objects.
163 * We may also ask the plugin to just allocate itself its own management object,
164 * returning it to the program (returning a pointer is possible because we are
165 * in the same process).
168 #define NA_MODULE_TYPE ( na_module_get_type())
169 #define NA_MODULE( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NA_MODULE_TYPE, NAModule ))
170 #define NA_MODULE_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NA_MODULE_TYPE, NAModuleClass ))
171 #define NA_IS_MODULE( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_MODULE_TYPE ))
172 #define NA_IS_MODULE_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_MODULE_TYPE ))
173 #define NA_MODULE_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_MODULE_TYPE, NAModuleClass ))
175 typedef struct _NAModulePrivate NAModulePrivate;
176 typedef struct _NAModuleClassPrivate NAModuleClassPrivate;
178 typedef struct {
179 /*< private >*/
180 GTypeModule parent;
181 NAModulePrivate *private;
183 NAModule;
185 typedef struct {
186 /*< private >*/
187 GTypeModuleClass parent;
188 NAModuleClassPrivate *private;
190 NAModuleClass;
192 GType na_module_get_type ( void );
194 /* private class data
196 struct _NAModuleClassPrivate {
197 void *empty; /* so that gcc -pedantic is happy */
200 /* private instance data
202 struct _NAModulePrivate {
203 gboolean dispose_has_run;
204 GModule *plugin;
207 static GTypeModuleClass *st_parent_class = NULL;
209 static GType register_type( void );
210 static void class_init( NAModuleClass *klass );
211 static void instance_init( GTypeInstance *instance, gpointer klass );
212 static void instance_dispose( GObject *object );
213 static void instance_finalize( GObject *object );
215 static NAModule *load_plugin( void );
216 static gboolean on_module_load( GTypeModule *module );
217 static void call_plugin_fn( NAModule *module );
218 static void on_unload_plugin( GTypeModule *module );
220 GType
221 na_module_get_type( void )
223 static GType object_type = 0;
225 if( !object_type ){
226 object_type = register_type();
229 return( object_type );
232 static GType
233 register_type( void )
235 static const gchar *thisfn = "na_module_register_type";
236 GType type;
238 static GTypeInfo info = {
239 sizeof( NAModuleClass ),
240 ( GBaseInitFunc ) NULL,
241 ( GBaseFinalizeFunc ) NULL,
242 ( GClassInitFunc ) class_init,
243 NULL,
244 NULL,
245 sizeof( NAModule ),
247 ( GInstanceInitFunc ) instance_init
250 g_debug( "%s", thisfn );
252 type = g_type_register_static( G_TYPE_TYPE_MODULE, "NAModule", &info, 0 );
254 return( type );
257 static void
258 class_init( NAModuleClass *klass )
260 static const gchar *thisfn = "na_module_class_init";
261 GObjectClass *object_class;
262 GTypeModuleClass *module_class;
264 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
266 st_parent_class = g_type_class_peek_parent( klass );
268 object_class = G_OBJECT_CLASS( klass );
269 object_class->dispose = instance_dispose;
270 object_class->finalize = instance_finalize;
272 module_class = G_TYPE_MODULE_CLASS( klass );
273 module_class->load = on_module_load;
274 module_class->unload = on_unload_plugin;
276 klass->private = g_new0( NAModuleClassPrivate, 1 );
279 static void
280 instance_init( GTypeInstance *instance, gpointer klass )
282 static const gchar *thisfn = "na_module_instance_init";
283 NAModule *self;
285 g_return_if_fail( NA_IS_MODULE( instance ));
287 g_debug( "%s: instance=%p (%s), klass=%p",
288 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
290 self = NA_MODULE( instance );
292 self->private = g_new0( NAModulePrivate, 1 );
294 self->private->dispose_has_run = FALSE;
297 static void
298 instance_dispose( GObject *object )
300 static const gchar *thisfn = "na_module_instance_dispose";
301 NAModule *self;
303 g_return_if_fail( NA_IS_MODULE( object ));
305 self = NA_MODULE( object );
307 if( !self->private->dispose_has_run ){
309 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
311 self->private->dispose_has_run = TRUE;
313 /* should trigger unload of the plugin */
314 /* refused by GLib
315 * GLib-GObject-WARNING **: gtypemodule.c:111: unsolicitated invocation of g_object_dispose() on GTypeModule
317 /*g_type_module_unuse( G_TYPE_MODULE( self ));*/
319 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
320 G_OBJECT_CLASS( st_parent_class )->dispose( object );
325 static void
326 instance_finalize( GObject *object )
328 static const gchar *thisfn = "na_module_instance_finalize";
329 NAModule *self;
331 g_return_if_fail( NA_IS_MODULE( object ));
333 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
335 self = NA_MODULE( object );
337 g_free( self->private );
339 /* chain call to parent class */
340 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
341 G_OBJECT_CLASS( st_parent_class )->finalize( object );
346 main( int argc, char **argv )
348 NAModule *module;
350 g_type_init();
352 /* dynamically load the module */
353 module = load_plugin();
355 if( module ){
356 /* call a function in the module */
357 call_plugin_fn( module );
359 /* try to just unref the NAModule */
360 /* not ok */
361 /*g_object_unref( module );*/
363 /* try to unload the plugin */
364 g_type_module_unuse( G_TYPE_MODULE( module ));
365 /* then unref the object */
366 /* not ok
367 * it happens that releasing the GTypeModule after having registered a GType or a
368 * GInterface is impossible
369 * see http://git.gnome.org/browse/glib/tree/gobject/gtypemodule.c
370 * and http://library.gnome.org/devel/gobject/unstable/GTypeModule.html#g-type-module-unuse
372 /*g_object_unref( module );*/
375 return( 0 );
378 static NAModule *
379 load_plugin( void )
381 NAModule *module;
383 module = NULL;
385 if( g_module_supported()){
387 module = g_object_new( NA_MODULE_TYPE, NULL );
388 g_debug( "test_module_load_plugin: module=%p", ( void * ) module );
390 if( !g_type_module_use( G_TYPE_MODULE( module ))){
391 g_object_unref( module );
395 return( module );
398 static gboolean
399 on_module_load( GTypeModule *module )
401 gboolean ok;
402 gchar *module_path;
403 NAModule *na_module = NA_MODULE( module );
405 g_debug( "test_module_on_module_load" );
407 ok = TRUE;
408 module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
410 g_debug( "test_module_on_module_load: opening the library" );
411 na_module->private->plugin = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
413 if( !na_module->private->plugin ){
414 g_printerr( "%s: %s\n", module_path, g_module_error());
415 ok = FALSE;
418 g_free( module_path );
420 return( ok );
423 static void
424 call_plugin_fn( NAModule *module )
426 typedef void ( *PluginInit )( NAModule *module );
427 PluginInit plugin_fn;
429 if( !g_module_symbol( module->private->plugin, "plugin_init", ( gpointer * ) &plugin_fn )){
430 g_printerr( "%s\n", g_module_error());
431 return;
433 if( !plugin_fn ){
434 g_printerr( "%s\n", g_module_error());
435 return;
437 plugin_fn( module );
440 static void
441 on_unload_plugin( GTypeModule *module )
443 g_debug( "test_module_on_unload_plugin" );
444 if( !g_module_close( NA_MODULE( module )->private->plugin )){
445 g_printerr( "%s\n", g_module_error());