1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
4 *
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8 *
9 * Nautilus-Actions 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.
13 *
14 * Nautilus-Actions 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 GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Nautilus-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 /* this is a module to test how to use the GLib dynamic-loading functions
35 * it tries to load, then unload, a test-module-plugin.so plugin
36 *
37 * more specifically, I am interested on releasing allocated resources
38 */
39
40 #include <stdlib.h>
41
42 #include <glib-object.h>
43 #include <gmodule.h>
44
45 #define PLUGIN_NAME "test_module_plugin"
46
47
48 #if 0
49 /* this is first version
50 */
51 static GModule *load_plugin( void );
52 static void call_plugin_fn( GModule *module );
53 static void unload_plugin( GModule *module );
54
55 int
56 main( int argc, char **argv )
57 {
58 GModule *module;
59
60 #if !GLIB_CHECK_VERSION( 2,36, 0 )
61 g_type_init();
62 #endif
63
64 /* dynamically load the module */
65 module = load_plugin();
66
67 if( module ){
68 /* call a function in the module */
69 call_plugin_fn( module );
70
71 /* unload the module */
72 unload_plugin( module );
73 }
74
75 return( 0 );
76 }
77
78 static GModule *
79 load_plugin( void )
80 {
81 gchar *module_path;
82 GModule *module;
83
84 module = NULL;
85
86 if( g_module_supported()){
87
88 module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
89 module = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
90 if( !module ){
91 g_printerr( "%s: %s\n", module_path, g_module_error());
92 }
93 g_free( module_path );
94 }
95
96 return( module );
97 }
98
99 static void
100 call_plugin_fn( GModule *module )
101 {
102 typedef void ( *PluginFn )( GModule *module );
103 PluginFn plugin_fn;
104
105 if( !g_module_symbol( module, "say_hello", ( gpointer * ) &plugin_fn )){
106 g_printerr( "%s\n", g_module_error());
107 return;
108 }
109 if( !plugin_fn ){
110 g_printerr( "%s\n", g_module_error());
111 return;
112 }
113 plugin_fn( module );
114 }
115
116 static void
117 unload_plugin( GModule *module )
118 {
119 if( !g_module_close( module )){
120 g_printerr( "%s\n", g_module_error());
121 }
122 }
123 #endif
124
125 /* version 2
126 * Having the plugin register dynamic GTypes require a GTypeModule
127 * This GTtypeModule is provided by the program as a GTypeModule-derived object
128 * NAModule embeds the GModule
129 *
130 * Result:
131 *
132 * - the main program (the loader) should define a GTypeModule derived class
133 *
134 * - the GTypeModule derived class (here NAModule) embeds a GModule pointer
135 *
136 * - when loading plugins:
137 *
138 * > allocate a new GTypeModule derived object for each module
139 * setup the path here
140 *
141 * > g_type_module_use() it
142 * this triggers the on_load() virtual method on GTypeModule derived class
143 * in on_load_derived(), g_module_open() the plugin and check the API
144 *
145 * on_load_derived() may return FALSE
146 * while dynamic types have not been registered, we are always safe to unref
147 * the allocated GTypeModule derived object
148 * setup the GModule pointer on the loaded library
149 *
150 * so, if g_module_use() returns FALSE, just unref the object
151 *
152 * so, g_module_use() cannot be called from instance_init or
153 * instance_constructed (which have no return value)
154 *
155 * At the end, it is impossible to release the GTypeModule objects.
156 * But we can safely unuse their loaded libraries.
157 *
158 * The main program does not known which GType or GInterface the plugin
159 * declares.
160 * Nautilus defines a get_types() API, and then allocates an object for each
161 * returned type. It is then easy to check if the object implements a given
162 * interface.
163 * Nautilus never release these objects.
164 * We may also ask the plugin to just allocate itself its own management object,
165 * returning it to the program (returning a pointer is possible because we are
166 * in the same process).
167 */
168
169 #define NA_TYPE_MODULE ( na_module_get_type())
170 #define NA_MODULE( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NA_TYPE_MODULE, NAModule ))
171 #define NA_MODULE_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NA_TYPE_MODULE, NAModuleClass ))
172 #define NA_IS_MODULE( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_TYPE_MODULE ))
173 #define NA_IS_MODULE_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_TYPE_MODULE ))
174 #define NA_MODULE_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_TYPE_MODULE, NAModuleClass ))
175
176 typedef struct _NAModulePrivate NAModulePrivate;
177 typedef struct _NAModuleClassPrivate NAModuleClassPrivate;
178
179 typedef struct {
180 /*< private >*/
181 GTypeModule parent;
182 NAModulePrivate *private;
183 }
184 NAModule;
185
186 typedef struct {
187 /*< private >*/
188 GTypeModuleClass parent;
189 NAModuleClassPrivate *private;
190 }
191 NAModuleClass;
192
193 GType na_module_get_type ( void );
194
195 /* private class data
196 */
197 struct _NAModuleClassPrivate {
198 void *empty; /* so that gcc -pedantic is happy */
199 };
200
201 /* private instance data
202 */
203 struct _NAModulePrivate {
204 gboolean dispose_has_run;
205 GModule *plugin;
206 };
207
208 static GTypeModuleClass *st_parent_class = NULL;
209
210 static GType register_type( void );
211 static void class_init( NAModuleClass *klass );
212 static void instance_init( GTypeInstance *instance, gpointer klass );
213 static void instance_dispose( GObject *object );
214 static void instance_finalize( GObject *object );
215
216 static NAModule *load_plugin( void );
217 static gboolean on_module_load( GTypeModule *module );
218 static void call_plugin_fn( NAModule *module );
219 static void on_unload_plugin( GTypeModule *module );
220
221 GType
na_module_get_type(void)222 na_module_get_type( void )
223 {
224 static GType object_type = 0;
225
226 if( !object_type ){
227 object_type = register_type();
228 }
229
230 return( object_type );
231 }
232
233 static GType
register_type(void)234 register_type( void )
235 {
236 static const gchar *thisfn = "na_module_register_type";
237 GType type;
238
239 static GTypeInfo info = {
240 sizeof( NAModuleClass ),
241 ( GBaseInitFunc ) NULL,
242 ( GBaseFinalizeFunc ) NULL,
243 ( GClassInitFunc ) class_init,
244 NULL,
245 NULL,
246 sizeof( NAModule ),
247 0,
248 ( GInstanceInitFunc ) instance_init
249 };
250
251 g_debug( "%s", thisfn );
252
253 type = g_type_register_static( G_TYPE_TYPE_MODULE, "NAModule", &info, 0 );
254
255 return( type );
256 }
257
258 static void
class_init(NAModuleClass * klass)259 class_init( NAModuleClass *klass )
260 {
261 static const gchar *thisfn = "na_module_class_init";
262 GObjectClass *object_class;
263 GTypeModuleClass *module_class;
264
265 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
266
267 st_parent_class = g_type_class_peek_parent( klass );
268
269 object_class = G_OBJECT_CLASS( klass );
270 object_class->dispose = instance_dispose;
271 object_class->finalize = instance_finalize;
272
273 module_class = G_TYPE_MODULE_CLASS( klass );
274 module_class->load = on_module_load;
275 module_class->unload = on_unload_plugin;
276
277 klass->private = g_new0( NAModuleClassPrivate, 1 );
278 }
279
280 static void
instance_init(GTypeInstance * instance,gpointer klass)281 instance_init( GTypeInstance *instance, gpointer klass )
282 {
283 static const gchar *thisfn = "na_module_instance_init";
284 NAModule *self;
285
286 g_return_if_fail( NA_IS_MODULE( instance ));
287
288 g_debug( "%s: instance=%p (%s), klass=%p",
289 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
290
291 self = NA_MODULE( instance );
292
293 self->private = g_new0( NAModulePrivate, 1 );
294
295 self->private->dispose_has_run = FALSE;
296 }
297
298 static void
instance_dispose(GObject * object)299 instance_dispose( GObject *object )
300 {
301 static const gchar *thisfn = "na_module_instance_dispose";
302 NAModule *self;
303
304 g_return_if_fail( NA_IS_MODULE( object ));
305
306 self = NA_MODULE( object );
307
308 if( !self->private->dispose_has_run ){
309
310 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
311
312 self->private->dispose_has_run = TRUE;
313
314 /* should trigger unload of the plugin */
315 /* refused by GLib
316 * GLib-GObject-WARNING **: gtypemodule.c:111: unsolicitated invocation of g_object_dispose() on GTypeModule
317 */
318 /*g_type_module_unuse( G_TYPE_MODULE( self ));*/
319
320 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
321 G_OBJECT_CLASS( st_parent_class )->dispose( object );
322 }
323 }
324 }
325
326 static void
instance_finalize(GObject * object)327 instance_finalize( GObject *object )
328 {
329 static const gchar *thisfn = "na_module_instance_finalize";
330 NAModule *self;
331
332 g_return_if_fail( NA_IS_MODULE( object ));
333
334 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
335
336 self = NA_MODULE( object );
337
338 g_free( self->private );
339
340 /* chain call to parent class */
341 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
342 G_OBJECT_CLASS( st_parent_class )->finalize( object );
343 }
344 }
345
346 int
main(int argc,char ** argv)347 main( int argc, char **argv )
348 {
349 NAModule *module;
350
351 #if !GLIB_CHECK_VERSION( 2,36, 0 )
352 g_type_init();
353 #endif
354
355 /* dynamically load the module */
356 module = load_plugin();
357
358 if( module ){
359 /* call a function in the module */
360 call_plugin_fn( module );
361
362 /* try to just unref the NAModule */
363 /* not ok */
364 /*g_object_unref( module );*/
365
366 /* try to unload the plugin */
367 g_type_module_unuse( G_TYPE_MODULE( module ));
368 /* then unref the object */
369 /* not ok
370 * it happens that releasing the GTypeModule after having registered a GType or a
371 * GInterface is impossible
372 * see http://git.gnome.org/browse/glib/tree/gobject/gtypemodule.c
373 * and http://library.gnome.org/devel/gobject/unstable/GTypeModule.html#g-type-module-unuse
374 */
375 /*g_object_unref( module );*/
376 }
377
378 return( 0 );
379 }
380
381 static NAModule *
load_plugin(void)382 load_plugin( void )
383 {
384 NAModule *module;
385
386 module = NULL;
387
388 if( g_module_supported()){
389
390 module = g_object_new( NA_TYPE_MODULE, NULL );
391 g_debug( "test_module_load_plugin: module=%p", ( void * ) module );
392
393 if( !g_type_module_use( G_TYPE_MODULE( module ))){
394 g_object_unref( module );
395 }
396 }
397
398 return( module );
399 }
400
401 static gboolean
on_module_load(GTypeModule * module)402 on_module_load( GTypeModule *module )
403 {
404 gboolean ok;
405 gchar *module_path;
406 NAModule *na_module = NA_MODULE( module );
407
408 g_debug( "test_module_on_module_load" );
409
410 ok = TRUE;
411 module_path = g_module_build_path( PKGLIBDIR, PLUGIN_NAME );
412
413 g_debug( "test_module_on_module_load: opening the library" );
414 na_module->private->plugin = g_module_open( module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
415
416 if( !na_module->private->plugin ){
417 g_printerr( "%s: %s\n", module_path, g_module_error());
418 ok = FALSE;
419 }
420
421 g_free( module_path );
422
423 return( ok );
424 }
425
426 static void
call_plugin_fn(NAModule * module)427 call_plugin_fn( NAModule *module )
428 {
429 typedef void ( *PluginInit )( NAModule *module );
430 PluginInit plugin_fn;
431
432 if( !g_module_symbol( module->private->plugin, "plugin_init", ( gpointer * ) &plugin_fn )){
433 g_printerr( "%s\n", g_module_error());
434 return;
435 }
436 if( !plugin_fn ){
437 g_printerr( "%s\n", g_module_error());
438 return;
439 }
440 plugin_fn( module );
441 }
442
443 static void
on_unload_plugin(GTypeModule * module)444 on_unload_plugin( GTypeModule *module )
445 {
446 g_debug( "test_module_on_unload_plugin" );
447 if( !g_module_close( NA_MODULE( module )->private->plugin )){
448 g_printerr( "%s\n", g_module_error());
449 }
450 }
451