1
/* $Id: thunar-extension-manager.c 18843 2005-11-14 14:25:58Z benny $ */
3
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the Free
7
* Software Foundation; either version 2 of the License, or (at your option)
10
* This program is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
* You should have received a copy of the GNU General Public License along with
16
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17
* Place, Suite 330, Boston, MA 02111-1307 USA
28
#include <thunar/thunar-extension-manager.h>
32
#define THUNAR_EXTENSIONS_DIRECTORY (LIBDIR G_DIR_SEPARATOR_S "thunarx-" THUNAR_VERSION_API)
44
typedef struct _ThunarExtensionClass ThunarExtensionClass;
45
typedef struct _ThunarExtension ThunarExtension;
49
#define THUNAR_TYPE_EXTENSION (thunar_extension_get_type ())
50
#define THUNAR_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_EXTENSION, ThunarExtension))
51
#define THUNAR_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_EXTENSION, ThunarExtensionClass))
52
#define THUNAR_IS_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_EXTENSION))
53
#define THUNAR_IS_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_EXTENSION))
54
#define THUNAR_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_EXTENSION, ThunarExtensionClass))
58
static GType thunar_extension_get_type (void) G_GNUC_CONST;
59
static void thunar_extension_class_init (ThunarExtensionClass *klass);
60
static void thunar_extension_finalize (GObject *object);
61
static void thunar_extension_get_property (GObject *object,
65
static void thunar_extension_set_property (GObject *object,
69
static gboolean thunar_extension_load (GTypeModule *module);
70
static void thunar_extension_unload (GTypeModule *module);
71
static void thunar_extension_list_types (ThunarExtension *extension,
77
struct _ThunarExtensionClass
79
GTypeModuleClass __parent__;
82
struct _ThunarExtension
84
GTypeModule __parent__;
90
void (*initialize) (GTypeModule *module);
91
void (*shutdown) (void);
92
void (*list_types) (const GType **types,
98
static GObjectClass *thunar_extension_parent_class;
103
thunar_extension_get_type (void)
105
static GType type = G_TYPE_INVALID;
107
if (G_UNLIKELY (type == G_TYPE_INVALID))
109
static const GTypeInfo info =
111
sizeof (ThunarExtensionClass),
114
(GClassInitFunc) thunar_extension_class_init,
117
sizeof (ThunarExtension),
123
type = g_type_register_static (G_TYPE_TYPE_MODULE, "ThunarExtension", &info, 0);
132
thunar_extension_class_init (ThunarExtensionClass *klass)
134
GTypeModuleClass *gtype_module_class;
135
GObjectClass *gobject_class;
137
/* determine the parent class */
138
thunar_extension_parent_class = g_type_class_peek_parent (klass);
140
gobject_class = G_OBJECT_CLASS (klass);
141
gobject_class->finalize = thunar_extension_finalize;
142
gobject_class->get_property = thunar_extension_get_property;
143
gobject_class->set_property = thunar_extension_set_property;
145
gtype_module_class = G_TYPE_MODULE_CLASS (klass);
146
gtype_module_class->load = thunar_extension_load;
147
gtype_module_class->unload = thunar_extension_unload;
150
* ThunarExtension::resident:
152
* Tells whether the extension must reside in memory once loaded
153
* for the first time.
155
g_object_class_install_property (gobject_class,
157
g_param_spec_boolean ("resident",
159
_("Ensures that an extension will never be unloaded."),
161
EXO_PARAM_READWRITE));
167
thunar_extension_finalize (GObject *object)
169
ThunarExtension *extension = THUNAR_EXTENSION (object);
171
/* free the path to the extension */
172
g_free (extension->path);
174
(*G_OBJECT_CLASS (thunar_extension_parent_class)->finalize) (object);
180
thunar_extension_get_property (GObject *object,
185
ThunarExtension *extension = THUNAR_EXTENSION (object);
190
g_value_set_boolean (value, extension->resident);
194
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202
thunar_extension_set_property (GObject *object,
207
ThunarExtension *extension = THUNAR_EXTENSION (object);
212
extension->resident = g_value_get_boolean (value);
216
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224
thunar_extension_load (GTypeModule *module)
226
ThunarExtension *extension = THUNAR_EXTENSION (module);
228
/* load the extension using the runtime link editor */
229
extension->module = g_module_open (extension->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
231
/* check if the load operation was successful */
232
if (G_UNLIKELY (extension->module == NULL))
234
g_warning ("Failed to load file manager extension from %s: %s", extension->path, g_module_error ());
238
/* verify that all required public symbols are present in the extension's symbol table */
239
if (!g_module_symbol (extension->module, "thunar_extension_shutdown", (gpointer) &extension->shutdown)
240
|| !g_module_symbol (extension->module, "thunar_extension_initialize", (gpointer) &extension->initialize)
241
|| !g_module_symbol (extension->module, "thunar_extension_list_types", (gpointer) &extension->list_types))
243
g_warning ("File manager extension loaded from %s lacks required symbols.", extension->path);
244
g_module_close (extension->module);
248
/* initialize the extension */
249
(*extension->initialize) (module);
251
/* ensure that the module will never be unloaded
252
* if the extension requests to be kept in memory
254
if (G_UNLIKELY (extension->resident))
255
g_module_make_resident (extension->module);
263
thunar_extension_unload (GTypeModule *module)
265
ThunarExtension *extension = THUNAR_EXTENSION (module);
267
/* shutdown the extension */
268
(*extension->shutdown) ();
270
/* unload the extension from memory */
271
g_module_close (extension->module);
273
/* reset extension state */
274
extension->module = NULL;
275
extension->shutdown = NULL;
276
extension->initialize = NULL;
277
extension->list_types = NULL;
283
thunar_extension_list_types (ThunarExtension *extension,
287
g_return_if_fail (THUNAR_IS_EXTENSION (extension));
288
g_return_if_fail (n_types != NULL);
289
g_return_if_fail (types != NULL);
291
(*extension->list_types) (types, n_types);
297
static void thunar_extension_manager_class_init (ThunarExtensionManagerClass *klass);
298
static void thunar_extension_manager_init (ThunarExtensionManager *manager);
299
static void thunar_extension_manager_finalize (GObject *object);
300
static void thunar_extension_manager_add (ThunarExtensionManager *manager,
301
ThunarExtension *extension);
305
struct _ThunarExtensionManagerClass
307
GObjectClass __parent__;
310
struct _ThunarExtensionManager
322
G_DEFINE_TYPE (ThunarExtensionManager, thunar_extension_manager, G_TYPE_OBJECT);
327
thunar_extension_manager_class_init (ThunarExtensionManagerClass *klass)
329
GObjectClass *gobject_class;
331
gobject_class = G_OBJECT_CLASS (klass);
332
gobject_class->finalize = thunar_extension_manager_finalize;
338
thunar_extension_manager_init (ThunarExtensionManager *manager)
340
ThunarExtension *extension;
344
// FIXME: Perform this in a timer as the extensions aren't required to
345
// be available instantly, maybe even load the files in a separate thread!
346
dp = g_dir_open (THUNAR_EXTENSIONS_DIRECTORY, 0, NULL);
347
if (G_LIKELY (dp != NULL))
349
/* determine the types for all existing extensions */
352
/* read the next entry from the directory */
353
name = g_dir_read_name (dp);
354
if (G_UNLIKELY (name == NULL))
357
/* check if this is a valid extension file */
358
if (g_str_has_suffix (name, "." G_MODULE_SUFFIX))
360
/* generate an extension object for the file */
361
extension = g_object_new (THUNAR_TYPE_EXTENSION, NULL);
362
extension->path = g_build_filename (THUNAR_EXTENSIONS_DIRECTORY, name, NULL);
364
/* try to load the extension */
365
if (g_type_module_use (G_TYPE_MODULE (extension)))
367
/* add the extension to our list of managed extensions */
368
thunar_extension_manager_add (manager, extension);
370
/* don't unuse the type plugin if it should be resident in memory */
371
if (G_LIKELY (!extension->resident))
372
g_type_module_unuse (G_TYPE_MODULE (extension));
375
/* drop the reference on the extension */
376
g_object_unref (G_OBJECT (extension));
387
thunar_extension_manager_finalize (GObject *object)
389
ThunarExtensionManager *manager = THUNAR_EXTENSION_MANAGER (object);
391
/* release the extensions */
392
g_list_foreach (manager->extensions, (GFunc) g_object_unref, NULL);
393
g_list_free (manager->extensions);
395
/* free the types list */
396
g_free (manager->types);
398
(*G_OBJECT_CLASS (thunar_extension_manager_parent_class)->finalize) (object);
404
thunar_extension_manager_add (ThunarExtensionManager *manager,
405
ThunarExtension *extension)
410
/* add the extension to our internal list */
411
manager->extensions = g_list_prepend (manager->extensions, g_object_ref (G_OBJECT (extension)));
413
/* determines the types provided by the extension */
414
thunar_extension_list_types (extension, &types, &n_types);
416
/* add the types provided by the extension */
417
manager->types = g_realloc (manager->types, sizeof (GType) * (manager->n_types + n_types));
418
for (; n_types-- > 0; ++types)
419
manager->types[manager->n_types++] = *types;
425
* thunar_extension_manager_get_default:
427
* Returns a reference to the default #ThunarExtensionManager
430
* The caller is responsible to free the returned object
431
* using g_object_unref() when no longer needed.
433
* Return value: a reference to the default
434
* #ThunarExtensionManager instance.
436
ThunarExtensionManager*
437
thunar_extension_manager_get_default (void)
439
static ThunarExtensionManager *manager = NULL;
441
if (G_UNLIKELY (manager == NULL))
442
manager = g_object_new (THUNAR_TYPE_EXTENSION_MANAGER, NULL);
444
g_object_ref (G_OBJECT (manager));
452
* thunar_extension_manager_list_providers:
453
* @manager : a #ThunarExtensionManager instance.
454
* @type : the provider #GType.
456
* Returns all providers of the given @type.
458
* The caller is responsible to release the returned
459
* list of providers using code like this:
460
* <informalexample><programlisting>
461
* g_list_foreach (list, (GFunc) g_object_unref, NULL);
462
* g_list_free (list);
463
* </programlisting></informalexample>
465
* Return value: the of providers for @type.
468
thunar_extension_manager_list_providers (ThunarExtensionManager *manager,
472
GList *providers = NULL;
476
for (n = manager->n_types, types = manager->types; n > 0; --n, ++types)
477
if (G_LIKELY (g_type_is_a (*types, type)))
479
provider = g_object_new (*types, NULL);
480
if (G_LIKELY (provider != NULL))
481
providers = g_list_append (providers, provider);