[glib/enums] enums
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/enums] enums
- Date: Fri, 11 Jun 2010 19:13:08 +0000 (UTC)
commit a586d0ea64f2a357cc617d9f550b3ae1e0111201
Author: Ryan Lortie <desrt desrt ca>
Date: Fri Jun 11 15:10:49 2010 -0400
enums
gio/gio.symbols | 2 +
gio/gschema-compile.c | 205 +++++++++++++++++++++----
gio/gsettings-mapping.c | 24 +++-
gio/gsettings.c | 304 ++++++++++++++++++++++++++++--------
gio/gsettings.h | 6 +-
gio/gsettingsbackend.c | 27 +++-
gio/tests/org.gtk.test.gschema.xml | 14 ++
7 files changed, 483 insertions(+), 99 deletions(-)
---
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 3f61cff..d200694 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1467,6 +1467,8 @@ g_settings_get_double
g_settings_set_double
g_settings_get_boolean
g_settings_set_boolean
+g_settings_get_enum
+g_settings_set_enum
g_settings_sync
#endif
#endif
diff --git a/gio/gschema-compile.c b/gio/gschema-compile.c
index f462a7b..14339e2 100644
--- a/gio/gschema-compile.c
+++ b/gio/gschema-compile.c
@@ -31,12 +31,35 @@
#include "gvdb/gvdb-builder.h"
+static gpointer
+g_memmem (gconstpointer haystack,
+ gsize haystack_len,
+ gconstpointer needle,
+ gsize needle_len)
+{
+#ifndef HAVE_MEMMEM
+ while (needle_len <= haystack_len)
+ {
+ if (memcmp (haystack, needle, needle_len) == 0)
+ return (gpointer) haystack;
+
+ haystack = ((gchar *) haystack) + 1;
+ haystack_len--;
+ }
+
+ return NULL;
+#else
+ return memmem (haystack, haystack_len, needle, needle_len);
+#endif
+}
+
typedef struct
{
gboolean byteswap;
GVariantBuilder key_options;
GHashTable *schemas;
+ GHashTable *enums;
gchar *schemalist_domain;
GHashTable *schema;
@@ -52,6 +75,8 @@ typedef struct
gchar l10n;
gchar *context;
GVariantType *type;
+
+ GString *enumdesc;
} ParseState;
static gboolean allow_any_name = FALSE;
@@ -140,40 +165,53 @@ type_allows_range (const GVariantType *type)
static gboolean
is_valid_choices (GVariant *variant,
- const gchar *choices)
+ const gchar *choices,
+ gsize choices_size)
{
switch (g_variant_classify (variant))
{
case G_VARIANT_CLASS_MAYBE:
case G_VARIANT_CLASS_ARRAY:
{
- gsize i, n;
- GVariant *child;
- gboolean is_valid;
+ gboolean valid = TRUE;
+ GVariantIter iter;
- n = g_variant_n_children (variant);
- for (i = 0; i < n; ++i)
- {
- child = g_variant_get_child_value (variant, i);
- is_valid = is_valid_choices (child, choices);
- g_variant_unref (child);
+ g_variant_iter_init (&iter, variant);
- if (!is_valid)
- return FALSE;
+ while (valid && (variant = g_variant_iter_next_value (&iter)))
+ {
+ valid = is_valid_choices (variant, choices, choices_size);
+ g_variant_unref (variant);
}
- return TRUE;
+ return valid;
}
case G_VARIANT_CLASS_STRING:
{
+ gchar stack_buffer[64];
const gchar *string;
+ gboolean matched;
+ gchar *buffer;
+ gsize length;
+
+ string = g_variant_get_string (variant, &length);
+
+ if (length + 2 <= sizeof stack_buffer)
+ buffer = stack_buffer;
+ else
+ buffer = g_malloc (length + 2);
+
+ buffer[0] = '\0';
+ memcpy (buffer + 1, string, length + 1);
- g_variant_get (variant, "&s", &string);
+ matched = g_memmem (choices, choices_size,
+ buffer, length + 2) != NULL;
- while ((choices = strstr (choices, string)) && choices[-1] != 0xff);
+ if (buffer != stack_buffer)
+ g_free (buffer);
- return choices != NULL;
+ return matched;
}
default:
@@ -254,18 +292,64 @@ start_element (GMarkupParseContext *context,
}
return;
}
+
+ if (strcmp (element_name, "enum") == 0)
+ {
+ const gchar *id;
+
+ if (COLLECT (STRING, "id", &id))
+ {
+ if (g_hash_table_lookup (state->enums, id))
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "<enum id='%s'> already specified", id);
+
+ g_hash_table_insert (state->enums, g_strdup (id),
+ state->enumdesc = g_string_new (NULL));
+ }
+
+ return;
+ }
}
else if (strcmp (container, "schema") == 0)
{
if (strcmp (element_name, "key") == 0)
{
- const gchar *name, *type;
+ const gchar *name, *type, *enumtype;
- if (COLLECT (STRING, "name", &name, STRING, "type", &type))
+ if (COLLECT (STRING, "name", &name,
+ OPTIONAL | STRING, "type", &type,
+ OPTIONAL | STRING, "enum", &enumtype))
{
+ GString *enumdata = NULL;
+
if (!is_valid_keyname (name, error))
return;
+ if ((type == NULL) == (enumtype == NULL))
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+ "exactly one of 'type' or 'enum' must "
+ "be specified as an attribute to <key>");
+ return;
+ }
+
+ if (enumtype)
+ {
+ enumdata = g_hash_table_lookup (state->enums, enumtype);
+
+ if (enumdata == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "<enum id='%s'> not (yet) defined.", enumtype);
+ return;
+ }
+
+ type = "s";
+ }
+
if (!g_hash_table_lookup (state->schema, name))
{
state->key = gvdb_hash_table_insert (state->schema, name);
@@ -291,6 +375,16 @@ start_element (GMarkupParseContext *context,
g_variant_builder_init (&state->key_options,
G_VARIANT_TYPE ("a{sv}"));
+
+ if (enumdata != NULL)
+ {
+ GVariant *array;
+
+ array = g_variant_new_byte_array (enumdata->str,
+ enumdata->len);
+ g_variant_builder_add (&state->key_options,
+ "{sv}", "enum", array);
+ }
}
return;
@@ -436,13 +530,14 @@ start_element (GMarkupParseContext *context,
gchar *type = g_variant_type_dup_string (state->type);
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT,
- "Element <%s> not allowed for keys of type \"%s\"\n",
+ "Element <%s> not allowed for keys of type '%s'",
element_name, type);
g_free (type);
return;
}
- state->choices = g_string_new ("\xff");
+ state->choices = g_string_new (NULL);
+ g_string_append_c (state->choices, 0);
NO_ATTRS ();
return;
@@ -455,7 +550,62 @@ start_element (GMarkupParseContext *context,
const gchar *value;
if (COLLECT (STRING, "value", &value))
- g_string_append_printf (state->choices, "%s\xff", value);
+ g_string_append_len (state->choices, value, strlen (value) + 1);
+
+ return;
+ }
+ }
+ else if (strcmp (container, "enum") == 0)
+ {
+ if (strcmp (element_name, "value") == 0)
+ {
+ const gchar *nick, *valuestr;
+
+ if (COLLECT (STRING, "nick", &nick,
+ STRING, "value", &valuestr))
+ {
+ gint64 big_value;
+ guint32 value;
+ gsize before;
+ gchar *end;
+
+ if (nick[0] == '\0' || nick[1] == '\0')
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "enum nick must be a minimum of 2 characters");
+ return;
+ }
+
+ big_value = g_ascii_strtoll (valuestr, &end, 0);
+ if (*end || big_value > G_MAXINT32 || big_value < G_MININT32)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "invalid numeric value");
+ return;
+ }
+
+ value = big_value;
+ value = GUINT32_TO_LE (value);
+
+ g_string_append_len (state->enumdesc, (gpointer) &value, 4);
+
+ before = state->enumdesc->len;
+ g_string_append_c (state->enumdesc, 0xff);
+ g_string_append (state->enumdesc, nick);
+ g_string_append_c (state->enumdesc, 0);
+ while (~state->enumdesc->len & 3)
+ g_string_append_c (state->enumdesc, 0);
+ g_string_append_c (state->enumdesc, 0xff);
+
+ if (g_memmem (state->enumdesc->str, before,
+ state->enumdesc->str + before,
+ state->enumdesc->len - before))
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "<value nick='%s'> already specified", nick);
+ }
return;
}
@@ -540,7 +690,9 @@ end_element (GMarkupParseContext *context,
}
else if (state->choices != NULL)
{
- if (!is_valid_choices (state->value, state->choices->str))
+ if (!is_valid_choices (state->value,
+ state->choices->str,
+ state->choices->len))
{
g_set_error_literal (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT,
@@ -566,12 +718,10 @@ end_element (GMarkupParseContext *context,
else if (strcmp (element_name, "choices") == 0)
{
- gchar *choices;
-
- choices = g_string_free (state->choices, FALSE);
g_variant_builder_add (&state->key_options, "{sv}", "choices",
- g_variant_new_byte_array (choices, -1));
- g_free (choices);
+ g_variant_new_byte_array (state->choices->str,
+ state->choices->len));
+ g_string_free (state->choices, TRUE);
}
}
@@ -613,6 +763,7 @@ parse_gschema_files (gchar **files,
context = g_markup_parse_context_new (&parser,
G_MARKUP_PREFIX_ERROR_POSITION,
&state, NULL);
+ state.enums = gvdb_hash_table_new (NULL, NULL);
state.schemas = gvdb_hash_table_new (NULL, NULL);
while ((filename = *files++) != NULL)
diff --git a/gio/gsettings-mapping.c b/gio/gsettings-mapping.c
index 6b17bfb..cf1ac11 100644
--- a/gio/gsettings-mapping.c
+++ b/gio/gsettings-mapping.c
@@ -377,6 +377,21 @@ g_settings_set_mapping (const GValue *value,
return g_variant_new_signature (g_value_get_string (value));
}
+ else if (G_VALUE_HOLDS_ENUM (value))
+ {
+ GEnumValue *enumval;
+ GEnumClass *eclass;
+
+ eclass = g_type_class_ref (G_VALUE_TYPE (value));
+ enumval = g_enum_get_value (eclass, g_value_get_enum (value));
+ g_type_class_unref (eclass);
+
+ if (enumval)
+ return g_variant_new_string (enumval->value_nick);
+ else
+ return NULL;
+ }
+
type_string = g_variant_type_dup_string (expected_type);
g_critical ("No GSettings bind handler for type \"%s\".", type_string);
g_free (type_string);
@@ -426,8 +441,11 @@ g_settings_get_mapping (GValue *value,
g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
{
- g_value_set_string (value, g_variant_get_string (variant, NULL));
- return TRUE;
+ if (G_VALUE_HOLDS_STRING (value))
+ {
+ g_value_set_string (value, g_variant_get_string (variant, NULL));
+ return TRUE;
+ }
}
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("ay")))
{
@@ -470,6 +488,8 @@ g_settings_mapping_is_compatible (GType gvalue_type,
g_variant_type_equal (variant_type, G_VARIANT_TYPE ("ay")) ||
g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE));
+ else if (G_TYPE_IS_ENUM (gvalue_type))
+ ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING);
return ok;
}
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 15de030..219d298 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -19,7 +19,9 @@
* Author: Ryan Lortie <desrt desrt ca>
*/
+#define _GNU_SOURCE
#include "config.h"
+
#include <glib.h>
#include <glibintl.h>
#include <locale.h>
@@ -144,6 +146,28 @@
* </refsect2>
*/
+static gpointer
+g_memmem (gconstpointer haystack,
+ gsize haystack_len,
+ gconstpointer needle,
+ gsize needle_len)
+{
+#ifndef HAVE_MEMMEM
+ while (needle_len <= haystack_len)
+ {
+ if (memcmp (haystack, needle, needle_len) == 0)
+ return (gpointer) haystack;
+
+ haystack = ((gchar *) haystack) + 1;
+ haystack_len--;
+ }
+
+ return NULL;
+#else
+ return memmem (haystack, haystack_len, needle, needle_len);
+#endif
+}
+
struct _GSettingsPrivate
{
/* where the signals go... */
@@ -730,6 +754,177 @@ g_settings_class_init (GSettingsClass *class)
}
+typedef struct
+{
+ GSettings *settings;
+ const gchar *key;
+
+ GSettingsSchema *schema;
+
+ const gchar *enumdata;
+ gsize enumsize;
+
+ const gchar *unparsed;
+ gchar lc_char;
+
+ const GVariantType *type;
+ GVariant *value;
+} GSettingsKeyInfo;
+
+static GVariant *
+g_settings_get_translated_default (GSettingsKeyInfo *info)
+{
+ const gchar *translated;
+ GError *error = NULL;
+ const gchar *domain;
+ GVariant *value;
+
+ if (info->lc_char == '\0')
+ return NULL;
+
+ domain = g_settings_schema_get_gettext_domain (info->schema);
+
+ if (info->lc_char == 't')
+ translated = g_dcgettext (domain, info->unparsed, LC_TIME);
+ else
+ translated = g_dgettext (domain, info->unparsed);
+
+ if (translated == info->unparsed)
+ return NULL;
+
+ value = g_variant_parse (info->type, translated, NULL, NULL, &error);
+
+ if (value == NULL)
+ {
+ g_warning ("Failed to parse translated string `%s' for "
+ "key `%s' in schema `%s': %s", info->unparsed, info->key,
+ info->settings->priv->schema_name, error->message);
+ g_warning ("Using untranslated default instead.");
+ g_error_free (error);
+ }
+
+ return value;
+}
+
+static gboolean
+g_settings_to_enum (GSettingsKeyInfo *info,
+ GVariant *value,
+ gint *result)
+{
+ const gchar *str;
+ gsize length;
+
+ if (info->enumdata == NULL)
+ {
+ g_critical ("g_settings_get_enum() called on key '%s' which is not "
+ "associated with an enumerated type", info->key);
+ *(gint *) result = 0;
+
+ return TRUE;
+ }
+
+ str = g_variant_get_string (value, &length);
+
+ if (2 < length && length <= 64)
+ {
+ guint32 *found_value;
+ gchar buffer[80];
+ gint pad;
+
+ pad = (2u - length) & 3;
+ buffer[0] = '\xff';
+ memcpy (buffer + 1, str, length + 1);
+ memset (buffer + length + 2, 0, pad);
+ buffer[length + pad + 2] = '\xff';
+ length += pad + 2;
+
+ found_value = g_memmem (info->enumdata, info->enumsize, buffer, length);
+
+ if (found_value)
+ {
+ *result = GUINT32_FROM_LE (found_value[-1]);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static GVariant *
+g_settings_from_enum (GSettingsKeyInfo *info,
+ gint value)
+{
+ guint32 pattern[] = { -1u, value, -1u };
+ const gchar *found_nick;
+
+ pattern[1] = GUINT32_TO_LE (pattern[1]);
+ found_nick = g_memmem (info->enumdata, info->enumsize,
+ ((gchar *) pattern) + 3, 6);
+
+ if (found_nick)
+ return g_variant_new_string (found_nick + 6);
+
+ return NULL;
+}
+
+static GSettingsKeyInfo
+g_settings_find_key (GSettings *settings,
+ const gchar *key)
+{
+ GSettingsKeyInfo info = { settings, key, settings->priv->schema };
+ GSettingsSchema *schema;
+ GVariant *array;
+
+ schema = settings->priv->schema;
+ info.value = g_settings_schema_get_value (schema, key, &array);
+
+ if G_UNLIKELY (info.value == NULL)
+ g_error ("schema '%s' does not contain a key named '%s'",
+ settings->priv->schema_name, key);
+
+ info.type = g_variant_get_type (info.value);
+
+ if (array != NULL)
+ {
+ GVariant *option_value;
+ const gchar *option;
+ GVariantIter iter;
+
+ g_variant_iter_init (&iter, array);
+ while (g_variant_iter_loop (&iter, "{&sv}", &option, &option_value))
+ {
+ if (strcmp (option, "l10n") == 0)
+ g_variant_get (option_value, "(y&s)",
+ &info.lc_char, &info.unparsed);
+
+ else if (strcmp (option, "enum") == 0)
+ info.enumdata = g_variant_get_byte_array (option_value,
+ &info.enumsize);
+
+ else
+ g_warning ("unknown schema extension '%s'", option);
+ }
+
+ g_variant_unref (array);
+ }
+
+ return info;
+}
+
+static GVariant *
+g_settings_get_from_backend (GSettingsKeyInfo *info)
+{
+ GVariant *value;
+ gchar *path;
+
+ path = g_strconcat (info->settings->priv->path, info->key, NULL);
+ value = g_settings_backend_read (info->settings->priv->backend,
+ path, info->type, FALSE);
+ g_free (path);
+
+ return value;
+}
+
/**
* g_settings_get_value:
* @settings: a #GSettings object
@@ -747,88 +942,73 @@ GVariant *
g_settings_get_value (GSettings *settings,
const gchar *key)
{
- const gchar *unparsed = NULL;
- GVariant *value, *options;
- const GVariantType *type;
- gchar lc_char = '\0';
- GVariant *sval;
- gchar *path;
+ GSettingsKeyInfo info;
+ GVariant *value;
g_return_val_if_fail (G_IS_SETTINGS (settings), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
- sval = g_settings_schema_get_value (settings->priv->schema, key, &options);
+ info = g_settings_find_key (settings, key);
+ value = g_settings_get_from_backend (&info);
- if G_UNLIKELY (sval == NULL)
- g_error ("schema '%s' does not contain a key named '%s'",
- settings->priv->schema_name, key);
+ if (value == NULL)
+ value = g_settings_get_translated_default (&info);
- path = g_strconcat (settings->priv->path, key, NULL);
- type = g_variant_get_type (sval);
- value = g_settings_backend_read (settings->priv->backend, path, type, FALSE);
- g_free (path);
+ if (value == NULL)
+ value = g_variant_ref (info.value);
- if (options != NULL)
- {
- GVariantIter iter;
- const gchar *option;
- GVariant *option_value;
+ g_variant_unref (info.value);
- g_variant_iter_init (&iter, options);
- while (g_variant_iter_loop (&iter, "{&sv}", &option, &option_value))
- {
- if (strcmp (option, "l10n") == 0)
- g_variant_get (option_value, "(y&s)", &lc_char, &unparsed);
- else
- g_warning ("unknown schema extension '%s'", option);
- }
- }
+ return value;
+}
- if (value && !g_variant_is_of_type (value, type))
+gint
+g_settings_get_enum (GSettings *settings,
+ const gchar *key)
+{
+ GSettingsKeyInfo info;
+ GVariant *value;
+ gint result;
+
+ g_return_val_if_fail (G_IS_SETTINGS (settings), -1);
+ g_return_val_if_fail (key != NULL, -1);
+
+ info = g_settings_find_key (settings, key);
+ value = g_settings_get_from_backend (&info);
+
+ if (value != NULL && !g_settings_to_enum (&info, value, &result))
{
g_variant_unref (value);
value = NULL;
}
- if (value == NULL && lc_char != '\0')
- /* we will need to translate the schema default value */
+ if (value == NULL)
{
- const gchar *translated;
- GError *error = NULL;
- const gchar *domain;
-
- domain = g_settings_schema_get_gettext_domain (settings->priv->schema);
+ value = g_settings_get_translated_default (&info);
- if (lc_char == 't')
- translated = g_dcgettext (domain, unparsed, LC_TIME);
- else
- translated = g_dgettext (domain, unparsed);
-
- if (translated != unparsed)
- /* it was translated, so we need to re-parse it */
+ if (value != NULL && !g_settings_to_enum (&info, value, &result))
{
- value = g_variant_parse (g_variant_get_type (sval),
- translated, NULL, NULL, &error);
-
- if (value == NULL)
- {
- g_warning ("Failed to parse translated string `%s' for "
- "key `%s' in schema `%s': %s", unparsed, key,
- settings->priv->schema_name, error->message);
- g_warning ("Using untranslated default instead.");
- g_error_free (error);
- }
+ g_variant_unref (value);
+ value = NULL;
}
}
if (value == NULL)
- /* either translation failed or there was none to do.
- * use the pre-compiled default.
- */
- value = g_variant_ref (sval);
+ g_settings_to_enum (&info, info.value, &result);
+ else
+ g_variant_unref (value);
- g_variant_unref (sval);
+ g_variant_unref (info.value);
- return value;
+ return result;
+}
+
+gboolean
+g_settings_set_enum (GSettings *settings,
+ const gchar *key,
+ gint value)
+{
+ return FALSE;
}
/**
@@ -1388,8 +1568,8 @@ g_settings_bind_with_mapping (GSettings *settings,
!g_settings_mapping_is_compatible (binding->property->value_type,
binding->type))
{
- g_critical ("g_settings_bind: property '%s' on class '%s' has type"
- "'%s' which is not compatible with type '%s' of key '%s'"
+ g_critical ("g_settings_bind: property '%s' on class '%s' has type "
+ "'%s' which is not compatible with type '%s' of key '%s' "
"on schema '%s'", property, G_OBJECT_TYPE_NAME (object),
g_type_name (binding->property->value_type),
g_variant_type_dup_string (binding->type), key,
diff --git a/gio/gsettings.h b/gio/gsettings.h
index d766bd0..aad224e 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -121,7 +121,11 @@ gchar ** g_settings_get_strv (GSettin
gboolean g_settings_set_strv (GSettings *settings,
const gchar *key,
const gchar *const *value);
-
+gint g_settings_get_enum (GSettings *settings,
+ const gchar *key);
+gboolean g_settings_set_enum (GSettings *settings,
+ const gchar *key,
+ gint value);
GSettings * g_settings_get_child (GSettings *settings,
const gchar *name);
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index dd22593..044ef48 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -732,7 +732,8 @@ g_settings_backend_changed_tree (GSettingsBackend *backend,
* g_settings_backend_read:
* @backend: a #GSettingsBackend implementation
* @key: the key to read
- * @expected_type: a #GVariantType hint
+ * @expected_type: a #GVariantType
+ * @default_value: if the default value should be returned
* @returns: the value that was read, or %NULL
*
* Reads a key. This call will never block.
@@ -740,11 +741,13 @@ g_settings_backend_changed_tree (GSettingsBackend *backend,
* If the key exists, the value associated with it will be returned.
* If the key does not exist, %NULL will be returned.
*
- * If @expected_type is given, it serves as a type hint to the backend.
- * If you expect a key of a certain type then you should give
- * @expected_type to increase your chances of getting it. Some backends
- * may ignore this argument and return values of a different type; it is
- * mostly used by backends that don't store strong type information.
+ * The returned value will be of the type given in @expected_type. If
+ * the backend stored a value of a different type then %NULL will be
+ * returned.
+ *
+ * If @default_value is %TRUE then this gets the default value from the
+ * backend (ie: the one that the backend would contain if
+ * g_settings_reset() were called).
*/
GVariant *
g_settings_backend_read (GSettingsBackend *backend,
@@ -752,8 +755,18 @@ g_settings_backend_read (GSettingsBackend *backend,
const GVariantType *expected_type,
gboolean default_value)
{
- return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ GVariant *value;
+
+ value = G_SETTINGS_BACKEND_GET_CLASS (backend)
->read (backend, key, expected_type, default_value);
+
+ if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type))
+ {
+ g_variant_unref (value);
+ value = NULL;
+ }
+
+ return value;
}
/*< private >
diff --git a/gio/tests/org.gtk.test.gschema.xml b/gio/tests/org.gtk.test.gschema.xml
index 9d1a821..48259f9 100644
--- a/gio/tests/org.gtk.test.gschema.xml
+++ b/gio/tests/org.gtk.test.gschema.xml
@@ -92,4 +92,18 @@
</key>
</schema>
+ <enum id='org.gtk.test.TestEnum'>
+ <value nick='invalid' value='0'/>
+ <value nick='foo' value='1'/>
+ <value nick='bar' value='2'/>
+ <value nick='baz' value='3'/>
+ <value nick='quux' value='4'/>
+ </enum>
+
+ <schema id='org.gtk.test.enums' path='/tests/enums/'>
+ <key name='test' enum='org.gtk.test.TestEnum'>
+ <default>'bar'</default>
+ </key>
+ </schema>
+
</schemalist>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]