~ubuntu-branches/debian/experimental/thunar/experimental

« back to all changes in this revision

Viewing changes to thunar/thunar-extension-manager.c

  • Committer: Bazaar Package Importer
  • Author(s): Yves-Alexis Perez
  • Date: 2006-01-02 23:42:32 UTC
  • Revision ID: james.westby@ubuntu.com-20060102234232-8xeq0lqhyn70syr0
Tags: upstream-0.1.4svn+r18850
ImportĀ upstreamĀ versionĀ 0.1.4svn+r18850

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: thunar-extension-manager.c 18843 2005-11-14 14:25:58Z benny $ */
 
2
/*-
 
3
 * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
 
4
 *
 
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)
 
8
 * any later version.
 
9
 *
 
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
 
13
 * more details.
 
14
 *
 
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
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include <config.h>
 
22
#endif
 
23
 
 
24
#include <gmodule.h>
 
25
 
 
26
#include <exo/exo.h>
 
27
 
 
28
#include <thunar/thunar-extension-manager.h>
 
29
 
 
30
 
 
31
 
 
32
#define THUNAR_EXTENSIONS_DIRECTORY (LIBDIR G_DIR_SEPARATOR_S "thunarx-" THUNAR_VERSION_API)
 
33
 
 
34
 
 
35
 
 
36
enum
 
37
{
 
38
  PROP_0,
 
39
  PROP_RESIDENT,
 
40
};
 
41
 
 
42
 
 
43
 
 
44
typedef struct _ThunarExtensionClass ThunarExtensionClass;
 
45
typedef struct _ThunarExtension      ThunarExtension;
 
46
 
 
47
 
 
48
 
 
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))
 
55
 
 
56
 
 
57
 
 
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,
 
62
                                               guint                 prop_id,
 
63
                                               GValue               *value,
 
64
                                               GParamSpec           *pspec);
 
65
static void     thunar_extension_set_property (GObject              *object,
 
66
                                               guint                 prop_id,
 
67
                                               const GValue         *value,
 
68
                                               GParamSpec           *pspec);
 
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,
 
72
                                               const GType         **types,
 
73
                                               gint                 *n_types);
 
74
 
 
75
 
 
76
 
 
77
struct _ThunarExtensionClass
 
78
{
 
79
  GTypeModuleClass __parent__;
 
80
};
 
81
 
 
82
struct _ThunarExtension
 
83
{
 
84
  GTypeModule __parent__;
 
85
 
 
86
  gchar   *path;
 
87
  GModule *module;
 
88
  gboolean resident;
 
89
 
 
90
  void (*initialize)  (GTypeModule  *module);
 
91
  void (*shutdown)    (void);
 
92
  void (*list_types)  (const GType **types,
 
93
                       gint         *n_types);
 
94
};
 
95
 
 
96
 
 
97
 
 
98
static GObjectClass *thunar_extension_parent_class;
 
99
 
 
100
 
 
101
 
 
102
static GType
 
103
thunar_extension_get_type (void)
 
104
{
 
105
  static GType type = G_TYPE_INVALID;
 
106
 
 
107
  if (G_UNLIKELY (type == G_TYPE_INVALID))
 
108
    {
 
109
      static const GTypeInfo info =
 
110
      {
 
111
        sizeof (ThunarExtensionClass),
 
112
        NULL,
 
113
        NULL,
 
114
        (GClassInitFunc) thunar_extension_class_init,
 
115
        NULL,
 
116
        NULL,
 
117
        sizeof (ThunarExtension),
 
118
        0,
 
119
        NULL,
 
120
        NULL,
 
121
      };
 
122
 
 
123
      type = g_type_register_static (G_TYPE_TYPE_MODULE, "ThunarExtension", &info, 0);
 
124
    }
 
125
 
 
126
  return type;
 
127
}
 
128
 
 
129
 
 
130
 
 
131
static void
 
132
thunar_extension_class_init (ThunarExtensionClass *klass)
 
133
{
 
134
  GTypeModuleClass *gtype_module_class;
 
135
  GObjectClass     *gobject_class;
 
136
 
 
137
  /* determine the parent class */
 
138
  thunar_extension_parent_class = g_type_class_peek_parent (klass);
 
139
 
 
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;
 
144
 
 
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;
 
148
 
 
149
  /**
 
150
   * ThunarExtension::resident:
 
151
   *
 
152
   * Tells whether the extension must reside in memory once loaded
 
153
   * for the first time.
 
154
   **/
 
155
  g_object_class_install_property (gobject_class,
 
156
                                   PROP_RESIDENT,
 
157
                                   g_param_spec_boolean ("resident",
 
158
                                                         _("Resident"),
 
159
                                                         _("Ensures that an extension will never be unloaded."),
 
160
                                                         FALSE,
 
161
                                                         EXO_PARAM_READWRITE));
 
162
}
 
163
 
 
164
 
 
165
 
 
166
static void
 
