diff options
author | Colin Walters <walters@verbum.org> | 2010-10-22 18:08:15 -0400 |
---|---|---|
committer | Philip Chimento <philip.chimento@gmail.com> | 2019-01-09 21:44:10 -0800 |
commit | 9826d952358c8330d72ecba062f489fbdc31bbd1 (patch) | |
tree | 297d02ca31635573db4026d9d30cd4604922811c | |
parent | 4f1374ba76d919c4e0d69c8a542f184d9d10df08 (diff) | |
download | gobject-introspection-9826d952358c8330d72ecba062f489fbdc31bbd1.tar.gz |
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.
-rw-r--r-- | docs/reference/gi-sections.txt | 2 | ||||
-rw-r--r-- | girepository/girepository.c | 99 | ||||
-rw-r--r-- | girepository/girepository.h | 6 |
3 files changed, 107 insertions, 0 deletions
diff --git a/docs/reference/gi-sections.txt b/docs/reference/gi-sections.txt index 28a59e0c..0ba40c8e 100644 --- a/docs/reference/gi-sections.txt +++ b/docs/reference/gi-sections.txt @@ -29,6 +29,8 @@ g_irepository_find_by_gtype g_irepository_find_by_error_domain g_irepository_find_by_name <SUBSECTION> +g_irepository_get_object_gtype_interfaces +<SUBSECTION> g_irepository_dump <SUBSECTION> gi_cclosure_marshal_generic diff --git a/girepository/girepository.c b/girepository/girepository.c index e262d3e8..84e44f4a 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -58,12 +58,29 @@ static GIRepository *default_repository = 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 { GHashTable *typelibs; /* (string) namespace -> GITypelib */ GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */ GHashTable *info_by_gtype; /* GType -> 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)); @@ -123,6 +140,10 @@ g_irepository_init (GIRepository *repository) = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, (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 @@ -134,6 +155,7 @@ g_irepository_finalize (GObject *object) 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_error_domain); + g_hash_table_destroy (repository->priv->interfaces_for_gtype); (* 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; } +/** + * 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 collect_namespaces (gpointer key, gpointer value, diff --git a/girepository/girepository.h b/girepository/girepository.h index 3934ab31..8dfcca2c 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -159,6 +159,12 @@ GI_AVAILABLE_IN_ALL GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository, 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 gint g_irepository_get_n_infos (GIRepository *repository, const gchar *namespace_); |