Add _g_io_module_get_default(), use to simplify other *_get_default()s
authorDan Winship <danw@gnome.org>
Tue, 21 Jun 2011 22:21:27 +0000 (18:21 -0400)
committerDan Winship <danw@gnome.org>
Tue, 4 Oct 2011 17:20:34 +0000 (13:20 -0400)
Add _g_io_module_get_default(), which implements the
figure-out-the-best-available-module-that-is-actually-usable logic,
and use that to simplify g_proxy_resolver_get_default(),
g_settings_backend_get_default(), g_tls_backend_get_default(), and
g_vfs_get_default().

https://bugzilla.gnome.org/show_bug.cgi?id=620932

gio/giomodule-priv.h
gio/giomodule.c
gio/gproxyresolver.c
gio/gsettingsbackend.c
gio/gtlsbackend.c
gio/gvfs.c

index a4677b0..b25d305 100644 (file)
@@ -30,6 +30,11 @@ G_BEGIN_DECLS
 void _g_io_modules_ensure_extension_points_registered (void);
 void _g_io_modules_ensure_loaded                      (void);
 
+typedef gboolean (*GIOModuleVerifyFunc) (gpointer);
+gpointer _g_io_module_get_default (const gchar         *extension_point,
+                                  const gchar         *envvar,
+                                  GIOModuleVerifyFunc  verify_func);
+
 G_END_DECLS
 
 #endif /* __G_IO_MODULE_PRIV_H__ */
index 2763a98..61638c0 100644 (file)
@@ -630,6 +630,133 @@ g_io_modules_load_all_in_directory (const char *dirname)
   return g_io_modules_load_all_in_directory_with_scope (dirname, NULL);
 }
 
+G_LOCK_DEFINE_STATIC (default_modules);
+GHashTable *default_modules;
+
+static gpointer
+try_implementation (GIOExtension         *extension,
+                   GIOModuleVerifyFunc   verify_func)
+{
+  GType type = g_io_extension_get_type (extension);
+  gpointer impl;
+
+  if (g_type_is_a (type, G_TYPE_INITABLE))
+    return g_initable_new (type, NULL, NULL, NULL);
+  else
+    {
+      impl = g_object_new (type, NULL);
+      if (!verify_func || verify_func (impl))
+       return impl;
+
+      g_object_unref (impl);
+      return NULL;
+    }
+}
+
+/**
+ * _g_io_module_get_default:
+ * @extension_point: the name of an extension point
+ * @envvar: (allow-none): the name of an environment variable to
+ *     override the default implementation.
+ * @verify_func: (allow-none): a function to call to verify that
+ *     a given implementation is usable in the current environment.
+ *
+ * Retrieves the default object implementing @extension_point.
+ *
+ * If @envvar is not %NULL, and the environment variable with that
+ * name is set, then the implementation it specifies will be tried
+ * first. After that, or if @envvar is not set, all other
+ * implementations will be tried in order of decreasing priority.
+ *
+ * If an extension point implementation implements #GInitable, then
+ * that implementation will only be used if it initializes
+ * successfully. Otherwise, if @verify_func is not %NULL, then it will
+ * be called on each candidate implementation after construction, to
+ * check if it is actually usable or not.
+ *
+ * The result is cached after it is generated the first time, and
+ * the function is thread-safe.
+ *
+ * Return value: (transfer none): an object implementing
+ *     @extension_point, or %NULL if there are no usable
+ *     implementations.
+ */
+gpointer
+_g_io_module_get_default (const gchar         *extension_point,
+                         const gchar         *envvar,
+                         GIOModuleVerifyFunc  verify_func)
+{
+  const char *use_this;
+  GList *l;
+  GIOExtensionPoint *ep;
+  GIOExtension *extension, *preferred;
+  gpointer impl;
+
+  G_LOCK (default_modules);
+  if (default_modules)
+    {
+      gpointer key;
+
+      if (g_hash_table_lookup_extended (default_modules, extension_point,
+                                       &key, &impl))
+       {
+         G_UNLOCK (default_modules);
+         return impl;
+       }
+    }
+  else
+    {
+      default_modules = g_hash_table_new (g_str_hash, g_str_equal);
+    }
+
+  _g_io_modules_ensure_loaded ();
+  ep = g_io_extension_point_lookup (extension_point);
+
+  if (!ep)
+    {
+      g_warn_if_reached ();
+      G_UNLOCK (default_modules);
+      return NULL;
+    }
+
+  use_this = envvar ? g_getenv (envvar) : NULL;
+  if (use_this)
+    {
+      preferred = g_io_extension_point_get_extension_by_name (ep, use_this);
+      if (preferred)
+       {
+         impl = try_implementation (preferred, verify_func);
+         if (impl)
+           goto done;
+       }
+      else
+       g_warning ("Can't find module '%s' specified in %s", use_this, envvar);
+    }
+  else
+    preferred = NULL;
+
+  for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
+    {
+      extension = l->data;
+      if (extension == preferred)
+       continue;
+
+      impl = try_implementation (extension, verify_func);
+      if (impl)
+       goto done;
+    }
+
+  impl = NULL;
+
+ done:
+  g_hash_table_insert (default_modules,
+                      g_strdup (extension_point),
+                      impl ? g_object_ref (impl) : NULL);
+  G_UNLOCK (default_modules);
+
+  return impl;
+}
+
 G_LOCK_DEFINE_STATIC (registered_extensions);
 G_LOCK_DEFINE_STATIC (loaded_dirs);
 
