mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
GSettings: properly support 'extends'
Support the 'extends' attribute that has been supported by the compiler for a long time by doing three things: - when creating a schema that extends another schema, lookup that other schema - when looking up keys and we can't find them in the schema, check (recursively) in the 'extends' schema - when listing all keys in a schema, also visit the extends schemas, but take care to avoid duplicates caused by overrides Extend the testsuite to verify that it works. https://bugzilla.gnome.org/show_bug.cgi?id=645453
This commit is contained in:
parent
3041d0a8db
commit
cbf8cf8598
@ -146,6 +146,8 @@ struct _GSettingsSchema
|
|||||||
GvdbTable *table;
|
GvdbTable *table;
|
||||||
gchar *id;
|
gchar *id;
|
||||||
|
|
||||||
|
GSettingsSchema *extends;
|
||||||
|
|
||||||
gint ref_count;
|
gint ref_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -407,6 +409,7 @@ g_settings_schema_source_lookup (GSettingsSchemaSource *source,
|
|||||||
{
|
{
|
||||||
GSettingsSchema *schema;
|
GSettingsSchema *schema;
|
||||||
GvdbTable *table;
|
GvdbTable *table;
|
||||||
|
const gchar *extends;
|
||||||
|
|
||||||
g_return_val_if_fail (source != NULL, NULL);
|
g_return_val_if_fail (source != NULL, NULL);
|
||||||
g_return_val_if_fail (schema_id != NULL, NULL);
|
g_return_val_if_fail (schema_id != NULL, NULL);
|
||||||
@ -432,6 +435,14 @@ g_settings_schema_source_lookup (GSettingsSchemaSource *source,
|
|||||||
if (schema->gettext_domain)
|
if (schema->gettext_domain)
|
||||||
bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
|
bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
|
||||||
|
|
||||||
|
extends = g_settings_schema_get_string (schema, ".extends");
|
||||||
|
if (extends)
|
||||||
|
{
|
||||||
|
schema->extends = g_settings_schema_source_lookup (source, extends, TRUE);
|
||||||
|
if (schema->extends == NULL)
|
||||||
|
g_warning ("Schema '%s' extends schema '%s' but we could not find it", schema_id, extends);
|
||||||
|
}
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,6 +903,9 @@ g_settings_schema_unref (GSettingsSchema *schema)
|
|||||||
{
|
{
|
||||||
if (g_atomic_int_dec_and_test (&schema->ref_count))
|
if (g_atomic_int_dec_and_test (&schema->ref_count))
|
||||||
{
|
{
|
||||||
|
if (schema->extends)
|
||||||
|
g_settings_schema_unref (schema->extends);
|
||||||
|
|
||||||
g_settings_schema_source_unref (schema->source);
|
g_settings_schema_source_unref (schema->source);
|
||||||
gvdb_table_unref (schema->table);
|
gvdb_table_unref (schema->table);
|
||||||
g_free (schema->items);
|
g_free (schema->items);
|
||||||
@ -921,10 +935,15 @@ GVariantIter *
|
|||||||
g_settings_schema_get_value (GSettingsSchema *schema,
|
g_settings_schema_get_value (GSettingsSchema *schema,
|
||||||
const gchar *key)
|
const gchar *key)
|
||||||
{
|
{
|
||||||
|
GSettingsSchema *s = schema;
|
||||||
GVariantIter *iter;
|
GVariantIter *iter;
|
||||||
GVariant *value;
|
GVariant *value;
|
||||||
|
|
||||||
value = gvdb_table_get_raw_value (schema->table, key);
|
g_return_val_if_fail (schema != NULL, NULL);
|
||||||
|
|
||||||
|
for (s = schema; s; s = schema->extends)
|
||||||
|
if ((value = gvdb_table_get_raw_value (schema->table, key)))
|
||||||
|
break;
|
||||||
|
|
||||||
if G_UNLIKELY (value == NULL || !g_variant_is_of_type (value, G_VARIANT_TYPE_TUPLE))
|
if G_UNLIKELY (value == NULL || !g_variant_is_of_type (value, G_VARIANT_TYPE_TUPLE))
|
||||||
g_error ("Settings schema '%s' does not contain a key named '%s'", schema->id, key);
|
g_error ("Settings schema '%s' does not contain a key named '%s'", schema->id, key);
|
||||||
@ -976,33 +995,42 @@ const GQuark *
|
|||||||
g_settings_schema_list (GSettingsSchema *schema,
|
g_settings_schema_list (GSettingsSchema *schema,
|
||||||
gint *n_items)
|
gint *n_items)
|
||||||
{
|
{
|
||||||
gint i, j;
|
|
||||||
|
|
||||||
if (schema->items == NULL)
|
if (schema->items == NULL)
|
||||||
{
|
{
|
||||||
gchar **list;
|
GSettingsSchema *s;
|
||||||
|
GHashTableIter iter;
|
||||||
|
GHashTable *items;
|
||||||
|
gpointer name;
|
||||||
gint len;
|
gint len;
|
||||||
|
gint i;
|
||||||
|
|
||||||
list = gvdb_table_list (schema->table, "");
|
items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
len = list ? g_strv_length (list) : 0;
|
|
||||||
|
|
||||||
schema->items = g_new (GQuark, len);
|
for (s = schema; s; s = s->extends)
|
||||||
j = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
if (list[i][0] != '.')
|
|
||||||
{
|
{
|
||||||
if (g_str_has_suffix (list[i], "/"))
|
gchar **list;
|
||||||
{
|
|
||||||
/* This is a child. Check to make sure that
|
list = gvdb_table_list (s->table, "");
|
||||||
* instantiating the child would actually work before we
|
|
||||||
* return it from list() and cause a crash.
|
for (i = 0; list[i]; i++)
|
||||||
|
g_hash_table_add (items, list[i]); /* transfer ownership */
|
||||||
|
|
||||||
|
g_free (list); /* free container only */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do a first pass to eliminate child items that do not map to
|
||||||
|
* valid schemas (ie: ones that would crash us if we actually
|
||||||
|
* tried to create them).
|
||||||
*/
|
*/
|
||||||
|
g_hash_table_iter_init (&iter, items);
|
||||||
|
while (g_hash_table_iter_next (&iter, &name, NULL))
|
||||||
|
if (g_str_has_suffix (name, "/"))
|
||||||
|
{
|
||||||
GSettingsSchemaSource *source;
|
GSettingsSchemaSource *source;
|
||||||
GVariant *child_schema;
|
GVariant *child_schema;
|
||||||
GvdbTable *child_table;
|
GvdbTable *child_table;
|
||||||
|
|
||||||
child_schema = gvdb_table_get_raw_value (schema->table, list[i]);
|
child_schema = gvdb_table_get_raw_value (schema->table, name);
|
||||||
if (!child_schema)
|
if (!child_schema)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1014,9 +1042,12 @@ g_settings_schema_list (GSettingsSchema *schema,
|
|||||||
|
|
||||||
g_variant_unref (child_schema);
|
g_variant_unref (child_schema);
|
||||||
|
|
||||||
/* Schema is not found -> don't add it to the list */
|
/* Schema is not found -> remove it from the list */
|
||||||
if (child_table == NULL)
|
if (child_table == NULL)
|
||||||
|
{
|
||||||
|
g_hash_table_iter_remove (&iter);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the schema is relocatable or at the
|
/* Make sure the schema is relocatable or at the
|
||||||
* expected path
|
* expected path
|
||||||
@ -1028,27 +1059,36 @@ g_settings_schema_list (GSettingsSchema *schema,
|
|||||||
gboolean same;
|
gboolean same;
|
||||||
|
|
||||||
path = gvdb_table_get_raw_value (child_table, ".path");
|
path = gvdb_table_get_raw_value (child_table, ".path");
|
||||||
expected = g_strconcat (schema->path, list[i], NULL);
|
expected = g_strconcat (schema->path, name, NULL);
|
||||||
same = g_str_equal (expected, g_variant_get_string (path, NULL));
|
same = g_str_equal (expected, g_variant_get_string (path, NULL));
|
||||||
g_variant_unref (path);
|
g_variant_unref (path);
|
||||||
g_free (expected);
|
g_free (expected);
|
||||||
|
|
||||||
|
/* Schema is non-relocatable and did not have the
|
||||||
|
* expected path -> remove it from the list
|
||||||
|
*/
|
||||||
if (!same)
|
if (!same)
|
||||||
|
g_hash_table_iter_remove (&iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
gvdb_table_unref (child_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now create the list */
|
||||||
|
len = g_hash_table_size (items);
|
||||||
|
schema->items = g_new (GQuark, len + 1);
|
||||||
|
i = 0;
|
||||||
|
g_hash_table_iter_init (&iter, items);
|
||||||
|
|
||||||
|
while (g_hash_table_iter_next (&iter, &name, NULL))
|
||||||
{
|
{
|
||||||
gvdb_table_unref (child_table);
|
schema->items[i++] = g_quark_from_string (name);
|
||||||
continue;
|
g_hash_table_iter_steal (&iter);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
schema->n_items = i;
|
||||||
|
g_assert (i == len);
|
||||||
|
|
||||||
gvdb_table_unref (child_table);
|
g_hash_table_unref (items);
|
||||||
/* Else, it's good... */
|
|
||||||
}
|
|
||||||
|
|
||||||
schema->items[j++] = g_quark_from_string (list[i]);
|
|
||||||
}
|
|
||||||
schema->n_items = j;
|
|
||||||
|
|
||||||
g_strfreev (list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*n_items = schema->n_items;
|
*n_items = schema->n_items;
|
||||||
|
Loading…
Reference in New Issue
Block a user