summaryrefslogtreecommitdiff
path: root/girepository
diff options
context:
space:
mode:
Diffstat (limited to 'girepository')
-rw-r--r--girepository/girepository.c105
-rw-r--r--girepository/gitypelib-internal.h8
-rw-r--r--girepository/gitypelib.c84
3 files changed, 118 insertions, 79 deletions
diff --git a/girepository/girepository.c b/girepository/girepository.c
index ccdd3611..0922fb09 100644
--- a/girepository/girepository.c
+++ b/girepository/girepository.c
@@ -593,28 +593,39 @@ g_irepository_get_info (GIRepository *repository,
}
typedef struct {
- GIRepository *repository;
- GType type;
-
- gboolean fastpass;
+ const gchar *gtype_name;
GITypelib *result_typelib;
- DirEntry *result;
+ gboolean found_prefix;
} FindByGTypeData;
-static void
-find_by_gtype_foreach (gpointer key,
- gpointer value,
- gpointer datap)
+static DirEntry *
+find_by_gtype (GHashTable *table, FindByGTypeData *data, gboolean check_prefix)
{
- GITypelib *typelib = (GITypelib*)value;
- FindByGTypeData *data = datap;
+ GHashTableIter iter;
+ gpointer key, value;
+ DirEntry *ret;
- if (data->result != NULL)
- return;
+ g_hash_table_iter_init (&iter, table);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ GITypelib *typelib = (GITypelib*)value;
+ if (check_prefix)
+ {
+ if (!g_typelib_matches_gtype_name_prefix (typelib, data->gtype_name))
+ continue;
- data->result = g_typelib_get_dir_entry_by_gtype (typelib, data->fastpass, data->type);
- if (data->result)
- data->result_typelib = typelib;
+ data->found_prefix = TRUE;
+ }
+
+ ret = g_typelib_get_dir_entry_by_gtype_name (typelib, data->gtype_name);
+ if (ret)
+ {
+ data->result_typelib = typelib;
+ return ret;
+ }
+ }
+
+ return NULL;
}
/**
@@ -637,6 +648,7 @@ g_irepository_find_by_gtype (GIRepository *repository,
{
FindByGTypeData data;
GIBaseInfo *cached;
+ DirEntry *entry;
repository = get_repository (repository);
@@ -646,30 +658,55 @@ g_irepository_find_by_gtype (GIRepository *repository,
if (cached != NULL)
return g_base_info_ref (cached);
- data.repository = repository;
- data.fastpass = TRUE;
- data.type = gtype;
+ data.gtype_name = g_type_name (gtype);
data.result_typelib = NULL;
- data.result = NULL;
+ data.found_prefix = FALSE;
+
+ /* There is a corner case regarding GdkRectangle. GdkRectangle is a
+ * boxed type, but it is just an alias to boxed struct
+ * CairoRectangleInt. Scanner automatically converts all references
+ * to GdkRectangle to CairoRectangleInt, so GdkRectangle does not
+ * appear in the typelibs at all, although user code might query it.
+ * So if we get such query, we also change it to lookup of
+ * CairoRectangleInt.
+ * https://bugzilla.gnome.org/show_bug.cgi?id=655423
+ */
+ if (G_UNLIKELY (!strcmp (data.gtype_name, "GdkRectangle")))
+ data.gtype_name = "CairoRectangleInt";
+
+ /* Inside each typelib, we include the "C prefix" which acts as
+ * a namespace mechanism. For GtkTreeView, the C prefix is Gtk.
+ * Given the assumption that GTypes for a library also use the
+ * C prefix, we know we can skip examining a typelib if our
+ * target type does not have this typelib's C prefix. Use this
+ * assumption as our first attempt at locating the DirEntry.
+ */
+ entry = find_by_gtype (repository->priv->typelibs, &data, TRUE);
+ if (entry == NULL)
+ entry = find_by_gtype (repository->priv->lazy_typelibs, &data, TRUE);
- g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
- if (data.result == NULL)
- g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
+ /* If we have no result, but we did find a typelib claiming to
+ * offer bindings for such a prefix, bail out now on the assumption
+ * that a more exhaustive search would not produce any results.
+ */
+ if (entry == NULL && data.found_prefix)
+ return NULL;
- /* We do two passes; see comment in find_interface */
- if (data.result == NULL)
- {
- data.fastpass = FALSE;
- g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
- }
- if (data.result == NULL)
- g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
+ /* Not ever class library necessarily specifies a correct c_prefix,
+ * so take a second pass. This time we will try a global lookup,
+ * ignoring prefixes.
+ * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
+ */
+ if (entry == NULL)
+ entry = find_by_gtype (repository->priv->typelibs, &data, FALSE);
+ if (entry == NULL)
+ entry = find_by_gtype (repository->priv->lazy_typelibs, &data, FALSE);
- if (data.result != NULL)
+ if (entry != NULL)
{
- cached = _g_info_new_full (data.result->blob_type,
+ cached = _g_info_new_full (entry->blob_type,
repository,
- NULL, data.result_typelib, data.result->offset);
+ NULL, data.result_typelib, entry->offset);
g_hash_table_insert (repository->priv->info_by_gtype,
(gpointer) gtype,
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 04662b4a..ac71008d 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -1126,13 +1126,15 @@ DirEntry *g_typelib_get_dir_entry (GITypelib *typelib,
DirEntry *g_typelib_get_dir_entry_by_name (GITypelib *typelib,
const char *name);
-DirEntry *g_typelib_get_dir_entry_by_gtype (GITypelib *typelib,
- gboolean fastpass,
- GType gtype);
+DirEntry *g_typelib_get_dir_entry_by_gtype_name (GITypelib *typelib,
+ const gchar *gtype_name);
DirEntry *g_typelib_get_dir_entry_by_error_domain (GITypelib *typelib,
GQuark error_domain);
+gboolean g_typelib_matches_gtype_name_prefix (GITypelib *typelib,
+ const gchar *gtype_name);
+
void g_typelib_check_sanity (void);
#define g_typelib_get_string(typelib,offset) ((const gchar*)&(typelib->data)[(offset)])
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c
index 76a55de8..2512e524 100644
--- a/girepository/gitypelib.c
+++ b/girepository/gitypelib.c
@@ -198,55 +198,17 @@ g_typelib_get_dir_entry_by_name (GITypelib *typelib,
}
DirEntry *
-g_typelib_get_dir_entry_by_gtype (GITypelib *typelib,
- gboolean fastpass,
- GType gtype)
+g_typelib_get_dir_entry_by_gtype_name (GITypelib *typelib,
+ const gchar *gtype_name)
{
Header *header = (Header *)typelib->data;
- guint n_entries = header->n_local_entries;
- const char *gtype_name = g_type_name (gtype);
- DirEntry *entry;
guint i;
- const char *c_prefix;
- /* There is a corner case regarding GdkRectangle. GdkRectangle is a
- boxed type, but it is just an alias to boxed struct
- CairoRectangleInt. Scanner automatically converts all references
- to GdkRectangle to CairoRectangleInt, so GdkRectangle does not
- appear in the typelibs at all, although user code might query it.
- So if we get such query, we also change it to lookup of
- CairoRectangleInt.
- https://bugzilla.gnome.org/show_bug.cgi?id=655423 */
- if (!fastpass && !strcmp (gtype_name, "GdkRectangle"))
- gtype_name = "CairoRectangleInt";
-
- /* Inside each typelib, we include the "C prefix" which acts as
- * a namespace mechanism. For GtkTreeView, the C prefix is Gtk.
- * Given the assumption that GTypes for a library also use the
- * C prefix, we know we can skip examining a typelib if our
- * target type does not have this typelib's C prefix.
- *
- * However, not every class library necessarily conforms to this,
- * e.g. Clutter has Cogl inside it. So, we split this into two
- * passes. First we try a lookup, skipping things which don't
- * have the prefix. If that fails then we try a global lookup,
- * ignoring the prefix.
- *
- * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
- */
- c_prefix = g_typelib_get_string (typelib, header->c_prefix);
- if (fastpass && c_prefix != NULL)
- {
- if (g_ascii_strncasecmp (c_prefix, gtype_name, strlen (c_prefix)) != 0)
- return NULL;
- }
-
- for (i = 1; i <= n_entries; i++)
+ for (i = 1; i <= header->n_local_entries; i++)
{
RegisteredTypeBlob *blob;
const char *type;
-
- entry = g_typelib_get_dir_entry (typelib, i);
+ DirEntry *entry = g_typelib_get_dir_entry (typelib, i);
if (!BLOB_IS_REGISTERED_TYPE (entry))
continue;
@@ -261,6 +223,44 @@ g_typelib_get_dir_entry_by_gtype (GITypelib *typelib,
return NULL;
}
+gboolean
+g_typelib_matches_gtype_name_prefix (GITypelib *typelib,
+ const gchar *gtype_name)
+{
+ Header *header = (Header *)typelib->data;
+ const char *c_prefix;
+ gchar **prefixes;
+ gchar **prefix;
+ gboolean ret = FALSE;
+
+ c_prefix = g_typelib_get_string (typelib, header->c_prefix);
+ if (c_prefix == NULL)
+ return FALSE;
+
+ /* c_prefix is a comma separated string of supported prefixes
+ * in the typelib.
+ * We match the specified gtype_name if the gtype_name starts
+ * with the prefix, and is followed by a capital letter.
+ * For example, a typelib offering the 'Gdk' prefix does match
+ * GdkX11Cursor, however a typelib offering the 'G' prefix does not.
+ */
+ prefixes = g_strsplit (c_prefix, ",", 0);
+ for (prefix = prefixes; *prefix; prefix++)
+ {
+ size_t len = strlen (*prefix);
+ if (strncmp (*prefix, gtype_name, len))
+ continue;
+
+ if (strlen (gtype_name) > len && g_ascii_isupper (gtype_name[len]))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+ g_strfreev(prefixes);
+ return ret;
+}
+
DirEntry *
g_typelib_get_dir_entry_by_error_domain (GITypelib *typelib,
GQuark error_domain)