882e224d43f5239afa83f894846e4907ea318164
[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 "gmemorysettingsbackend.h"
30 #include "glocalfilemonitor.h"
31 #include "glocaldirectorymonitor.h"
32 #include "gnativevolumemonitor.h"
33 #include "gproxyresolver.h"
34 #include "gproxy.h"
35 #include "gsocks4proxy.h"
36 #include "gsocks4aproxy.h"
37 #include "gsocks5proxy.h"
38 #include "gvfs.h"
39 #ifdef G_OS_UNIX
40 #include "gdesktopappinfo.h"
41 #endif
42 #include <glib/gstdio.h>
43
44 /**
45  * SECTION:giomodule
46  * @short_description: Loadable GIO Modules
47  * @include: gio/gio.h
48  *
49  * Provides an interface and default functions for loading and unloading 
50  * modules. This is used internally to make GIO extensible, but can also
51  * be used by others to implement module loading.
52  * 
53  **/
54
55 /**
56  * SECTION:extensionpoints
57  * @short_description: Extension Points
58  * @include: gio.h
59  * @see_also: <link linkend="extending-gio">Extending GIO</link>
60  *
61  * #GIOExtensionPoint provides a mechanism for modules to extend the
62  * functionality of the library or application that loaded it in an 
63  * organized fashion.  
64  *
65  * An extension point is identified by a name, and it may optionally
66  * require that any implementation must by of a certain type (or derived
67  * thereof). Use g_io_extension_point_register() to register an
68  * extension point, and g_io_extension_point_set_required_type() to
69  * set a required type.
70  *
71  * A module can implement an extension point by specifying the #GType 
72  * that implements the functionality. Additionally, each implementation
73  * of an extension point has a name, and a priority. Use
74  * g_io_extension_point_implement() to implement an extension point.
75  * 
76  *  |[
77  *  GIOExtensionPoint *ep;
78  *
79  *  /&ast; Register an extension point &ast;/
80  *  ep = g_io_extension_point_register ("my-extension-point");
81  *  g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
82  *  ]|
83  *
84  *  |[
85  *  /&ast; Implement an extension point &ast;/
86  *  G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE);
87  *  g_io_extension_point_implement ("my-extension-point",
88  *                                  my_example_impl_get_type (),
89  *                                  "my-example",
90  *                                  10);
91  *  ]|
92  *
93  *  It is up to the code that registered the extension point how
94  *  it uses the implementations that have been associated with it.
95  *  Depending on the use case, it may use all implementations, or
96  *  only the one with the highest priority, or pick a specific
97  *  one by name.
98  *
99  *  To avoid opening all modules just to find out what extension
100  *  points they implement, GIO makes use of a caching mechanism,
101  *  see <link linkend="gio-querymodules">gio-querymodules</link>.
102  *  You are expected to run this command after installing a
103  *  GIO module.
104  */
105 struct _GIOModule {
106   GTypeModule parent_instance;
107
108   gchar       *filename;
109   GModule     *library;
110   gboolean     initialized; /* The module was loaded at least once */
111
112   void (* load)   (GIOModule *module);
113   void (* unload) (GIOModule *module);
114 };
115
116 struct _GIOModuleClass
117 {
118   GTypeModuleClass parent_class;
119
120 };
121
122 static void      g_io_module_finalize      (GObject      *object);
123 static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
124 static void      g_io_module_unload_module (GTypeModule  *gmodule);
125
126 struct _GIOExtension {
127   char *name;
128   GType type;
129   gint priority;
130 };
131
132 struct _GIOExtensionPoint {
133   GType required_type;
134   char *name;
135   GList *extensions;
136   GList *lazy_load_modules;
137 };
138
139 static GHashTable *extension_points = NULL;
140 G_LOCK_DEFINE_STATIC(extension_points);
141
142 G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE);
143
144 static void
145 g_io_module_class_init (GIOModuleClass *class)
146 {
147   GObjectClass     *object_class      = G_OBJECT_CLASS (class);
148   GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
149
150   object_class->finalize     = g_io_module_finalize;
151
152   type_module_class->load    = g_io_module_load_module;
153   type_module_class->unload  = g_io_module_unload_module;
154 }
155
156 static void
157 g_io_module_init (GIOModule *module)
158 {
159 }
160
161 static void
162 g_io_module_finalize (GObject *object)
163 {
164   GIOModule *module = G_IO_MODULE (object);
165
166   g_free (module->filename);
167
168   G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
169 }
170
171 static gboolean
172 g_io_module_load_module (GTypeModule *gmodule)
173 {
174   GIOModule *module = G_IO_MODULE (gmodule);
175
176   if (!module->filename)
177     {
178       g_warning ("GIOModule path not set");
179       return FALSE;
180     }
181
182   module->library = g_module_open (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
183
184   if (!module->library)
185     {
186       g_printerr ("%s\n", g_module_error ());
187       return FALSE;
188     }
189
190   /* Make sure that the loaded library contains the required methods */
191   if (! g_module_symbol (module->library,
192                          "g_io_module_load",
193                          (gpointer) &module->load) ||
194       ! g_module_symbol (module->library,
195                          "g_io_module_unload",
196                          (gpointer) &module->unload))
197     {
198       g_printerr ("%s\n", g_module_error ());
199       g_module_close (module->library);
200
201       return FALSE;
202     }
203
204   /* Initialize the loaded module */
205   module->load (module);
206   module->initialized = TRUE;
207
208   return TRUE;
209 }
210
211 static void
212 g_io_module_unload_module (GTypeModule *gmodule)
213 {
214   GIOModule *module = G_IO_MODULE (gmodule);
215
216   module->unload (module);
217
218   g_module_close (module->library);
219   module->library = NULL;
220
221   module->load   = NULL;
222   module->unload = NULL;
223 }
224
225 /**
226  * g_io_module_new:
227  * @filename: filename of the shared library module.
228  * 
229  * Creates a new GIOModule that will load the specific
230  * shared library when in use.
231  * 
232  * Returns: a #GIOModule from given @filename, 
233  * or %NULL on error.
234  **/
235 GIOModule *
236 g_io_module_new (const gchar *filename)
237 {
238   GIOModule *module;
239
240   g_return_val_if_fail (filename != NULL, NULL);
241
242   module = g_object_new (G_IO_TYPE_MODULE, NULL);
243   module->filename = g_strdup (filename);
244
245   return module;
246 }
247
248 static gboolean
249 is_valid_module_name (const gchar *basename)
250 {
251 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
252   return
253     g_str_has_prefix (basename, "lib") &&
254     g_str_has_suffix (basename, ".so");
255 #else
256   return g_str_has_suffix (basename, ".dll");
257 #endif
258 }
259
260 /**
261  * g_io_modules_scan_all_in_directory:
262  * @dirname: pathname for a directory containing modules to scan.
263  *
264  * Scans all the modules in the specified directory, ensuring that
265  * any extension point implemented by a module is registered.
266  *
267  * This may not actually load and initialize all the types in each
268  * module, some modules may be lazily loaded and initialized when
269  * an extension point it implementes is used with e.g.
270  * g_io_extension_point_get_extensions() or
271  * g_io_extension_point_get_extension_by_name().
272  *
273  * If you need to guarantee that all types are loaded in all the modules,
274  * use g_io_modules_scan_all_in_directory().
275  *
276  * Since: 2.24
277  **/
278 void
279 g_io_modules_scan_all_in_directory (const char *dirname)
280 {
281   const gchar *name;
282   char *filename;
283   GDir *dir;
284   GStatBuf statbuf;
285   char *data;
286   time_t cache_mtime;
287   GHashTable *cache;
288
289   if (!g_module_supported ())
290     return;
291
292   dir = g_dir_open (dirname, 0, NULL);
293   if (!dir)
294     return;
295
296   filename = g_build_filename (dirname, "giomodule.cache", NULL);
297
298   cache = g_hash_table_new_full (g_str_hash, g_str_equal,
299                                  g_free, (GDestroyNotify)g_strfreev);
300
301   cache_mtime = 0;
302   if (g_stat (filename, &statbuf) == 0 &&
303       g_file_get_contents (filename, &data, NULL, NULL))
304     {
305       char **lines;
306       int i;
307
308       /* Cache mtime is the time the cache file was created, any file
309        * that has a ctime before this was created then and not modified
310        * since then (userspace can't change ctime). Its possible to change
311        * the ctime forward without changing the file content, by e.g.
312        * chmoding the file, but this is uncommon and will only cause us
313        * to not use the cache so will not cause bugs.
314        */
315       cache_mtime = statbuf.st_mtime;
316
317       lines = g_strsplit (data, "\n", -1);
318       g_free (data);
319
320       for (i = 0;  lines[i] != NULL; i++)
321         {
322           char *line = lines[i];
323           char *file;
324           char *colon;
325           char **extension_points;
326
327           if (line[0] == '#')
328             continue;
329
330           colon = strchr (line, ':');
331           if (colon == NULL || line == colon)
332             continue; /* Invalid line, ignore */
333
334           *colon = 0; /* terminate filename */
335           file = g_strdup (line);
336           colon++; /* after colon */
337
338           while (g_ascii_isspace (*colon))
339             colon++;
340
341           extension_points = g_strsplit (colon, ",", -1);
342           g_hash_table_insert (cache, file, extension_points);
343         }
344       g_strfreev (lines);
345     }
346
347   while ((name = g_dir_read_name (dir)))
348     {
349       if (is_valid_module_name (name))
350         {
351           GIOExtensionPoint *extension_point;
352           GIOModule *module;
353           gchar *path;
354           char **extension_points;
355           int i;
356
357           path = g_build_filename (dirname, name, NULL);
358           module = g_io_module_new (path);
359
360           extension_points = g_hash_table_lookup (cache, name);
361           if (extension_points != NULL &&
362               g_stat (path, &statbuf) == 0 &&
363               statbuf.st_ctime <= cache_mtime)
364             {
365               /* Lazy load/init the library when first required */
366               for (i = 0; extension_points[i] != NULL; i++)
367                 {
368                   extension_point =
369                     g_io_extension_point_register (extension_points[i]);
370                   extension_point->lazy_load_modules =
371                     g_list_prepend (extension_point->lazy_load_modules,
372                                     module);
373                 }
374             }
375           else
376             {
377               /* Try to load and init types */
378               if (g_type_module_use (G_TYPE_MODULE (module)))
379                 g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
380               else
381                 { /* Failure to load */
382                   g_printerr ("Failed to load module: %s\n", path);
383                   g_object_unref (module);
384                   g_free (path);
385                   continue;
386                 }
387             }
388
389           g_free (path);
390         }
391     }
392
393   g_dir_close (dir);
394
395   g_hash_table_destroy (cache);
396
397   g_free (filename);
398 }
399
400
401 /**
402  * g_io_modules_load_all_in_directory:
403  * @dirname: pathname for a directory containing modules to load.
404  *
405  * Loads all the modules in the specified directory.
406  *
407  * If don't require all modules to be initialized (and thus registering
408  * all gtypes) then you can use g_io_modules_scan_all_in_directory()
409  * which allows delayed/lazy loading of modules.
410  *
411  * Returns: a list of #GIOModules loaded from the directory,
412  *      All the modules are loaded into memory, if you want to
413  *      unload them (enabling on-demand loading) you must call
414  *      g_type_module_unuse() on all the modules. Free the list
415  *      with g_list_free().
416  **/
417 GList *
418 g_io_modules_load_all_in_directory (const char *dirname)
419 {
420   const gchar *name;
421   GDir        *dir;
422   GList *modules;
423
424   if (!g_module_supported ())
425     return NULL;
426
427   dir = g_dir_open (dirname, 0, NULL);
428   if (!dir)
429     return NULL;
430
431   modules = NULL;
432   while ((name = g_dir_read_name (dir)))
433     {
434       if (is_valid_module_name (name))
435         {
436           GIOModule *module;
437           gchar     *path;
438
439           path = g_build_filename (dirname, name, NULL);
440           module = g_io_module_new (path);
441
442           if (!g_type_module_use (G_TYPE_MODULE (module)))
443             {
444               g_printerr ("Failed to load module: %s\n", path);
445               g_object_unref (module);
446               g_free (path);
447               continue;
448             }
449           
450           g_free (path);
451
452           modules = g_list_prepend (modules, module);
453         }
454     }
455   
456   g_dir_close (dir);
457
458   return modules;
459 }
460
461 G_LOCK_DEFINE_STATIC (registered_extensions);
462 G_LOCK_DEFINE_STATIC (loaded_dirs);
463
464 extern GType _g_fen_directory_monitor_get_type (void);
465 extern GType _g_fen_file_monitor_get_type (void);
466 extern GType _g_inotify_directory_monitor_get_type (void);
467 extern GType _g_inotify_file_monitor_get_type (void);
468 extern GType _g_unix_volume_monitor_get_type (void);
469 extern GType _g_local_vfs_get_type (void);
470
471 extern GType _g_win32_volume_monitor_get_type (void);
472 extern GType g_win32_directory_monitor_get_type (void);
473 extern GType _g_winhttp_vfs_get_type (void);
474
475 extern GType _g_dummy_proxy_resolver_get_type (void);
476
477 #ifdef G_PLATFORM_WIN32
478
479 #include <windows.h>
480
481 static HMODULE gio_dll = NULL;
482
483 #ifdef DLL_EXPORT
484
485 BOOL WINAPI
486 DllMain (HINSTANCE hinstDLL,
487          DWORD     fdwReason,
488          LPVOID    lpvReserved)
489 {
490   if (fdwReason == DLL_PROCESS_ATTACH)
491       gio_dll = hinstDLL;
492
493   return TRUE;
494 }
495
496 #endif
497
498 #undef GIO_MODULE_DIR
499
500 /* GIO_MODULE_DIR is used only in code called just once,
501  * so no problem leaking this
502  */
503 #define GIO_MODULE_DIR \
504   g_build_filename (g_win32_get_package_installation_directory_of_module (gio_dll), \
505                     "lib/gio/modules", \
506                     NULL)
507
508 #endif
509
510 void
511 _g_io_modules_ensure_extension_points_registered (void)
512 {
513   static gboolean registered_extensions = FALSE;
514   GIOExtensionPoint *ep;
515
516   G_LOCK (registered_extensions);
517   
518   if (!registered_extensions)
519     {
520       registered_extensions = TRUE;
521       
522 #ifdef G_OS_UNIX
523       ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
524       g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
525 #endif
526       
527       ep = g_io_extension_point_register (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME);
528       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_DIRECTORY_MONITOR);
529       
530       ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
531       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
532       
533       ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
534       g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
535       
536       ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
537       g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
538       
539       ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
540       g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
541
542       ep = g_io_extension_point_register ("gsettings-backend");
543       g_io_extension_point_set_required_type (ep, G_TYPE_OBJECT);
544
545       ep = g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
546       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY_RESOLVER);
547
548       ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
549       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
550     }
551   
552   G_UNLOCK (registered_extensions);
553  }
554
555 void
556 _g_io_modules_ensure_loaded (void)
557 {
558   static gboolean loaded_dirs = FALSE;
559   const char *module_path;
560
561   _g_io_modules_ensure_extension_points_registered ();
562   
563   G_LOCK (loaded_dirs);
564
565   if (!loaded_dirs)
566     {
567       loaded_dirs = TRUE;
568
569       g_io_modules_scan_all_in_directory (GIO_MODULE_DIR);
570
571       module_path = g_getenv ("GIO_EXTRA_MODULES");
572
573       if (module_path)
574         {
575           gchar **paths;
576           int i;
577
578           paths = g_strsplit (module_path, ":", 0);
579
580           for (i = 0; paths[i] != NULL; i++)
581             g_io_modules_scan_all_in_directory (paths[i]);
582
583           g_strfreev (paths);
584         }
585
586       /* Initialize types from built-in "modules" */
587       g_memory_settings_backend_get_type ();
588 #if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
589       _g_inotify_directory_monitor_get_type ();
590       _g_inotify_file_monitor_get_type ();
591 #endif
592 #if defined(HAVE_FEN)
593       _g_fen_directory_monitor_get_type ();
594       _g_fen_file_monitor_get_type ();
595 #endif
596 #ifdef G_OS_WIN32
597       _g_win32_volume_monitor_get_type ();
598       g_win32_directory_monitor_get_type ();
599 #endif
600 #ifdef G_OS_UNIX
601       _g_unix_volume_monitor_get_type ();
602 #endif
603 #ifdef G_OS_WIN32
604       _g_winhttp_vfs_get_type ();
605 #endif
606       _g_local_vfs_get_type ();
607       _g_dummy_proxy_resolver_get_type ();
608       _g_socks4a_proxy_get_type ();
609       _g_socks4_proxy_get_type ();
610       _g_socks5_proxy_get_type ();
611     }
612
613   G_UNLOCK (loaded_dirs);
614 }
615
616 static void
617 g_io_extension_point_free (GIOExtensionPoint *ep)
618 {
619   g_free (ep->name);
620   g_free (ep);
621 }
622
623 /**
624  * g_io_extension_point_register:
625  * @name: The name of the extension point
626  *
627  * Registers an extension point.
628  *
629  * Returns: the new #GIOExtensionPoint. This object is owned by GIO
630  *    and should not be freed
631  */
632 GIOExtensionPoint *
633 g_io_extension_point_register (const char *name)
634 {
635   GIOExtensionPoint *ep;
636   
637   G_LOCK (extension_points);
638   if (extension_points == NULL)
639     extension_points = g_hash_table_new_full (g_str_hash,
640                                               g_str_equal,
641                                               NULL,
642                                               (GDestroyNotify)g_io_extension_point_free);
643
644   ep = g_hash_table_lookup (extension_points, name);
645   if (ep != NULL)
646     {
647       G_UNLOCK (extension_points);
648       return ep;
649     }
650
651   ep = g_new0 (GIOExtensionPoint, 1);
652   ep->name = g_strdup (name);
653   
654   g_hash_table_insert (extension_points, ep->name, ep);
655   
656   G_UNLOCK (extension_points);
657
658   return ep;
659 }
660
661 /**
662  * g_io_extension_point_lookup:
663  * @name: the name of the extension point
664  *
665  * Looks up an existing extension point.
666  *
667  * Returns: the #GIOExtensionPoint, or %NULL if there is no
668  *    registered extension point with the given name
669  */
670 GIOExtensionPoint *
671 g_io_extension_point_lookup (const char *name)
672 {
673   GIOExtensionPoint *ep;
674
675   G_LOCK (extension_points);
676   ep = NULL;
677   if (extension_points != NULL)
678     ep = g_hash_table_lookup (extension_points, name);
679   
680   G_UNLOCK (extension_points);
681
682   return ep;
683   
684 }
685
686 /**
687  * g_io_extension_point_set_required_type:
688  * @extension_point: a #GIOExtensionPoint
689  * @type: the #GType to require
690  *
691  * Sets the required type for @extension_point to @type. 
692  * All implementations must henceforth have this type.
693  */
694 void
695 g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
696                                         GType              type)
697 {
698   extension_point->required_type = type;
699 }
700
701 /**
702  * g_io_extension_point_get_required_type:
703  * @extension_point: a #GIOExtensionPoint
704  *
705  * Gets the required type for @extension_point.
706  *
707  * Returns: the #GType that all implementations must have, 
708  *     or #G_TYPE_INVALID if the extension point has no required type
709  */
710 GType
711 g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
712 {
713   return extension_point->required_type;
714 }
715
716 void
717 lazy_load_modules (GIOExtensionPoint *extension_point)
718 {
719   GIOModule *module;
720   GList *l;
721
722   for (l = extension_point->lazy_load_modules; l != NULL; l = l->next)
723     {
724       module = l->data;
725
726       if (!module->initialized)
727         {
728           if (g_type_module_use (G_TYPE_MODULE (module)))
729             g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
730           else
731             g_printerr ("Failed to load module: %s\n",
732                         module->filename);
733         }
734     }
735 }
736
737 /**
738  * g_io_extension_point_get_extensions:
739  * @extension_point: a #GIOExtensionPoint
740  *
741  * Gets a list of all extensions that implement this extension point.
742  * The list is sorted by priority, beginning with the highest priority.
743  *
744  * Returns: (element-type GIOExtension) (transfer none): a #GList of
745  * #GIOExtension<!-- -->s. The list is owned by GIO and should not be
746  * modified.
747  */
748 GList *
749 g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
750 {
751   lazy_load_modules (extension_point);
752   return extension_point->extensions;
753 }
754
755 /**
756  * g_io_extension_point_get_extension_by_name:
757  * @extension_point: a #GIOExtensionPoint
758  * @name: the name of the extension to get
759  *
760  * Finds a #GIOExtension for an extension point by name.
761  *
762  * Returns: the #GIOExtension for @extension_point that has the
763  *    given name, or %NULL if there is no extension with that name
764  */
765 GIOExtension *
766 g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
767                                             const char        *name)
768 {
769   GList *l;
770
771   lazy_load_modules (extension_point);
772   for (l = extension_point->extensions; l != NULL; l = l->next)
773     {
774       GIOExtension *e = l->data;
775
776       if (e->name != NULL &&
777           strcmp (e->name, name) == 0)
778         return e;
779     }
780   
781   return NULL;
782 }
783
784 static gint
785 extension_prio_compare (gconstpointer  a,
786                         gconstpointer  b)
787 {
788   const GIOExtension *extension_a = a, *extension_b = b;
789
790   return extension_b->priority - extension_a->priority;
791 }
792
793 /**
794  * g_io_extension_point_implement:
795  * @extension_point_name: the name of the extension point
796  * @type: the #GType to register as extension 
797  * @extension_name: the name for the extension
798  * @priority: the priority for the extension
799  *
800  * Registers @type as extension for the extension point with name
801  * @extension_point_name. 
802  *
803  * If @type has already been registered as an extension for this 
804  * extension point, the existing #GIOExtension object is returned.
805  *
806  * Returns: a #GIOExtension object for #GType
807  */
808 GIOExtension *
809 g_io_extension_point_implement (const char *extension_point_name,
810                                 GType       type,
811                                 const char *extension_name,
812                                 gint        priority)
813 {
814   GIOExtensionPoint *extension_point;
815   GIOExtension *extension;
816   GList *l;
817
818   g_return_val_if_fail (extension_point_name != NULL, NULL);
819
820   extension_point = g_io_extension_point_lookup (extension_point_name);
821   if (extension_point == NULL)
822     {
823       g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
824       return NULL;
825     }
826   
827   if (extension_point->required_type != 0 &&
828       !g_type_is_a (type, extension_point->required_type))
829     {
830       g_warning ("Tried to register an extension of the type %s to extension point %s. "
831                  "Expected type is %s.",
832                  g_type_name (type),
833                  extension_point_name, 
834                  g_type_name (extension_point->required_type));
835       return NULL;
836     }      
837
838   /* It's safe to register the same type multiple times */
839   for (l = extension_point->extensions; l != NULL; l = l->next)
840     {
841       extension = l->data;
842       if (extension->type == type)
843         return extension;
844     }
845   
846   extension = g_slice_new0 (GIOExtension);
847   extension->type = type;
848   extension->name = g_strdup (extension_name);
849   extension->priority = priority;
850   
851   extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
852                                                       extension, extension_prio_compare);
853   
854   return extension;
855 }
856
857 /**
858  * g_io_extension_ref_class:
859  * @extension: a #GIOExtension
860  *
861  * Gets a reference to the class for the type that is 
862  * associated with @extension.
863  *
864  * Returns: the #GTypeClass for the type of @extension
865  */
866 GTypeClass *
867 g_io_extension_ref_class (GIOExtension *extension)
868 {
869   return g_type_class_ref (extension->type);
870 }
871
872 /**
873  * g_io_extension_get_type:
874  * @extension: a #GIOExtension
875  *
876  * Gets the type associated with @extension.
877  *
878  * Returns: the type of @extension
879  */
880 GType
881 g_io_extension_get_type (GIOExtension *extension)
882 {
883   return extension->type;
884 }
885
886 /**
887  * g_io_extension_get_name:
888  * @extension: a #GIOExtension
889  *
890  * Gets the name under which @extension was registered.
891  *
892  * Note that the same type may be registered as extension
893  * for multiple extension points, under different names.
894  *
895  * Returns: the name of @extension.
896  */
897 const char *
898 g_io_extension_get_name (GIOExtension *extension)
899 {
900   return extension->name;
901 }
902
903 /**
904  * g_io_extension_get_priority:
905  * @extension: a #GIOExtension
906  *
907  * Gets the priority with which @extension was registered.
908  *
909  * Returns: the priority of @extension
910  */
911 gint
912 g_io_extension_get_priority (GIOExtension *extension)
913 {
914   return extension->priority;
915 }