Add g_file_query_default_handler utility to easily look up the GAppInfo
[platform/upstream/glib.git] / gio / giomodule.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include "giomodule.h"
28 #include "giomodule-priv.h"
29 #include "glocalfilemonitor.h"
30 #include "glocaldirectorymonitor.h"
31 #include "gnativevolumemonitor.h"
32 #include "gvfs.h"
33 #ifdef G_OS_UNIX
34 #include "gdesktopappinfo.h"
35 #endif
36 #include "gioalias.h"
37
38 /**
39  * SECTION:giomodule
40  * @short_description: Loadable GIO Modules
41  * @include: gio.h
42  *
43  * Provides an interface and default functions for loading and unloading 
44  * modules. This is used internally to make gio extensible, but can also
45  * be used by other to implement module loading.
46  * 
47  **/
48
49 struct _GIOModule {
50   GTypeModule parent_instance;
51   
52   gchar       *filename;
53   GModule     *library;
54   
55   void (* load)   (GIOModule *module);
56   void (* unload) (GIOModule *module);
57 };
58
59 struct _GIOModuleClass
60 {
61   GTypeModuleClass parent_class;
62
63 };
64
65 static void      g_io_module_finalize      (GObject      *object);
66 static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
67 static void      g_io_module_unload_module (GTypeModule  *gmodule);
68
69 G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE);
70
71 static void
72 g_io_module_class_init (GIOModuleClass *class)
73 {
74   GObjectClass     *object_class      = G_OBJECT_CLASS (class);
75   GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
76
77   object_class->finalize     = g_io_module_finalize;
78
79   type_module_class->load    = g_io_module_load_module;
80   type_module_class->unload  = g_io_module_unload_module;
81 }
82
83 static void
84 g_io_module_init (GIOModule *module)
85 {
86 }
87
88 static void
89 g_io_module_finalize (GObject *object)
90 {
91   GIOModule *module = G_IO_MODULE (object);
92
93   g_free (module->filename);
94
95   G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
96 }
97
98 static gboolean
99 g_io_module_load_module (GTypeModule *gmodule)
100 {
101   GIOModule *module = G_IO_MODULE (gmodule);
102
103   if (!module->filename)
104     {
105       g_warning ("GIOModule path not set");
106       return FALSE;
107     }
108
109   module->library = g_module_open (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
110
111   if (!module->library)
112     {
113       g_printerr ("%s\n", g_module_error ());
114       return FALSE;
115     }
116
117   /* Make sure that the loaded library contains the required methods */
118   if (! g_module_symbol (module->library,
119                          "g_io_module_load",
120                          (gpointer) &module->load) ||
121       ! g_module_symbol (module->library,
122                          "g_io_module_unload",
123                          (gpointer) &module->unload))
124     {
125       g_printerr ("%s\n", g_module_error ());
126       g_module_close (module->library);
127
128       return FALSE;
129     }
130
131   /* Initialize the loaded module */
132   module->load (module);
133
134   return TRUE;
135 }
136
137 static void
138 g_io_module_unload_module (GTypeModule *gmodule)
139 {
140   GIOModule *module = G_IO_MODULE (gmodule);
141
142   module->unload (module);
143
144   g_module_close (module->library);
145   module->library = NULL;
146
147   module->load   = NULL;
148   module->unload = NULL;
149 }
150
151 /**
152  * g_io_module_new:
153  * @filename: filename of the shared library module.
154  * 
155  * Creates a new GIOModule that will load the specific
156  * shared library when in use.
157  * 
158  * Returns: a #GIOModule from given @filename, 
159  * or %NULL on error.
160  **/
161 GIOModule *
162 g_io_module_new (const gchar *filename)
163 {
164   GIOModule *module;
165
166   g_return_val_if_fail (filename != NULL, NULL);
167
168   module = g_object_new (G_IO_TYPE_MODULE, NULL);
169   module->filename = g_strdup (filename);
170
171   return module;
172 }
173
174 static gboolean
175 is_valid_module_name (const gchar *basename)
176 {
177 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
178   return
179     g_str_has_prefix (basename, "lib") &&
180     g_str_has_suffix (basename, ".so");
181 #else
182   return g_str_has_suffix (basename, ".dll");
183 #endif
184 }
185
186 /**
187  * g_io_modules_load_all_in_directory:
188  * @dirname: pathname for a directory containing modules to load.
189  * 
190  * Loads all the modules in the the specified directory. 
191  * 
192  * Returns: a list of #GIOModules loaded from the directory,
193  *      All the modules are loaded into memory, if you want to
194  *      unload them (enabling on-demand loading) you must call
195  *      g_type_module_unuse() on all the modules. Free the list
196  *      with g_list_free().
197  **/
198 GList *
199 g_io_modules_load_all_in_directory (const char *dirname)
200 {
201   const gchar *name;
202   GDir        *dir;
203   GList *modules;
204
205   if (!g_module_supported ())
206     return NULL;
207
208   dir = g_dir_open (dirname, 0, NULL);
209   if (!dir)
210     return NULL;
211
212   modules = NULL;
213   while ((name = g_dir_read_name (dir)))
214     {
215       if (is_valid_module_name (name))
216         {
217           GIOModule *module;
218           gchar     *path;
219
220           path = g_build_filename (dirname, name, NULL);
221           module = g_io_module_new (path);
222
223           if (!g_type_module_use (G_TYPE_MODULE (module)))
224             {
225               g_printerr ("Failed to load module: %s\n", path);
226               g_object_unref (module);
227               g_free (path);
228               continue;
229             }
230           
231           g_free (path);
232
233           modules = g_list_prepend (modules, module);
234         }
235     }
236   
237   g_dir_close (dir);
238
239   return modules;
240 }
241
242 G_LOCK_DEFINE_STATIC (loaded_dirs);
243
244 extern GType _g_inotify_directory_monitor_get_type (void);
245 extern GType _g_inotify_file_monitor_get_type (void);
246 extern GType _g_unix_volume_monitor_get_type (void);
247 extern GType _g_local_vfs_get_type (void);
248
249 void
250 _g_io_modules_ensure_loaded (void)
251 {
252   GList *modules, *l;
253   static gboolean loaded_dirs = FALSE;
254   GIOExtensionPoint *ep;
255
256   G_LOCK (loaded_dirs);
257
258   if (!loaded_dirs)
259     {
260       loaded_dirs = TRUE;
261
262 #ifdef G_OS_UNIX
263       ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
264       g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
265 #endif
266       
267       ep = g_io_extension_point_register (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME);
268       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_DIRECTORY_MONITOR);
269       
270       ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
271       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
272
273       ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
274       g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
275       
276       ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
277       g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
278       
279       ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
280       g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
281       
282       modules = g_io_modules_load_all_in_directory (GIO_MODULE_DIR);
283
284       /* Initialize types from built-in "modules" */
285 #if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
286       _g_inotify_directory_monitor_get_type ();
287       _g_inotify_file_monitor_get_type ();
288 #endif
289 #ifdef G_OS_UNIX
290       _g_unix_volume_monitor_get_type ();
291 #endif
292       _g_local_vfs_get_type ();
293     
294       for (l = modules; l != NULL; l = l->next)
295         g_type_module_unuse (G_TYPE_MODULE (l->data));
296       
297       g_list_free (modules);
298     }
299
300   G_UNLOCK (loaded_dirs);
301 }
302
303 struct _GIOExtension {
304   char *name;
305   GType type;
306   gint priority;
307 };
308
309 struct _GIOExtensionPoint {
310   GType required_type;
311   char *name;
312   GList *extensions;
313 };
314
315 static GHashTable *extension_points = NULL;
316 G_LOCK_DEFINE_STATIC(extension_points);
317
318
319 static void
320 g_io_extension_point_free (GIOExtensionPoint *ep)
321 {
322   g_free (ep->name);
323   g_free (ep);
324 }
325
326 GIOExtensionPoint *
327 g_io_extension_point_register (const char *name)
328 {
329   GIOExtensionPoint *ep;
330   
331   G_LOCK (extension_points);
332   if (extension_points == NULL)
333     extension_points = g_hash_table_new_full (g_str_hash,
334                                               g_str_equal,
335                                               NULL,
336                                               (GDestroyNotify)g_io_extension_point_free);
337
338   if (g_hash_table_lookup (extension_points, name) != NULL)
339     {
340       g_warning ("Extension point %s registered multiple times", name);
341       G_UNLOCK (extension_points);
342       return NULL;
343     }
344
345   ep = g_new0 (GIOExtensionPoint, 1);
346   ep->name = g_strdup (name);
347   
348   g_hash_table_insert (extension_points, ep->name, ep);
349   
350   G_UNLOCK (extension_points);
351
352   return ep;
353 }
354
355 GIOExtensionPoint *
356 g_io_extension_point_lookup (const char *name)
357 {
358   GIOExtensionPoint *ep;
359
360   G_LOCK (extension_points);
361   ep = NULL;
362   if (extension_points != NULL)
363     ep = g_hash_table_lookup (extension_points, name);
364   
365   G_UNLOCK (extension_points);
366
367   return ep;
368   
369 }
370
371 void
372 g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
373                                         GType              type)
374 {
375   extension_point->required_type = type;
376 }
377
378 GType
379 g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
380 {
381   return extension_point->required_type;
382 }
383
384 GList *
385 g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
386 {
387   return extension_point->extensions;
388 }
389
390 GIOExtension *
391 g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
392                                             const char        *name)
393 {
394   GList *l;
395
396   for (l = extension_point->extensions; l != NULL; l = l->next)
397     {
398       GIOExtension *e = l->data;
399
400       if (e->name != NULL &&
401           strcmp (e->name, name) == 0)
402         return e;
403     }
404   
405   return NULL;
406 }
407
408 static gint
409 extension_prio_compare (gconstpointer  a,
410                         gconstpointer  b)
411 {
412   const GIOExtension *extension_a = a, *extension_b = b;
413
414   return extension_b->priority - extension_a->priority;
415 }
416
417 GIOExtension *
418 g_io_extension_point_implement (const char *extension_point_name,
419                                 GType type,
420                                 const char *extension_name,
421                                 gint priority)
422 {
423   GIOExtensionPoint *extension_point;
424   GIOExtension *extension;
425   GList *l;
426
427   g_return_val_if_fail (extension_point_name != NULL, NULL);
428
429   extension_point = g_io_extension_point_lookup (extension_point_name);
430   if (extension_point == NULL)
431     {
432       g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
433       return NULL;
434     }
435   
436   if (extension_point->required_type != 0 &&
437       !g_type_is_a (type, extension_point->required_type))
438     {
439       g_warning ("Tried to register an extension of the type %s to extension point %s. "
440                  "Expected type is %s.",
441                  g_type_name (type),
442                  extension_point_name, 
443                  g_type_name (extension_point->required_type));
444       return NULL;
445     }      
446
447   /* Its safe to register the same type multiple times */
448   for (l = extension_point->extensions; l != NULL; l = l->next)
449     {
450       extension = l->data;
451       if (extension->type == type)
452         return extension;
453     }
454   
455   extension = g_slice_new0 (GIOExtension);
456   extension->type = type;
457   extension->name = g_strdup (extension_name);
458   extension->priority = priority;
459   
460   extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
461                                                       extension, extension_prio_compare);
462   
463   return extension;
464 }
465
466 GTypeClass *
467 g_io_extension_ref_class (GIOExtension *extension)
468 {
469   return g_type_class_ref (extension->type);
470 }
471
472
473 GType
474 g_io_extension_get_type (GIOExtension *extension)
475 {
476   return extension->type;
477 }
478
479 const char *
480 g_io_extension_get_name (GIOExtension *extension)
481 {
482   return extension->name;
483 }
484
485 gint
486 g_io_extension_get_priority (GIOExtension *extension)
487 {
488   return extension->priority;
489 }
490
491 #define __G_IO_MODULE_C__
492 #include "gioaliasdef.c"