167
thunar_extension_finalize (GObject *object)
 
168
{
 
169
  ThunarExtension *extension = THUNAR_EXTENSION (object);
 
170
 
 
171
  /* free the path to the extension */
 
172
  g_free (extension->path);
 
173
 
 
174
  (*G_OBJECT_CLASS (thunar_extension_parent_class)->finalize) (object);
 
175
}
 
176
 
 
177
 
 
178
 
 
179
static void
 
180
thunar_extension_get_property (GObject    *object,
 
181
                               guint       prop_id,
 
182
                               GValue     *value,
 
183
                               GParamSpec *pspec)
 
184
{
 
185
  ThunarExtension *extension = THUNAR_EXTENSION (object);
 
186
 
 
187
  switch (prop_id)
 
188
    {
 
189
    case PROP_RESIDENT:
 
190
      g_value_set_boolean (value, extension->resident);
 
191
      break;
 
192
 
 
193
    default:
 
194
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
195
      break;
 
196
    }
 
197
}
 
198
 
 
199
 
 
200
 
 
201
static void
 
202
thunar_extension_set_property (GObject      *object,
 
203
                               guint         prop_id,
 
204
                               const GValue *value,
 
205
                               GParamSpec   *pspec)
 
206
{
 
207
  ThunarExtension *extension = THUNAR_EXTENSION (object);
 
208
 
 
209
  switch (prop_id)
 
210
    {
 
211
    case PROP_RESIDENT:
 
212
      extension->resident = g_value_get_boolean (value);
 
213
      break;
 
214
 
 
215
    default:
 
216
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
217
      break;
 
218
    }
 
219
}
 
220
 
 
221
 
 
222
 
 
223
static gboolean
 
224
thunar_extension_load (GTypeModule *module)
 
225
{
 
226
  ThunarExtension *extension = THUNAR_EXTENSION (module);
 
227
 
 
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);
 
230
 
 
231
  /* check if the load operation was successful */
 
232
  if (G_UNLIKELY (extension->module == NULL))
 
233
    {
 
234
      g_warning ("Failed to load file manager extension from %s: %s", extension->path, g_module_error ());
 
235
      return FALSE;
 
236
    }
 
237
 
 
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))
 
242
    {
 
243
      g_warning ("File manager extension loaded from %s lacks required symbols.", extension->path);
 
244
      g_module_close (extension->module);
 
245
      return FALSE;
 
246
    }
 
247
 
 
248
  /* initialize the extension */
 
249
  (*extension->initialize) (module);
 
250
 
 
251
  /* ensure that the module will never be unloaded
 
252
   * if the extension requests to be kept in memory
 
253
   */
 
254
  if (G_UNLIKELY (extension->resident))
 
255
    g_module_make_resident (extension->module);
 
256
 
 
257
  return TRUE;
 
258
}
 
259
 
 
260
 
 
261
 
 
262
static void
 
263
thunar_extension_unload (GTypeModule *module)
 
264
{
 
265
  ThunarExtension *extension = THUNAR_EXTENSION (module);
 
266
 
 
267
  /* shutdown the extension */
 
268
  (*extension->shutdown) ();
 
269
 
 
270
  /* unload the extension from memory */
 
271
  g_module_close (extension->module);
 
272
 
 
273
  /* reset extension state */
 
274
  extension->module = NULL;
 
275
  extension->shutdown = NULL;
 
276
  extension->initialize = NULL;
 
277
  extension->list_types = NULL;
 
278
}
 
279
 
 
280
 
 
281
 
 
282
static void
 
283
thunar_extension_list_types (ThunarExtension *extension,
 
284
                             const GType    **types,
 
285
                             gint            *n_types)
 
286
{
 
287
  g_return_if_fail (THUNAR_IS_EXTENSION (extension));
 
288
  g_return_if_fail (n_types != NULL);
 
289
  g_return_if_fail (types != NULL);
 
290
 
 
291
  (*extension->list_types) (types, n_types);
 
292
}
 
293
 
 
294
 
 
295
 
 
296
 
 
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);
 
302
 
 
303
 
 
304
 
 
305
struct _ThunarExtensionManagerClass
 
306
{
 
307
  GObjectClass __parent__;
 
308
};
 
309
 
 
310
struct _ThunarExtensionManager
 
311
{
 
312
  GObject __parent__;
 
313
 
 
314
  GList *extensions;
 
315
 
 
316
  GType *types;
 
317
  gint   n_types;
 
318
};
 
319
 
 
320
 
 
321
 
 
322
G_DEFINE_TYPE (ThunarExtensionManager, thunar_extension_manager, G_TYPE_OBJECT);
 
323
 
 
324
 
 
325
 
 
326
static void
 
327
thunar_extension_manager_class_init (ThunarExtensionManagerClass *klass)
 
