Define new 'pivot-prop-loadable' property
[nautilus-actions.git] / src / core / na-module.c
blob01b8c8d7f200b4375979bdec4a0149e27acc8c3a
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 #include <gmodule.h>
37 #include <api/na-core-utils.h>
39 #include "na-module.h"
41 /* private class data
43 struct _NAModuleClassPrivate {
44 void *empty; /* so that gcc -pedantic is happy */
47 /* private instance data
49 struct _NAModulePrivate {
50 gboolean dispose_has_run;
51 gchar *path; /* full pathname of the plugin */
52 gchar *name; /* basename without the extension */
53 GModule *library;
54 GList *objects;
56 /* api
58 gboolean ( *startup ) ( GTypeModule *module );
59 guint ( *get_version )( void );
60 gint ( *list_types ) ( const GType **types );
61 void ( *shutdown ) ( void );
64 static GTypeModuleClass *st_parent_class = NULL;
66 static GType register_type( void );
67 static void class_init( NAModuleClass *klass );
68 static void instance_init( GTypeInstance *instance, gpointer klass );
69 static void instance_dispose( GObject *object );
70 static void instance_finalize( GObject *object );
72 static NAModule *module_new( const gchar *filename );
73 static gboolean on_module_load( GTypeModule *gmodule );
74 static gboolean is_a_na_plugin( NAModule *module );
75 static gboolean plugin_check( NAModule *module, const gchar *symbol, gpointer *pfn );
76 static void register_module_types( NAModule *module );
77 static void add_module_type( NAModule *module, GType type );
78 static void object_weak_notify( NAModule *module, GObject *object );
80 static void on_module_unload( GTypeModule *gmodule );
82 GType
83 na_module_get_type( void )
85 static GType object_type = 0;
87 if( !object_type ){
88 object_type = register_type();
91 return( object_type );
94 static GType
95 register_type( void )
97 static const gchar *thisfn = "na_module_register_type";
98 GType type;
100 static GTypeInfo info = {
101 sizeof( NAModuleClass ),
102 ( GBaseInitFunc ) NULL,
103 ( GBaseFinalizeFunc ) NULL,
104 ( GClassInitFunc ) class_init,
105 NULL,
106 NULL,
107 sizeof( NAModule ),
109 ( GInstanceInitFunc ) instance_init
112 g_debug( "%s", thisfn );
114 type = g_type_register_static( G_TYPE_TYPE_MODULE, "NAModule", &info, 0 );
116 return( type );
119 static void
120 class_init( NAModuleClass *klass )
122 static const gchar *thisfn = "na_module_class_init";
123 GObjectClass *object_class;
124 GTypeModuleClass *module_class;
126 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
128 st_parent_class = g_type_class_peek_parent( klass );
130 object_class = G_OBJECT_CLASS( klass );
131 object_class->dispose = instance_dispose;
132 object_class->finalize = instance_finalize;
134 module_class = G_TYPE_MODULE_CLASS( klass );
135 module_class->load = on_module_load;
136 module_class->unload = on_module_unload;
138 klass->private = g_new0( NAModuleClassPrivate, 1 );
141 static void
142 instance_init( GTypeInstance *instance, gpointer klass )
144 static const gchar *thisfn = "na_module_instance_init";
145 NAModule *self;
147 g_return_if_fail( NA_IS_MODULE( instance ));
149 g_debug( "%s: instance=%p (%s), klass=%p",
150 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
152 self = NA_MODULE( instance );
154 self->private = g_new0( NAModulePrivate, 1 );
156 self->private->dispose_has_run = FALSE;
159 static void
160 instance_dispose( GObject *object )
162 static const gchar *thisfn = "na_module_instance_dispose";
163 NAModule *self;
165 g_return_if_fail( NA_IS_MODULE( object ));
167 self = NA_MODULE( object );
169 if( !self->private->dispose_has_run ){
171 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
173 self->private->dispose_has_run = TRUE;
175 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
176 G_OBJECT_CLASS( st_parent_class )->dispose( object );
181 static void
182 instance_finalize( GObject *object )
184 static const gchar *thisfn = "na_module_instance_finalize";
185 NAModule *self;
187 g_return_if_fail( NA_IS_MODULE( object ));
189 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
191 self = NA_MODULE( object );
193 g_free( self->private->path );
194 g_free( self->private->name );
196 g_free( self->private );
198 /* chain call to parent class */
199 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
200 G_OBJECT_CLASS( st_parent_class )->finalize( object );
205 * na_module_dump:
206 * @module: this #NAModule instance.
208 * Dumps the content of the module.
210 void
211 na_module_dump( const NAModule *module )
213 static const gchar *thisfn = "na_module_dump";
214 GList *iobj;
216 g_debug( "%s: path=%s", thisfn, module->private->path );
217 g_debug( "%s: name=%s", thisfn, module->private->name );
218 g_debug( "%s: library=%p", thisfn, ( void * ) module->private->library );
219 g_debug( "%s: objects=%p (count=%d)", thisfn, ( void * ) module->private->objects, g_list_length( module->private->objects ));
220 for( iobj = module->private->objects ; iobj ; iobj = iobj->next ){
221 g_debug( "%s: iobj=%p (%s)", thisfn, ( void * ) iobj->data, G_OBJECT_TYPE_NAME( iobj->data ));
226 * na_module_load_modules:
228 * Load availables dynamically loadable extension libraries (plugins).
230 * Returns: a #GList of #NAModule, each object representing a dynamically
231 * loaded library. The list should be na_module_release_modules() by the
232 * caller after use.
234 GList *
235 na_module_load_modules( void )
237 static const gchar *thisfn = "na_module_load_modules";
238 const gchar *dirname = PKGLIBDIR;
239 const gchar *suffix = ".so";
240 GList *modules;
241 GDir *api_dir;
242 GError *error;
243 const gchar *entry;
244 gchar *fname;
245 NAModule *module;
247 g_debug( "%s", thisfn );
249 modules = NULL;
250 error = NULL;
252 api_dir = g_dir_open( dirname, 0, &error );
253 if( error ){
254 g_warning( "%s: g_dir_open: %s", thisfn, error->message );
255 g_error_free( error );
256 error = NULL;
258 } else {
259 while(( entry = g_dir_read_name( api_dir )) != NULL ){
260 if( g_str_has_suffix( entry, suffix )){
261 fname = g_build_filename( dirname, entry, NULL );
262 module = module_new( fname );
263 if( module ){
264 module->private->name = na_core_utils_str_remove_suffix( entry, suffix );
265 modules = g_list_prepend( modules, module );
266 g_debug( "%s: module %s successfully loaded", thisfn, entry );
268 g_free( fname );
271 g_dir_close( api_dir );
274 return( modules );
278 * @fname: full pathname of the being-loaded dynamic library.
280 static NAModule *
281 module_new( const gchar *fname )
283 NAModule *module;
285 module = g_object_new( NA_MODULE_TYPE, NULL );
286 module->private->path = g_strdup( fname );
288 if( !g_type_module_use( G_TYPE_MODULE( module )) || !is_a_na_plugin( module )){
289 g_object_unref( module );
290 return( NULL );
293 register_module_types( module );
295 return( module );
299 * triggered by GTypeModule base class when first loading the library,
300 * which is itself triggered by module_new:g_type_module_use()
302 * returns: %TRUE if the module is successfully loaded
304 static gboolean
305 on_module_load( GTypeModule *gmodule )
307 static const gchar *thisfn = "na_module_on_module_load";
308 NAModule *module;
309 gboolean loaded;
311 g_return_val_if_fail( G_IS_TYPE_MODULE( gmodule ), FALSE );
313 g_debug( "%s: gmodule=%p", thisfn, ( void * ) gmodule );
315 loaded = FALSE;
316 module = NA_MODULE( gmodule );
318 module->private->library = g_module_open(
319 module->private->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
321 if( !module->private->library ){
322 g_warning( "%s: g_module_open: path=%s, error=%s", thisfn, module->private->path, g_module_error());
324 } else {
325 loaded = TRUE;
328 return( loaded );
332 * the module has been successfully loaded
333 * is it a Nautilus-Action plugin ?
334 * if ok, we ask the plugin to initialize itself
336 * As of API v 1:
337 * - na_extension_startup, na_extension_list_types and na_extension_shutdown
338 * are mandatory, and MUST be implemented by the plugin
339 * - na_extension_get_version is optional, and defaults to 1.
341 static gboolean
342 is_a_na_plugin( NAModule *module )
344 static const gchar *thisfn = "na_module_is_a_na_plugin";
345 gboolean ok;
347 ok =
348 plugin_check( module, "na_extension_startup" , ( gpointer * ) &module->private->startup) &&
349 plugin_check( module, "na_extension_list_types" , ( gpointer * ) &module->private->list_types ) &&
350 plugin_check( module, "na_extension_shutdown" , ( gpointer * ) &module->private->shutdown ) &&
351 module->private->startup( G_TYPE_MODULE( module ));
353 if( ok ){
354 g_debug( "%s: %s: ok", thisfn, module->private->path );
357 return( ok );
360 static gboolean
361 plugin_check( NAModule *module, const gchar *symbol, gpointer *pfn )
363 static const gchar *thisfn = "na_module_plugin_check";
364 gboolean ok;
366 ok = g_module_symbol( module->private->library, symbol, pfn );
368 if( !ok || !pfn ){
369 g_debug("%s: %s: %s: symbol not found", thisfn, module->private->path, symbol );
372 return( ok );
376 * The 'na_extension_startup' function of the plugin has been already
377 * called ; the GType types the plugin provides have so already been
378 * registered in the GType system
380 * We ask here the plugin to give us a list of these GTypes.
381 * For each GType, we allocate a new object of the given class
382 * and keep this object in the module's list
384 static void
385 register_module_types( NAModule *module )
387 const GType *types;
388 guint count, i;
390 count = module->private->list_types( &types );
391 module->private->objects = NULL;
393 for( i = 0 ; i < count ; i++ ){
394 if( types[i] ){
395 add_module_type( module, types[i] );
400 static void
401 add_module_type( NAModule *module, GType type )
403 GObject *object;
405 object = g_object_new( type, NULL );
406 g_debug( "na_module_add_module_type: allocating object=%p (%s)", ( void * ) object, G_OBJECT_TYPE_NAME( object ));
408 g_object_weak_ref( object, ( GWeakNotify ) object_weak_notify, module );
410 module->private->objects = g_list_prepend( module->private->objects, object );
413 static void
414 object_weak_notify( NAModule *module, GObject *object )
416 static const gchar *thisfn = "na_module_object_weak_notify";
418 g_debug( "%s: module=%p, object=%p (%s)",
419 thisfn, ( void * ) module, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
421 module->private->objects = g_list_remove( module->private->objects, object );
425 * 'unload' is triggered by the last 'unuse' call
426 * which is itself called in na_module::instance_dispose
428 static void
429 on_module_unload( GTypeModule *gmodule )
431 static const gchar *thisfn = "na_module_on_module_unload";
432 NAModule *module;
434 g_return_if_fail( G_IS_TYPE_MODULE( gmodule ));
436 g_debug( "%s: gmodule=%p", thisfn, ( void * ) gmodule );
438 module = NA_MODULE( gmodule );
440 if( module->private->shutdown ){
441 module->private->shutdown();
444 if( module->private->library ){
445 g_module_close( module->private->library );
448 module->private->startup = NULL;
449 module->private->get_version = NULL;
450 module->private->list_types = NULL;
451 module->private->shutdown = NULL;
455 * na_module_get_extensions_for_type:
456 * @type: the serched GType.
458 * Returns: a list of loaded modules willing to deal with requested @type.
460 * The returned list should be na_module_free_extensions_list() by the caller.
462 GList *
463 na_module_get_extensions_for_type( GList *modules, GType type )
465 GList *willing_to, *im, *io;
466 NAModule *a_modul;
468 willing_to = NULL;
470 for( im = modules; im ; im = im->next ){
471 a_modul = NA_MODULE( im->data );
472 for( io = a_modul->private->objects ; io ; io = io->next ){
473 if( G_TYPE_CHECK_INSTANCE_TYPE( G_OBJECT( io->data ), type )){
474 willing_to = g_list_prepend( willing_to, g_object_ref( io->data ));
479 return( willing_to );
483 * na_module_free_extensions_list:
484 * @extensions: a #GList as returned by #na_module_get_extensions_for_type().
486 * Free the previously returned list.
488 void
489 na_module_free_extensions_list( GList *extensions )
491 g_list_foreach( extensions, ( GFunc ) g_object_unref, NULL );
492 g_list_free( extensions );
496 * na_module_has_id:
497 * @module: this #NAModule object.
498 * @id: the searched id.
500 * Returns: %TRUE if one of the interfaces advertised by the module has
501 * the given id, %FALSE else.
503 gboolean
504 na_module_has_id( NAModule *module, const gchar *id )
506 gboolean id_ok;
507 GList *iobj;
509 id_ok = FALSE;
510 for( iobj = module->private->objects ; iobj && !id_ok ; iobj = iobj->next ){
511 g_debug( "na_module_has_id: object=%s", G_OBJECT_TYPE_NAME( iobj->data ));
514 return( id_ok );
518 * na_module_release_modules:
519 * @modules: the list of loaded modules.
521 * Release resources allocated to the loaded modules on #NAPivot dispose.
523 void
524 na_module_release_modules( GList *modules )
526 static const gchar *thisfn = "na_modules_release_modules";
527 NAModule *module;
528 GList *imod;
529 GList *iobj;
531 g_debug( "%s: modules=%p (count=%d)", thisfn, ( void * ) modules, g_list_length( modules ));
533 for( imod = modules ; imod ; imod = imod->next ){
534 module = NA_MODULE( imod->data );
536 for( iobj = module->private->objects ; iobj ; iobj = iobj->next ){
537 g_object_unref( iobj->data );
540 g_type_module_unuse( G_TYPE_MODULE( module ));
543 g_list_free( modules );