From 168cfc592283c992d6a6803a91528f87cec2d902 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Mon, 28 Jun 2010 10:18:45 -0400 Subject: [PATCH] Bug 622127 - GSettings extended key validation First shot at attempting to implement this in a reasonable way. See the bug for more information about why this is needed. --- docs/reference/gio/gio-sections.txt | 4 ++ gio/gio.symbols | 1 + gio/gsettings.c | 83 ++++++++++++++++++++++++++++- gio/gsettings.h | 27 ++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index b1d86d19b..e6dbac0f4 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -2169,6 +2169,10 @@ g_settings_set_strv g_settings_get_enum g_settings_set_enum + +GSettingsGetMapping +g_settings_get_mapped + GSettingsBindFlags g_settings_bind diff --git a/gio/gio.symbols b/gio/gio.symbols index e2bb8daa7..3e0301109 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1479,6 +1479,7 @@ g_settings_get_enum g_settings_set_enum g_settings_sync g_settings_list_keys +g_settings_get_mapped #endif #endif diff --git a/gio/gsettings.c b/gio/gsettings.c index b51723747..54b66ed85 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -1126,7 +1126,7 @@ g_settings_from_enum (GSettingsKeyInfo *info, return g_variant_ref_sink (g_variant_new_string (string)); } -/* Public Get/Set API {{{1 (get, get_value, set, set_value) */ +/* Public Get/Set API {{{1 (get, get_value, set, set_value, get_mapped) */ /** * g_settings_get_value: * @settings: a #GSettings object @@ -1384,6 +1384,87 @@ g_settings_set (GSettings *settings, return g_settings_set_value (settings, key, value); } +/** + * g_settings_get_mapped: + * @settings: a #GSettings object + * @key: the key to get the value for + * @mapping: the function to map the value in the settings database to + * the value used by the application + * @user_data: user data for @mapping + * + * Gets the value that is stored at @key in @settings, subject to + * application-level validation/mapping. + * + * You should use this function when the application needs to perform + * some processing on the value of the key (for example, parsing). The + * @mapping function performs that processing. If the function + * indicates that the processing was unsuccessful (due to a parse error, + * for example) then the mapping is tried again with another value. + + * This allows a robust 'fall back to defaults' behaviour to be + * implemented somewhat automatically. + * + * The first value that is tried is the user's setting for the key. If + * the mapping function fails to map this value, other values may be + * tried in an unspecified order (system or site defaults, translated + * schema default values, untranslated schema default values, etc). + * + * If the mapping function fails for all possible values, one additional + * attempt is made: the mapping function is called with a %NULL value. + * If the mapping function still indicates failure at this point then + * the application will be aborted. + * + * The result parameter for the @mapping function is pointed to a + * #gpointer which is initially set to %NULL. The same pointer is given + * to each invocation of @mapping. The final value of that #gpointer is + * what is returned by this function. %NULL is valid; it is returned + * just as any other value would be. + **/ +gpointer +g_settings_get_mapped (GSettings *settings, + const gchar *key, + GSettingsGetMapping mapping, + gpointer user_data) +{ + gpointer result = NULL; + GSettingsKeyInfo info; + GVariant *value; + gboolean okay; + + g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (mapping != NULL, NULL); + + g_settings_get_key_info (&info, settings, key); + + if ((value = g_settings_read_from_backend (&info))) + { + okay = mapping (value, &result, user_data); + g_variant_unref (value); + if (okay) goto okay; + } + + if ((value = g_settings_get_translated_default (&info))) + { + okay = mapping (value, &result, user_data); + g_variant_unref (value); + if (okay) goto okay; + } + + if (mapping (info.default_value, &result, user_data)) + goto okay; + + if (!mapping (NULL, &result, user_data)) + g_error ("The mapping function given to g_settings_get_mapped() for key " + "`%s' in schema `%s' returned FALSE when given a NULL value.", + key, settings->priv->schema_name); + + okay: + g_settings_free_key_info (&info); + + return result; +} + /* Convenience API (get, set_string, int, double, boolean, strv) {{{1 */ /** * g_settings_get_string: diff --git a/gio/gsettings.h b/gio/gsettings.h index c3cbb488f..40d0cbf9e 100644 --- a/gio/gsettings.h +++ b/gio/gsettings.h @@ -168,6 +168,28 @@ typedef gboolean (*GSettingsBindGetMapping) (GValue GVariant *variant, gpointer user_data); +/** + * GSettingsGetMapping: + * @value: the #GVariant to map, or %NULL + * @result: the result of the mapping + * @user_data: the user data that was passed to g_settings_get_mapped() + * Returns: %TRUE if the conversion succeeded, %FALSE in case of an error + * + * The type of the function that is used to convert from a value stored + * in a #GSettings to a value that is useful to the application. + * + * If the value is successfully mapped, the result should be stored at + * @result and %TRUE returned. If mapping fails (for example, if @value + * is not in the right format) then %FALSE should be returned. + * + * If @value is %NULL then it means that the mapping function is being + * given a "last chance" to successfully return a valid value. %TRUE + * must be returned in this case. + **/ +typedef gboolean (*GSettingsGetMapping) (GVariant *value, + gpointer *result, + gpointer user_data); + /** * GSettingsBindFlags: * @G_SETTINGS_BIND_DEFAULT: Equivalent to G_SETTINGS_BIND_GET|G_SETTINGS_BIND_SET @@ -214,6 +236,11 @@ void g_settings_bind_writable (GSettin void g_settings_unbind (gpointer object, const gchar *property); +gpointer g_settings_get_mapped (GSettings *settings, + const gchar *key, + GSettingsGetMapping mapping, + gpointer user_data); + G_END_DECLS #endif /* __G_SETTINGS_H__ */