328
{
 
329
  GObjectClass *gobject_class;
 
330
 
 
331
  gobject_class = G_OBJECT_CLASS (klass);
 
332
  gobject_class->finalize = thunar_extension_manager_finalize;
 
333
}
 
334
 
 
335
 
 
336
 
 
337
static void
 
338
thunar_extension_manager_init (ThunarExtensionManager *manager)
 
339
{
 
340
  ThunarExtension *extension;
 
341
  const gchar     *name;
 
342
  GDir            *dp;
 
343
 
 
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))
 
348
    {
 
349
      /* determine the types for all existing extensions */
 
350
      for (;;)
 
351
        {
 
352
          /* read the next entry from the directory */
 
353
          name = g_dir_read_name (dp);
 
354
          if (G_UNLIKELY (name == NULL))
 
355
            break;
 
356
 
 
357
          /* check if this is a valid extension file */
 
358
          if (g_str_has_suffix (name, "." G_MODULE_SUFFIX))
 
359
            {
 
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);
 
363
 
 
364
              /* try to load the extension */
 
365
              if (g_type_module_use (G_TYPE_MODULE (extension)))
 
366
                {
 
367
                  /* add the extension to our list of managed extensions */
 
368
                  thunar_extension_manager_add (manager, extension);
 
369
 
 
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));
 
373
                }
 
374
 
 
375
              /* drop the reference on the extension */
 
376
              g_object_unref (G_OBJECT (extension));
 
377
            }
 
378
        }
 
379
 
 
380
      g_dir_close (dp);
 
381
    }
 
382
}
 
383
 
 
384
 
 
385
 
 
386
static void
 
387
thunar_extension_manager_finalize (GObject *object)
 
388
{
 
389
  ThunarExtensionManager *manager = THUNAR_EXTENSION_MANAGER (object);
 
390
 
 
391
  /* release the extensions */
 
392
  g_list_foreach (manager->extensions, (GFunc) g_object_unref, NULL);
 
393
  g_list_free (manager->extensions);
 
394
 
 
395
  /* free the types list */
 
396
  g_free (manager->types);
 
397
 
 
398
  (*G_OBJECT_CLASS (thunar_extension_manager_parent_class)->finalize) (object);
 
399
}
 
400
 
 
401
 
 
402
 
 
403
static void
 
404
thunar_extension_manager_add (ThunarExtensionManager *manager,
 
405
                              ThunarExtension        *extension)
 
406
{
 
407
  const GType *types;
 
408
  gint         n_types;
 
409
 
 
410
  /* add the extension to our internal list */
 
411
  manager->extensions = g_list_prepend (manager->extensions, g_object_ref (G_OBJECT (extension)));
 
412
 
 
413
  /* determines the types provided by the extension */
 
414
  thunar_extension_list_types (extension, &types, &n_types);
 
415
 
 
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;
 
420
}
 
421
 
 
422
 
 
423
 
 
424
/**
 
425
 * thunar_extension_manager_get_default:
 
426
 *
 
427
 * Returns a reference to the default #ThunarExtensionManager
 
428
 * instance.
 
429
 *
 
430
 * The caller is responsible to free the returned object
 
431
 * using g_object_unref() when no longer needed.
 
432
 *
 
433
 * Return value: a reference to the default
 
434
 *               #ThunarExtensionManager instance.
 
435
 **/
 
436
ThunarExtensionManager*
 
437
thunar_extension_manager_get_default (void)
 
438
{
 
439
  static ThunarExtensionManager *manager = NULL;
 
440
 
 
441
  if (G_UNLIKELY (manager == NULL))
 
442
    manager = g_object_new (THUNAR_TYPE_EXTENSION_MANAGER, NULL);
 
443
 
 
444
  g_object_ref (G_OBJECT (manager));
 
445
 
 
446
  return manager;
 
447
}
 
448
 
 
449
 
 
450
 
 
451
/**
 
452
 * thunar_extension_manager_list_providers:
 
453
 * @manager : a #ThunarExtensionManager instance.
 
454
 * @type    : the provider #GType.
 
455
 *
 
456
 * Returns all providers of the given @type.
 
457
 *
 
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>
 
464
 *
 
465
 * Return value: the of providers for @type.
 
466
 **/
 
467
GList*
 
468
thunar_extension_manager_list_providers (ThunarExtensionManager *manager,
 
469
                                         GType                   type)
 
470
{
 
471
  GObject *provider;
 
472
  GList   *providers = NULL;
 
473
  GType   *types;
 
474
  gint     n;
 
475
 
 
476
  for (n = manager->n_types, types = manager->types; n > 0; --n, ++types)
 
477
    if (G_LIKELY (g_type_is_a (*types, type)))
 
478
      {
 
479
        provider = g_object_new (*types, NULL);
 
480
        if (G_LIKELY (provider != NULL))
 
481
          providers = g_list_append (providers, provider);
 
482
      }
 
483
 
 
484
  return providers;
 
485
}
 
486
 
 
487
 
 
488