mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
giomodule: add a new "get default" function
_gio_module_get_default() is a very convenient function for modules implementing a singleton -- it finds the default module by priority subject to override by a given environment variable name, instantiates it, and caches the instance for future calls. It also has the ability to query instances for being 'active' using a callback. It doesn't work very well for non-singletons (like file monitors). Add a new function _gio_module_get_default_type() that skips the instantiation, returning the GType instead. As a replacement for the 'active' callback, a vtable offset can be given for a virtual function to use to query if a particular backend is supported. https://bugzilla.gnome.org/show_bug.cgi?id=592211
This commit is contained in:
parent
ca58dae277
commit
3a7b44c007
@ -35,6 +35,10 @@ gpointer _g_io_module_get_default (const gchar *extension_point,
|
||||
const gchar *envvar,
|
||||
GIOModuleVerifyFunc verify_func);
|
||||
|
||||
GType _g_io_module_get_default_type (const gchar *extension_point,
|
||||
const gchar *envvar,
|
||||
guint is_supported_offset);
|
||||
|
||||
#ifdef G_PLATFORM_WIN32
|
||||
void *_g_io_win32_get_module (void);
|
||||
#endif
|
||||
|
120
gio/giomodule.c
120
gio/giomodule.c
@ -628,8 +628,122 @@ g_io_modules_load_all_in_directory (const char *dirname)
|
||||
return g_io_modules_load_all_in_directory_with_scope (dirname, NULL);
|
||||
}
|
||||
|
||||
GRecMutex default_modules_lock;
|
||||
GHashTable *default_modules;
|
||||
static gpointer
|
||||
try_class (GIOExtension *extension,
|
||||
guint is_supported_offset)
|
||||
{
|
||||
GType type = g_io_extension_get_type (extension);
|
||||
typedef gboolean (*verify_func) (void);
|
||||
gpointer class;
|
||||
|
||||
class = g_type_class_ref (type);
|
||||
if (!is_supported_offset || (* G_STRUCT_MEMBER(verify_func, class, is_supported_offset)) ())
|
||||
return class;
|
||||
|
||||
g_type_class_unref (class);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _g_io_module_get_default_type:
|
||||
* @extension_point: the name of an extension point
|
||||
* @envvar: (allow-none): the name of an environment variable to
|
||||
* override the default implementation.
|
||||
* @is_supported_offset: a vtable offset, or zero
|
||||
*
|
||||
* Retrieves the default class 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 @is_supported_offset is non-zero, then it is the offset into the
|
||||
* class vtable at which there is a function that takes no arguments and
|
||||
* returns a boolean. This function will be called on each candidate
|
||||
* implementation 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.
|
||||
*/
|
||||
GType
|
||||
_g_io_module_get_default_type (const gchar *extension_point,
|
||||
const gchar *envvar,
|
||||
guint is_supported_offset)
|
||||
{
|
||||
static GRecMutex default_modules_lock;
|
||||
static GHashTable *default_modules;
|
||||
const char *use_this;
|
||||
GList *l;
|
||||
GIOExtensionPoint *ep;
|
||||
GIOExtension *extension, *preferred;
|
||||
gpointer impl;
|
||||
|
||||
g_rec_mutex_lock (&default_modules_lock);
|
||||
if (default_modules)
|
||||
{
|
||||
gpointer key;
|
||||
|
||||
if (g_hash_table_lookup_extended (default_modules, extension_point, &key, &impl))
|
||||
{
|
||||
g_rec_mutex_unlock (&default_modules_lock);
|
||||
return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
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_rec_mutex_unlock (&default_modules_lock);
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
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_class (preferred, is_supported_offset);
|
||||
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_class (extension, is_supported_offset);
|
||||
if (impl)
|
||||
goto done;
|
||||
}
|
||||
|
||||
impl = NULL;
|
||||
|
||||
done:
|
||||
g_hash_table_insert (default_modules, g_strdup (extension_point), impl);
|
||||
g_rec_mutex_unlock (&default_modules_lock);
|
||||
|
||||
return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
try_implementation (GIOExtension *extension,
|
||||
@ -684,6 +798,8 @@ _g_io_module_get_default (const gchar *extension_point,
|
||||
const gchar *envvar,
|
||||
GIOModuleVerifyFunc verify_func)
|
||||
{
|
||||
static GRecMutex default_modules_lock;
|
||||
static GHashTable *default_modules;
|
||||
const char *use_this;
|
||||
GList *l;
|
||||
GIOExtensionPoint *ep;
|
||||
|
Loading…
Reference in New Issue
Block a user