summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-22 18:08:15 -0400
committerPhilip Chimento <philip.chimento@gmail.com>2019-01-09 21:44:10 -0800
commit9826d952358c8330d72ecba062f489fbdc31bbd1 (patch)
tree297d02ca31635573db4026d9d30cd4604922811c
parent4f1374ba76d919c4e0d69c8a542f184d9d10df08 (diff)
downloadgobject-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.txt2
-rw-r--r--girepository/girepository.c99
-rw-r--r--girepository/girepository.h6
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_);