[glib/new-gsettings] GSettings seems to work now
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/new-gsettings] GSettings seems to work now
- Date: Tue, 13 Apr 2010 20:47:18 +0000 (UTC)
commit 14173184a7ced3d31f4a3bb3d11efb28baf67ce5
Author: Ryan Lortie <desrt desrt ca>
Date: Tue Apr 13 16:46:40 2010 -0400
GSettings seems to work now
gio/Makefile.am | 13 +-
gio/gio.h | 1 +
gio/gsettings.c | 848 ++++++++++++++++++++++++++++++++++++++++++++++++
gio/gsettings.h | 114 +++++++
gio/gsettingsbackend.c | 19 +-
gio/gsettingsschema.c | 33 ++-
gio/gsettingsschema.h | 6 +-
gio/gvdb/gvdb-reader.c | 14 +-
gio/tests/.gitignore | 3 +-
gio/tests/Makefile.am | 5 +-
gio/tests/gsettings.c | 25 ++
11 files changed, 1060 insertions(+), 21 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index b34d9d1..f736d87 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -83,8 +83,16 @@ settings_sources = \
gvdb/gvdb-format.h \
gvdb/gvdb-reader.h \
gvdb/gvdb-reader.c \
+ gdelayedsettingsbackend.h \
+ gdelayedsettingsbackend.c \
+ gmemorysettingsbackend.h \
+ gmemorysettingsbackend.c \
+ gsettingsbackend.h \
+ gsettingsbackend.c \
gsettingsschema.h \
- gsettingsschema.c
+ gsettingsschema.c \
+ gsettings.h \
+ gsettings.c
local_sources = \
glocaldirectorymonitor.c \
@@ -257,9 +265,6 @@ libgio_2_0_la_SOURCES = \
gpollfilemonitor.h \
gresolver.c \
gseekable.c \
- gdelayedsettingsbackend.c\
- gsettingsbackend.c \
- gmemorysettingsbackend.c\
gsimpleasyncresult.c \
gsocket.c \
gsocketaddress.c \
diff --git a/gio/gio.h b/gio/gio.h
index 861f172..e05a164 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -95,6 +95,7 @@
#include <gio/gvolumemonitor.h>
#include <gio/gzlibcompressor.h>
#include <gio/gzlibdecompressor.h>
+#include <gio/gsettings.h>
#undef __GIO_GIO_H_INSIDE__
diff --git a/gio/gsettings.c b/gio/gsettings.c
new file mode 100644
index 0000000..e63bf47
--- /dev/null
+++ b/gio/gsettings.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "gsettings.h"
+
+#include "gdelayedsettingsbackend.h"
+#include "gio-marshal.h"
+#include "gsettingsschema.h"
+
+#include <string.h>
+
+#include "gioalias.h"
+
+struct _GSettingsPrivate {
+ GSettingsBackend *backend;
+ gchar *base_path;
+
+ GSettingsSchema *schema;
+ gchar *schema_name;
+
+ guint handler_id;
+ guint unapplied_handler;
+ gboolean locked;
+ gboolean delayed;
+};
+
+enum
+{
+ PROP_0,
+ PROP_SCHEMA_NAME,
+ PROP_SCHEMA,
+ PROP_DELAY_APPLY,
+ PROP_STORAGE,
+ PROP_BASE_PATH,
+ PROP_HAS_UNAPPLIED,
+};
+
+enum
+{
+ SIGNAL_CHANGES,
+ SIGNAL_CHANGED,
+ SIGNAL_DESTROYED,
+ N_SIGNALS
+};
+
+static guint g_settings_signals[N_SIGNALS];
+
+G_DEFINE_TYPE (GSettings, g_settings, G_TYPE_OBJECT)
+
+static void
+g_settings_storage_changed (GSettingsBackend *backend,
+ const gchar *prefix,
+ gchar const * const *names,
+ gint n_names,
+ gpointer origin_tag,
+ gpointer user_data)
+{
+ GSettings *settings = G_SETTINGS (user_data);
+ gchar **changes;
+ GQuark *quarks;
+ gint i, c;
+
+ g_assert (settings->priv->backend == backend);
+
+ /* slow and stupid. */
+ changes = g_new (gchar *, n_names);
+ quarks = g_new (GQuark, n_names);
+ for (i = 0; i < n_names; i++)
+ changes[i] = g_strconcat (prefix, names[i], NULL);
+
+ /* check which are for us */
+ c = 0;
+ for (i = 0; i < n_names; i++)
+ if (g_str_has_prefix (changes[i], settings->priv->base_path))
+ {
+ const gchar *rel = changes[i] + strlen (settings->priv->base_path);
+
+ if (strchr (rel, '/') == NULL)
+ /* XXX also check schema to ensure it's really a key */
+ quarks[c++] = g_quark_from_string (rel);
+ }
+
+ g_settings_changes (settings, quarks, c);
+
+ for (i = 0; i < n_names; i++)
+ g_free (changes[i]);
+ g_free (changes);
+ g_free (quarks);
+}
+
+/**
+ * g_settings_changes:
+ * @settings: a #GSettings object
+ * @keys: an array of #GQuark key names
+ * @n_keys: the length of @keys
+ *
+ * Emits the "changes" signal on a #GSettings object.
+ *
+ * It is an error to call this function with a quark in @keys that is
+ * not a valid key for @settings (according to its schema).
+ **/
+void
+g_settings_changes (GSettings *settings,
+ const GQuark *keys,
+ gint n_keys)
+{
+ g_return_if_fail (settings != NULL);
+
+ if (n_keys == 0)
+ return;
+
+ g_return_if_fail (keys != NULL);
+ g_return_if_fail (n_keys > 0);
+
+ g_signal_emit (settings,
+ g_settings_signals[SIGNAL_CHANGES], 0,
+ keys, n_keys);
+}
+
+static void
+g_settings_real_changes (GSettings *settings,
+ const GQuark *keys,
+ gint n_keys)
+{
+ gint i;
+
+ for (i = 0; i < n_keys; i++)
+ g_signal_emit (settings,
+ g_settings_signals[SIGNAL_CHANGED],
+ keys[i], g_quark_to_string (keys[i]));
+}
+
+static void
+g_settings_init (GSettings *settings)
+{
+ settings->priv = G_TYPE_INSTANCE_GET_PRIVATE (settings,
+ G_TYPE_SETTINGS,
+ GSettingsPrivate);
+}
+
+static void
+g_settings_notify_unapplied (GSettings *settings)
+{
+ g_object_notify (G_OBJECT (settings), "has-unapplied");
+}
+
+void
+g_settings_set_delay_apply (GSettings *settings,
+ gboolean delayed)
+{
+ delayed = !!delayed;
+
+ if (delayed != settings->priv->delayed)
+ {
+ GSettingsBackend *backend;
+
+ if G_UNLIKELY (settings->priv->locked)
+ g_error ("Can only set delayed-apply attribute on "
+ "freshly-created GSettings instances");
+
+ g_assert (delayed);
+
+ backend = g_delayed_settings_backend_new (settings->priv->backend,
+ settings->priv->base_path);
+ g_settings_backend_subscribe (backend, "");
+ g_settings_backend_unsubscribe (settings->priv->backend,
+ settings->priv->base_path);
+ g_signal_handler_disconnect (settings->priv->backend,
+ settings->priv->handler_id);
+ g_object_unref (settings->priv->backend);
+
+ settings->priv->backend = backend;
+ settings->priv->unapplied_handler =
+ g_signal_connect_swapped (backend, "notify::has-unapplied",
+ G_CALLBACK (g_settings_notify_unapplied),
+ settings);
+ settings->priv->handler_id =
+ g_signal_connect (settings->priv->backend, "changed",
+ G_CALLBACK (g_settings_storage_changed),
+ settings);
+
+ g_free (settings->priv->base_path);
+ settings->priv->base_path = g_strdup ("");
+
+ settings->priv->delayed = TRUE;
+ settings->priv->locked = TRUE;
+ }
+}
+
+gboolean
+g_settings_get_delay_apply (GSettings *settings)
+{
+ return settings->priv->delayed;
+}
+
+/**
+ * g_settings_apply:
+ * @settings: a #GSettings instance
+ *
+ * Applies any changes that have been made to the settings. This
+ * function does nothing unless @settings is in 'delay-apply' mode;
+ * see g_settings_set_delay_apply(). In the normal case settings are
+ * always applied immediately.
+ **/
+void
+g_settings_apply (GSettings *settings)
+{
+ if (settings->priv->delayed)
+ {
+ GDelayedSettingsBackend *delayed;
+
+ delayed = G_DELAYED_SETTINGS_BACKEND (settings->priv->backend);
+ g_delayed_settings_backend_apply (delayed);
+ }
+}
+
+/**
+ * g_settings_revert:
+ * @settings: a #GSettings instance
+ *
+ * Reverts all non-applied changes to the settings. This function
+ * does nothing unless @settings is in 'delay-apply' mode; see
+ * g_settings_set_delay_apply(). In the normal case settings are
+ * always applied immediately.
+ *
+ * Change notifications will be emitted for affected keys.
+ **/
+void
+g_settings_revert (GSettings *settings)
+{
+ if (settings->priv->delayed)
+ {
+ GDelayedSettingsBackend *delayed;
+
+ delayed = G_DELAYED_SETTINGS_BACKEND (settings->priv->backend);
+ g_delayed_settings_backend_revert (delayed);
+ }
+}
+
+static void
+g_settings_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GSettings *settings = G_SETTINGS (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCHEMA_NAME:
+ g_assert (settings->priv->schema_name == NULL);
+ settings->priv->schema_name = g_value_dup_string (value);
+ break;
+
+ case PROP_SCHEMA:
+ g_assert (settings->priv->schema == NULL);
+ settings->priv->schema = g_value_dup_object (value);
+ break;
+
+ case PROP_DELAY_APPLY:
+ g_settings_set_delay_apply (settings, g_value_get_boolean (value));
+ break;
+
+ case PROP_BASE_PATH:
+ settings->priv->base_path = g_value_dup_string (value);
+ break;
+
+ case PROP_STORAGE:
+ settings->priv->backend = g_value_dup_object (value);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+gboolean
+g_settings_get_has_unapplied (GSettings *settings)
+{
+ return settings->priv->delayed &&
+ g_delayed_settings_backend_get_has_unapplied (
+ G_DELAYED_SETTINGS_BACKEND (settings->priv->backend));
+}
+
+static void
+g_settings_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GSettings *settings = G_SETTINGS (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCHEMA:
+ g_value_set_object (value, settings->priv->schema);
+ break;
+
+ case PROP_HAS_UNAPPLIED:
+ g_value_set_boolean (value, g_settings_get_has_unapplied (settings));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+g_settings_finalize (GObject *object)
+{
+ GSettings *settings = G_SETTINGS (object);
+
+ g_signal_handler_disconnect (settings->priv->backend, settings->priv->handler_id);
+ g_object_unref (settings->priv->backend);
+ g_object_unref (settings->priv->schema);
+ g_free (settings->priv->schema_name);
+ g_free (settings->priv->base_path);
+}
+
+static void
+g_settings_constructed (GObject *object)
+{
+ GSettings *settings = G_SETTINGS (object);
+
+ if (settings->priv->backend == NULL)
+ settings->priv->backend = g_settings_backend_get_with_context (NULL);
+
+ settings->priv->handler_id =
+ g_signal_connect (settings->priv->backend, "changed",
+ G_CALLBACK (g_settings_storage_changed),
+ settings);
+
+ if (settings->priv->schema != NULL && settings->priv->schema_name != NULL)
+ g_error ("Schema and schema name specified");
+
+ if (settings->priv->schema == NULL && settings->priv->schema_name != NULL)
+ settings->priv->schema = g_settings_schema_new (settings->priv->schema_name);
+
+ if (settings->priv->schema == NULL)
+ settings->priv->schema = g_settings_schema_new ("empty");
+
+ if (settings->priv->base_path == NULL && settings->priv->schema == NULL)
+ g_error ("Attempting to make settings with no schema or path");
+
+ if (settings->priv->base_path != NULL && settings->priv->schema != NULL)
+ {
+ const gchar *schema_path, *given_path;
+
+ schema_path = g_settings_schema_get_path (settings->priv->schema);
+ given_path = settings->priv->base_path;
+
+ if (schema_path && strcmp (schema_path, given_path) != 0)
+ g_error ("Specified path of '%s' but schema says '%s'",
+ given_path, schema_path);
+ }
+
+ if (settings->priv->base_path == NULL)
+ settings->priv->base_path = g_strdup (
+ g_settings_schema_get_path (settings->priv->schema));
+
+ if (settings->priv->base_path == NULL)
+ g_error ("No base path given and none from schema");
+
+ g_settings_backend_subscribe (settings->priv->backend,
+ settings->priv->base_path);
+}
+
+GSettings *
+g_settings_new (const gchar *schema)
+{
+ return g_object_new (G_TYPE_SETTINGS, "schema-name", schema, NULL);
+}
+
+GSettings *
+g_settings_new_from_path (const gchar *path)
+{
+ return g_object_new (G_TYPE_SETTINGS, "base-path", path, NULL);
+}
+
+#if 0
+static GType
+g_settings_get_gtype_for_schema (GSettingsSchema *schema)
+{
+ GVariantIter iter;
+ const gchar *item;
+ GVariant *list;
+
+ list = g_settings_schema_get_inheritance (schema);
+ g_variant_iter_init (&iter, list);
+ g_variant_unref (list);
+
+ while (g_variant_iter_next (&iter, "s", &item))
+ if (strcmp (item, "list") == 0)
+ return G_TYPE_SETTINGS_LIST;
+
+ return G_TYPE_SETTINGS;
+}
+
+GSettings *
+g_settings_get_settings (GSettings *settings,
+ const gchar *name)
+{
+ const gchar *schema_name;
+ GSettingsSchema *schema;
+ GSettings *child;
+ gchar *path;
+
+ schema_name = g_settings_schema_get_schema (settings->priv->schema, name);
+
+ if (schema_name == NULL)
+ {
+ schema_name = g_settings_schema_get_schema (settings->priv->schema,
+ "/default");
+
+ if G_UNLIKELY (schema_name == NULL)
+ g_error ("Schema has no child schema named '%s' and no "
+ "default child schema", name);
+ }
+
+ schema = g_settings_schema_new (schema_name);
+ path = g_strdup_printf ("%s%s/", settings->priv->base_path, name);
+
+ child = g_object_new (g_settings_get_gtype_for_schema (schema),
+ "schema", schema,
+ "backend", settings->priv->backend,
+ "base-path", path,
+ NULL);
+
+ g_free (path);
+
+ return child;
+}
+#endif
+
+static void
+g_settings_class_init (GSettingsClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ class->changes = g_settings_real_changes;
+
+ object_class->set_property = g_settings_set_property;
+ object_class->get_property = g_settings_get_property;
+ object_class->constructed = g_settings_constructed;
+ object_class->finalize = g_settings_finalize;
+
+ g_type_class_add_private (object_class, sizeof (GSettingsPrivate));
+
+ g_settings_signals[SIGNAL_CHANGES] =
+ g_signal_new ("changes", G_TYPE_SETTINGS,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GSettingsClass, changes),
+ NULL, NULL,
+ _gio_marshal_VOID__POINTER_INT,
+ G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_INT);
+
+ g_settings_signals[SIGNAL_CHANGED] =
+ g_signal_new ("changed", G_TYPE_SETTINGS,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (GSettingsClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ g_settings_signals[SIGNAL_DESTROYED] =
+ g_signal_new ("destroyed", G_TYPE_SETTINGS,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GSettingsClass, destroyed),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ g_object_class_install_property (object_class, PROP_STORAGE,
+ g_param_spec_object ("backend", "backend storage",
+ "The GSettingsBackend object for this GSettings",
+ G_TYPE_SETTINGS_BACKEND, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class, PROP_SCHEMA_NAME,
+ g_param_spec_string ("schema-name", "schema name",
+ "The name of the schema for this settings object",
+ NULL, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class, PROP_DELAY_APPLY,
+ g_param_spec_boolean ("delay-apply", "delayed apply",
+ "If TRUE, you must call apply() to write changes",
+ FALSE, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class, PROP_HAS_UNAPPLIED,
+ g_param_spec_boolean ("has-unapplied", "has unapplied changes",
+ "TRUE if there are outstanding changes to apply()",
+ FALSE, G_PARAM_READABLE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class, PROP_SCHEMA,
+ g_param_spec_object ("schema", "schema",
+ "The GSettingsSchema object for this GSettings",
+ G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (object_class, PROP_BASE_PATH,
+ g_param_spec_string ("base-path", "base path",
+ "the path within the backend where the settings are",
+ NULL, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
+}
+
+GVariant *
+g_settings_get_value (GSettings *settings,
+ const gchar *key)
+{
+ const GVariantType *type;
+ const gchar *format;
+ GVariant *value;
+ GVariant *sval;
+ gchar *path;
+
+ path = g_strconcat (settings->priv->base_path, key, NULL);
+ sval = g_settings_schema_get_value (settings->priv->schema, key, NULL);
+ type = g_variant_get_type (sval);
+ value = g_settings_backend_read (settings->priv->backend, path, type);
+ g_free (path);
+
+ if (value && !g_variant_is_of_type (value, type))
+ {
+ g_variant_unref (value);
+ value = NULL;
+ }
+
+ if (value == NULL)
+ value = g_variant_ref (sval);
+
+ g_variant_unref (sval);
+
+ return value;
+}
+
+/**
+ * g_settings_set_value:
+ * @settings: a #GSettings object
+ * @key: the name of the key to set
+ * @value: a #GVariant of the correct type
+ *
+ * Sets @key in @settings to @value.
+ *
+ * It is a programmer error to give a @key that isn't valid for
+ * @settings. It is a programmer error to give a @value of the
+ * incorrect type.
+ *
+ * If @value is floating then this function consumes the reference.
+ **/
+void
+g_settings_set_value (GSettings *settings,
+ const gchar *key,
+ GVariant *value)
+{
+ GTree *tree;
+ gchar *path;
+
+ tree = g_settings_backend_create_tree ();
+ path = g_strconcat (settings->priv->base_path, key, NULL);
+ g_tree_insert (tree, g_strdup (""), g_variant_ref_sink (value));
+ g_settings_backend_write (settings->priv->backend, path, tree, NULL);
+ g_free (path);
+}
+
+void
+g_settings_get (GSettings *settings,
+ const gchar *key,
+ const gchar *format,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ value = g_settings_get_value (settings, key);
+
+ va_start (ap, format);
+ g_variant_get_va (value, format, NULL, &ap);
+ va_end (ap);
+
+ g_variant_unref (value);
+}
+
+void
+g_settings_set (GSettings *settings,
+ const gchar *key,
+ const gchar *format,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ va_start (ap, format);
+ value = g_variant_new_va (format, NULL, &ap);
+ va_end (ap);
+
+ g_settings_set_value (settings, key, value);
+}
+
+gboolean
+g_settings_is_writable (GSettings *settings,
+ const gchar *name)
+{
+ gboolean writable;
+ gchar *path;
+
+ path = g_strconcat (settings->priv->base_path, name, NULL);
+ writable = g_settings_backend_get_writable (settings->priv->backend, path);
+ g_free (path);
+
+ return writable;
+}
+
+void
+g_settings_destroy (GSettings *settings)
+{
+ g_signal_emit (settings, g_settings_signals[SIGNAL_DESTROYED], 0);
+}
+
+#if 0
+typedef struct
+{
+ GSettings *settings;
+ GObject *object;
+
+ guint property_handler_id;
+ const GParamSpec *property;
+ guint key_handler_id;
+ const GVariantType *type;
+ const gchar *key;
+
+ /* prevent recursion */
+ gboolean running;
+} GSettingsBinding;
+
+static void
+g_settings_binding_free (gpointer data)
+{
+ GSettingsBinding *binding = data;
+
+ g_assert (!binding->running);
+
+ if (binding->key_handler_id)
+ g_signal_handler_disconnect (binding->settings,
+ binding->key_handler_id);
+
+ if (binding->property_handler_id)
+ g_signal_handler_disconnect (binding->object,
+ binding->property_handler_id);
+
+ g_object_unref (binding->settings);
+
+ g_slice_free (GSettingsBinding, binding);
+}
+
+static GQuark
+g_settings_binding_quark (const char *property)
+{
+ GQuark quark;
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("gsettingsbinding-%s", property);
+ quark = g_quark_from_string (tmp);
+ g_free (tmp);
+
+ return quark;
+}
+
+static void
+g_settings_binding_key_changed (GSettings *settings,
+ const gchar *key,
+ gpointer user_data)
+{
+ GSettingsBinding *binding = user_data;
+ GValue value = { };
+ GVariant *variant;
+
+ g_assert (settings == binding->settings);
+ g_assert (key == binding->key);
+
+ if (binding->running)
+ return;
+
+ binding->running = TRUE;
+
+ g_value_init (&value, binding->property->value_type);
+ variant = g_settings_get_value (settings, key);
+ if (g_value_deserialise (&value, variant))
+ g_object_set_property (binding->object,
+ binding->property->name,
+ &value);
+ g_value_unset (&value);
+
+ binding->running = FALSE;
+}
+
+static void
+g_settings_binding_property_changed (GObject *object,
+ const GParamSpec *pspec,
+ gpointer user_data)
+{
+ GSettingsBinding *binding = user_data;
+ GValue value = { };
+ GVariant *variant;
+
+ g_assert (object == binding->object);
+ g_assert (pspec == binding->property);
+
+ if (binding->running)
+ return;
+
+ binding->running = TRUE;
+
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (object, pspec->name, &value);
+ if ((variant = g_value_serialise (&value, binding->type)))
+ {
+ g_settings_set_value (binding->settings,
+ binding->key,
+ variant);
+ g_variant_unref (variant);
+ }
+ g_value_unset (&value);
+
+ binding->running = FALSE;
+}
+
+void
+g_settings_bind (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags)
+{
+ GSettingsBinding *binding;
+ GObjectClass *objectclass;
+ gchar *detailed_signal;
+ GQuark binding_quark;
+ gboolean insensitive;
+
+ objectclass = G_OBJECT_GET_CLASS (object);
+
+ binding = g_slice_new (GSettingsBinding);
+ binding->settings = g_object_ref (settings);
+ binding->object = object;
+ binding->key = g_intern_string (key);
+ binding->property = g_object_class_find_property (objectclass, property);
+ binding->running = FALSE;
+
+ if (!(flags & (G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET)))
+ flags |= G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET;
+
+ if (binding->property == NULL)
+ {
+ g_critical ("g_settings_bind: no property '%s' on class '%s'",
+ property, G_OBJECT_TYPE_NAME (object));
+ return;
+ }
+
+ binding->type = g_settings_schema_get_key_type (settings->priv->schema,
+ key);
+
+ if (binding->type == NULL)
+ {
+ g_critical ("g_settings_bind: no key '%s' on schema '%s'",
+ key, settings->priv->schema_name);
+ return;
+ }
+
+ if (!g_type_serialiser_check (G_PARAM_SPEC_VALUE_TYPE (binding->property),
+ binding->type))
+ {
+ g_critical ("g_settings_bind: property '%s' on class '%s' has type"
+ "'%s' which is not compatible with type '%s' of key '%s'"
+ "on schema '%s'", property, G_OBJECT_TYPE_NAME (object),
+ g_type_name (binding->property->value_type),
+ g_variant_type_dup_string (binding->type), key,
+ settings->priv->schema_name);
+ return;
+ }
+
+ if (~flags & G_SETTINGS_BIND_NO_SENSITIVITY)
+ {
+ GParamSpec *sensitive;
+
+ sensitive = g_object_class_find_property (objectclass, "sensitive");
+ if (sensitive && sensitive->value_type == G_TYPE_BOOLEAN)
+ {
+ insensitive = !g_settings_is_writable (settings, key);
+ g_object_set (object, "sensitive", !insensitive, NULL);
+ }
+ else
+ insensitive = FALSE;
+ }
+ else
+ insensitive = FALSE;
+
+ if (!insensitive && (flags & G_SETTINGS_BIND_SET))
+ {
+ detailed_signal = g_strdup_printf ("notify::%s", property);
+ binding->property_handler_id =
+ g_signal_connect (object, detailed_signal,
+ G_CALLBACK (g_settings_binding_property_changed),
+ binding);
+ g_free (detailed_signal);
+
+ if (~flags & G_SETTINGS_BIND_GET)
+ g_settings_binding_property_changed (object,
+ binding->property,
+ binding);
+ }
+
+ if (flags & G_SETTINGS_BIND_GET)
+ {
+ detailed_signal = g_strdup_printf ("changed::%s", key);
+ binding->key_handler_id =
+ g_signal_connect (settings, detailed_signal,
+ G_CALLBACK (g_settings_binding_key_changed),
+ binding);
+ g_free (detailed_signal);
+
+ g_settings_binding_key_changed (settings, binding->key, binding);
+ }
+
+ binding_quark = g_settings_binding_quark (property);
+ g_object_set_qdata_full (object, binding_quark,
+ binding, g_settings_binding_free);
+}
+
+void
+g_settings_unbind (gpointer object,
+ const gchar *property)
+{
+ GQuark binding_quark;
+
+ binding_quark = g_settings_binding_quark (property);
+ g_object_set_qdata (object, binding_quark, NULL);
+}
+#endif
diff --git a/gio/gsettings.h b/gio/gsettings.h
new file mode 100644
index 0000000..9ace2e4
--- /dev/null
+++ b/gio/gsettings.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#ifndef _gsettings_h_
+#define _gsettings_h_
+
+#include "gsettingsbackend.h"
+
+#define G_TYPE_SETTINGS (g_settings_get_type ())
+#define G_SETTINGS(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_SETTINGS, GSettings))
+#define G_SETTINGS_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_SETTINGS, GSettingsClass))
+#define G_IS_SETTINGS(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_SETTINGS))
+#define G_IS_SETTINGS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_SETTINGS))
+#define G_SETTINGS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_SETTINGS, GSettingsClass))
+
+typedef struct _GSettingsPrivate GSettingsPrivate;
+typedef struct _GSettingsClass GSettingsClass;
+typedef struct _GSettings GSettings;
+
+struct _GSettingsClass
+{
+ GObjectClass parent_class;
+
+
+ GSettings * (*get_settings) (GSettings *settings,
+ const gchar *name);
+
+
+ void (*changes) (GSettings *settings,
+ const GQuark *keys,
+ gint n_keys);
+ void (*changed) (GSettings *settings,
+ const gchar *key);
+ void (*destroyed) (GSettings *settings);
+};
+
+struct _GSettings
+{
+ GObject parent_instance;
+ GSettingsPrivate *priv;
+};
+
+typedef enum
+{
+ G_SETTINGS_BIND_DEFAULT,
+ G_SETTINGS_BIND_GET = (1<<0),
+ G_SETTINGS_BIND_SET = (1<<1),
+ G_SETTINGS_BIND_NO_SENSITIVITY = (1<<2)
+} GSettingsBindFlags;
+
+G_BEGIN_DECLS
+
+GType g_settings_get_type (void);
+void g_settings_revert (GSettings *settings);
+void g_settings_apply (GSettings *settings);
+
+gboolean g_settings_get_delay_apply (GSettings *settings);
+gboolean g_settings_get_has_unapplied (GSettings *settings);
+void g_settings_set_delay_apply (GSettings *settings,
+ gboolean delay_apply);
+gboolean g_settings_get_locked (GSettings *settings);
+void g_settings_lock (GSettings *settings);
+
+GSettings * g_settings_new (const gchar *schema);
+GSettings * g_settings_new_from_path (const gchar *path);
+
+void g_settings_set_value (GSettings *settings,
+ const gchar *key,
+ GVariant *value);
+
+GVariant * g_settings_get_value (GSettings *settings,
+ const gchar *key);
+
+void g_settings_set (GSettings *settings,
+ const gchar *key,
+ const gchar *format,
+ ...);
+
+void g_settings_get (GSettings *settings,
+ const gchar *key,
+ const gchar *format_string,
+ ...);
+
+GSettings * g_settings_get_settings (GSettings *settings,
+ const gchar *name);
+
+gboolean g_settings_is_writable (GSettings *settings,
+ const gchar *name);
+void g_settings_changes (GSettings *settings,
+ const GQuark *keys,
+ gint n_keys);
+void g_settings_destroy (GSettings *settings);
+
+void g_settings_bind (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags);
+void g_settings_unbind (gpointer object,
+ const gchar *key);
+
+G_END_DECLS
+
+#endif /* _gsettings_h_ */
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index f10d3d4..9b07a3e 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -9,7 +9,7 @@
*/
#include "gsettingsbackend.h"
-
+#include "gmemorysettingsbackend.h"
#include "giomodule-priv.h"
#include "gio-marshal.h"
@@ -29,6 +29,7 @@ G_DEFINE_ABSTRACT_TYPE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
static guint changed_signal;
enum {
+ PROP_ZERO,
PROP_CONTEXT
};
@@ -322,10 +323,19 @@ g_settings_backend_finalize (GObject *object)
}
static void
+ignore_subscription (GSettingsBackend *backend,
+ const gchar *key)
+{
+}
+
+static void
g_settings_backend_class_init (GSettingsBackendClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ class->subscribe = ignore_subscription;
+ class->unsubscribe = ignore_subscription;
+
gobject_class->get_property = g_settings_backend_get_property;
gobject_class->set_property = g_settings_backend_set_property;
gobject_class->finalize = g_settings_backend_finalize;
@@ -485,6 +495,13 @@ g_settings_backend_get_with_context (const gchar *context)
static GHashTable *backends;
GSettingsBackend *backend;
+ _g_io_modules_ensure_extension_points_registered ();
+ G_TYPE_MEMORY_SETTINGS_BACKEND;
+
+ /* FIXME: hash null properly? */
+ if (!context)
+ context = "";
+
if (!backends)
backends = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index f7cb9ec..f14edbe 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -94,7 +94,7 @@ g_settings_schema_class_init (GSettingsSchemaClass *class)
GSettingsSchema *
g_settings_schema_new (const gchar *name)
{
- GSettingsSchema *schema = NULL;
+ GSettingsSchema *schema;
GvdbTable *table = NULL;
GSList *source;
@@ -108,12 +108,12 @@ g_settings_schema_new (const gchar *name)
break;
}
- if (table != NULL)
- {
- schema = g_object_new (G_TYPE_SETTINGS_SCHEMA, NULL);
- schema->priv->name = g_strdup (name);
- schema->priv->table = table;
- }
+ if (table == NULL)
+ g_error ("Settings schema '%s' is not installed\n", name);
+
+ schema = g_object_new (G_TYPE_SETTINGS_SCHEMA, NULL);
+ schema->priv->name = g_strdup (name);
+ schema->priv->table = table;
return schema;
}
@@ -125,3 +125,22 @@ g_settings_schema_get_value (GSettingsSchema *schema,
{
return gvdb_table_get_value (schema->priv->table, key, options);
}
+
+const gchar *
+g_settings_schema_get_path (GSettingsSchema *schema)
+{
+ const gchar *result;
+ GVariant *value;
+
+ value = gvdb_table_get_value (schema->priv->table, ".path", NULL);
+
+ if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ result = g_variant_get_string (value, NULL);
+ g_variant_unref (value);
+ }
+ else
+ result = NULL;
+
+ return result;
+}
diff --git a/gio/gsettingsschema.h b/gio/gsettingsschema.h
index 3acaca1..8cc0881 100644
--- a/gio/gsettingsschema.h
+++ b/gio/gsettingsschema.h
@@ -53,7 +53,11 @@ struct _GSettingsSchema
GSettingsSchemaPrivate *priv;
};
-GSettingsSchema * g_settings_schema_new (const gchar *name);
+GSettingsSchema * g_settings_schema_new (const gchar *name);
+const gchar * g_settings_schema_get_path (GSettingsSchema *schema);
+GVariant * g_settings_schema_get_value (GSettingsSchema *schema,
+ const gchar *key,
+ GVariant **options);
G_END_DECLS
diff --git a/gio/gvdb/gvdb-reader.c b/gio/gvdb/gvdb-reader.c
index 0cdbc4d..5f80d1f 100644
--- a/gio/gvdb/gvdb-reader.c
+++ b/gio/gvdb/gvdb-reader.c
@@ -224,6 +224,7 @@ gvdb_table_lookup (GvdbTable *file,
{
guint32 hash_value = 5381;
guint key_length;
+ guint32 lastno;
guint32 itemno;
if G_UNLIKELY (file->n_buckets == 0 || file->n_hash_items == 0)
@@ -236,20 +237,21 @@ gvdb_table_lookup (GvdbTable *file,
return NULL;
itemno = file->hash_buckets[hash_value % file->n_buckets];
- hash_value &= ~(1u << 31);
- while G_LIKELY (itemno < file->n_hash_items)
+ if (hash_value % file->n_buckets != file->n_buckets - 1)
+ lastno = file->hash_buckets[hash_value % file->n_buckets + 1];
+ else
+ lastno = file->n_hash_items;
+
+ while G_LIKELY (itemno < lastno)
{
struct gvdb_hash_item *item = &file->hash_items[itemno];
- if (hash_value == (guint32_from_le (item->hash_value) & ~(1u << 31)))
+ if (hash_value == guint32_from_le (item->hash_value))
if G_LIKELY (gvdb_table_check_name (file, item, key, key_length))
if G_LIKELY (item->type == type)
return item;
- if (guint32_from_le (item->hash_value) & (1u << 31))
- return NULL;
-
itemno++;
}
diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore
index c75c8cd..d7fc756 100644
--- a/gio/tests/.gitignore
+++ b/gio/tests/.gitignore
@@ -11,6 +11,7 @@ filter-streams
g-file
g-file-info
g-icon
+gsettings
httpd
live-g-file
memory-input-stream
@@ -25,4 +26,4 @@ socket-server
srvtarget
unix-fd
unix-streams
-utf8-input-stream
\ No newline at end of file
+utf8-input-stream
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 8f9f483..61773ae 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -32,7 +32,8 @@ TEST_PROGS += \
filter-streams \
simple-async-result \
srvtarget \
- contexts
+ contexts \
+ gsettings
SAMPLE_PROGS = \
resolver \
@@ -133,4 +134,6 @@ contexts_SOURCES = contexts.c
contexts_LDADD = $(progs_ldadd) \
$(top_builddir)/gthread/libgthread-2.0.la
+gsettings_LDADD = $(progs_ldadd)
+
DISTCLEAN_FILES = applications/mimeinfo.cache
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
new file mode 100644
index 0000000..f3bcb27
--- /dev/null
+++ b/gio/tests/gsettings.c
@@ -0,0 +1,25 @@
+#include <gio.h>
+
+int
+main (void)
+{
+ GSettings *settings;
+ gchar *str = NULL;
+
+ g_type_init ();
+
+ settings = g_settings_new ("org.gtk.test");
+
+ g_settings_get (settings, "greeting", "s", &str);
+ g_print ("it was '%s'\n", str);
+
+ g_settings_set (settings, "greeting", "s", "goodbye world");
+
+ g_settings_get (settings, "greeting", "s", &str);
+ g_print ("it is now '%s'\n", str);
+
+ g_settings_set (settings, "greeting", "i", 555);
+
+ g_settings_get (settings, "greeting", "s", &str);
+ g_print ("finally, it is '%s'\n", str);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]