X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsettings.c;h=23a14bcc90db2540da6dd8c182aa62a172f7dc27;hb=a3d86afa81ff34ce797a3928fd619ead219a37af;hp=1672ee7729d37577518365021a8c9c2812c9ef47;hpb=ca2004fe73ca853bc1f9ade6160c1b59d2865c67;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsettings.c b/gio/gsettings.c index 1672ee7..23a14bc 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . * * Author: Ryan Lortie */ @@ -24,7 +22,6 @@ #include #include -#include #include "gsettings.h" @@ -32,15 +29,14 @@ #include "gsettingsbackendinternal.h" #include "gsettings-mapping.h" #include "gsettingsschema-internal.h" - -#include - +#include "gaction.h" #include "strinfo.c" /** * SECTION:gsettings * @short_description: High-level API for application settings + * @include: gio/gio.h * * The #GSettings class provides a convenient API for storing and retrieving * application settings. @@ -72,6 +68,14 @@ * useful e.g. when the schema describes an 'account', and you want to be * able to store a arbitrary number of accounts. * + * Paths must start with and end with a forward slash character ('/') + * and must not contain two sequential slash characters. Paths should + * be chosen based on a domain name associated with the program or + * library to which the settings belong. Examples of paths are + * "/org/gtk/settings/file-chooser/" and "/ca/desrt/dconf-editor/". + * Paths should not start with "/apps/", "/desktop/" or "/system/" as + * they often did in GConf. + * * Unlike other configuration systems (like GConf), GSettings does not * restrict keys to basic types like strings and numbers. GSettings stores * values as #GVariant, and allows any #GVariantType for keys. Key names @@ -79,45 +83,54 @@ * the names must begin with a lowercase character, must not end * with a '-', and must not contain consecutive dashes. * + * GSettings supports change notification. The primary mechanism to + * watch for changes is to connect to the "changed" signal. You can + * optionally watch for changes on only a single key by using a signal + * detail. Signals are only guaranteed to be emitted for a given key + * after you have read the value of that key while a signal handler was + * connected for that key. Signals may or may not be emitted in the + * case that the key "changed" to the value that you had previously + * read. Signals may be reported in additional cases as well and the + * "changed" signal should really be treated as "may have changed". + * * Similar to GConf, the default values in GSettings schemas can be * localized, but the localized values are stored in gettext catalogs * and looked up with the domain that is specified in the - * gettext-domain attribute of the - * schemalist or schema - * elements and the category that is specified in the l10n attribute of the - * key element. + * gettext-domain attribute of the or + * elements and the category that is specified in the l10n attribute of + * the element. * * GSettings uses schemas in a compact binary form that is created - * by the glib-compile-schemas - * utility. The input is a schema description in an XML format that can be - * described by the following DTD: - * |[FIXME: MISSING XINCLUDE CONTENT]| - * - * glib-compile-schemas expects schema files to have the extension .gschema.xml - * - * At runtime, schemas are identified by their id (as specified - * in the id attribute of the - * schema element). The - * convention for schema ids is to use a dotted name, similar in - * style to a D-Bus bus name, e.g. "org.gnome.SessionManager". In particular, - * if the settings are for a specific service that owns a D-Bus bus name, - * the D-Bus bus name and schema id should match. For schemas which deal - * with settings not associated with one named application, the id should - * not use StudlyCaps, e.g. "org.gnome.font-rendering". - * - * In addition to #GVariant types, keys can have types that have enumerated - * types. These can be described by a choice, - * enum or flags element, see - * . The underlying type of - * such a key is string, but you can use g_settings_get_enum(), - * g_settings_set_enum(), g_settings_get_flags(), g_settings_set_flags() - * access the numeric values corresponding to the string value of enum - * and flags keys. - * - * Default values - * element). The convention for schema + * ids is to use a dotted name, similar in style to a D-Bus bus name, + * e.g. "org.gnome.SessionManager". In particular, if the settings are + * for a specific service that owns a D-Bus bus name, the D-Bus bus name + * and schema id should match. For schemas which deal with settings not + * associated with one named application, the id should not use + * StudlyCaps, e.g. "org.gnome.font-rendering". + * + * In addition to #GVariant types, keys can have types that have + * enumerated types. These can be described by a , + * or element, as seen in the + * [example][schema-enumerated]. The underlying type of such a key + * is string, but you can use g_settings_get_enum(), g_settings_set_enum(), + * g_settings_get_flags(), g_settings_set_flags() access the numeric values + * corresponding to the string value of enum and flags keys. + * + * An example for default value: + * |[ * - * + * * * * "Hello, earthlings" @@ -133,10 +146,10 @@ * * * - * ]]> + * ]| * - * Ranges, choices and enumerated types - * * * @@ -179,52 +192,43 @@ * * * - * ]]> - * - * - * Vendor overrides - * - * Default values are defined in the schemas that get installed by - * an application. Sometimes, it is necessary for a vendor or distributor - * to adjust these defaults. Since patching the XML source for the schema - * is inconvenient and error-prone, - * glib-compile-schemas reads - * so-called 'vendor override' files. These are keyfiles in the same - * directory as the XML schema sources which can override default values. - * The schema id serves as the group name in the key file, and the values - * are expected in serialized GVariant form, as in the following example: - * + * ]| + * + * ## Vendor overrides + * + * Default values are defined in the schemas that get installed by + * an application. Sometimes, it is necessary for a vendor or distributor + * to adjust these defaults. Since patching the XML source for the schema + * is inconvenient and error-prone, + * [glib-compile-schemas][glib-compile-schemas] reads so-called vendor + * override' files. These are keyfiles in the same directory as the XML + * schema sources which can override default values. The schema id serves + * as the group name in the key file, and the values are expected in + * serialized GVariant form, as in the following example: + * |[ * [org.gtk.Example] * key1='string' * key2=1.5 - * - * - * - * glib-compile-schemas expects schema files to have the extension - * .gschema.override - * - * - * - * - * Binding - * - * A very convenient feature of GSettings lets you bind #GObject properties - * directly to settings, using g_settings_bind(). Once a GObject property - * has been bound to a setting, changes on either side are automatically - * propagated to the other side. GSettings handles details like - * mapping between GObject and GVariant types, and preventing infinite - * cycles. - * - * - * This makes it very easy to hook up a preferences dialog to the - * underlying settings. To make this even more convenient, GSettings - * looks for a boolean property with the name "sensitivity" and - * automatically binds it to the writability of the bound setting. - * If this 'magic' gets in the way, it can be suppressed with the - * #G_SETTINGS_BIND_NO_SENSITIVITY flag. - * - * - **/ + * ]| + * + * glib-compile-schemas expects schema files to have the extension + * `.gschema.override`. + * + * ## Binding + * + * A very convenient feature of GSettings lets you bind #GObject properties + * directly to settings, using g_settings_bind(). Once a GObject property + * has been bound to a setting, changes on either side are automatically + * propagated to the other side. GSettings handles details like mapping + * between GObject and GVariant types, and preventing infinite cycles. + * + * This makes it very easy to hook up a preferences dialog to the + * underlying settings. To make this even more convenient, GSettings + * looks for a boolean property with the name "sensitivity" and + * automatically binds it to the writability of the bound setting. + * If this 'magic' gets in the way, it can be suppressed with the + * #G_SETTINGS_BIND_NO_SENSITIVITY flag. + */ struct _GSettingsPrivate { @@ -233,9 +237,10 @@ struct _GSettingsPrivate GSettingsBackend *backend; GSettingsSchema *schema; - gchar *schema_name; gchar *path; + gboolean is_subscribed; + GDelayedSettingsBackend *delayed; }; @@ -243,6 +248,7 @@ enum { PROP_0, PROP_SCHEMA, + PROP_SCHEMA_ID, PROP_BACKEND, PROP_PATH, PROP_HAS_UNAPPLIED, @@ -260,7 +266,7 @@ enum static guint g_settings_signals[N_SIGNALS]; -G_DEFINE_TYPE (GSettings, g_settings, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_PRIVATE (GSettings, g_settings, G_TYPE_OBJECT) /* Signals {{{1 */ static gboolean @@ -274,8 +280,14 @@ g_settings_real_change_event (GSettings *settings, keys = g_settings_schema_list (settings->priv->schema, &n_keys); for (i = 0; i < n_keys; i++) - g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGED], - keys[i], g_quark_to_string (keys[i])); + { + const gchar *key = g_quark_to_string (keys[i]); + + if (g_str_has_suffix (key, "/")) + continue; + + g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGED], keys[i], key); + } return FALSE; } @@ -292,12 +304,44 @@ g_settings_real_writable_change_event (GSettings *settings, keys = g_settings_schema_list (settings->priv->schema, &n_keys); for (i = 0; i < n_keys; i++) - g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], - keys[i], g_quark_to_string (keys[i])); + { + const gchar *key = g_quark_to_string (keys[i]); + + if (g_str_has_suffix (key, "/")) + continue; + + g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], keys[i], key); + } return FALSE; } +static gboolean +g_settings_has_signal_handlers (GSettings *settings, + const gchar *key) +{ + GSettingsClass *class = G_SETTINGS_GET_CLASS (settings); + GQuark keyq; + + if (class->change_event != g_settings_real_change_event || + class->writable_change_event != g_settings_real_writable_change_event) + return TRUE; + + keyq = g_quark_from_string (key); + + if (g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT], 0, TRUE) || + g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], 0, TRUE) || + g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], keyq, TRUE) || + g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGE_EVENT], 0, TRUE) || + g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGED], 0, TRUE) || + g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGED], keyq, TRUE)) + return TRUE; + + /* None of that? Then surely nobody is watching.... */ + return FALSE; +} + + static void settings_backend_changed (GObject *target, GSettingsBackend *backend, @@ -351,8 +395,8 @@ static void settings_backend_keys_changed (GObject *target, GSettingsBackend *backend, const gchar *path, - const gchar * const *items, - gpointer origin_tag) + gpointer origin_tag, + const gchar * const *items) { GSettings *settings = G_SETTINGS (target); gboolean ignore_this; @@ -431,8 +475,50 @@ g_settings_set_property (GObject *object, switch (prop_id) { case PROP_SCHEMA: - g_assert (settings->priv->schema_name == NULL); - settings->priv->schema_name = g_value_dup_string (value); + { + GSettingsSchema *schema; + + schema = g_value_dup_boxed (value); + + /* we receive a set_property() call for "settings-schema" even + * if it was not specified (ie: with NULL value). ->schema + * could already be set at this point (ie: via "schema-id"). + * check for NULL to avoid clobbering the existing value. + */ + if (schema != NULL) + { + g_assert (settings->priv->schema == NULL); + settings->priv->schema = schema; + } + } + break; + + case PROP_SCHEMA_ID: + { + const gchar *schema_id; + + schema_id = g_value_get_string (value); + + /* we receive a set_property() call for both "schema" and + * "schema-id", even if they are not set. Hopefully only one of + * them is non-NULL. + */ + if (schema_id != NULL) + { + GSettingsSchemaSource *default_source; + + g_assert (settings->priv->schema == NULL); + default_source = g_settings_schema_source_get_default (); + + if (default_source == NULL) + g_error ("No GSettings schemas are installed on the system"); + + settings->priv->schema = g_settings_schema_source_lookup (default_source, schema_id, TRUE); + + if (settings->priv->schema == NULL) + g_error ("Settings schema '%s' is not installed\n", schema_id); + } + } break; case PROP_PATH: @@ -458,8 +544,12 @@ g_settings_get_property (GObject *object, switch (prop_id) { - case PROP_SCHEMA: - g_value_set_string (value, settings->priv->schema_name); + case PROP_SCHEMA: + g_value_set_boxed (value, settings->priv->schema); + break; + + case PROP_SCHEMA_ID: + g_value_set_string (value, g_settings_schema_get_id (settings->priv->schema)); break; case PROP_BACKEND: @@ -497,19 +587,17 @@ g_settings_constructed (GObject *object) GSettings *settings = G_SETTINGS (object); const gchar *schema_path; - settings->priv->schema = g_settings_schema_new (settings->priv->schema_name); schema_path = g_settings_schema_get_path (settings->priv->schema); if (settings->priv->path && schema_path && strcmp (settings->priv->path, schema_path) != 0) - g_error ("settings object created with schema '%s' and path '%s', but " - "path '%s' is specified by schema", - settings->priv->schema_name, settings->priv->path, schema_path); + g_error ("settings object created with schema '%s' and path '%s', but path '%s' is specified by schema", + g_settings_schema_get_id (settings->priv->schema), settings->priv->path, schema_path); if (settings->priv->path == NULL) { if (schema_path == NULL) g_error ("attempting to create schema '%s' without a path", - settings->priv->schema_name); + g_settings_schema_get_id (settings->priv->schema)); settings->priv->path = g_strdup (schema_path); } @@ -520,8 +608,6 @@ g_settings_constructed (GObject *object) g_settings_backend_watch (settings->priv->backend, &listener_vtable, G_OBJECT (settings), settings->priv->main_context); - g_settings_backend_subscribe (settings->priv->backend, - settings->priv->path); } static void @@ -529,12 +615,13 @@ g_settings_finalize (GObject *object) { GSettings *settings = G_SETTINGS (object); - g_settings_backend_unsubscribe (settings->priv->backend, - settings->priv->path); + if (settings->priv->is_subscribed) + g_settings_backend_unsubscribe (settings->priv->backend, + settings->priv->path); + g_main_context_unref (settings->priv->main_context); g_object_unref (settings->priv->backend); g_settings_schema_unref (settings->priv->schema); - g_free (settings->priv->schema_name); g_free (settings->priv->path); G_OBJECT_CLASS (g_settings_parent_class)->finalize (object); @@ -543,10 +630,7 @@ g_settings_finalize (GObject *object) static void g_settings_init (GSettings *settings) { - settings->priv = G_TYPE_INSTANCE_GET_PRIVATE (settings, - G_TYPE_SETTINGS, - GSettingsPrivate); - + settings->priv = g_settings_get_instance_private (settings); settings->priv->main_context = g_main_context_ref_thread_default (); } @@ -563,8 +647,6 @@ g_settings_class_init (GSettingsClass *class) object_class->constructed = g_settings_constructed; object_class->finalize = g_settings_finalize; - g_type_class_add_private (object_class, sizeof (GSettingsPrivate)); - /** * GSettings::changed: * @settings: the object on which the signal was emitted @@ -589,10 +671,8 @@ g_settings_class_init (GSettingsClass *class) * GSettings::change-event: * @settings: the object on which the signal was emitted * @keys: (array length=n_keys) (element-type GQuark) (allow-none): - * an array of #GQuarks for the changed keys, or %NULL + * an array of #GQuarks for the changed keys, or %NULL * @n_keys: the length of the @keys array, or 0 - * @returns: %TRUE to stop other handlers from being invoked for the - * event. FALSE to propagate the event further. * * The "change-event" signal is emitted once per change event that * affects this settings object. You should connect to this signal @@ -609,6 +689,9 @@ g_settings_class_init (GSettingsClass *class) * The default handler for this signal invokes the "changed" signal * for each affected key. If any other connected handler returns * %TRUE then this default functionality will be suppressed. + * + * Returns: %TRUE to stop other handlers from being invoked for the + * event. FALSE to propagate the event further. */ g_settings_signals[SIGNAL_CHANGE_EVENT] = g_signal_new ("change-event", G_TYPE_SETTINGS, @@ -642,8 +725,6 @@ g_settings_class_init (GSettingsClass *class) * GSettings::writable-change-event: * @settings: the object on which the signal was emitted * @key: the quark of the key, or 0 - * @returns: %TRUE to stop other handlers from being invoked for the - * event. FALSE to propagate the event further. * * The "writable-change-event" signal is emitted once per writability * change event that affects this settings object. You should connect @@ -663,6 +744,9 @@ g_settings_class_init (GSettingsClass *class) * example, a new mandatory setting is introduced). If any other * connected handler returns %TRUE then this default functionality * will be suppressed. + * + * Returns: %TRUE to stop other handlers from being invoked for the + * event. FALSE to propagate the event further. */ g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT] = g_signal_new ("writable-change-event", G_TYPE_SETTINGS, @@ -684,17 +768,60 @@ g_settings_class_init (GSettingsClass *class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** + * GSettings:settings-schema: + * + * The #GSettingsSchema describing the types of keys for this + * #GSettings object. + * + * Ideally, this property would be called 'schema'. #GSettingsSchema + * has only existed since version 2.32, however, and before then the + * 'schema' property was used to refer to the ID of the schema rather + * than the schema itself. Take care. + */ + g_object_class_install_property (object_class, PROP_SCHEMA, + g_param_spec_boxed ("settings-schema", + P_("schema"), + P_("The GSettingsSchema for this settings object"), + G_TYPE_SETTINGS_SCHEMA, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** * GSettings:schema: * * The name of the schema that describes the types of keys * for this #GSettings object. + * + * The type of this property is *not* #GSettingsSchema. + * #GSettingsSchema has only existed since version 2.32 and + * unfortunately this name was used in previous versions to refer to + * the schema ID rather than the schema itself. Take care to use the + * 'settings-schema' property if you wish to pass in a + * #GSettingsSchema. + * + * Deprecated:2.32:Use the 'schema-id' property instead. In a future + * version, this property may instead refer to a #GSettingsSchema. */ - g_object_class_install_property (object_class, PROP_SCHEMA, + g_object_class_install_property (object_class, PROP_SCHEMA_ID, g_param_spec_string ("schema", P_("Schema name"), P_("The name of the schema for this settings object"), NULL, G_PARAM_CONSTRUCT_ONLY | + G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GSettings:schema-id: + * + * The name of the schema that describes the types of keys + * for this #GSettings object. + */ + g_object_class_install_property (object_class, PROP_SCHEMA_ID, + g_param_spec_string ("schema-id", + P_("Schema name"), + P_("The name of the schema for this settings object"), + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** @@ -742,35 +869,52 @@ g_settings_class_init (GSettingsClass *class) /* Construction (new, new_with_path, etc.) {{{1 */ /** * g_settings_new: - * @schema: the name of the schema - * @returns: a new #GSettings object + * @schema_id: the id of the schema * - * Creates a new #GSettings object with a given schema. + * Creates a new #GSettings object with the schema specified by + * @schema_id. * * Signals on the newly created #GSettings object will be dispatched * via the thread-default #GMainContext in effect at the time of the * call to g_settings_new(). The new #GSettings will hold a reference * on the context. See g_main_context_push_thread_default(). * + * Returns: a new #GSettings object + * * Since: 2.26 */ GSettings * -g_settings_new (const gchar *schema) +g_settings_new (const gchar *schema_id) { - g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (schema_id != NULL, NULL); return g_object_new (G_TYPE_SETTINGS, - "schema", schema, + "schema-id", schema_id, NULL); } +static gboolean +path_is_valid (const gchar *path) +{ + if (!path) + return FALSE; + + if (path[0] != '/') + return FALSE; + + if (!g_str_has_suffix (path, "/")) + return FALSE; + + return strstr (path, "//") == NULL; +} + /** * g_settings_new_with_path: - * @schema: the name of the schema + * @schema_id: the id of the schema * @path: the path to use - * @returns: a new #GSettings object * - * Creates a new #GSettings object with a given schema and path. + * Creates a new #GSettings object with the relocatable schema specified + * by @schema_id and a given path. * * You only need to do this if you want to directly create a settings * object with a schema that doesn't have a specified path of its own. @@ -779,28 +923,34 @@ g_settings_new (const gchar *schema) * It is a programmer error to call this function for a schema that * has an explicitly specified path. * + * It is a programmer error if @path is not a valid path. A valid path + * begins and ends with '/' and does not contain two consecutive '/' + * characters. + * + * Returns: a new #GSettings object + * * Since: 2.26 */ GSettings * -g_settings_new_with_path (const gchar *schema, +g_settings_new_with_path (const gchar *schema_id, const gchar *path) { - g_return_val_if_fail (schema != NULL, NULL); - g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (schema_id != NULL, NULL); + g_return_val_if_fail (path_is_valid (path), NULL); return g_object_new (G_TYPE_SETTINGS, - "schema", schema, + "schema-id", schema_id, "path", path, NULL); } /** * g_settings_new_with_backend: - * @schema: the name of the schema + * @schema_id: the id of the schema * @backend: the #GSettingsBackend to use - * @returns: a new #GSettings object * - * Creates a new #GSettings object with a given schema and backend. + * Creates a new #GSettings object with the schema specified by + * @schema_id and a given #GSettingsBackend. * * Creating a #GSettings object with a different backend allows accessing * settings from a database other than the usual one. For example, it may make @@ -808,279 +958,148 @@ g_settings_new_with_path (const gchar *schema, * the system to get a settings object that modifies the system default * settings instead of the settings for this user. * + * Returns: a new #GSettings object + * * Since: 2.26 */ GSettings * -g_settings_new_with_backend (const gchar *schema, +g_settings_new_with_backend (const gchar *schema_id, GSettingsBackend *backend) { - g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (schema_id != NULL, NULL); g_return_val_if_fail (G_IS_SETTINGS_BACKEND (backend), NULL); return g_object_new (G_TYPE_SETTINGS, - "schema", schema, + "schema-id", schema_id, "backend", backend, NULL); } /** * g_settings_new_with_backend_and_path: - * @schema: the name of the schema + * @schema_id: the id of the schema * @backend: the #GSettingsBackend to use * @path: the path to use - * @returns: a new #GSettings object * - * Creates a new #GSettings object with a given schema, backend and - * path. + * Creates a new #GSettings object with the schema specified by + * @schema_id and a given #GSettingsBackend and path. * * This is a mix of g_settings_new_with_backend() and * g_settings_new_with_path(). * + * Returns: a new #GSettings object + * * Since: 2.26 */ GSettings * -g_settings_new_with_backend_and_path (const gchar *schema, +g_settings_new_with_backend_and_path (const gchar *schema_id, GSettingsBackend *backend, const gchar *path) { - g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (schema_id != NULL, NULL); g_return_val_if_fail (G_IS_SETTINGS_BACKEND (backend), NULL); - g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (path_is_valid (path), NULL); return g_object_new (G_TYPE_SETTINGS, - "schema", schema, + "schema-id", schema_id, "backend", backend, "path", path, NULL); } -/* Internal read/write utilities, enum/flags conversion, validation {{{1 */ -typedef struct -{ - const gchar *schema_name; - const gchar *gettext_domain; - const gchar *key; - - guint is_flags : 1; - guint is_enum : 1; - - const guint32 *strinfo; - gsize strinfo_length; - - const gchar *unparsed; - gchar lc_char; - - const GVariantType *type; - GVariant *minimum, *maximum; - GVariant *default_value; -} GSettingsKeyInfo; - -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 -} - -static void -g_settings_get_key_info (GSettingsKeyInfo *info, - GSettings *settings, - const gchar *key) -{ - GVariantIter *iter; - GVariant *data; - guchar code; - - memset (info, 0, sizeof *info); - - iter = g_settings_schema_get_value (settings->priv->schema, key); - - info->gettext_domain = g_settings_schema_get_gettext_domain (settings->priv->schema); - info->schema_name = settings->priv->schema_name; - info->default_value = g_variant_iter_next_value (iter); - endian_fixup (&info->default_value); - info->type = g_variant_get_type (info->default_value); - info->key = g_intern_string (key); - - while (g_variant_iter_next (iter, "(y*)", &code, &data)) - { - switch (code) - { - case 'l': - /* translation requested */ - g_variant_get (data, "(y&s)", &info->lc_char, &info->unparsed); - break; - - case 'e': - /* enumerated types... */ - info->is_enum = TRUE; - goto choice; - - case 'f': - /* flags... */ - info->is_flags = TRUE; - goto choice; - - choice: case 'c': - /* ..., choices, aliases */ - info->strinfo = g_variant_get_fixed_array (data, - &info->strinfo_length, - sizeof (guint32)); - break; - - case 'r': - g_variant_get (data, "(**)", &info->minimum, &info->maximum); - endian_fixup (&info->minimum); - endian_fixup (&info->maximum); - break; - - default: - g_warning ("unknown schema extension '%c'", code); - break; - } - - g_variant_unref (data); - } - - g_variant_iter_free (iter); -} - -static void -g_settings_free_key_info (GSettingsKeyInfo *info) +/** + * g_settings_new_full: + * @schema: a #GSettingsSchema + * @backend: (allow-none): a #GSettingsBackend + * @path: (allow-none): the path to use + * + * Creates a new #GSettings object with a given schema, backend and + * path. + * + * It should be extremely rare that you ever want to use this function. + * It is made available for advanced use-cases (such as plugin systems + * that want to provide access to schemas loaded from custom locations, + * etc). + * + * At the most basic level, a #GSettings object is a pure composition of + * 4 things: a #GSettingsSchema, a #GSettingsBackend, a path within that + * backend, and a #GMainContext to which signals are dispatched. + * + * This constructor therefore gives you full control over constructing + * #GSettings instances. The first 4 parameters are given directly as + * @schema, @backend and @path, and the main context is taken from the + * thread-default (as per g_settings_new()). + * + * If @backend is %NULL then the default backend is used. + * + * If @path is %NULL then the path from the schema is used. It is an + * error f @path is %NULL and the schema has no path of its own or if + * @path is non-%NULL and not equal to the path that the schema does + * have. + * + * Returns: a new #GSettings object + * + * Since: 2.32 + */ +GSettings * +g_settings_new_full (GSettingsSchema *schema, + GSettingsBackend *backend, + const gchar *path) { - if (info->minimum) - g_variant_unref (info->minimum); - - if (info->maximum) - g_variant_unref (info->maximum); + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (backend == NULL || G_IS_SETTINGS_BACKEND (backend), NULL); + g_return_val_if_fail (path == NULL || path_is_valid (path), NULL); - g_variant_unref (info->default_value); + return g_object_new (G_TYPE_SETTINGS, + "settings-schema", schema, + "backend", backend, + "path", path, + NULL); } +/* Internal read/write utilities {{{1 */ static gboolean -g_settings_write_to_backend (GSettings *settings, - GSettingsKeyInfo *info, - GVariant *value) +g_settings_write_to_backend (GSettings *settings, + GSettingsSchemaKey *key, + GVariant *value) { gboolean success; gchar *path; - path = g_strconcat (settings->priv->path, info->key, NULL); + path = g_strconcat (settings->priv->path, key->name, NULL); success = g_settings_backend_write (settings->priv->backend, path, value, NULL); g_free (path); return success; } -static gboolean -g_settings_type_check (GSettingsKeyInfo *info, - GVariant *value) -{ - g_return_val_if_fail (value != NULL, FALSE); - - return g_variant_is_of_type (value, info->type); -} - -static gboolean -g_settings_key_info_range_check (GSettingsKeyInfo *info, - GVariant *value) -{ - if (info->minimum == NULL && info->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_key_info_range_check (info, child); - g_variant_unref (child); - } - - return ok; - } - - if (info->minimum) - { - return g_variant_compare (info->minimum, value) <= 0 && - g_variant_compare (value, info->maximum) <= 0; - } - - return strinfo_is_string_valid (info->strinfo, - info->strinfo_length, - g_variant_get_string (value, NULL)); -} - -static GVariant * -g_settings_range_fixup (GSettingsKeyInfo *info, - GVariant *value) -{ - const gchar *target; - - if (g_settings_key_info_range_check (info, value)) - return g_variant_ref (value); - - if (info->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_range_fixup (info, 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 (info->strinfo, info->strinfo_length, - g_variant_get_string (value, NULL)); - return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL; -} - static GVariant * -g_settings_read_from_backend (GSettings *settings, - GSettingsKeyInfo *info) +g_settings_read_from_backend (GSettings *settings, + GSettingsSchemaKey *key, + gboolean user_value_only, + gboolean default_value) { GVariant *value; GVariant *fixup; gchar *path; - path = g_strconcat (settings->priv->path, info->key, NULL); - value = g_settings_backend_read (settings->priv->backend, path, info->type, FALSE); + /* If we are not yet watching for changes, consider doing it now... */ + if (!settings->priv->is_subscribed && g_settings_has_signal_handlers (settings, key->name)) + { + g_settings_backend_subscribe (settings->priv->backend, settings->priv->path); + settings->priv->is_subscribed = TRUE; + } + + path = g_strconcat (settings->priv->path, key->name, NULL); + if (user_value_only) + value = g_settings_backend_read_user_value (settings->priv->backend, path, key->type); + else + value = g_settings_backend_read (settings->priv->backend, path, key->type, default_value); g_free (path); if (value != NULL) { - fixup = g_settings_range_fixup (info, value); + fixup = g_settings_schema_key_range_fixup (key, value); g_variant_unref (value); } else @@ -1089,178 +1108,141 @@ g_settings_read_from_backend (GSettings *settings, return fixup; } -static GVariant * -g_settings_get_translated_default (GSettingsKeyInfo *info) +/* Public Get/Set API {{{1 (get, get_value, set, set_value, get_mapped) */ +/** + * g_settings_get_value: + * @settings: a #GSettings object + * @key: the key to get the value for + * + * Gets the value that is stored in @settings for @key. + * + * It is a programmer error to give a @key that isn't contained in the + * schema for @settings. + * + * Returns: a new #GVariant + * + * Since: 2.26 + */ +GVariant * +g_settings_get_value (GSettings *settings, + const gchar *key) { - const gchar *translated; - GError *error = NULL; + GSettingsSchemaKey skey; GVariant *value; - if (info->lc_char == '\0') - /* translation not requested for this key */ - return NULL; - - if (info->lc_char == 't') - translated = g_dcgettext (info->gettext_domain, info->unparsed, LC_TIME); - else - translated = g_dgettext (info->gettext_domain, info->unparsed); + g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); + g_return_val_if_fail (key != NULL, NULL); - if (translated == info->unparsed) - /* the default value was not translated */ - return NULL; + g_settings_schema_key_init (&skey, settings->priv->schema, key); + value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE); - /* try to parse the translation of the unparsed default */ - value = g_variant_parse (info->type, translated, NULL, NULL, &error); + if (value == NULL) + value = g_settings_schema_key_get_translated_default (&skey); if (value == NULL) - { - g_warning ("Failed to parse translated string `%s' for " - "key `%s' in schema `%s': %s", info->unparsed, info->key, - info->schema_name, error->message); - g_warning ("Using untranslated default instead."); - g_error_free (error); - } + value = g_variant_ref (skey.default_value); - else if (!g_settings_key_info_range_check (info, value)) - { - g_warning ("Translated default `%s' for key `%s' in schema `%s' " - "is outside of valid range", info->unparsed, info->key, - info->schema_name); - g_variant_unref (value); - value = NULL; - } + g_settings_schema_key_clear (&skey); return value; } -static gint -g_settings_to_enum (GSettingsKeyInfo *info, - GVariant *value) -{ - gboolean it_worked; - guint result; - - it_worked = strinfo_enum_from_string (info->strinfo, info->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; -} - -static GVariant * -g_settings_from_enum (GSettingsKeyInfo *info, - gint value) -{ - const gchar *string; - - string = strinfo_string_from_enum (info->strinfo, - info->strinfo_length, - value); - - if (string == NULL) - return NULL; - - return g_variant_new_string (string); -} - -static guint -g_settings_to_flags (GSettingsKeyInfo *info, - 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 (info->strinfo, - info->strinfo_length, - flag, &flag_value); - /* as in g_settings_to_enum() */ - g_assert (it_worked); - - result |= flag_value; - } - - return result; -} - -static GVariant * -g_settings_from_flags (GSettingsKeyInfo *info, - guint value) +/** + * g_settings_get_user_value: + * @settings: a #GSettings object + * @key: the key to get the user value for + * + * Checks the "user value" of a key, if there is one. + * + * The user value of a key is the last value that was set by the user. + * + * After calling g_settings_reset() this function should always return + * %NULL (assuming something is not wrong with the system + * configuration). + * + * It is possible that g_settings_get_value() will return a different + * value than this function. This can happen in the case that the user + * set a value for a key that was subsequently locked down by the system + * administrator -- this function will return the user's old value. + * + * This function may be useful for adding a "reset" option to a UI or + * for providing indication that a particular value has been changed. + * + * It is a programmer error to give a @key that isn't contained in the + * schema for @settings. + * + * Returns: (allow-none) (transfer full): the user's value, if set + * + * Since: 2.40 + **/ +GVariant * +g_settings_get_user_value (GSettings *settings, + const gchar *key) { - 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; + GSettingsSchemaKey skey; + GVariant *value; - string = strinfo_string_from_enum (info->strinfo, - info->strinfo_length, - 1u << i); + g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); + g_return_val_if_fail (key != NULL, NULL); - if (string == NULL) - { - g_variant_builder_clear (&builder); - return NULL; - } + g_settings_schema_key_init (&skey, settings->priv->schema, key); + value = g_settings_read_from_backend (settings, &skey, TRUE, FALSE); + g_settings_schema_key_clear (&skey); - g_variant_builder_add (&builder, "s", string); - } - - return g_variant_builder_end (&builder); + return value; } -/* Public Get/Set API {{{1 (get, get_value, set, set_value, get_mapped) */ /** - * g_settings_get_value: + * g_settings_get_default_value: * @settings: a #GSettings object - * @key: the key to get the value for - * @returns: a new #GVariant + * @key: the key to get the default value for * - * Gets the value that is stored in @settings for @key. + * Gets the "default value" of a key. + * + * This is the value that would be read if g_settings_reset() were to be + * called on the key. + * + * Note that this may be a different value than returned by + * g_settings_schema_key_get_default_value() if the system administrator + * has provided a default value. + * + * Comparing the return values of g_settings_get_default_value() and + * g_settings_get_value() is not sufficient for determining if a value + * has been set because the user may have explicitly set the value to + * something that happens to be equal to the default. The difference + * here is that if the default changes in the future, the user's key + * will still be set. + * + * This function may be useful for adding an indication to a UI of what + * the default value was before the user set it. * * It is a programmer error to give a @key that isn't contained in the * schema for @settings. * - * Since: 2.26 - */ + * Returns: (allow-none) (transfer full): the default value + * + * Since: 2.40 + **/ GVariant * -g_settings_get_value (GSettings *settings, - const gchar *key) +g_settings_get_default_value (GSettings *settings, + const gchar *key) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *value; g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); g_return_val_if_fail (key != NULL, NULL); - g_settings_get_key_info (&info, settings, key); - value = g_settings_read_from_backend (settings, &info); + g_settings_schema_key_init (&skey, settings->priv->schema, key); + value = g_settings_read_from_backend (settings, &skey, FALSE, TRUE); if (value == NULL) - value = g_settings_get_translated_default (&info); + value = g_settings_schema_key_get_translated_default (&skey); if (value == NULL) - value = g_variant_ref (info.default_value); + value = g_variant_ref (skey.default_value); - g_settings_free_key_info (&info); + g_settings_schema_key_clear (&skey); return value; } @@ -1269,7 +1251,6 @@ g_settings_get_value (GSettings *settings, * g_settings_get_enum: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: the enum value * * Gets the value that is stored in @settings for @key and converts it * to the enum value that it represents. @@ -1284,39 +1265,41 @@ g_settings_get_value (GSettings *settings, * value for the enumerated type then this function will return the * default value. * + * Returns: the enum value + * * Since: 2.26 **/ gint g_settings_get_enum (GSettings *settings, const gchar *key) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *value; gint result; g_return_val_if_fail (G_IS_SETTINGS (settings), -1); g_return_val_if_fail (key != NULL, -1); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if (!info.is_enum) + if (!skey.is_enum) { - g_critical ("g_settings_get_enum() called on key `%s' which is not " - "associated with an enumerated type", info.key); - g_settings_free_key_info (&info); + g_critical ("g_settings_get_enum() called on key '%s' which is not " + "associated with an enumerated type", skey.name); + g_settings_schema_key_clear (&skey); return -1; } - value = g_settings_read_from_backend (settings, &info); + value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE); if (value == NULL) - value = g_settings_get_translated_default (&info); + value = g_settings_schema_key_get_translated_default (&skey); if (value == NULL) - value = g_variant_ref (info.default_value); + value = g_variant_ref (skey.default_value); - result = g_settings_to_enum (&info, value); - g_settings_free_key_info (&info); + result = g_settings_schema_key_to_enum (&skey, value); + g_settings_schema_key_clear (&skey); g_variant_unref (value); return result; @@ -1327,7 +1310,6 @@ g_settings_get_enum (GSettings *settings, * @settings: a #GSettings object * @key: a key, within @settings * @value: an enumerated value - * @returns: %TRUE, if the set succeeds * * Looks up the enumerated type nick for @value and writes it to @key, * within @settings. @@ -1339,39 +1321,41 @@ g_settings_get_enum (GSettings *settings, * After performing the write, accessing @key directly with * g_settings_get_string() will return the 'nick' associated with * @value. + * + * Returns: %TRUE, if the set succeeds **/ gboolean g_settings_set_enum (GSettings *settings, const gchar *key, gint value) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *variant; gboolean success; g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE); g_return_val_if_fail (key != NULL, FALSE); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if (!info.is_enum) + if (!skey.is_enum) { - g_critical ("g_settings_set_enum() called on key `%s' which is not " - "associated with an enumerated type", info.key); + g_critical ("g_settings_set_enum() called on key '%s' which is not " + "associated with an enumerated type", skey.name); return FALSE; } - if (!(variant = g_settings_from_enum (&info, value))) + if (!(variant = g_settings_schema_key_from_enum (&skey, value))) { - g_critical ("g_settings_set_enum(): invalid enum value %d for key `%s' " - "in schema `%s'. Doing nothing.", value, info.key, - info.schema_name); - g_settings_free_key_info (&info); + g_critical ("g_settings_set_enum(): invalid enum value %d for key '%s' " + "in schema '%s'. Doing nothing.", value, skey.name, + g_settings_schema_get_id (skey.schema)); + g_settings_schema_key_clear (&skey); return FALSE; } - success = g_settings_write_to_backend (settings, &info, variant); - g_settings_free_key_info (&info); + success = g_settings_write_to_backend (settings, &skey, variant); + g_settings_schema_key_clear (&skey); return success; } @@ -1380,7 +1364,6 @@ g_settings_set_enum (GSettings *settings, * g_settings_get_flags: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: the flags value * * Gets the value that is stored in @settings for @key and converts it * to the flags value that it represents. @@ -1395,39 +1378,41 @@ g_settings_set_enum (GSettings *settings, * value for the flags type then this function will return the default * value. * + * Returns: the flags value + * * Since: 2.26 **/ guint g_settings_get_flags (GSettings *settings, const gchar *key) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *value; guint result; g_return_val_if_fail (G_IS_SETTINGS (settings), -1); g_return_val_if_fail (key != NULL, -1); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if (!info.is_flags) + if (!skey.is_flags) { - g_critical ("g_settings_get_flags() called on key `%s' which is not " - "associated with a flags type", info.key); - g_settings_free_key_info (&info); + g_critical ("g_settings_get_flags() called on key '%s' which is not " + "associated with a flags type", skey.name); + g_settings_schema_key_clear (&skey); return -1; } - value = g_settings_read_from_backend (settings, &info); + value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE); if (value == NULL) - value = g_settings_get_translated_default (&info); + value = g_settings_schema_key_get_translated_default (&skey); if (value == NULL) - value = g_variant_ref (info.default_value); + value = g_variant_ref (skey.default_value); - result = g_settings_to_flags (&info, value); - g_settings_free_key_info (&info); + result = g_settings_schema_key_to_flags (&skey, value); + g_settings_schema_key_clear (&skey); g_variant_unref (value); return result; @@ -1438,7 +1423,6 @@ g_settings_get_flags (GSettings *settings, * @settings: a #GSettings object * @key: a key, within @settings * @value: a flags value - * @returns: %TRUE, if the set succeeds * * Looks up the flags type nicks for the bits specified by @value, puts * them in an array of strings and writes the array to @key, within @@ -1451,39 +1435,41 @@ g_settings_get_flags (GSettings *settings, * After performing the write, accessing @key directly with * g_settings_get_strv() will return an array of 'nicks'; one for each * bit in @value. + * + * Returns: %TRUE, if the set succeeds **/ gboolean g_settings_set_flags (GSettings *settings, const gchar *key, guint value) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *variant; gboolean success; g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE); g_return_val_if_fail (key != NULL, FALSE); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if (!info.is_flags) + if (!skey.is_flags) { - g_critical ("g_settings_set_flags() called on key `%s' which is not " - "associated with a flags type", info.key); + g_critical ("g_settings_set_flags() called on key '%s' which is not " + "associated with a flags type", skey.name); return FALSE; } - if (!(variant = g_settings_from_flags (&info, value))) + if (!(variant = g_settings_schema_key_from_flags (&skey, value))) { g_critical ("g_settings_set_flags(): invalid flags value 0x%08x " - "for key `%s' in schema `%s'. Doing nothing.", - value, info.key, info.schema_name); - g_settings_free_key_info (&info); + "for key '%s' in schema '%s'. Doing nothing.", + value, skey.name, g_settings_schema_get_id (skey.schema)); + g_settings_schema_key_clear (&skey); return FALSE; } - success = g_settings_write_to_backend (settings, &info, variant); - g_settings_free_key_info (&info); + success = g_settings_write_to_backend (settings, &skey, variant); + g_settings_schema_key_clear (&skey); return success; } @@ -1493,8 +1479,6 @@ g_settings_set_flags (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: a #GVariant of the correct type - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1504,6 +1488,9 @@ g_settings_set_flags (GSettings *settings, * * If @value is floating then this function consumes the reference. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 **/ gboolean @@ -1511,37 +1498,39 @@ g_settings_set_value (GSettings *settings, const gchar *key, GVariant *value) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; + gboolean success; g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE); g_return_val_if_fail (key != NULL, FALSE); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if (!g_settings_type_check (&info, value)) + if (!g_settings_schema_key_type_check (&skey, value)) { g_critical ("g_settings_set_value: key '%s' in '%s' expects type '%s', but a GVariant of type '%s' was given", key, - settings->priv->schema_name, - g_variant_type_peek_string (info.type), + g_settings_schema_get_id (settings->priv->schema), + g_variant_type_peek_string (skey.type), g_variant_get_type_string (value)); return FALSE; } - if (!g_settings_key_info_range_check (&info, value)) + if (!g_settings_schema_key_range_check (&skey, value)) { g_warning ("g_settings_set_value: value for key '%s' in schema '%s' " "is outside of valid range", key, - settings->priv->schema_name); + g_settings_schema_get_id (settings->priv->schema)); return FALSE; } - g_settings_free_key_info (&info); + success = g_settings_write_to_backend (settings, &skey, value); + g_settings_schema_key_clear (&skey); - return g_settings_write_to_backend (settings, &info, value); + return success; } /** @@ -1573,6 +1562,13 @@ g_settings_get (GSettings *settings, value = g_settings_get_value (settings, key); + if (strchr (format, '&')) + { + g_critical ("%s: the format string may not contain '&' (key '%s' from schema '%s'). " + "This call will probably stop working with a future version of glib.", + G_STRFUNC, key, g_settings_schema_get_id (settings->priv->schema)); + } + va_start (ap, format); g_variant_get_va (value, format, NULL, &ap); va_end (ap); @@ -1586,8 +1582,6 @@ g_settings_get (GSettings *settings, * @key: the name of the key to set * @format: a #GVariant format string * @...: arguments as per @format - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1598,6 +1592,9 @@ g_settings_get (GSettings *settings, * schema for @settings or for the #GVariantType of @format to mismatch * the type given in the schema. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -1623,7 +1620,6 @@ g_settings_set (GSettings *settings, * @mapping: (scope call): the function to map the value in the * settings database to the value used by the application * @user_data: user data for @mapping - * @returns: (transfer full): the result, which may be %NULL * * Gets the value that is stored at @key in @settings, subject to * application-level validation/mapping. @@ -1633,7 +1629,7 @@ g_settings_set (GSettings *settings, * @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. * @@ -1652,6 +1648,8 @@ g_settings_set (GSettings *settings, * 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. + * + * Returns: (transfer full): the result, which may be %NULL **/ gpointer g_settings_get_mapped (GSettings *settings, @@ -1660,7 +1658,7 @@ g_settings_get_mapped (GSettings *settings, gpointer user_data) { gpointer result = NULL; - GSettingsKeyInfo info; + GSettingsSchemaKey skey; GVariant *value; gboolean okay; @@ -1668,32 +1666,32 @@ g_settings_get_mapped (GSettings *settings, g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (mapping != NULL, NULL); - g_settings_get_key_info (&info, settings, key); + g_settings_schema_key_init (&skey, settings->priv->schema, key); - if ((value = g_settings_read_from_backend (settings, &info))) + if ((value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE))) { okay = mapping (value, &result, user_data); g_variant_unref (value); if (okay) goto okay; } - if ((value = g_settings_get_translated_default (&info))) + if ((value = g_settings_schema_key_get_translated_default (&skey))) { okay = mapping (value, &result, user_data); g_variant_unref (value); if (okay) goto okay; } - if (mapping (info.default_value, &result, user_data)) + if (mapping (skey.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); + "'%s' in schema '%s' returned FALSE when given a NULL value.", + key, g_settings_schema_get_id (settings->priv->schema)); okay: - g_settings_free_key_info (&info); + g_settings_schema_key_clear (&skey); return result; } @@ -1703,7 +1701,6 @@ g_settings_get_mapped (GSettings *settings, * g_settings_get_string: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: a newly-allocated string * * Gets the value that is stored at @key in @settings. * @@ -1712,6 +1709,8 @@ g_settings_get_mapped (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a string type in the schema for @settings. * + * Returns: a newly-allocated string + * * Since: 2.26 */ gchar * @@ -1733,8 +1732,6 @@ g_settings_get_string (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: the value to set it to - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1743,6 +1740,9 @@ g_settings_get_string (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a string type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -1757,7 +1757,6 @@ g_settings_set_string (GSettings *settings, * g_settings_get_int: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: an integer * * Gets the value that is stored at @key in @settings. * @@ -1766,6 +1765,8 @@ g_settings_set_string (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a int32 type in the schema for @settings. * + * Returns: an integer + * * Since: 2.26 */ gint @@ -1787,8 +1788,6 @@ g_settings_get_int (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: the value to set it to - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1797,6 +1796,9 @@ g_settings_get_int (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a int32 type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -1811,7 +1813,6 @@ g_settings_set_int (GSettings *settings, * g_settings_get_uint: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: an unsigned integer * * Gets the value that is stored at @key in @settings. * @@ -1821,6 +1822,8 @@ g_settings_set_int (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a uint32 type in the schema for @settings. * + * Returns: an unsigned integer + * * Since: 2.30 */ guint @@ -1842,8 +1845,6 @@ g_settings_get_uint (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: the value to set it to - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1853,6 +1854,9 @@ g_settings_get_uint (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a uint32 type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.30 */ gboolean @@ -1867,7 +1871,6 @@ g_settings_set_uint (GSettings *settings, * g_settings_get_double: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: a double * * Gets the value that is stored at @key in @settings. * @@ -1876,6 +1879,8 @@ g_settings_set_uint (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a 'double' type in the schema for @settings. * + * Returns: a double + * * Since: 2.26 */ gdouble @@ -1897,8 +1902,6 @@ g_settings_get_double (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: the value to set it to - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1907,6 +1910,9 @@ g_settings_get_double (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a 'double' type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -1921,7 +1927,6 @@ g_settings_set_double (GSettings *settings, * g_settings_get_boolean: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: a boolean * * Gets the value that is stored at @key in @settings. * @@ -1930,6 +1935,8 @@ g_settings_set_double (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a boolean type in the schema for @settings. * + * Returns: a boolean + * * Since: 2.26 */ gboolean @@ -1951,8 +1958,6 @@ g_settings_get_boolean (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: the value to set it to - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -1961,6 +1966,9 @@ g_settings_get_boolean (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having a boolean type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -1975,15 +1983,16 @@ g_settings_set_boolean (GSettings *settings, * g_settings_get_strv: * @settings: a #GSettings object * @key: the key to get the value for - * @returns: (array zero-terminated=1) (transfer full): a - * newly-allocated, %NULL-terminated array of strings, the value that - * is stored at @key in @settings. * * A convenience variant of g_settings_get() for string arrays. * * It is a programmer error to give a @key that isn't specified as * having an array of strings type in the schema for @settings. * + * Returns: (array zero-terminated=1) (transfer full): a + * newly-allocated, %NULL-terminated array of strings, the value that + * is stored at @key in @settings. + * * Since: 2.26 */ gchar ** @@ -2005,8 +2014,6 @@ g_settings_get_strv (GSettings *settings, * @settings: a #GSettings object * @key: the name of the key to set * @value: (allow-none) (array zero-terminated=1): the value to set it to, or %NULL - * @returns: %TRUE if setting the key succeeded, - * %FALSE if the key was not writable * * Sets @key in @settings to @value. * @@ -2016,6 +2023,9 @@ g_settings_get_strv (GSettings *settings, * It is a programmer error to give a @key that isn't specified as * having an array of strings type in the schema for @settings. * + * Returns: %TRUE if setting the key succeeded, + * %FALSE if the key was not writable + * * Since: 2.26 */ gboolean @@ -2114,11 +2124,12 @@ g_settings_revert (GSettings *settings) /** * g_settings_get_has_unapplied: * @settings: a #GSettings object - * @returns: %TRUE if @settings has unapplied changes * * Returns whether the #GSettings object has any unapplied * changes. This can only be the case if it is in 'delayed-apply' mode. * + * Returns: %TRUE if @settings has unapplied changes + * * Since: 2.26 */ gboolean @@ -2179,10 +2190,11 @@ g_settings_sync (void) * g_settings_is_writable: * @settings: a #GSettings object * @name: the name of a key - * @returns: %TRUE if the key @name is writable * * Finds out if a key can be written or not * + * Returns: %TRUE if the key @name is writable + * * Since: 2.26 */ gboolean @@ -2204,15 +2216,16 @@ g_settings_is_writable (GSettings *settings, /** * g_settings_get_child: * @settings: a #GSettings object - * @name: the name of the 'child' schema - * @returns: (transfer full): a 'child' settings object + * @name: the name of the child schema * - * Creates a 'child' settings object which has a base path of - * base-path/@name, where - * base-path is the base path of @settings. + * Creates a child settings object which has a base path of + * `base-path/@name`, where `base-path` is the base path of + * @settings. * * The schema for the child settings object must have been declared - * in the schema of @settings using a child element. + * in the schema of @settings using a element. + * + * Returns: (transfer full): a 'child' settings object * * Since: 2.26 */ @@ -2232,11 +2245,12 @@ g_settings_get_child (GSettings *settings, child_name); if (child_schema == NULL) g_error ("Schema '%s' has no child '%s'", - settings->priv->schema_name, name); + g_settings_schema_get_id (settings->priv->schema), name); child_path = g_strconcat (settings->priv->path, child_name, NULL); child = g_object_new (G_TYPE_SETTINGS, - "schema", child_schema, + "backend", settings->priv->backend, + "schema-id", child_schema, "path", child_path, NULL); g_free (child_path); @@ -2248,7 +2262,6 @@ g_settings_get_child (GSettings *settings, /** * g_settings_list_keys: * @settings: a #GSettings object - * @returns: (transfer full) (element-type utf8): a list of the keys on @settings * * Introspects the list of keys on @settings. * @@ -2258,6 +2271,8 @@ g_settings_get_child (GSettings *settings, * * You should free the return value with g_strfreev() when you are done * with it. + * + * Returns: (transfer full) (element-type utf8): a list of the keys on @settings */ gchar ** g_settings_list_keys (GSettings *settings) @@ -2284,7 +2299,6 @@ g_settings_list_keys (GSettings *settings) /** * g_settings_list_children: * @settings: a #GSettings object - * @returns: (transfer full) (element-type utf8): a list of the children on @settings * * Gets the list of children on @settings. * @@ -2305,6 +2319,8 @@ g_settings_list_keys (GSettings *settings) * * You should free the return value with g_strfreev() when you are done * with it. + * + * Returns: (transfer full) (element-type utf8): a list of the children on @settings */ gchar ** g_settings_list_children (GSettings *settings) @@ -2338,82 +2354,25 @@ g_settings_list_children (GSettings *settings) * 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 + * + * Deprecated:2.40:Use g_settings_schema_key_get_range() instead. **/ GVariant * g_settings_get_range (GSettings *settings, const gchar *key) { - GSettingsKeyInfo info; - const gchar *type; + GSettingsSchemaKey skey; 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); + g_settings_schema_key_init (&skey, settings->priv->schema, key); + range = g_settings_schema_key_get_range (&skey); + g_settings_schema_key_clear (&skey); - return g_variant_ref_sink (g_variant_new ("(sv)", type, range)); + return range; } /** @@ -2421,32 +2380,27 @@ g_settings_get_range (GSettings *settings, * @settings: a #GSettings * @key: the key to check * @value: the value to check - * @returns: %TRUE if @value is valid for @key * * Checks if the given @value is of the correct type and within the * permitted range for @key. * - * This API is not intended to be used by normal programs -- they should - * already know what is permitted by their own schemas. This API is - * meant to be used by programs such as editors or commandline tools. - * - * It is a programmer error to give a @key that isn't contained in the - * schema for @settings. + * Returns: %TRUE if @value is valid for @key * * Since: 2.28 + * + * Deprecated:2.40:Use g_settings_schema_key_range_check() instead. **/ gboolean g_settings_range_check (GSettings *settings, const gchar *key, GVariant *value) { - GSettingsKeyInfo info; + GSettingsSchemaKey skey; gboolean good; - g_settings_get_key_info (&info, settings, key); - good = g_settings_type_check (&info, value) && - g_settings_key_info_range_check (&info, value); - g_settings_free_key_info (&info); + g_settings_schema_key_init (&skey, settings->priv->schema, key); + good = g_settings_schema_key_range_check (&skey, value); + g_settings_schema_key_clear (&skey); return good; } @@ -2454,7 +2408,7 @@ g_settings_range_check (GSettings *settings, /* Binding {{{1 */ typedef struct { - GSettingsKeyInfo info; + GSettingsSchemaKey key; GSettings *settings; GObject *object; @@ -2492,7 +2446,7 @@ g_settings_binding_free (gpointer data) g_signal_handler_disconnect (binding->object, binding->property_handler_id); - g_settings_free_key_info (&binding->info); + g_settings_schema_key_clear (&binding->key); if (binding->destroy) binding->destroy (binding->user_data); @@ -2525,7 +2479,7 @@ g_settings_binding_key_changed (GSettings *settings, GVariant *variant; g_assert (settings == binding->settings); - g_assert (key == binding->info.key); + g_assert (key == binding->key.name); if (binding->running) return; @@ -2534,7 +2488,7 @@ g_settings_binding_key_changed (GSettings *settings, g_value_init (&value, binding->property->value_type); - variant = g_settings_read_from_backend (binding->settings, &binding->info); + variant = g_settings_read_from_backend (binding->settings, &binding->key, FALSE, FALSE); if (variant && !binding->get_mapping (&value, variant, binding->user_data)) { /* silently ignore errors in the user's config database */ @@ -2544,15 +2498,15 @@ g_settings_binding_key_changed (GSettings *settings, if (variant == NULL) { - variant = g_settings_get_translated_default (&binding->info); + variant = g_settings_schema_key_get_translated_default (&binding->key); if (variant && !binding->get_mapping (&value, variant, binding->user_data)) { /* flag translation errors with a warning */ - g_warning ("Translated default `%s' for key `%s' in schema `%s' " + g_warning ("Translated default '%s' for key '%s' in schema '%s' " "was rejected by the binding mapping function", - binding->info.unparsed, binding->info.key, - binding->info.schema_name); + binding->key.unparsed, binding->key.name, + g_settings_schema_get_id (binding->key.schema)); g_variant_unref (variant); variant = NULL; } @@ -2560,12 +2514,11 @@ g_settings_binding_key_changed (GSettings *settings, if (variant == NULL) { - variant = g_variant_ref (binding->info.default_value); + variant = g_variant_ref (binding->key.default_value); if (!binding->get_mapping (&value, variant, binding->user_data)) - g_error ("The schema default value for key `%s' in schema `%s' " + g_error ("The schema default value for key '%s' in schema '%s' " "was rejected by the binding mapping function.", - binding->info.key, - binding->info.schema_name); + binding->key.name, g_settings_schema_get_id (binding->key.schema)); } g_object_set_property (binding->object, binding->property->name, &value); @@ -2594,32 +2547,31 @@ g_settings_binding_property_changed (GObject *object, g_value_init (&value, pspec->value_type); g_object_get_property (object, pspec->name, &value); - if ((variant = binding->set_mapping (&value, binding->info.type, + if ((variant = binding->set_mapping (&value, binding->key.type, binding->user_data))) { g_variant_take_ref (variant); - if (!g_settings_type_check (&binding->info, variant)) + if (!g_settings_schema_key_type_check (&binding->key, variant)) { - g_critical ("binding mapping function for key `%s' returned " - "GVariant of type `%s' when type `%s' was requested", - binding->info.key, g_variant_get_type_string (variant), - g_variant_type_dup_string (binding->info.type)); + g_critical ("binding mapping function for key '%s' returned " + "GVariant of type '%s' when type '%s' was requested", + binding->key.name, g_variant_get_type_string (variant), + g_variant_type_dup_string (binding->key.type)); return; } - if (!g_settings_key_info_range_check (&binding->info, variant)) + if (!g_settings_schema_key_range_check (&binding->key, variant)) { - g_critical ("GObject property `%s' on a `%s' object is out of " - "schema-specified range for key `%s' of `%s': %s", - binding->property->name, - g_type_name (binding->property->owner_type), - binding->info.key, binding->info.schema_name, + g_critical ("GObject property '%s' on a '%s' object is out of " + "schema-specified range for key '%s' of '%s': %s", + binding->property->name, g_type_name (binding->property->owner_type), + binding->key.name, g_settings_schema_get_id (binding->key.schema), g_variant_print (variant, TRUE)); return; } - g_settings_write_to_backend (binding->settings, &binding->info, variant); + g_settings_write_to_backend (binding->settings, &binding->key, variant); g_variant_unref (variant); } g_value_unset (&value); @@ -2750,7 +2702,7 @@ g_settings_bind_with_mapping (GSettings *settings, objectclass = G_OBJECT_GET_CLASS (object); binding = g_slice_new0 (GSettingsBinding); - g_settings_get_key_info (&binding->info, settings, key); + g_settings_schema_key_init (&binding->key, settings->priv->schema, key); binding->settings = g_object_ref (settings); binding->object = object; binding->property = g_object_class_find_property (objectclass, property); @@ -2773,14 +2725,14 @@ g_settings_bind_with_mapping (GSettings *settings, (binding->property->flags & G_PARAM_WRITABLE) == 0) { g_critical ("g_settings_bind: property '%s' on class '%s' is not " - "writable", property, G_OBJECT_TYPE_NAME (object)); + "writable", binding->property->name, G_OBJECT_TYPE_NAME (object)); return; } if ((flags & G_SETTINGS_BIND_SET) && (binding->property->flags & G_PARAM_READABLE) == 0) { g_critical ("g_settings_bind: property '%s' on class '%s' is not " - "readable", property, G_OBJECT_TYPE_NAME (object)); + "readable", binding->property->name, G_OBJECT_TYPE_NAME (object)); return; } @@ -2796,18 +2748,18 @@ g_settings_bind_with_mapping (GSettings *settings, if (binding->property->value_type != G_TYPE_BOOLEAN) { g_critical ("g_settings_bind: G_SETTINGS_BIND_INVERT_BOOLEAN " - "was specified, but property `%s' on type `%s' has " - "type `%s'", property, G_OBJECT_TYPE_NAME (object), + "was specified, but property '%s' on type '%s' has " + "type '%s'", binding->property->name, G_OBJECT_TYPE_NAME (object), g_type_name ((binding->property->value_type))); return; } - if (!g_variant_type_equal (binding->info.type, G_VARIANT_TYPE_BOOLEAN)) + if (!g_variant_type_equal (binding->key.type, G_VARIANT_TYPE_BOOLEAN)) { g_critical ("g_settings_bind: G_SETTINGS_BIND_INVERT_BOOLEAN " - "was specified, but key `%s' on schema `%s' has " - "type `%s'", key, settings->priv->schema_name, - g_variant_type_dup_string (binding->info.type)); + "was specified, but key '%s' on schema '%s' has " + "type '%s'", key, g_settings_schema_get_id (settings->priv->schema), + g_variant_type_dup_string (binding->key.type)); return; } @@ -2816,14 +2768,14 @@ g_settings_bind_with_mapping (GSettings *settings, else if (((get_mapping == NULL && (flags & G_SETTINGS_BIND_GET)) || (set_mapping == NULL && (flags & G_SETTINGS_BIND_SET))) && !g_settings_mapping_is_compatible (binding->property->value_type, - binding->info.type)) + binding->key.type)) { 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), + "on schema '%s'", binding->property->name, G_OBJECT_TYPE_NAME (object), g_type_name (binding->property->value_type), - g_variant_type_dup_string (binding->info.type), key, - settings->priv->schema_name); + g_variant_type_dup_string (binding->key.type), key, + g_settings_schema_get_id (settings->priv->schema)); return; } @@ -2836,13 +2788,12 @@ g_settings_bind_with_mapping (GSettings *settings, if (sensitive && sensitive->value_type == G_TYPE_BOOLEAN && (sensitive->flags & G_PARAM_WRITABLE)) - g_settings_bind_writable (settings, binding->info.key, - object, "sensitive", FALSE); + g_settings_bind_writable (settings, binding->key.name, object, "sensitive", FALSE); } if (flags & G_SETTINGS_BIND_SET) { - detailed_signal = g_strdup_printf ("notify::%s", property); + detailed_signal = g_strdup_printf ("notify::%s", binding->property->name); binding->property_handler_id = g_signal_connect (object, detailed_signal, G_CALLBACK (g_settings_binding_property_changed), @@ -2867,10 +2818,10 @@ g_settings_bind_with_mapping (GSettings *settings, g_free (detailed_signal); } - g_settings_binding_key_changed (settings, binding->info.key, binding); + g_settings_binding_key_changed (settings, binding->key.name, binding); } - binding_quark = g_settings_binding_quark (property); + binding_quark = g_settings_binding_quark (binding->property->name); g_object_set_qdata_full (object, binding_quark, binding, g_settings_binding_free); } @@ -2934,8 +2885,7 @@ g_settings_binding_writable_changed (GSettings *settings, * * When the @inverted argument is %TRUE, the binding inverts the * value as it passes from the setting to the object, i.e. @property - * will be set to %TRUE if the key is not - * writable. + * will be set to %TRUE if the key is not writable. * * Note that the lifecycle of the binding is tied to the object, * and that you can have only one binding per object property. @@ -3014,6 +2964,267 @@ g_settings_unbind (gpointer object, g_object_set_qdata (object, binding_quark, NULL); } +/* GAction {{{1 */ + +typedef struct +{ + GObject parent_instance; + + GSettingsSchemaKey key; + GSettings *settings; +} GSettingsAction; + +typedef GObjectClass GSettingsActionClass; + +static GType g_settings_action_get_type (void); +static void g_settings_action_iface_init (GActionInterface *iface); +G_DEFINE_TYPE_WITH_CODE (GSettingsAction, g_settings_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_settings_action_iface_init)) + +enum +{ + ACTION_PROP_0, + ACTION_PROP_NAME, + ACTION_PROP_PARAMETER_TYPE, + ACTION_PROP_ENABLED, + ACTION_PROP_STATE_TYPE, + ACTION_PROP_STATE +}; + +static const gchar * +g_settings_action_get_name (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return gsa->key.name; +} + +static const GVariantType * +g_settings_action_get_parameter_type (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + const GVariantType *type; + + type = g_variant_get_type (gsa->key.default_value); + if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) + type = NULL; + + return type; +} + +static gboolean +g_settings_action_get_enabled (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return g_settings_is_writable (gsa->settings, gsa->key.name); +} + +static const GVariantType * +g_settings_action_get_state_type (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return g_variant_get_type (gsa->key.default_value); +} + +static GVariant * +g_settings_action_get_state (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + GVariant *value; + + value = g_settings_read_from_backend (gsa->settings, &gsa->key, FALSE, FALSE); + + if (value == NULL) + value = g_settings_schema_key_get_translated_default (&gsa->key); + + if (value == NULL) + value = g_variant_ref (gsa->key.default_value); + + return value; +} + +static GVariant * +g_settings_action_get_state_hint (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + /* no point in reimplementing this... */ + return g_settings_schema_key_get_range (&gsa->key); +} + +static void +g_settings_action_change_state (GAction *action, + GVariant *value) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + if (g_settings_schema_key_type_check (&gsa->key, value) && g_settings_schema_key_range_check (&gsa->key, value)) + g_settings_write_to_backend (gsa->settings, &gsa->key, value); +} + +static void +g_settings_action_activate (GAction *action, + GVariant *parameter) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + if (g_variant_is_of_type (gsa->key.default_value, G_VARIANT_TYPE_BOOLEAN)) + { + GVariant *old; + + if (parameter != NULL) + return; + + old = g_settings_action_get_state (action); + parameter = g_variant_new_boolean (!g_variant_get_boolean (old)); + g_variant_unref (old); + } + + g_action_change_state (action, parameter); +} + +static void +g_settings_action_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GAction *action = G_ACTION (object); + + switch (prop_id) + { + case ACTION_PROP_NAME: + g_value_set_string (value, g_settings_action_get_name (action)); + break; + + case ACTION_PROP_PARAMETER_TYPE: + g_value_set_boxed (value, g_settings_action_get_parameter_type (action)); + break; + + case ACTION_PROP_ENABLED: + g_value_set_boolean (value, g_settings_action_get_enabled (action)); + break; + + case ACTION_PROP_STATE_TYPE: + g_value_set_boxed (value, g_settings_action_get_state_type (action)); + break; + + case ACTION_PROP_STATE: + g_value_set_variant (value, g_settings_action_get_state (action)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +g_settings_action_finalize (GObject *object) +{ + GSettingsAction *gsa = (GSettingsAction *) object; + + g_signal_handlers_disconnect_by_data (gsa->settings, gsa); + g_object_unref (gsa->settings); + + G_OBJECT_CLASS (g_settings_action_parent_class) + ->finalize (object); +} + +static void +g_settings_action_init (GSettingsAction *gsa) +{ +} + +static void +g_settings_action_iface_init (GActionInterface *iface) +{ + iface->get_name = g_settings_action_get_name; + iface->get_parameter_type = g_settings_action_get_parameter_type; + iface->get_enabled = g_settings_action_get_enabled; + iface->get_state_type = g_settings_action_get_state_type; + iface->get_state = g_settings_action_get_state; + iface->get_state_hint = g_settings_action_get_state_hint; + iface->change_state = g_settings_action_change_state; + iface->activate = g_settings_action_activate; +} + +static void +g_settings_action_class_init (GSettingsActionClass *class) +{ + class->get_property = g_settings_action_get_property; + class->finalize = g_settings_action_finalize; + + g_object_class_override_property (class, ACTION_PROP_NAME, "name"); + g_object_class_override_property (class, ACTION_PROP_PARAMETER_TYPE, "parameter-type"); + g_object_class_override_property (class, ACTION_PROP_ENABLED, "enabled"); + g_object_class_override_property (class, ACTION_PROP_STATE_TYPE, "state-type"); + g_object_class_override_property (class, ACTION_PROP_STATE, "state"); +} + +static void +g_settings_action_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + g_object_notify (user_data, "state"); +} + +static void +g_settings_action_enabled_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + g_object_notify (user_data, "enabled"); +} + +/** + * g_settings_create_action: + * @settings: a #GSettings + * @key: the name of a key in @settings + * + * Creates a #GAction corresponding to a given #GSettings key. + * + * The action has the same name as the key. + * + * The value of the key becomes the state of the action and the action + * is enabled when the key is writable. Changing the state of the + * action results in the key being written to. Changes to the value or + * writability of the key cause appropriate change notifications to be + * emitted for the action. + * + * For boolean-valued keys, action activations take no parameter and + * result in the toggling of the value. For all other types, + * activations take the new value for the key (which must have the + * correct type). + * + * Returns: (transfer full): a new #GAction + * + * Since: 2.32 + **/ +GAction * +g_settings_create_action (GSettings *settings, + const gchar *key) +{ + GSettingsAction *gsa; + gchar *detailed_signal; + + g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); + g_return_val_if_fail (key != NULL, NULL); + + gsa = g_object_new (g_settings_action_get_type (), NULL); + gsa->settings = g_object_ref (settings); + g_settings_schema_key_init (&gsa->key, settings->priv->schema, key); + + detailed_signal = g_strdup_printf ("changed::%s", key); + g_signal_connect (settings, detailed_signal, G_CALLBACK (g_settings_action_changed), gsa); + g_free (detailed_signal); + detailed_signal = g_strdup_printf ("writable-changed::%s", key); + g_signal_connect (settings, detailed_signal, G_CALLBACK (g_settings_action_enabled_changed), gsa); + g_free (detailed_signal); + + return G_ACTION (gsa); +} + /* Epilogue {{{1 */ /* vim:set foldmethod=marker: */