index 2bc9733..db2e475 100644 (file)
@@ -50,52 +50,6 @@ g_proxy_resolver_default_init (GProxyResolverInterface *iface)
 {
 }
 
-static gpointer
-get_default_proxy_resolver (gpointer arg)
-{
-  const gchar *use_this;
-  GProxyResolver *resolver;
-  GList *l;
-  GIOExtensionPoint *ep;
-  GIOExtension *extension;
-  
-
-  use_this = g_getenv ("GIO_USE_PROXY_RESOLVER");
-  
-  /* Ensure proxy-resolver modules loaded */
-  _g_io_modules_ensure_loaded ();
-
-  ep = g_io_extension_point_lookup (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
-
-  if (use_this)
-    {
-      extension = g_io_extension_point_get_extension_by_name (ep, use_this);
-      if (extension)
-       {
-          resolver = g_object_new (g_io_extension_get_type (extension), NULL);
-         
-          if (g_proxy_resolver_is_supported (resolver))
-            return resolver;
-         
-         g_object_unref (resolver);
-       }
-    }
-
-  for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
-    {
-      extension = l->data;
-
-      resolver = g_object_new (g_io_extension_get_type (extension), NULL);
-
-      if (g_proxy_resolver_is_supported (resolver))
-       return resolver;
-
-      g_object_unref (resolver);
-    }
-  
-  return NULL;
-}
-
 /**
  * g_proxy_resolver_get_default:
  *
@@ -108,9 +62,9 @@ get_default_proxy_resolver (gpointer arg)
 GProxyResolver *
 g_proxy_resolver_get_default (void)
 {
-  static GOnce once_init = G_ONCE_INIT;
-
-  return g_once (&once_init, get_default_proxy_resolver, NULL);
+  return _g_io_module_get_default (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
+                                  "GIO_USE_PROXY_RESOLVER",
+                                  (GIOModuleVerifyFunc)g_proxy_resolver_is_supported);
 }
 
 /**
index f824b93..a170241 100644 (file)
@@ -935,6 +935,22 @@ g_settings_backend_create_tree (void)
                           g_free, g_settings_backend_variant_unref0);
 }
 
+static gboolean
+g_settings_backend_verify (gpointer impl)
+{
+  GSettingsBackend *backend = impl;
+
+  if (strcmp (G_OBJECT_TYPE_NAME (backend), "GMemorySettingsBackend") == 0 &&
+      g_strcmp0 (g_getenv ("GSETTINGS_BACKEND"), "memory") != 0)
+    {
+      g_message ("Using the 'memory' GSettings backend.  Your settings "
+                "will not be saved or shared with other applications.");
+    }
+
+  g_settings_has_backend = TRUE;
+  return TRUE;
+}
+
 /**
  * g_settings_backend_get_default:
  * @returns: (transfer full): the default #GSettingsBackend
@@ -950,49 +966,12 @@ g_settings_backend_create_tree (void)
 GSettingsBackend *
 g_settings_backend_get_default (void)
 {
-  static gsize backend;
-
-  if (g_once_init_enter (&backend))
-    {
-      GSettingsBackend *instance;
-      GIOExtensionPoint *point;
-      GIOExtension *extension;
-      GType extension_type;
-      GList *extensions;
-      const gchar *env;
-
-      _g_io_modules_ensure_loaded ();
-
-      point = g_io_extension_point_lookup (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME);
-      extension = NULL;
-
-      if ((env = getenv ("GSETTINGS_BACKEND")))
-        {
-          extension = g_io_extension_point_get_extension_by_name (point, env);
-
-          if (extension == NULL)
-            g_warning ("Can't find GSettings backend '%s' given in "
-                       "GSETTINGS_BACKEND environment variable", env);
-        }
-
-      if (extension == NULL)
-        {
-          extensions = g_io_extension_point_get_extensions (point);
-          extension = extensions->data;
-
-          if (strcmp (g_io_extension_get_name (extension), "memory") == 0)
-            g_message ("Using the 'memory' GSettings backend.  Your settings "
-                       "will not be saved or shared with other applications.");
-        }
-
-      extension_type = g_io_extension_get_type (extension);
-      instance = g_object_new (extension_type, NULL);
-      g_settings_has_backend = TRUE;
-
-      g_once_init_leave (&backend, (gsize) instance);
-    }
+  GSettingsBackend *backend;
 
-  return g_object_ref ((void *) backend);
+  backend = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
+                                     "GSETTINGS_BACKEND",
+                                     g_settings_backend_verify);
+  return g_object_ref (backend);
 }
 
 /*< private >
index 13fff17..2d6913a 100644 (file)
@@ -80,36 +80,6 @@ g_tls_backend_default_init (GTlsBackendInterface *iface)
 {
 }
 
-static gpointer
-get_default_tls_backend (gpointer arg)
-{
-  const char *use_this;
-  GList *extensions;
-  GIOExtensionPoint *ep;
-  GIOExtension *extension;
-
-  _g_io_modules_ensure_loaded ();
-
-  ep = g_io_extension_point_lookup (G_TLS_BACKEND_EXTENSION_POINT_NAME);
-
-  use_this = g_getenv ("GIO_USE_TLS");
-  if (use_this)
-    {
-      extension = g_io_extension_point_get_extension_by_name (ep, use_this);
-      if (extension)
-       return g_object_new (g_io_extension_get_type (extension), NULL);
-    }
-
-  extensions = g_io_extension_point_get_extensions (ep);
-  if (extensions)
-    {
-      extension = extensions->data;
-      return g_object_new (g_io_extension_get_type (extension), NULL);
-    }
-
-  return NULL;
-}
-
 /**
  * g_tls_backend_get_default:
  *
@@ -122,9 +92,8 @@ get_default_tls_backend (gpointer arg)
 GTlsBackend *
 g_tls_backend_get_default (void)
 {
-  static GOnce once_init = G_ONCE_INIT;
-
-  return g_once (&once_init, get_default_tls_backend, NULL);
+  return _g_io_module_get_default (G_TLS_BACKEND_EXTENSION_POINT_NAME,
+                                  "GIO_USE_TLS", NULL);
 }
 
 /**
index 697c69b..cbe7f2f 100644 (file)
@@ -170,53 +170,6 @@ g_vfs_parse_name (GVfs       *vfs,
   return (* class->parse_name) (vfs, parse_name);
 }
 
-static gpointer
-get_default_vfs (gpointer arg)
-{
-  const char *use_this;
-  GVfs *vfs;
-  GList *l;
-  GIOExtensionPoint *ep;
-  GIOExtension *extension;
-  
-
-  use_this = g_getenv ("GIO_USE_VFS");
-  
-  /* Ensure vfs in modules loaded */
-  _g_io_modules_ensure_loaded ();
-
-  ep = g_io_extension_point_lookup (G_VFS_EXTENSION_POINT_NAME);
-
-  if (use_this)
-    {
-      extension = g_io_extension_point_get_extension_by_name (ep, use_this);
-      if (extension)
-       {
-         vfs = g_object_new (g_io_extension_get_type (extension), NULL);
-         
-         if (g_vfs_is_active (vfs))
-           return vfs;
-         
-         g_object_unref (vfs);
-       }
-    }
-
-  for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
-    {
-      extension = l->data;
-
-      vfs = g_object_new (g_io_extension_get_type (extension), NULL);
-
-      if (g_vfs_is_active (vfs))
-       return vfs;
-
-      g_object_unref (vfs);
-    }
-  
-
-  return NULL;
-}
-
 /**
  * g_vfs_get_default:
  * 
@@ -227,9 +180,9 @@ get_default_vfs (gpointer arg)
 GVfs *
 g_vfs_get_default (void)
 {
-  static GOnce once_init = G_ONCE_INIT;
-  
-  return g_once (&once_init, get_default_vfs, NULL);
+  return _g_io_module_get_default (G_VFS_EXTENSION_POINT_NAME,
+                                  "GIO_USE_VFS",
+                                  (GIOModuleVerifyFunc)g_vfs_is_active);
 }
 
 /**