+
+ /* Only the first source if recursive not requested */
+ if (!recursive)
+ break;
+ }
+
+ if (non_relocatable)
+ {
+ *non_relocatable = (gchar **) g_hash_table_get_keys_as_array (single, NULL);
+ g_hash_table_steal_all (single);
+ }
+
+ if (relocatable)
+ {
+ *relocatable = (gchar **) g_hash_table_get_keys_as_array (reloc, NULL);
+ g_hash_table_steal_all (reloc);
+ }
+
+ g_hash_table_unref (single);
+ g_hash_table_unref (reloc);
+}
+
+static gchar **non_relocatable_schema_list;
+static gchar **relocatable_schema_list;
+static gsize schema_lists_initialised;
+
+static void
+ensure_schema_lists (void)
+{
+ if (g_once_init_enter (&schema_lists_initialised))
+ {
+ initialise_schema_sources ();
+
+ g_settings_schema_source_list_schemas (schema_sources, TRUE,
+ &non_relocatable_schema_list,
+ &relocatable_schema_list);
+
+ g_once_init_leave (&schema_lists_initialised, TRUE);
+ }
+}
+
+/**
+ * g_settings_list_schemas:
+ *
+ * Returns: (element-type utf8) (transfer none): a list of #GSettings
+ * schemas that are available. The list must not be modified or
+ * freed.
+ *
+ * Since: 2.26
+ *
+ * Deprecated:2.40: Use g_settings_schema_source_list_schemas() instead.
+ * If you used g_settings_list_schemas() to check for the presence of
+ * a particular schema, use g_settings_schema_source_lookup() instead
+ * of your whole loop.
+ **/
+const gchar * const *
+g_settings_list_schemas (void)
+{
+ ensure_schema_lists ();
+
+ return (const gchar **) non_relocatable_schema_list;
+}
+
+/**
+ * g_settings_list_relocatable_schemas:
+ *
+ * Returns: (element-type utf8) (transfer none): a list of relocatable
+ * #GSettings schemas that are available. The list must not be
+ * modified or freed.
+ *
+ * Since: 2.28
+ *
+ * Deprecated:2.40: Use g_settings_schema_source_list_schemas() instead
+ **/
+const gchar * const *
+g_settings_list_relocatable_schemas (void)
+{
+ ensure_schema_lists ();
+
+ return (const gchar **) relocatable_schema_list;
+}
+
+/**
+ * g_settings_schema_ref:
+ * @schema: a #GSettingsSchema
+ *
+ * Increase the reference count of @schema, returning a new reference.
+ *
+ * Returns: a new reference to @schema
+ *
+ * Since: 2.32
+ **/
+GSettingsSchema *
+g_settings_schema_ref (GSettingsSchema *schema)
+{
+ g_atomic_int_inc (&schema->ref_count);
+
+ return schema;
+}
+
+/**
+ * g_settings_schema_unref:
+ * @schema: a #GSettingsSchema
+ *
+ * Decrease the reference count of @schema, possibly freeing it.
+ *
+ * Since: 2.32
+ **/
+void
+g_settings_schema_unref (GSettingsSchema *schema)
+{
+ 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);
+ gvdb_table_unref (schema->table);
+ g_free (schema->items);
+ g_free (schema->id);
+
+ g_slice_free (GSettingsSchema, schema);
+ }
+}
+
+const gchar *
+g_settings_schema_get_string (GSettingsSchema *schema,
+ const gchar *key)
+{
+ const gchar *result = NULL;
+ GVariant *value;
+
+ if ((value = gvdb_table_get_raw_value (schema->table, key)))
+ {
+ result = g_variant_get_string (value, NULL);
+ g_variant_unref (value);
+ }
+
+ return result;
+}
+
+GVariantIter *
+g_settings_schema_get_value (GSettingsSchema *schema,
+ const gchar *key)
+{
+ GSettingsSchema *s = schema;
+ GVariantIter *iter;
+ GVariant *value;
+
+ g_return_val_if_fail (schema != NULL, NULL);
+
+ for (s = schema; s; s = s->extends)
+ if ((value = gvdb_table_get_raw_value (s->table, key)))
+ break;
+
+ 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);
+
+ iter = g_variant_iter_new (value);
+ g_variant_unref (value);
+
+ return iter;
+}
+
+/**
+ * g_settings_schema_get_path:
+ * @schema: a #GSettingsSchema
+ *
+ * Gets the path associated with @schema, or %NULL.
+ *
+ * Schemas may be single-instance or relocatable. Single-instance
+ * schemas correspond to exactly one set of keys in the backend
+ * database: those located at the path returned by this function.
+ *
+ * Relocatable schemas can be referenced by other schemas and can
+ * threfore describe multiple sets of keys at different locations. For
+ * relocatable schemas, this function will return %NULL.
+ *
+ * Returns: (transfer none): the path of the schema, or %NULL
+ *
+ * Since: 2.32
+ **/
+const gchar *
+g_settings_schema_get_path (GSettingsSchema *schema)
+{
+ return schema->path;
+}
+
+const gchar *
+g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
+{
+ return schema->gettext_domain;
+}
+
+/**
+ * g_settings_schema_has_key:
+ * @schema: a #GSettingsSchema
+ * @name: the name of a key
+ *
+ * Checks if @schema has a key named @name.
+ *
+ * Returns: %TRUE if such a key exists
+ *
+ * Since: 2.40
+ **/
+gboolean
+g_settings_schema_has_key (GSettingsSchema *schema,
+ const gchar *key)
+{
+ return gvdb_table_has_value (schema->table, key);
+}
+
+const GQuark *
+g_settings_schema_list (GSettingsSchema *schema,
+ gint *n_items)
+{
+ if (schema->items == NULL)
+ {
+ GSettingsSchema *s;
+ GHashTableIter iter;
+ GHashTable *items;
+ gpointer name;
+ gint len;
+ gint i;
+
+ items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ for (s = schema; s; s = s->extends)
+ {
+ gchar **list;
+
+ list = gvdb_table_list (s->table, "");
+
+ if (list)
+ {
+ 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;
+ GVariant *child_schema;
+ GvdbTable *child_table;
+
+ child_schema = gvdb_table_get_raw_value (schema->table, name);
+ if (!child_schema)
+ continue;
+
+ child_table = NULL;
+
+ for (source = schema_sources; source; source = source->parent)
+ if ((child_table = gvdb_table_get_table (source->table, g_variant_get_string (child_schema, NULL))))
+ break;
+
+ g_variant_unref (child_schema);
+
+ /* Schema is not found -> remove it from the list */
+ if (child_table == NULL)
+ {
+ g_hash_table_iter_remove (&iter);
+ continue;
+ }
+
+ /* Make sure the schema is relocatable or at the
+ * expected path
+ */
+ if (gvdb_table_has_value (child_table, ".path"))
+ {
+ GVariant *path;
+ gchar *expected;
+ gboolean same;
+
+ path = gvdb_table_get_raw_value (child_table, ".path");
+ expected = g_strconcat (schema->path, name, NULL);
+ same = g_str_equal (expected, g_variant_get_string (path, NULL));
+ g_variant_unref (path);
+ g_free (expected);
+
+ /* Schema is non-relocatable and did not have the
+ * expected path -> remove it from the list
+ */
+ 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);
+ i = 0;
+ g_hash_table_iter_init (&iter, items);
+
+ while (g_hash_table_iter_next (&iter, &name, NULL))
+ schema->items[i++] = g_quark_from_string (name);
+ schema->n_items = i;
+ g_assert (i == len);
+
+ g_hash_table_unref (items);
+ }
+
+ *n_items = schema->n_items;
+ return schema->items;
+}
+
+/**
+ * g_settings_schema_get_id:
+ * @schema: a #GSettingsSchema
+ *
+ * Get the ID of @schema.
+ *
+ * Returns: (transfer none): the ID
+ **/
+const gchar *
+g_settings_schema_get_id (GSettingsSchema *schema)
+{
+ return schema->id;
+}
+
+static inline void
+endian_fixup (GVariant **value)
+{
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ GVariant *tmp;
+
+ tmp = g_variant_byteswap (*value);
+ g_variant_unref (*value);
+ *value = tmp;
+#endif
+}
+
+void
+g_settings_schema_key_init (GSettingsSchemaKey *key,
+ GSettingsSchema *schema,
+ const gchar *name)
+{
+ GVariantIter *iter;
+ GVariant *data;
+ guchar code;
+
+ memset (key, 0, sizeof *key);
+
+ iter = g_settings_schema_get_value (schema, name);
+
+ key->schema = g_settings_schema_ref (schema);
+ key->default_value = g_variant_iter_next_value (iter);
+ endian_fixup (&key->default_value);
+ key->type = g_variant_get_type (key->default_value);
+ key->name = g_intern_string (name);
+
+ while (g_variant_iter_next (iter, "(y*)", &code, &data))
+ {
+ switch (code)
+ {
+ case 'l':
+ /* translation requested */
+ g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed);
+ break;
+
+ case 'e':
+ /* enumerated types... */
+ key->is_enum = TRUE;
+ goto choice;
+
+ case 'f':
+ /* flags... */
+ key->is_flags = TRUE;
+ goto choice;
+
+ choice: case 'c':
+ /* ..., choices, aliases */
+ key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32));
+ break;
+
+ case 'r':
+ g_variant_get (data, "(**)", &key->minimum, &key->maximum);
+ endian_fixup (&key->minimum);
+ endian_fixup (&key->maximum);
+ break;
+
+ default:
+ g_warning ("unknown schema extension '%c'", code);
+ break;
+ }
+
+ g_variant_unref (data);
+ }
+
+ g_variant_iter_free (iter);
+}
+
+void
+g_settings_schema_key_clear (GSettingsSchemaKey *key)
+{
+ if (key->minimum)
+ g_variant_unref (key->minimum);
+
+ if (key->maximum)
+ g_variant_unref (key->maximum);
+
+ g_variant_unref (key->default_value);
+
+ g_settings_schema_unref (key->schema);
+}
+
+gboolean
+g_settings_schema_key_type_check (GSettingsSchemaKey *key,
+ GVariant *value)
+{
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ return g_variant_is_of_type (value, key->type);
+}
+
+GVariant *
+g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
+ GVariant *value)
+{
+ const gchar *target;
+
+ if (g_settings_schema_key_range_check (key, value))
+ return g_variant_ref (value);
+
+ if (key->strinfo == NULL)
+ return NULL;
+
+ if (g_variant_is_container (value))
+ {
+ GVariantBuilder builder;
+ GVariantIter iter;
+ GVariant *child;
+
+ g_variant_iter_init (&iter, value);
+ g_variant_builder_init (&builder, g_variant_get_type (value));
+
+ while ((child = g_variant_iter_next_value (&iter)))
+ {
+ GVariant *fixed;
+
+ fixed = g_settings_schema_key_range_fixup (key, child);
+ g_variant_unref (child);
+
+ if (fixed == NULL)
+ {
+ g_variant_builder_clear (&builder);
+ return NULL;
+ }
+
+ g_variant_builder_add_value (&builder, fixed);
+ g_variant_unref (fixed);
+ }
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+ }
+
+ target = strinfo_string_from_alias (key->strinfo, key->strinfo_length,
+ g_variant_get_string (value, NULL));
+ return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL;
+}
+
+GVariant *
+g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
+{
+ const gchar *translated;
+ GError *error = NULL;
+ const gchar *domain;
+ GVariant *value;
+
+ domain = g_settings_schema_get_gettext_domain (key->schema);
+
+ if (key->lc_char == '\0')
+ /* translation not requested for this key */
+ return NULL;
+
+ if (key->lc_char == 't')
+ translated = g_dcgettext (domain, key->unparsed, LC_TIME);
+ else
+ translated = g_dgettext (domain, key->unparsed);
+
+ if (translated == key->unparsed)
+ /* the default value was not translated */
+ return NULL;
+
+ /* try to parse the translation of the unparsed default */
+ value = g_variant_parse (key->type, translated, NULL, NULL, &error);
+
+ if (value == NULL)
+ {
+ g_warning ("Failed to parse translated string '%s' for "
+ "key '%s' in schema '%s': %s", translated, key->name,
+ g_settings_schema_get_id (key->schema), error->message);
+ g_warning ("Using untranslated default instead.");
+ g_error_free (error);
+ }
+
+ else if (!g_settings_schema_key_range_check (key, value))
+ {
+ g_warning ("Translated default '%s' for key '%s' in schema '%s' "
+ "is outside of valid range", key->unparsed, key->name,
+ g_settings_schema_get_id (key->schema));
+ g_variant_unref (value);
+ value = NULL;
+ }
+
+ return value;
+}
+
+gint
+g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
+ GVariant *value)
+{
+ gboolean it_worked;
+ guint result;
+
+ it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length,
+ g_variant_get_string (value, NULL),
+ &result);
+
+ /* 'value' can only come from the backend after being filtered for validity,
+ * from the translation after being filtered for validity, or from the schema
+ * itself (which the schema compiler checks for validity). If this assertion
+ * fails then it's really a bug in GSettings or the schema compiler...
+ */
+ g_assert (it_worked);
+
+ return result;
+}
+
+GVariant *
+g_settings_schema_key_from_enum (GSettingsSchemaKey *key,
+ gint value)
+{
+ const gchar *string;
+
+ string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value);
+
+ if (string == NULL)
+ return NULL;
+
+ return g_variant_new_string (string);
+}
+
+guint
+g_settings_schema_key_to_flags (GSettingsSchemaKey *key,
+ GVariant *value)
+{
+ GVariantIter iter;
+ const gchar *flag;
+ guint result;
+
+ result = 0;
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_next (&iter, "&s", &flag))
+ {
+ gboolean it_worked;
+ guint flag_value;
+
+ it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value);
+ /* as in g_settings_to_enum() */
+ g_assert (it_worked);
+
+ result |= flag_value;
+ }
+
+ return result;
+}
+
+GVariant *
+g_settings_schema_key_from_flags (GSettingsSchemaKey *key,
+ guint value)
+{
+ GVariantBuilder builder;
+ gint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (i = 0; i < 32; i++)
+ if (value & (1u << i))
+ {
+ const gchar *string;
+
+ string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i);
+
+ if (string == NULL)
+ {
+ g_variant_builder_clear (&builder);
+ return NULL;
+ }
+
+ g_variant_builder_add (&builder, "s", string);
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+G_DEFINE_BOXED_TYPE (GSettingsSchemaKey, g_settings_schema_key, g_settings_schema_key_ref, g_settings_schema_key_unref)
+
+/**
+ * g_settings_schema_key_ref:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Increase the reference count of @key, returning a new reference.
+ *
+ * Returns: a new reference to @key
+ *
+ * Since: 2.40
+ **/
+GSettingsSchemaKey *
+g_settings_schema_key_ref (GSettingsSchemaKey *key)
+{
+ g_return_val_if_fail (key != NULL, NULL);
+
+ g_atomic_int_inc (&key->ref_count);
+
+ return key;
+}
+
+/**
+ * g_settings_schema_key_unref:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Decrease the reference count of @key, possibly freeing it.
+ *
+ * Since: 2.40
+ **/
+void
+g_settings_schema_key_unref (GSettingsSchemaKey *key)
+{
+ g_return_if_fail (key != NULL);
+
+ if (g_atomic_int_dec_and_test (&key->ref_count))
+ {
+ g_settings_schema_key_clear (key);
+
+ g_slice_free (GSettingsSchemaKey, key);
+ }
+}
+
+/**
+ * g_settings_schema_get_key:
+ * @schema: a #GSettingsSchema
+ * @name: the name of a key
+ *
+ * Gets the key named @name from @schema.
+ *
+ * It is a programmer error to request a key that does not exist. See
+ * g_settings_schema_list_keys().
+ *
+ * Returns: (transfer full): the #GSettingsSchemaKey for @name
+ *
+ * Since: 2.40
+ **/
+GSettingsSchemaKey *
+g_settings_schema_get_key (GSettingsSchema *schema,
+ const gchar *name)
+{
+ GSettingsSchemaKey *key;
+
+ g_return_val_if_fail (schema != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ key = g_slice_new (GSettingsSchemaKey);
+ g_settings_schema_key_init (key, schema, name);
+ key->ref_count = 1;
+
+ return key;
+}
+
+/**
+ * g_settings_schema_key_get_summary:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Gets the summary for @key.
+ *
+ * If no summary has been provided in the schema for @key, returns
+ * %NULL.
+ *
+ * The summary is a short description of the purpose of the key; usually
+ * one short sentence. Summaries can be translated and the value
+ * returned from this function is is the current locale.
+ *
+ * This function is slow. The summary and description information for
+ * the schemas is not stored in the compiled schema database so this
+ * function has to parse all of the source XML files in the schema
+ * directory.
+ *
+ * Returns: the summary for @key, or %NULL
+ *
+ * Since: 2.34
+ **/
+const gchar *
+g_settings_schema_key_get_summary (GSettingsSchemaKey *key)
+{
+ GHashTable **text_tables;
+ GHashTable *summaries;
+
+ text_tables = g_settings_schema_source_get_text_tables (key->schema->source);
+ summaries = g_hash_table_lookup (text_tables[0], key->schema->id);
+
+ return summaries ? g_hash_table_lookup (summaries, key->name) : NULL;
+}
+
+/**
+ * g_settings_schema_key_get_description:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Gets the description for @key.
+ *
+ * If no description has been provided in the schema for @key, returns
+ * %NULL.
+ *
+ * The description can be one sentence to several paragraphs in length.
+ * Paragraphs are delimited with a double newline. Descriptions can be
+ * translated and the value returned from this function is is the
+ * current locale.
+ *
+ * This function is slow. The summary and description information for
+ * the schemas is not stored in the compiled schema database so this
+ * function has to parse all of the source XML files in the schema
+ * directory.
+ *
+ * Returns: the description for @key, or %NULL
+ *
+ * Since: 2.34
+ **/
+const gchar *
+g_settings_schema_key_get_description (GSettingsSchemaKey *key)
+{
+ GHashTable **text_tables;
+ GHashTable *descriptions;
+
+ text_tables = g_settings_schema_source_get_text_tables (key->schema->source);
+ descriptions = g_hash_table_lookup (text_tables[1], key->schema->id);
+
+ return descriptions ? g_hash_table_lookup (descriptions, key->name) : NULL;
+}
+
+/**
+ * g_settings_schema_key_get_value_type:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Gets the #GVariantType of @key.
+ *
+ * Returns: (transfer none): the type of @key
+ *
+ * Since: 2.40
+ **/
+const GVariantType *
+g_settings_schema_key_get_value_type (GSettingsSchemaKey *key)
+{
+ g_return_val_if_fail (key, NULL);
+
+ return key->type;
+}
+
+/**
+ * g_settings_schema_key_get_default_value:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Gets the default value for @key.
+ *
+ * Note that this is the default value according to the schema. System
+ * administrator defaults and lockdown are not visible via this API.
+ *
+ * Returns: (transfer full): the default value for the key
+ *
+ * Since: 2.40
+ **/
+GVariant *
+g_settings_schema_key_get_default_value (GSettingsSchemaKey *key)
+{
+ GVariant *value;
+
+ g_return_val_if_fail (key, NULL);
+
+ value = g_settings_schema_key_get_translated_default (key);
+
+ if (!value)
+ value = g_variant_ref (key->default_value);
+
+ return value;
+}
+
+/**
+ * g_settings_schema_key_get_range:
+ * @key: a #GSettingsSchemaKey
+ *
+ * Queries the range of a key.
+ *
+ * This function will return a #GVariant that fully describes the range
+ * of values that are valid for @key.
+ *
+ * The type of #GVariant returned is `(sv)`. The string describes
+ * the type of range restriction in effect. The type and meaning of
+ * the value contained in the variant depends on the string.
+ *
+ * If the string is `'type'` then the variant contains an empty array.
+ * The element type of that empty array is the expected type of value
+ * and all values of that type are valid.
+ *
+ * If the string is `'enum'` then the variant contains an array
+ * enumerating the possible values. Each item in the array is
+ * a possible valid value and no other values are valid.
+ *
+ * If the string is `'flags'` then the variant contains an array. Each
+ * item in the array is a value that may appear zero or one times in an
+ * array to be used as the value for this key. For example, if the
+ * variant contained the array `['x', 'y']` then the valid values for
+ * the key would be `[]`, `['x']`, `['y']`, `['x', 'y']` and
+ * `['y', 'x']`.
+ *
+ * Finally, if the string is `'range'` then the variant contains a pair
+ * of like-typed values -- the minimum and maximum permissible values
+ * for this key.
+ *
+ * This information should not be used by normal programs. It is
+ * considered to be a hint for introspection purposes. Normal programs
+ * should already know what is permitted by their own schema. The
+ * format may change in any way in the future -- but particularly, new
+ * forms may be added to the possibilities described above.
+ *
+ * You should free the returned value with g_variant_unref() when it is
+ * no longer needed.
+ *
+ * Returns: (transfer full): a #GVariant describing the range
+ *
+ * Since: 2.40
+ **/
+GVariant *
+g_settings_schema_key_get_range (GSettingsSchemaKey *key)
+{
+ const gchar *type;
+ GVariant *range;
+
+ if (key->minimum)
+ {
+ range = g_variant_new ("(**)", key->minimum, key->maximum);
+ type = "range";
+ }
+ else if (key->strinfo)
+ {
+ range = strinfo_enumerate (key->strinfo, key->strinfo_length);
+ type = key->is_flags ? "flags" : "enum";
+ }
+ else
+ {
+ range = g_variant_new_array (key->type, NULL, 0);
+ type = "type";
+ }
+
+ return g_variant_ref_sink (g_variant_new ("(sv)", type, range));
+}
+
+/**
+ * g_settings_schema_key_range_check:
+ * @key: a #GSettingsSchemaKey
+ * @value: the value to check
+ *
+ * Checks if the given @value is of the correct type and within the
+ * permitted range for @key.
+ *
+ * It is a programmer error if @value is not of the correct type -- you
+ * must check for this first.
+ *
+ * Returns: %TRUE if @value is valid for @key
+ *
+ * Since: 2.40
+ **/
+gboolean
+g_settings_schema_key_range_check (GSettingsSchemaKey *key,
+ GVariant *value)
+{
+ if (key->minimum == NULL && key->strinfo == NULL)
+ return TRUE;
+
+ if (g_variant_is_container (value))
+ {
+ gboolean ok = TRUE;
+ GVariantIter iter;
+ GVariant *child;
+
+ g_variant_iter_init (&iter, value);
+ while (ok && (child = g_variant_iter_next_value (&iter)))
+ {
+ ok = g_settings_schema_key_range_check (key, child);
+ g_variant_unref (child);
+ }
+
+ return ok;
+ }
+
+ if (key->minimum)
+ {
+ return g_variant_compare (key->minimum, value) <= 0 &&
+ g_variant_compare (value, key->maximum) <= 0;