From d6d76783ae9fc473d7fe38683d729d6c2c8e80c4 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Mon, 4 Oct 2010 02:58:46 -0400 Subject: [PATCH] Bug 631263 - GSettings needs range/choice APIs Add g_settings_get_range() to describe the possible values that may be provided to g_settings_set_value() without causing an error. Add a test case. --- gio/gsettings.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- gio/gsettings.h | 2 ++ gio/strinfo.c | 31 +++++++++++++++++++ gio/tests/gsettings.c | 43 ++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/gio/gsettings.c b/gio/gsettings.c index 34a69ce..5d7cb5e 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -1995,7 +1995,7 @@ g_settings_get_has_unapplied (GSettings *settings) G_DELAYED_SETTINGS_BACKEND (settings->priv->backend)); } -/* Extra API (reset, sync, get_child, is_writable, list_*) {{{1 */ +/* Extra API (reset, sync, get_child, is_writable, list_*, get_range) {{{1 */ /** * g_settings_reset: * @settings: a #GSettings object @@ -2198,6 +2198,88 @@ g_settings_list_children (GSettings *settings) return strv; } +/** + * g_settings_get_range: + * @settings: a #GSettings + * @key: the key to query the range of + * @returns: a #GVariant describing the range + * + * 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. + * + * It is a programmer error to give a @key that isn't contained in the + * schema for @settings. + * + * You should free the returned value with g_variant_unref() when it is + * no longer needed. + * + * Since: 2.28 + **/ +GVariant * +g_settings_get_range (GSettings *settings, + const gchar *key) +{ + GSettingsKeyInfo info; + const gchar *type; + GVariant *range; + + g_settings_get_key_info (&info, settings, key); + + if (info.minimum) + { + range = g_variant_new ("(**)", info.minimum, info.maximum); + type = "range"; + } + else if (info.strinfo) + { + range = strinfo_enumerate (info.strinfo, info.strinfo_length); + type = info.is_flags ? "flags" : "enum"; + } + else + { + range = g_variant_new_array (info.type, NULL, 0); + type = "type"; + } + + g_settings_free_key_info (&info); + + return g_variant_ref_sink (g_variant_new ("(sv)", type, range)); +} + /* Binding {{{1 */ typedef struct { diff --git a/gio/gsettings.h b/gio/gsettings.h index 2b4e2f6..a90cd0b 100644 --- a/gio/gsettings.h +++ b/gio/gsettings.h @@ -82,6 +82,8 @@ GSettings * g_settings_new_with_backend_and_path (const g const gchar *path); gchar ** g_settings_list_children (GSettings *settings); gchar ** g_settings_list_keys (GSettings *settings); +GVariant * g_settings_get_range (GSettings *settings, + const gchar *key); gboolean g_settings_set_value (GSettings *settings, const gchar *key, diff --git a/gio/strinfo.c b/gio/strinfo.c index 6836b59..cfefe13 100644 --- a/gio/strinfo.c +++ b/gio/strinfo.c @@ -260,6 +260,37 @@ strinfo_string_from_alias (const guint32 *strinfo, return 1 + (const gchar *) &strinfo[GUINT32_TO_LE (strinfo[index]) + 1]; } +G_GNUC_UNUSED static GVariant * +strinfo_enumerate (const guint32 *strinfo, + guint length) +{ + GVariantBuilder builder; + const gchar *ptr, *end; + + ptr = (gpointer) strinfo; + end = ptr + 4 * length; + + ptr += 4; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY); + + while (ptr < end) + { + /* don't include aliases */ + if (*ptr == '\xff') + g_variant_builder_add (&builder, "s", ptr + 1); + + /* find the end of this string */ + ptr = memchr (ptr, '\xff', end - ptr); + g_assert (ptr != NULL); + + /* skip over the int to the next string */ + ptr += 5; + } + + return g_variant_builder_end (&builder); +} + G_GNUC_UNUSED static void strinfo_builder_append_item (GString *builder, const gchar *string, diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index f86a2f8..b0168a9 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -14,6 +14,20 @@ static gboolean backend_set; * to be compiled and installed in the same directory. */ +static void +check_and_free (GVariant *value, + const gchar *expected) +{ + gchar *printed; + + printed = g_variant_print (value, TRUE); + g_assert_cmpstr (printed, ==, expected); + g_free (printed); + + g_variant_unref (value); +} + + /* Just to get warmed up: Read and set a string, and * verify that can read the changed string back */ @@ -1843,6 +1857,34 @@ test_get_mapped (void) g_object_unref (settings); } +static void +test_get_range (void) +{ + GSettings *settings; + GVariant *range; + + settings = g_settings_new ("org.gtk.test.range"); + range = g_settings_get_range (settings, "val"); + check_and_free (range, "('range', <(2, 44)>)"); + g_object_unref (settings); + + settings = g_settings_new ("org.gtk.test.enums"); + range = g_settings_get_range (settings, "test"); + check_and_free (range, "('enum', <['foo', 'bar', 'baz', 'quux']>)"); + g_object_unref (settings); + + settings = g_settings_new ("org.gtk.test.enums"); + range = g_settings_get_range (settings, "f-test"); + check_and_free (range, "('flags', " + "<['mourning', 'laughing', 'talking', 'walking']>)"); + g_object_unref (settings); + + settings = g_settings_new ("org.gtk.test"); + range = g_settings_get_range (settings, "greeting"); + check_and_free (range, "('type', <@as []>)"); + g_object_unref (settings); +} + int main (int argc, char *argv[]) { @@ -1926,6 +1968,7 @@ main (int argc, char *argv[]) g_test_add_func ("/gsettings/list-items", test_list_items); g_test_add_func ("/gsettings/list-schemas", test_list_schemas); g_test_add_func ("/gsettings/mapped", test_get_mapped); + g_test_add_func ("/gsettings/get-range", test_get_range); result = g_test_run (); -- 2.7.4