mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-27 22:46:15 +01:00
repository: g_irepository_get_object_gtype_interfaces
Bindings in some cases need to look up information from a GType dynamically. Support that better by supplying a cache for this information. (Rebased and versioning / gtk-doc stuff added by Philip Chimento.) Closes #38. See gjs#55.
This commit is contained in:
parent
9b367e74ef
commit
8de3abd642
@ -58,12 +58,29 @@
|
|||||||
static GIRepository *default_repository = NULL;
|
static GIRepository *default_repository = NULL;
|
||||||
static GSList *typelib_search_path = NULL;
|
static GSList *typelib_search_path = NULL;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint n_interfaces;
|
||||||
|
GIBaseInfo *interfaces[];
|
||||||
|
} GTypeInterfaceCache;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtype_interface_cache_free (gpointer data)
|
||||||
|
{
|
||||||
|
GTypeInterfaceCache *cache = data;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < cache->n_interfaces; i++)
|
||||||
|
g_base_info_unref ((GIBaseInfo*) cache->interfaces[i]);
|
||||||
|
g_free (cache);
|
||||||
|
}
|
||||||
|
|
||||||
struct _GIRepositoryPrivate
|
struct _GIRepositoryPrivate
|
||||||
{
|
{
|
||||||
GHashTable *typelibs; /* (string) namespace -> GITypelib */
|
GHashTable *typelibs; /* (string) namespace -> GITypelib */
|
||||||
GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */
|
GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */
|
||||||
GHashTable *info_by_gtype; /* GType -> GIBaseInfo */
|
GHashTable *info_by_gtype; /* GType -> GIBaseInfo */
|
||||||
GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */
|
GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */
|
||||||
|
GHashTable *interfaces_for_gtype; /* GType -> GTypeInterfaceCache */
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_CODE (GIRepository, g_irepository, G_TYPE_OBJECT, G_ADD_PRIVATE (GIRepository));
|
G_DEFINE_TYPE_WITH_CODE (GIRepository, g_irepository, G_TYPE_OBJECT, G_ADD_PRIVATE (GIRepository));
|
||||||
@ -123,6 +140,10 @@ g_irepository_init (GIRepository *repository)
|
|||||||
= g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
= g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
(GDestroyNotify) NULL,
|
(GDestroyNotify) NULL,
|
||||||
(GDestroyNotify) g_base_info_unref);
|
(GDestroyNotify) g_base_info_unref);
|
||||||
|
repository->priv->interfaces_for_gtype
|
||||||
|
= g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
(GDestroyNotify) NULL,
|
||||||
|
(GDestroyNotify) gtype_interface_cache_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -134,6 +155,7 @@ g_irepository_finalize (GObject *object)
|
|||||||
g_hash_table_destroy (repository->priv->lazy_typelibs);
|
g_hash_table_destroy (repository->priv->lazy_typelibs);
|
||||||
g_hash_table_destroy (repository->priv->info_by_gtype);
|
g_hash_table_destroy (repository->priv->info_by_gtype);
|
||||||
g_hash_table_destroy (repository->priv->info_by_error_domain);
|
g_hash_table_destroy (repository->priv->info_by_error_domain);
|
||||||
|
g_hash_table_destroy (repository->priv->interfaces_for_gtype);
|
||||||
|
|
||||||
(* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
|
(* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
|
||||||
}
|
}
|
||||||
@ -942,6 +964,83 @@ g_irepository_find_by_error_domain (GIRepository *repository,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_irepository_get_object_gtype_interfaces:
|
||||||
|
* @repository: (nullable): a #GIRepository, or %NULL for the default repository
|
||||||
|
* @gtype: a #GType whose fundamental type is G_TYPE_OBJECT
|
||||||
|
* @n_interfaces: (out): Number of interfaces
|
||||||
|
* @interfaces: (out) (transfer none) (array length=n_interfaces): Interfaces for @gtype
|
||||||
|
*
|
||||||
|
* Look up the implemented interfaces for @gtype. This function
|
||||||
|
* cannot fail per se; but for a totally "unknown" #GType, it may
|
||||||
|
* return 0 implemented interfaces.
|
||||||
|
*
|
||||||
|
* The semantics of this function are designed for a dynamic binding,
|
||||||
|
* where in certain cases (such as a function which returns an
|
||||||
|
* interface which may have "hidden" implementation classes), not all
|
||||||
|
* data may be statically known, and will have to be determined from
|
||||||
|
* the #GType of the object. An example is g_file_new_for_path()
|
||||||
|
* returning a concrete class of #GLocalFile, which is a #GType we
|
||||||
|
* see at runtime, but not statically.
|
||||||
|
*
|
||||||
|
* Since: 1.60
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_irepository_get_object_gtype_interfaces (GIRepository *repository,
|
||||||
|
GType gtype,
|
||||||
|
guint *n_interfaces_out,
|
||||||
|
GIInterfaceInfo **interfaces_out)
|
||||||
|
{
|
||||||
|
GTypeInterfaceCache *cache;
|
||||||
|
|
||||||
|
g_return_if_fail (g_type_fundamental (gtype) == G_TYPE_OBJECT);
|
||||||
|
|
||||||
|
repository = get_repository (repository);
|
||||||
|
|
||||||
|
cache = g_hash_table_lookup (repository->priv->interfaces_for_gtype,
|
||||||
|
(gpointer) gtype);
|
||||||
|
if (cache == NULL)
|
||||||
|
{
|
||||||
|
GType *interfaces;
|
||||||
|
guint n_interfaces;
|
||||||
|
guint i;
|
||||||
|
GList *interface_infos = NULL, *iter;
|
||||||
|
|
||||||
|
interfaces = g_type_interfaces (gtype, &n_interfaces);
|
||||||
|
for (i = 0; i < n_interfaces; i++)
|
||||||
|
{
|
||||||
|
GIBaseInfo *base_info;
|
||||||
|
|
||||||
|
base_info = g_irepository_find_by_gtype (repository, interfaces[i]);
|
||||||
|
if (base_info == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (g_base_info_get_type (base_info) != GI_INFO_TYPE_INTERFACE)
|
||||||
|
{
|
||||||
|
/* FIXME - could this really happen? */
|
||||||
|
g_base_info_unref (base_info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_list_find (interface_infos, base_info))
|
||||||
|
interface_infos = g_list_prepend (interface_infos, base_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = g_malloc (sizeof (GTypeInterfaceCache)
|
||||||
|
+ sizeof (GIBaseInfo*) * g_list_length (interface_infos));
|
||||||
|
cache->n_interfaces = g_list_length (interface_infos);
|
||||||
|
for (iter = interface_infos, i = 0; iter; iter = iter->next, i++)
|
||||||
|
cache->interfaces[i] = iter->data;
|
||||||
|
g_list_free (interface_infos);
|
||||||
|
|
||||||
|
g_hash_table_insert (repository->priv->interfaces_for_gtype, (gpointer) gtype,
|
||||||
|
cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
*n_interfaces_out = cache->n_interfaces;
|
||||||
|
*interfaces_out = *((GIInterfaceInfo**)&(cache->interfaces[0]));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
collect_namespaces (gpointer key,
|
collect_namespaces (gpointer key,
|
||||||
gpointer value,
|
gpointer value,
|
||||||
|
@ -159,6 +159,12 @@ GI_AVAILABLE_IN_ALL
|
|||||||
GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository,
|
GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository,
|
||||||
GType gtype);
|
GType gtype);
|
||||||
|
|
||||||
|
GI_AVAILABLE_IN_1_60
|
||||||
|
void g_irepository_get_object_gtype_interfaces (GIRepository *repository,
|
||||||
|
GType gtype,
|
||||||
|
guint *n_interfaces_out,
|
||||||
|
GIInterfaceInfo **interfaces_out);
|
||||||
|
|
||||||
GI_AVAILABLE_IN_ALL
|
GI_AVAILABLE_IN_ALL
|
||||||
gint g_irepository_get_n_infos (GIRepository *repository,
|
gint g_irepository_get_n_infos (GIRepository *repository,
|
||||||
const gchar *namespace_);
|
const gchar *namespace_);
|
||||||
|
Loading…
Reference in New Issue
Block a user