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.
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)
37 #include <api/na-core-utils.h>
39 #include "na-module.h"
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 */
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
);
83 na_module_get_type( void )
85 static GType object_type
= 0;
88 object_type
= register_type();
91 return( object_type
);
97 static const gchar
*thisfn
= "na_module_register_type";
100 static GTypeInfo info
= {
101 sizeof( NAModuleClass
),
102 ( GBaseInitFunc
) NULL
,
103 ( GBaseFinalizeFunc
) NULL
,
104 ( GClassInitFunc
) class_init
,
109 ( GInstanceInitFunc
) instance_init
112 g_debug( "%s", thisfn
);
114 type
= g_type_register_static( G_TYPE_TYPE_MODULE
, "NAModule", &info
, 0 );
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 );
142 instance_init( GTypeInstance
*instance
, gpointer klass
)
144 static const gchar
*thisfn
= "na_module_instance_init";
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
;
160 instance_dispose( GObject
*object
)
162 static const gchar
*thisfn
= "na_module_instance_dispose";
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
);
182 instance_finalize( GObject
*object
)
184 static const gchar
*thisfn
= "na_module_instance_finalize";
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
);
206 * @module: this #NAModule instance.
208 * Dumps the content of the module.
211 na_module_dump( const NAModule
*module
)
213 static const gchar
*thisfn
= "na_module_dump";
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
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";
247 g_debug( "%s", thisfn
);
252 api_dir
= g_dir_open( dirname
, 0, &error
);
254 g_warning( "%s: g_dir_open: %s", thisfn
, error
->message
);
255 g_error_free( error
);
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
);
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
);
271 g_dir_close( api_dir
);
278 * @fname: full pathname of the being-loaded dynamic library.
281 module_new( const gchar
*fname
)
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
);
293 register_module_types( 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
305 on_module_load( GTypeModule
*gmodule
)
307 static const gchar
*thisfn
= "na_module_on_module_load";
311 g_return_val_if_fail( G_IS_TYPE_MODULE( gmodule
), FALSE
);
313 g_debug( "%s: gmodule=%p", thisfn
, ( void * ) gmodule
);
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());
332 * the module has been successfully loaded
333 * is it a Nautilus-Action plugin ?
334 * if ok, we ask the plugin to initialize itself
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.
342 is_a_na_plugin( NAModule
*module
)
344 static const gchar
*thisfn
= "na_module_is_a_na_plugin";
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
));
354 g_debug( "%s: %s: ok", thisfn
, module
->private->path
);
361 plugin_check( NAModule
*module
, const gchar
*symbol
, gpointer
*pfn
)
363 static const gchar
*thisfn
= "na_module_plugin_check";
366 ok
= g_module_symbol( module
->private->library
, symbol
, pfn
);
369 g_debug("%s: %s: %s: symbol not found", thisfn
, module
->private->path
, symbol
);
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
385 register_module_types( NAModule
*module
)
390 count
= module
->private->list_types( &types
);
391 module
->private->objects
= NULL
;
393 for( i
= 0 ; i
< count
; i
++ ){
395 add_module_type( module
, types
[i
] );
401 add_module_type( NAModule
*module
, GType type
)
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
);
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
429 on_module_unload( GTypeModule
*gmodule
)
431 static const gchar
*thisfn
= "na_module_on_module_unload";
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.
463 na_module_get_extensions_for_type( GList
*modules
, GType type
)
465 GList
*willing_to
, *im
, *io
;
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.
489 na_module_free_extensions_list( GList
*extensions
)
491 g_list_foreach( extensions
, ( GFunc
) g_object_unref
, NULL
);
492 g_list_free( extensions
);
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.
504 na_module_has_id( NAModule
*module
, const gchar
*id
)
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
));
518 * na_module_release_modules:
519 * @modules: the list of loaded modules.
521 * Release resources allocated to the loaded modules on #NAPivot dispose.
524 na_module_release_modules( GList
*modules
)
526 static const gchar
*thisfn
= "na_modules_release_modules";
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
);