[glib/wip/gsettingsbackendchangeset: 5/5] more stuff
- From: Allison Ryan Lortie <desrt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gsettingsbackendchangeset: 5/5] more stuff
- Date: Wed, 3 Feb 2016 11:09:57 +0000 (UTC)
commit 5506c54b7e1da72dcb3ed6dfec612b3ee3f68ae7
Author: Allison Ryan Lortie <desrt desrt ca>
Date: Mon Jan 18 12:10:04 2016 -0500
more stuff
gio/gdelayedsettingsbackend.c | 470 ++++++++++++++--------------------------
gio/gdelayedsettingsbackend.h | 35 +---
gio/gkeyfilesettingsbackend.c | 267 +++++++++++------------
gio/gmemorysettingsbackend.c | 133 ++++--------
gio/gregistrysettingsbackend.c | 16 --
gio/gsettings.c | 6 +-
gio/gsettingsbackend.c | 369 ++++++++++++++------------------
gio/gsettingsbackend.h | 36 +++-
gio/gsettingsbackendinternal.h | 10 +-
9 files changed, 546 insertions(+), 796 deletions(-)
---
diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c
index 22a42eb..e375880 100644
--- a/gio/gdelayedsettingsbackend.c
+++ b/gio/gdelayedsettingsbackend.c
@@ -25,107 +25,117 @@
#include <string.h>
-struct _GDelayedSettingsBackendPrivate
+struct _GDelayedSettingsBackend
{
+ GSettingsBackend parent_instance;
+
+ GSettingsBackendChangeset *changeset;
GSettingsBackend *backend;
+ gboolean has_unapplied;
GMutex lock;
- GTree *delayed;
GMainContext *owner_context;
- gpointer owner;
+ GWeakRef owner;
};
-G_DEFINE_TYPE_WITH_PRIVATE (GDelayedSettingsBackend,
- g_delayed_settings_backend,
- G_TYPE_SETTINGS_BACKEND)
+G_DEFINE_TYPE (GDelayedSettingsBackend, g_delayed_settings_backend, G_TYPE_SETTINGS_BACKEND)
+
+/* {{{1 Handling of GSettings::has-unapplied property */
+static void
+g_delayed_settings_backend_lock_for_write (GDelayedSettingsBackend *self)
+{
+ g_mutex_lock (&self->lock);
+}
static gboolean
-invoke_notify_unapplied (gpointer data)
+g_delayed_settings_backend_notify_unapplied (gpointer user_data)
{
- g_object_notify (data, "has-unapplied");
- g_object_unref (data);
+ g_object_notify (user_data, "has-unapplied");
return FALSE;
}
static void
-g_delayed_settings_backend_notify_unapplied (GDelayedSettingsBackend *delayed)
+g_delayed_settings_backend_unlock_for_write (GDelayedSettingsBackend *self,
+ const gchar *key,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
{
- GMainContext *target_context;
- GObject *target;
+ gboolean has_unapplied;
+ gboolean need_notify;
- g_mutex_lock (&delayed->priv->lock);
- if (delayed->priv->owner)
- {
- target_context = delayed->priv->owner_context;
- target = g_object_ref (delayed->priv->owner);
- }
- else
+ has_unapplied = g_settings_backend_changeset_is_empty (self->changeset) == FALSE;
+ need_notify = self->has_unapplied != has_unapplied;
+ self->has_unapplied = has_unapplied;
+
+ g_mutex_unlock (&self->lock);
+
+ if (key)
+ g_settings_backend_changed (G_SETTINGS_BACKEND (self), key, origin_tag);
+
+ if (changeset)
+ g_settings_backend_changeset_applied (G_SETTINGS_BACKEND (self), changeset, origin_tag);
+
+ if (need_notify)
{
- target_context = NULL;
- target = NULL;
- }
- g_mutex_unlock (&delayed->priv->lock);
+ gpointer owner = g_weak_ref_get (&self->owner);
- if (target != NULL)
- g_main_context_invoke (target_context, invoke_notify_unapplied, target);
+ if (owner)
+ g_main_context_invoke_full (self->owner_context, G_PRIORITY_DEFAULT,
+ g_delayed_settings_backend_notify_unapplied, owner, g_object_unref);
+ }
}
+gboolean
+g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *self)
+{
+ gboolean has_unapplied;
+
+ g_mutex_lock (&self->lock);
+ has_unapplied = self->has_unapplied;
+ g_mutex_unlock (&self->lock);
+
+ return has_unapplied;
+}
+/* {{{1 GSettingsBackend method calls */
static GVariant *
-g_delayed_settings_backend_read (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type,
- gboolean default_value)
+g_delayed_settings_backend_read_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type,
+ GQueue *read_through,
+ gboolean user_value_only,
+ gboolean default_value)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- gpointer result = NULL;
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (backend);
+ GVariant *value;
- if (!default_value)
+ if (read_through == NULL)
{
- g_mutex_lock (&delayed->priv->lock);
- if (g_tree_lookup_extended (delayed->priv->delayed, key, NULL, &result))
- {
- /* NULL in the tree means we should consult the default value */
- if (result != NULL)
- g_variant_ref (result);
- else
- default_value = TRUE;
- }
- g_mutex_unlock (&delayed->priv->lock);
+ read_through = g_newa (GQueue, 1);
+ memset (read_through, 0, sizeof (GQueue));
}
- if (result == NULL)
- result = g_settings_backend_read (delayed->priv->backend, key,
- expected_type, default_value);
+ g_mutex_lock (&self->lock);
+ {
+ GList link = { self->changeset, NULL, NULL };
+
+ g_queue_push_head_link (read_through, &link);
+ value = g_settings_backend_read_value (self->backend, key, expected_type, read_through, user_value_only,
default_value);
+ g_queue_pop_head_link (read_through);
+ }
+ g_mutex_unlock (&self->lock);
- return result;
+ return value;
}
-static GVariant *
-g_delayed_settings_backend_read_user_value (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type)
+static gboolean
+g_delayed_settings_backend_get_writable (GSettingsBackend *backend,
+ const gchar *name)
{
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- gboolean value_found = FALSE;
- gpointer result = NULL;
-
- /* If we find an explicit NULL in our changeset then we want to return
- * NULL (because the user value has been reset).
- *
- * Otherwise, chain up.
- */
- g_mutex_lock (&delayed->priv->lock);
- value_found = g_tree_lookup_extended (delayed->priv->delayed, key, NULL, &result);
- if (result)
- g_variant_ref (result);
- g_mutex_unlock (&delayed->priv->lock);
-
- if (value_found)
- return result;
-
- return g_settings_backend_read_user_value (delayed->priv->backend, key, expected_type);
+
+ return g_settings_backend_get_writable (delayed->backend, name);
}
static gboolean
@@ -134,78 +144,45 @@ g_delayed_settings_backend_write (GSettingsBackend *backend,
GVariant *value,
gpointer origin_tag)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- gboolean was_empty;
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (backend);
- g_mutex_lock (&delayed->priv->lock);
- was_empty = g_tree_nnodes (delayed->priv->delayed) == 0;
- g_tree_insert (delayed->priv->delayed, g_strdup (key),
- g_variant_ref_sink (value));
- g_mutex_unlock (&delayed->priv->lock);
+ g_delayed_settings_backend_lock_for_write (self);
- g_settings_backend_changed (backend, key, origin_tag);
+ g_settings_backend_changeset_set (self->changeset, key, value);
- if (was_empty)
- g_delayed_settings_backend_notify_unapplied (delayed);
+ g_delayed_settings_backend_unlock_for_write (self, key, NULL, origin_tag);
return TRUE;
}
-static gboolean
-add_to_tree (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- g_tree_insert (user_data, g_strdup (key), g_variant_ref (value));
- return FALSE;
-}
-
-static gboolean
-g_delayed_settings_backend_write_tree (GSettingsBackend *backend,
- GTree *tree,
- gpointer origin_tag)
+static void
+g_delayed_settings_backend_reset (GSettingsBackend *backend,
+ const gchar *key,
+ gpointer origin_tag)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- gboolean was_empty;
-
- g_mutex_lock (&delayed->priv->lock);
- was_empty = g_tree_nnodes (delayed->priv->delayed) == 0;
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (backend);
- g_tree_foreach (tree, add_to_tree, delayed->priv->delayed);
- g_mutex_unlock (&delayed->priv->lock);
+ g_delayed_settings_backend_lock_for_write (self);
- g_settings_backend_changed_tree (backend, tree, origin_tag);
+ g_settings_backend_changeset_set (self->changeset, key, NULL);
- if (was_empty)
- g_delayed_settings_backend_notify_unapplied (delayed);
-
- return TRUE;
+ g_delayed_settings_backend_unlock_for_write (self, key, NULL, origin_tag);
}
static gboolean
-g_delayed_settings_backend_get_writable (GSettingsBackend *backend,
- const gchar *name)
+g_delayed_settings_backend_write_changeset (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (backend);
- return g_settings_backend_get_writable (delayed->priv->backend, name);
-}
+ g_delayed_settings_backend_lock_for_write (self);
-static void
-g_delayed_settings_backend_reset (GSettingsBackend *backend,
- const gchar *key,
- gpointer origin_tag)
-{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- gboolean was_empty;
+ g_settings_backend_changeset_change (self->changeset, changeset);
- g_mutex_lock (&delayed->priv->lock);
- was_empty = g_tree_nnodes (delayed->priv->delayed) == 0;
- g_tree_insert (delayed->priv->delayed, g_strdup (key), NULL);
- g_mutex_unlock (&delayed->priv->lock);
+ g_delayed_settings_backend_unlock_for_write (self, NULL, changeset, origin_tag);
- if (was_empty)
- g_delayed_settings_backend_notify_unapplied (delayed);
+ return TRUE;
}
static void
@@ -214,7 +191,7 @@ g_delayed_settings_backend_subscribe (GSettingsBackend *backend,
{
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- g_settings_backend_subscribe (delayed->priv->backend, name);
+ g_settings_backend_subscribe (delayed->backend, name);
}
static void
@@ -223,83 +200,67 @@ g_delayed_settings_backend_unsubscribe (GSettingsBackend *backend,
{
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
- g_settings_backend_unsubscribe (delayed->priv->backend, name);
-}
-
-static GPermission *
-g_delayed_settings_backend_get_permission (GSettingsBackend *backend,
- const gchar *path)
-{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
-
- return g_settings_backend_get_permission (delayed->priv->backend, path);
+ g_settings_backend_unsubscribe (delayed->backend, name);
}
-
-/* method calls */
-gboolean
-g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *delayed)
+/* {{{1 apply() and revert() method calls */
+void
+g_delayed_settings_backend_apply (GDelayedSettingsBackend *self)
{
- /* we don't need to lock for this... */
+ GSettingsBackendChangeset *changeset = NULL;
- return g_tree_nnodes (delayed->priv->delayed) > 0;
-}
+ g_delayed_settings_backend_lock_for_write (self);
-void
-g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed)
-{
- if (g_tree_nnodes (delayed->priv->delayed) > 0)
+ if (!g_settings_backend_changeset_is_empty (self->changeset))
{
- gboolean success;
- GTree *tmp;
-
- g_mutex_lock (&delayed->priv->lock);
- tmp = delayed->priv->delayed;
- delayed->priv->delayed = g_settings_backend_create_tree ();
- success = g_settings_backend_write_tree (delayed->priv->backend,
- tmp, delayed->priv);
- g_mutex_unlock (&delayed->priv->lock);
+ changeset = self->changeset;
+ self->changeset = g_settings_backend_changeset_new ();
- if (!success)
- g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed),
- tmp, NULL);
+ /* If the write is successful then we should not notify since our
+ * children already see the new value and that is the value that
+ * was just applied.
+ *
+ * In case of failure, we must notify so that they see the
+ * previous (old) value again.
+ */
+ if (g_settings_backend_write_changeset (self->backend, changeset, self))
+ g_clear_pointer (&changeset, g_settings_backend_changeset_unref);
+ }
- g_tree_unref (tmp);
+ g_delayed_settings_backend_unlock_for_write (self, NULL, changeset, NULL);
- g_delayed_settings_backend_notify_unapplied (delayed);
- }
+ g_clear_pointer (&changeset, g_settings_backend_changeset_unref);
}
void
-g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed)
+g_delayed_settings_backend_revert (GDelayedSettingsBackend *self)
{
- if (g_tree_nnodes (delayed->priv->delayed) > 0)
- {
- GTree *tmp;
+ GSettingsBackendChangeset *changeset = NULL;
- g_mutex_lock (&delayed->priv->lock);
- tmp = delayed->priv->delayed;
- delayed->priv->delayed = g_settings_backend_create_tree ();
- g_mutex_unlock (&delayed->priv->lock);
- g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed), tmp, NULL);
- g_tree_unref (tmp);
+ g_delayed_settings_backend_lock_for_write (self);
- g_delayed_settings_backend_notify_unapplied (delayed);
+ if (!g_settings_backend_changeset_is_empty (self->changeset))
+ {
+ changeset = self->changeset;
+ self->changeset = g_settings_backend_changeset_new ();
}
+
+ g_delayed_settings_backend_unlock_for_write (self, NULL, changeset, NULL);
+
+ g_clear_pointer (&changeset, g_settings_backend_changeset_unref);
}
-/* change notification */
+/* {{{1 change notification */
static void
delayed_backend_changed (GObject *target,
GSettingsBackend *backend,
const gchar *key,
gpointer origin_tag)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (target);
- if (origin_tag != delayed->priv)
- g_settings_backend_changed (G_SETTINGS_BACKEND (delayed),
- key, origin_tag);
+ if (origin_tag != self)
+ g_settings_backend_changed (G_SETTINGS_BACKEND (self), key, origin_tag);
}
static void
@@ -309,11 +270,10 @@ delayed_backend_keys_changed (GObject *target,
gpointer origin_tag,
const gchar * const *items)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (target);
- if (origin_tag != delayed->priv)
- g_settings_backend_keys_changed (G_SETTINGS_BACKEND (delayed),
- path, items, origin_tag);
+ if (origin_tag != self)
+ g_settings_backend_keys_changed (G_SETTINGS_BACKEND (self), path, items, origin_tag);
}
static void
@@ -322,11 +282,10 @@ delayed_backend_path_changed (GObject *target,
const gchar *path,
gpointer origin_tag)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (target);
- if (origin_tag != delayed->priv)
- g_settings_backend_path_changed (G_SETTINGS_BACKEND (delayed),
- path, origin_tag);
+ if (origin_tag != self)
+ g_settings_backend_path_changed (G_SETTINGS_BACKEND (self), path, origin_tag);
}
static void
@@ -334,56 +293,9 @@ delayed_backend_writable_changed (GObject *target,
GSettingsBackend *backend,
const gchar *key)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
- gboolean last_one = FALSE;
-
- g_mutex_lock (&delayed->priv->lock);
-
- if (g_tree_lookup (delayed->priv->delayed, key) != NULL &&
- !g_settings_backend_get_writable (delayed->priv->backend, key))
- {
- /* drop the key from our changeset if it just became read-only.
- * no need to signal since the writable change below implies it.
- *
- * note that the item in the tree may very well be set to NULL in
- * the case that the user stored a reset. we intentionally don't
- * drop the key in this case since a reset will always succeed
- * (even against a non-writable key).
- */
- g_tree_remove (delayed->priv->delayed, key);
-
- /* if that was the only key... */
- last_one = g_tree_nnodes (delayed->priv->delayed) == 0;
- }
-
- g_mutex_unlock (&delayed->priv->lock);
-
- if (last_one)
- g_delayed_settings_backend_notify_unapplied (delayed);
-
- g_settings_backend_writable_changed (G_SETTINGS_BACKEND (delayed), key);
-}
-
-/* slow method until we get foreach-with-remove in GTree
- */
-typedef struct
-{
- const gchar *path;
- const gchar **keys;
- gsize index;
-} CheckPrefixState;
-
-static gboolean
-check_prefix (gpointer key,
- gpointer value,
- gpointer data)
-{
- CheckPrefixState *state = data;
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (target);
- if (g_str_has_prefix (key, state->path))
- state->keys[state->index++] = key;
-
- return FALSE;
+ g_settings_backend_writable_changed (G_SETTINGS_BACKEND (self), key);
}
static void
@@ -391,59 +303,26 @@ delayed_backend_path_writable_changed (GObject *target,
GSettingsBackend *backend,
const gchar *path)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
- gboolean last_one = FALSE;
- gsize n_keys;
-
- g_mutex_lock (&delayed->priv->lock);
-
- n_keys = g_tree_nnodes (delayed->priv->delayed);
-
- if (n_keys > 0)
- {
- CheckPrefixState state = { path, g_new (const gchar *, n_keys) };
- gsize i;
-
- /* collect a list of possibly-affected keys (ie: matching the path) */
- g_tree_foreach (delayed->priv->delayed, check_prefix, &state);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (target);
- /* drop the keys that have been affected.
- *
- * don't drop 'reset' keys (see above) */
- for (i = 0; i < state.index; i++)
- if (g_tree_lookup (delayed->priv->delayed, state.keys[i]) != NULL &&
- !g_settings_backend_get_writable (delayed->priv->backend,
- state.keys[i]))
- g_tree_remove (delayed->priv->delayed, state.keys[i]);
-
- g_free (state.keys);
-
- last_one = g_tree_nnodes (delayed->priv->delayed) == 0;
- }
-
- g_mutex_unlock (&delayed->priv->lock);
-
- if (last_one)
- g_delayed_settings_backend_notify_unapplied (delayed);
-
- g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (delayed),
- path);
+ g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (self), path);
}
static void
g_delayed_settings_backend_finalize (GObject *object)
{
- GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object);
+ GDelayedSettingsBackend *self = G_DELAYED_SETTINGS_BACKEND (object);
- g_mutex_clear (&delayed->priv->lock);
- g_object_unref (delayed->priv->backend);
- g_tree_unref (delayed->priv->delayed);
+ g_settings_backend_changeset_unref (self->changeset);
+ if (self->owner_context)
+ g_main_context_unref (self->owner_context);
+ g_object_unref (self->backend);
+ g_mutex_clear (&self->lock);
/* if our owner is still alive, why are we finalizing? */
- g_assert (delayed->priv->owner == NULL);
+ g_assert (g_weak_ref_get (&self->owner) == NULL);
- G_OBJECT_CLASS (g_delayed_settings_backend_parent_class)
- ->finalize (object);
+ G_OBJECT_CLASS (g_delayed_settings_backend_parent_class)->finalize (object);
}
static void
@@ -452,37 +331,22 @@ g_delayed_settings_backend_class_init (GDelayedSettingsBackendClass *class)
GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
- backend_class->read = g_delayed_settings_backend_read;
- backend_class->read_user_value = g_delayed_settings_backend_read_user_value;
+ backend_class->read_value = g_delayed_settings_backend_read_value;
backend_class->write = g_delayed_settings_backend_write;
- backend_class->write_tree = g_delayed_settings_backend_write_tree;
backend_class->reset = g_delayed_settings_backend_reset;
+ backend_class->write_changeset = g_delayed_settings_backend_write_changeset;
backend_class->get_writable = g_delayed_settings_backend_get_writable;
backend_class->subscribe = g_delayed_settings_backend_subscribe;
backend_class->unsubscribe = g_delayed_settings_backend_unsubscribe;
- backend_class->get_permission = g_delayed_settings_backend_get_permission;
object_class->finalize = g_delayed_settings_backend_finalize;
}
static void
-g_delayed_settings_backend_init (GDelayedSettingsBackend *delayed)
+g_delayed_settings_backend_init (GDelayedSettingsBackend *self)
{
- delayed->priv = g_delayed_settings_backend_get_instance_private (delayed);
- delayed->priv->delayed = g_settings_backend_create_tree ();
- g_mutex_init (&delayed->priv->lock);
-}
-
-static void
-g_delayed_settings_backend_disown (gpointer data,
- GObject *where_the_object_was)
-{
- GDelayedSettingsBackend *delayed = data;
-
- g_mutex_lock (&delayed->priv->lock);
- delayed->priv->owner_context = NULL;
- delayed->priv->owner = NULL;
- g_mutex_unlock (&delayed->priv->lock);
+ self->changeset = g_settings_backend_changeset_new ();
+ g_mutex_init (&self->lock);
}
GDelayedSettingsBackend *
@@ -497,17 +361,17 @@ g_delayed_settings_backend_new (GSettingsBackend *backend,
delayed_backend_writable_changed,
delayed_backend_path_writable_changed
};
- GDelayedSettingsBackend *delayed;
+ GDelayedSettingsBackend *self;
+
+ self = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL);
+ self->backend = g_object_ref (backend);
- delayed = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL);
- delayed->priv->backend = g_object_ref (backend);
- delayed->priv->owner_context = owner_context;
- delayed->priv->owner = owner;
+ if (owner_context)
+ self->owner_context = g_main_context_ref (owner_context);
- g_object_weak_ref (owner, g_delayed_settings_backend_disown, delayed);
+ g_weak_ref_init (&self->owner, owner);
- g_settings_backend_watch (delayed->priv->backend,
- &vtable, G_OBJECT (delayed), NULL);
+ g_settings_backend_watch (self->backend, &vtable, G_OBJECT (self), NULL);
- return delayed;
+ return self;
}
diff --git a/gio/gdelayedsettingsbackend.h b/gio/gdelayedsettingsbackend.h
index 1f3c8f0..4e0989e 100644
--- a/gio/gdelayedsettingsbackend.h
+++ b/gio/gdelayedsettingsbackend.h
@@ -24,37 +24,12 @@
#include <gio/gsettingsbackend.h>
-#define G_TYPE_DELAYED_SETTINGS_BACKEND (g_delayed_settings_backend_get_type ())
-#define G_DELAYED_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst),
\
- G_TYPE_DELAYED_SETTINGS_BACKEND,
\
- GDelayedSettingsBackend))
-#define G_DELAYED_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),
\
- G_TYPE_DELAYED_SETTINGS_BACKEND,
\
- GDelayedSettingsBackendClass))
-#define G_IS_DELAYED_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst),
\
- G_TYPE_DELAYED_SETTINGS_BACKEND))
-#define G_IS_DELAYED_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),
\
- G_TYPE_DELAYED_SETTINGS_BACKEND))
-#define G_DELAYED_SETTINGS_BACKEND_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst),
\
- G_TYPE_DELAYED_SETTINGS_BACKEND,
\
- GDelayedSettingsBackendClass))
+#define G_TYPE_DELAYED_SETTINGS_BACKEND (g_delayed_settings_backend_get_type ())
+G_DECLARE_FINAL_TYPE(GDelayedSettingsBackend,
+ g_delayed_settings_backend,
+ G, DELAYED_SETTINGS_BACKEND,
+ GSettingsBackend)
-typedef struct _GDelayedSettingsBackendPrivate GDelayedSettingsBackendPrivate;
-typedef struct _GDelayedSettingsBackendClass GDelayedSettingsBackendClass;
-typedef struct _GDelayedSettingsBackend GDelayedSettingsBackend;
-
-struct _GDelayedSettingsBackendClass
-{
- GSettingsBackendClass parent_class;
-};
-
-struct _GDelayedSettingsBackend
-{
- GSettingsBackend parent_instance;
- GDelayedSettingsBackendPrivate *priv;
-};
-
-GType g_delayed_settings_backend_get_type (void);
GDelayedSettingsBackend * g_delayed_settings_backend_new (GSettingsBackend *backend,
gpointer owner,
GMainContext
*owner_context);
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
index 8eb7681..e862b2a 100644
--- a/gio/gkeyfilesettingsbackend.c
+++ b/gio/gkeyfilesettingsbackend.c
@@ -27,7 +27,6 @@
#include "gfile.h"
#include "gfileinfo.h"
#include "gfilemonitor.h"
-#include "gsimplepermission.h"
#include "gsettingsbackend.h"
@@ -45,8 +44,9 @@ typedef struct
{
GSettingsBackend parent_instance;
+ GSettingsBackendChangeset *database;
+
GKeyFile *keyfile;
- GPermission *permission;
gboolean writable;
gchar *prefix;
@@ -167,148 +167,143 @@ convert_path (GKeyfileSettingsBackend *kfsb,
}
static gboolean
-path_is_valid (GKeyfileSettingsBackend *kfsb,
- const gchar *path)
+g_keyfile_settings_backend_can_write (GKeyfileSettingsBackend *self,
+ const gchar *path,
+ gboolean is_reset)
{
- return convert_path (kfsb, path, NULL, NULL);
-}
-
-static GVariant *
-get_from_keyfile (GKeyfileSettingsBackend *kfsb,
- const GVariantType *type,
- const gchar *key)
-{
- GVariant *return_value = NULL;
- gchar *group, *name;
-
- if (convert_path (kfsb, key, &group, &name))
- {
- gchar *str;
-
- g_assert (*name);
+ /* reset is always successful */
+ if (is_reset)
+ return TRUE;
- str = g_key_file_get_value (kfsb->keyfile, group, name, NULL);
-
- if (str)
- {
- return_value = g_variant_parse (type, str, NULL, NULL, NULL);
- g_free (str);
- }
-
- g_free (group);
- g_free (name);
- }
+ /* can't write if this database does not contain user values */
+ if (self->does_not_contain & G_SETTINGS_BACKEND_READ_USER_VALUE)
+ return FALSE;
- return return_value;
+ /* otherwise, we can write it if it is a valid path within the keyfile */
+ return convert_path (self, path, NULL, NULL);
}
static gboolean
-set_to_keyfile (GKeyfileSettingsBackend *kfsb,
- const gchar *key,
- GVariant *value)
+g_keyfile_settings_backend_write_internal (GKeyfileSettingsBackend *self,
+ const gchar *key,
+ GVariant *value)
{
gchar *group, *name;
- if (convert_path (kfsb, key, &group, &name))
+ /* do not attempt the write if this is not a user database */
+ if (~self->does_not_contain & G_SETTINGS_BACKEND_READ_USER_VALUE)
{
- if (value)
- {
- gchar *str = g_variant_print (value, FALSE);
- g_key_file_set_value (kfsb->keyfile, group, name, str);
- g_variant_unref (g_variant_ref_sink (value));
- g_free (str);
- }
- else
+ /* or if the path is outside of the scope of the keyfile... */
+ if (convert_path (self, key, &group, &name))
{
- if (*name == '\0')
+ if (value)
+ {
+ gchar *str = g_variant_print (value, FALSE);
+ g_key_file_set_value (self->keyfile, group, name, str);
+ g_settings_backend_changeset_set (self->database, key, value);
+ g_variant_unref (g_variant_ref_sink (value));
+ g_free (str);
+ }
+ else
{
- gchar **groups;
- gint i;
+ if (*name == '\0')
+ {
+ gchar **groups;
+ gint i;
- groups = g_key_file_get_groups (kfsb->keyfile, NULL);
+ groups = g_key_file_get_groups (self->keyfile, NULL);
- for (i = 0; groups[i]; i++)
- if (group_name_matches (groups[i], group))
- g_key_file_remove_group (kfsb->keyfile, groups[i], NULL);
+ for (i = 0; groups[i]; i++)
+ if (group_name_matches (groups[i], group))
+ g_key_file_remove_group (self->keyfile, groups[i], NULL);
- g_strfreev (groups);
+ g_strfreev (groups);
+ }
+ else
+ g_key_file_remove_key (self->keyfile, group, name, NULL);
}
- else
- g_key_file_remove_key (kfsb->keyfile, group, name, NULL);
- }
- g_free (group);
- g_free (name);
+ g_free (group);
+ g_free (name);
- return TRUE;
+ return TRUE;
+ }
}
- return FALSE;
+ /* we didn't do anything, but resets are always successful */
+ return (value == NULL) ? TRUE : FALSE;
}
static GVariant *
-g_keyfile_settings_backend_read (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type,
- gboolean default_value)
+g_keyfile_settings_backend_read_value (GSettingsBackend *backend,
+ const gchar *key,
+ GSettingsBackendReadFlags flags,
+ GQueue *read_through,
+ const GVariantType *expected_type)
{
- GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
+ GKeyfileSettingsBackend *self = G_KEYFILE_SETTINGS_BACKEND (backend);
+ GVariant *string_form;
+ GVariant *value;
- if (default_value)
+ if (g_settings_backend_check_changeset_queue (read_through, key, flags, &value))
+ return value;
+
+ /* If the user is requesting information from a specific database,
+ * ensure that it's the one that we have.
+ */
+ if (flags & self->does_not_contain)
return NULL;
- return get_from_keyfile (kfsb, expected_type, key);
-}
+ if (!g_settings_backend_changeset_get (kfsb->database, key, &string_form))
+ return NULL;
-typedef struct
-{
- GKeyfileSettingsBackend *kfsb;
- gboolean failed;
-} WriteManyData;
+ value_form = g_variant_parse (expected_type, g_variant_get_string (string_form, NULL), NULL, NULL, NULL);
+
+ g_variant_unref (string_form);
+
+ return value_form;
+}
static gboolean
-g_keyfile_settings_backend_write_one (gpointer key,
- gpointer value,
- gpointer user_data)
+g_keyfile_settings_backend_write_one (const gchar *key,
+ GVariant *value,
+ gpointer user_data)
{
- WriteManyData *data = user_data;
+ GKeyfileSettingsBackend *self = user_data;
gboolean success;
- success = set_to_keyfile (data->kfsb, key, value);
+ success = g_keyfile_settings_backend_write_internal (self, key, value);
g_assert (success);
- return FALSE;
+ return TRUE;
}
static gboolean
-g_keyfile_settings_backend_check_one (gpointer key,
- gpointer value,
- gpointer user_data)
+g_keyfile_settings_backend_check_one (const gchar *key,
+ GVariant *value,
+ gpointer user_data)
{
- WriteManyData *data = user_data;
+ GKeyfileSettingsBackend *self = user_data;
- return data->failed = !path_is_valid (data->kfsb, key);
+ return path_is_valid (self, key);
}
static gboolean
-g_keyfile_settings_backend_write_tree (GSettingsBackend *backend,
- GTree *tree,
- gpointer origin_tag)
+g_keyfile_settings_backend_write_changeset (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
{
- WriteManyData data = { G_KEYFILE_SETTINGS_BACKEND (backend) };
-
- if (!data.kfsb->writable)
- return FALSE;
-
- g_tree_foreach (tree, g_keyfile_settings_backend_check_one, &data);
+ GKeyfileSettingsBackend *self = G_KEYFILE_SETTINGS_BACKEND (backend);
+ gboolean success;
- if (data.failed)
+ if (!g_settings_backend_changeset_all (changeset, g_keyfile_settings_backend_check_one, self))
return FALSE;
- g_tree_foreach (tree, g_keyfile_settings_backend_write_one, &data);
- g_keyfile_settings_backend_keyfile_write (data.kfsb);
+ success = g_settings_backend_changeset_all (changeset, g_keyfile_settings_backend_write_one, self);
+ g_assert (success); /* otherwise the check should have failed above */
- g_settings_backend_changed_tree (backend, tree, origin_tag);
+ g_settings_backend_changeset_applied (backend, changeset, origin_tag);
+ g_keyfile_settings_backend_keyfile_write (self);
return TRUE;
}
@@ -319,18 +314,18 @@ g_keyfile_settings_backend_write (GSettingsBackend *backend,
GVariant *value,
gpointer origin_tag)
{
- GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
+ GKeyfileSettingsBackend *self = G_KEYFILE_SETTINGS_BACKEND (backend);
gboolean success;
- if (!kfsb->writable)
+ if (!self->writable)
return FALSE;
- success = set_to_keyfile (kfsb, key, value);
+ success = g_keyfile_settings_backend_write_internal (self, key, value);
if (success)
{
g_settings_backend_changed (backend, key, origin_tag);
- g_keyfile_settings_backend_keyfile_write (kfsb);
+ g_keyfile_settings_backend_keyfile_write (self);
}
return success;
@@ -341,10 +336,10 @@ g_keyfile_settings_backend_reset (GSettingsBackend *backend,
const gchar *key,
gpointer origin_tag)
{
- GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
+ GKeyfileSettingsBackend *self = G_KEYFILE_SETTINGS_BACKEND (backend);
- if (set_to_keyfile (kfsb, key, NULL))
- g_keyfile_settings_backend_keyfile_write (kfsb);
+ if (g_keyfile_settings_backend_write_internal (self, key, NULL))
+ g_keyfile_settings_backend_keyfile_write (self);
g_settings_backend_changed (backend, key, origin_tag);
}
@@ -358,24 +353,16 @@ g_keyfile_settings_backend_get_writable (GSettingsBackend *backend,
return kfsb->writable && path_is_valid (kfsb, name);
}
-static GPermission *
-g_keyfile_settings_backend_get_permission (GSettingsBackend *backend,
- const gchar *path)
-{
- GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
-
- return g_object_ref (kfsb->permission);
-}
-
-static void
-keyfile_to_tree (GKeyfileSettingsBackend *kfsb,
- GTree *tree,
- GKeyFile *keyfile,
- gboolean dup_check)
+static GSettingsBackendChangeset *
+g_keyfile_settings_backend_keyfile_to_changeset (GKeyfileSettingsBackend *kfsb,
+ GKeyFile *keyfile)
{
+ GSettingsBackendChangeset *changeset;
gchar **groups;
gint i;
+ changeset = g_settings_backend_changeset_new_database (NULL);
+
groups = g_key_file_get_groups (keyfile, NULL);
for (i = 0; groups[i]; i++)
{
@@ -409,19 +396,17 @@ keyfile_to_tree (GKeyfileSettingsBackend *kfsb,
value = g_key_file_get_value (keyfile, groups[i], keys[j], NULL);
- if (dup_check && g_strcmp0 (g_tree_lookup (tree, path), value) == 0)
- {
- g_tree_remove (tree, path);
- g_free (value);
- g_free (path);
- }
- else
- g_tree_insert (tree, path, value);
+ g_settings_backend_changeset_set (changeset, path, g_variant_new_string (value));
+
+ g_free (value);
+ g_free (path);
}
g_strfreev (keys);
}
g_strfreev (groups);
+
+ return changeset;
}
static void
@@ -439,29 +424,26 @@ g_keyfile_settings_backend_keyfile_reload (GKeyfileSettingsBackend *kfsb)
if (memcmp (kfsb->digest, digest, sizeof digest) != 0)
{
- GKeyFile *keyfiles[2];
- GTree *tree;
+ GSettingsBackendChangeset *old, *diff;
- tree = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
- g_free, g_free);
+ g_key_file_unref (kfsb->keyfile);
- keyfiles[0] = kfsb->keyfile;
- keyfiles[1] = g_key_file_new ();
+ kfsb->keyfile = g_key_file_new ();
if (length > 0)
- g_key_file_load_from_data (keyfiles[1], contents, length,
+ g_key_file_load_from_data (kfsb->keyfile, contents, length,
G_KEY_FILE_KEEP_COMMENTS |
G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
- keyfile_to_tree (kfsb, tree, keyfiles[0], FALSE);
- keyfile_to_tree (kfsb, tree, keyfiles[1], TRUE);
- g_key_file_free (keyfiles[0]);
- kfsb->keyfile = keyfiles[1];
+ old = kfsb->database;
+ kfsb->database = g_keyfile_settings_backend_keyfile_to_changeset (kfsb, kfsb->keyfile);
+
+ diff = g_settings_backend_changeset_diff (old, kfsb->database);
- if (g_tree_nnodes (tree) > 0)
- g_settings_backend_changed_tree (&kfsb->parent_instance, tree, NULL);
+ g_settings_backend_changeset_applied (G_SETTINGS_BACKEND (kfsb), diff, NULL);
- g_tree_unref (tree);
+ g_settings_backend_changeset_unref (diff);
+ g_settings_backend_changeset_unref (old);
memcpy (kfsb->digest, digest, sizeof digest);
}
@@ -500,7 +482,6 @@ g_keyfile_settings_backend_finalize (GObject *object)
GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);
g_key_file_free (kfsb->keyfile);
- g_object_unref (kfsb->permission);
g_file_monitor_cancel (kfsb->file_monitor);
g_object_unref (kfsb->file_monitor);
@@ -529,12 +510,11 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class)
object_class->finalize = g_keyfile_settings_backend_finalize;
- class->read = g_keyfile_settings_backend_read;
+ class->read_value = g_keyfile_settings_backend_read_value;
class->write = g_keyfile_settings_backend_write;
- class->write_tree = g_keyfile_settings_backend_write_tree;
+ class->write_changeset = g_keyfile_settings_backend_write_changeset;
class->reset = g_keyfile_settings_backend_reset;
class->get_writable = g_keyfile_settings_backend_get_writable;
- class->get_permission = g_keyfile_settings_backend_get_permission;
/* No need to implement subscribed/unsubscribe: the only point would be to
* stop monitoring the file when there's no GSettings anymore, which is no
* big win.
@@ -636,7 +616,6 @@ g_keyfile_settings_backend_new (const gchar *filename,
kfsb = g_object_new (G_TYPE_KEYFILE_SETTINGS_BACKEND, NULL);
kfsb->keyfile = g_key_file_new ();
- kfsb->permission = g_simple_permission_new (TRUE);
kfsb->file = g_file_new_for_path (filename);
kfsb->dir = g_file_get_parent (kfsb->file);
diff --git a/gio/gmemorysettingsbackend.c b/gio/gmemorysettingsbackend.c
index b0d58b5..20957b0 100644
--- a/gio/gmemorysettingsbackend.c
+++ b/gio/gmemorysettingsbackend.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2010 Codethink Limited
+ * Copyright © 2015 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
- * Author: Ryan Lortie <desrt desrt ca>
+ * Author: Allison Ryan Lortie <desrt desrt ca>
*/
#include "config.h"
@@ -24,17 +25,16 @@
#include "giomodule.h"
-#define G_TYPE_MEMORY_SETTINGS_BACKEND (g_memory_settings_backend_get_type())
-#define G_MEMORY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
- G_TYPE_MEMORY_SETTINGS_BACKEND, \
- GMemorySettingsBackend))
+#define G_TYPE_MEMORY_SETTINGS_BACKEND (g_memory_settings_backend_get_type ())
+G_DECLARE_FINAL_TYPE(GMemorySettingsBackend, g_memory_settings_backend, G, MEMORY_SETTINGS_BACKEND,
GSettingsBackend)
-typedef GSettingsBackendClass GMemorySettingsBackendClass;
-typedef struct
+struct _GMemorySettingsBackend
{
GSettingsBackend parent_instance;
- GHashTable *table;
-} GMemorySettingsBackend;
+
+ GSettingsBackendChangeset *database;
+ GMutex lock;
+};
G_DEFINE_TYPE_WITH_CODE (GMemorySettingsBackend,
g_memory_settings_backend,
@@ -43,21 +43,23 @@ G_DEFINE_TYPE_WITH_CODE (GMemorySettingsBackend,
g_define_type_id, "memory", 10))
static GVariant *
-g_memory_settings_backend_read (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type,
- gboolean default_value)
+g_memory_settings_backend_read_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type,
+ GQueue *read_through,
+ gboolean user_value_only,
+ gboolean default_value)
{
- GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (backend);
- GVariant *value;
+ GMemorySettingsBackend *self = G_MEMORY_SETTINGS_BACKEND (backend);
+ GVariant *value = NULL;
- if (default_value)
- return NULL;
+ g_mutex_lock (&self->lock);
- value = g_hash_table_lookup (memory->table, key);
+ (void) (default_value ||
+ g_settings_backend_check_changeset_queue (read_through, key, &value) ||
+ g_settings_backend_changeset_get (self->database, key, &value));
- if (value != NULL)
- g_variant_ref (value);
+ g_mutex_unlock (&self->lock);
return value;
}
@@ -68,93 +70,53 @@ g_memory_settings_backend_write (GSettingsBackend *backend,
GVariant *value,
gpointer origin_tag)
{
- GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (backend);
- GVariant *old_value;
+ GMemorySettingsBackend *self = G_MEMORY_SETTINGS_BACKEND (backend);
- old_value = g_hash_table_lookup (memory->table, key);
- g_variant_ref_sink (value);
+ g_mutex_lock (&self->lock);
- if (old_value == NULL || !g_variant_equal (value, old_value))
- {
- g_hash_table_insert (memory->table, g_strdup (key), value);
- g_settings_backend_changed (backend, key, origin_tag);
- }
- else
- g_variant_unref (value);
+ g_settings_backend_changeset_set (self->database, key, value);
- return TRUE;
-}
-
-static gboolean
-g_memory_settings_backend_write_one (gpointer key,
- gpointer value,
- gpointer data)
-{
- GMemorySettingsBackend *memory = data;
+ g_mutex_unlock (&self->lock);
- if (value != NULL)
- g_hash_table_insert (memory->table, g_strdup (key), g_variant_ref (value));
- else
- g_hash_table_remove (memory->table, key);
+ g_settings_backend_changed (backend, key, origin_tag);
- return FALSE;
+ return TRUE;
}
static gboolean
-g_memory_settings_backend_write_tree (GSettingsBackend *backend,
- GTree *tree,
- gpointer origin_tag)
+g_memory_settings_backend_write_changeset (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
{
- g_tree_foreach (tree, g_memory_settings_backend_write_one, backend);
- g_settings_backend_changed_tree (backend, tree, origin_tag);
+ GMemorySettingsBackend *self = G_MEMORY_SETTINGS_BACKEND (backend);
- return TRUE;
-}
+ g_mutex_lock (&self->lock);
-static void
-g_memory_settings_backend_reset (GSettingsBackend *backend,
- const gchar *key,
- gpointer origin_tag)
-{
- GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (backend);
+ g_settings_backend_changeset_change (self->database, changeset);
- if (g_hash_table_lookup (memory->table, key))
- {
- g_hash_table_remove (memory->table, key);
- g_settings_backend_changed (backend, key, origin_tag);
- }
-}
+ g_mutex_unlock (&self->lock);
-static gboolean
-g_memory_settings_backend_get_writable (GSettingsBackend *backend,
- const gchar *name)
-{
- return TRUE;
-}
+ g_settings_backend_changeset_applied (backend, changeset, origin_tag);
-static GPermission *
-g_memory_settings_backend_get_permission (GSettingsBackend *backend,
- const gchar *path)
-{
- return g_simple_permission_new (TRUE);
+ return TRUE;
}
static void
g_memory_settings_backend_finalize (GObject *object)
{
- GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (object);
+ GMemorySettingsBackend *self = G_MEMORY_SETTINGS_BACKEND (object);
- g_hash_table_unref (memory->table);
+ g_settings_backend_changeset_unref (self->database);
+ g_mutex_clear (&self->lock);
- G_OBJECT_CLASS (g_memory_settings_backend_parent_class)
- ->finalize (object);
+ G_OBJECT_CLASS (g_memory_settings_backend_parent_class)->finalize (object);
}
static void
-g_memory_settings_backend_init (GMemorySettingsBackend *memory)
+g_memory_settings_backend_init (GMemorySettingsBackend *self)
{
- memory->table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) g_variant_unref);
+ self->database = g_settings_backend_changeset_new_database (NULL);
+ g_mutex_init (&self->lock);
}
static void
@@ -163,12 +125,9 @@ g_memory_settings_backend_class_init (GMemorySettingsBackendClass *class)
GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
- backend_class->read = g_memory_settings_backend_read;
+ backend_class->read_value = g_memory_settings_backend_read_value;
backend_class->write = g_memory_settings_backend_write;
- backend_class->write_tree = g_memory_settings_backend_write_tree;
- backend_class->reset = g_memory_settings_backend_reset;
- backend_class->get_writable = g_memory_settings_backend_get_writable;
- backend_class->get_permission = g_memory_settings_backend_get_permission;
+ backend_class->write_changeset = g_memory_settings_backend_write_changeset;
object_class->finalize = g_memory_settings_backend_finalize;
}
diff --git a/gio/gregistrysettingsbackend.c b/gio/gregistrysettingsbackend.c
index 922a9ea..0a45cb1 100644
--- a/gio/gregistrysettingsbackend.c
+++ b/gio/gregistrysettingsbackend.c
@@ -1100,22 +1100,6 @@ g_registry_backend_reset (GSettingsBackend *backend,
g_settings_backend_changed (backend, key_name, origin_tag);
}
-/* Not implemented and probably beyond the scope of this backend */
-static gboolean
-g_registry_backend_get_writable (GSettingsBackend *backend,
- const gchar *key_name)
-{
- return TRUE;
-}
-
-static GPermission *
-g_registry_backend_get_permission (GSettingsBackend *backend,
- const gchar *key_name)
-{
- return g_simple_permission_new (TRUE);
-}
-
-
/********************************************************************************
* Spot-the-difference engine
********************************************************************************/
diff --git a/gio/gsettings.c b/gio/gsettings.c
index e421e0c..609f22c 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1155,10 +1155,8 @@ g_settings_read_from_backend (GSettings *settings,
gchar *path;
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);
+ value = g_settings_backend_read_value (settings->priv->backend, path, key->type,
+ NULL, user_value_only, default_value);
g_free (path);
if (value != NULL)
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index cf14fb3..960376a 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -518,124 +518,25 @@ g_settings_backend_path_writable_changed (GSettingsBackend *backend,
path, NULL, NULL);
}
-typedef struct
-{
- const gchar **keys;
- GVariant **values;
- gint prefix_len;
- gchar *prefix;
-} FlattenState;
-
-static gboolean
-g_settings_backend_flatten_one (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- FlattenState *state = user_data;
- const gchar *skey = key;
- gint i;
-
- g_return_val_if_fail (is_key (key), TRUE);
-
- /* calculate longest common prefix */
- if (state->prefix == NULL)
- {
- gchar *last_byte;
-
- /* first key? just take the prefix up to the last '/' */
- state->prefix = g_strdup (skey);
- last_byte = strrchr (state->prefix, '/') + 1;
- state->prefix_len = last_byte - state->prefix;
- *last_byte = '\0';
- }
- else
- {
- /* find the first character that does not match. we will
- * definitely find one because the prefix ends in '/' and the key
- * does not. also: no two keys in the tree are the same.
- */
- for (i = 0; state->prefix[i] == skey[i]; i++);
-
- /* check if we need to shorten the prefix */
- if (state->prefix[i] != '\0')
- {
- /* find the nearest '/', terminate after it */
- while (state->prefix[i - 1] != '/')
- i--;
-
- state->prefix[i] = '\0';
- state->prefix_len = i;
- }
- }
-
-
- /* save the entire item into the array.
- * the prefixes will be removed later.
- */
- *state->keys++ = key;
-
- if (state->values)
- *state->values++ = value;
-
- return FALSE;
-}
-
-/**
- * g_settings_backend_flatten_tree:
- * @tree: a #GTree containing the changes
- * @path: (out): the location to save the path
- * @keys: (out) (transfer container) (array zero-terminated=1): the
- * location to save the relative keys
- * @values: (out) (allow-none) (transfer container) (array zero-terminated=1):
- * the location to save the values, or %NULL
- *
- * Calculate the longest common prefix of all keys in a tree and write
- * out an array of the key names relative to that prefix and,
- * optionally, the value to store at each of those keys.
- *
- * You must free the value returned in @path, @keys and @values using
- * g_free(). You should not attempt to free or unref the contents of
- * @keys or @values.
- *
- * Since: 2.26
- **/
void
g_settings_backend_flatten_tree (GTree *tree,
gchar **path,
const gchar ***keys,
GVariant ***values)
{
- FlattenState state = { 0, };
- gsize nnodes;
-
- nnodes = g_tree_nnodes (tree);
-
- *keys = state.keys = g_new (const gchar *, nnodes + 1);
- state.keys[nnodes] = NULL;
-
- if (values != NULL)
- {
- *values = state.values = g_new (GVariant *, nnodes + 1);
- state.values[nnodes] = NULL;
- }
-
- g_tree_foreach (tree, g_settings_backend_flatten_one, &state);
- g_return_if_fail (*keys + nnodes == state.keys);
-
- *path = state.prefix;
- while (nnodes--)
- *--state.keys += state.prefix_len;
+ g_assert_not_reached ();
}
/**
- * g_settings_backend_changed_tree:
+ * g_settings_backend_changeset_applied:
* @backend: a #GSettingsBackend implementation
- * @tree: a #GTree containing the changes
+ * @changeset: the #GSettingsBackendChangeset corresponding to the change
* @origin_tag: the origin tag
*
* This call is a convenience wrapper. It gets the list of changes from
- * @tree, computes the longest common prefix and calls
- * g_settings_backend_changed().
+ * the changeset and emits the correct set of change signals. If the
+ * changeset is not already sealed, then calling this function will seal
+ * it.
*
* Since: 2.26
**/
@@ -644,36 +545,39 @@ g_settings_backend_changed_tree (GSettingsBackend *backend,
GTree *tree,
gpointer origin_tag)
{
- const gchar **keys;
- gchar *path;
+ g_assert_not_reached ();
+}
- g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
- g_settings_backend_flatten_tree (tree, &path, &keys, NULL);
+void
+g_settings_backend_changeset_applied (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
+{
+ const gchar * const *paths;
+ const gchar *prefix;
+ guint n_items;
+
+ g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
-#ifdef DEBUG_CHANGES
- {
- gint i;
+ n_items = g_settings_backend_changeset_describe (changeset, &prefix, &paths, NULL);
- g_print ("----\n");
- g_print ("changed_tree(): prefix %s\n", path);
- for (i = 0; keys[i]; i++)
- g_print (" %s\n", keys[i]);
- g_print ("----\n");
- }
-#endif
+ if (n_items == 1)
+ {
+ g_assert (paths[0][0] == '\0');
+ g_settings_backend_changed (backend, prefix, origin_tag);
+ }
- g_settings_backend_keys_changed (backend, path, keys, origin_tag);
- g_free (path);
- g_free (keys);
+ else if (n_items > 1)
+ g_settings_backend_keys_changed (backend, prefix, paths, origin_tag);
}
/*< private >
- * g_settings_backend_read:
+ * g_settings_backend_read_value:
* @backend: a #GSettingsBackend implementation
* @key: the key to read
* @expected_type: a #GVariantType
- * @default_value: if the default value should be returned
+ * @read_through: a #GQueue of #GSettingsBackendChangeset
*
* Reads a key. This call will never block.
*
@@ -684,22 +588,30 @@ g_settings_backend_changed_tree (GSettingsBackend *backend,
* the backend stored a value of a different type then %NULL will be
* returned.
*
- * If @default_value is %TRUE then this gets the default value from the
- * backend (ie: the one that the backend would contain if
- * g_settings_reset() were called).
+ * If @read_through is given then the read is performed as if the
+ * changesets in the queue had first been applied to the underlying
+ * backend. @read_through may be modified during the duration of this
+ * call but it will be returned to its original value before the call
+ * returns.
+ *
+ * Unlike the backend vfuncs, this function will always return a value
+ * of the correct type. If the backend returned an incorrect type then
+ * this function will return %NULL.
*
* Returns: the value that was read, or %NULL
*/
GVariant *
-g_settings_backend_read (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type,
- gboolean default_value)
+g_settings_backend_read_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type,
+ GQueue *read_through,
+ gboolean user_value_only,
+ gboolean default_value)
{
GVariant *value;
- value = G_SETTINGS_BACKEND_GET_CLASS (backend)
- ->read (backend, key, expected_type, default_value);
+ value = G_SETTINGS_BACKEND_GET_CLASS (backend)->read_value (backend, key, expected_type,
+ read_through, user_value_only, default_value);
if (value != NULL)
value = g_variant_take_ref (value);
@@ -790,20 +702,14 @@ g_settings_backend_write (GSettingsBackend *backend,
/*< private >
* g_settings_backend_write_tree:
* @backend: a #GSettingsBackend implementation
- * @tree: a #GTree containing key-value pairs to write
+ * @changeset: a #GSettingsBackendChangeset containing the change
* @origin_tag: the origin tag
*
* Writes one or more keys. This call will never block.
*
- * The key of each item in the tree is the key name to write to and the
- * value is a #GVariant to write. The proper type of #GTree for this
- * call can be created with g_settings_backend_create_tree(). This call
- * might take a reference to the tree; you must not modified the #GTree
- * after passing it to this call.
- *
- * This call does not fail. During this call a #GSettingsBackend::changed
- * signal will be emitted if any keys have been changed. The new values of
- * all updated keys will be visible to any signal callbacks.
+ * During this call a #GSettingsBackend::changed signal will be emitted
+ * if any keys have been changed. The new values of all updated keys
+ * will be visible to any signal callbacks.
*
* One possible method that an implementation might deal with failures is
* to emit a second "changed" signal (either during this call, or later)
@@ -811,12 +717,11 @@ g_settings_backend_write (GSettingsBackend *backend,
* old values.
*/
gboolean
-g_settings_backend_write_tree (GSettingsBackend *backend,
- GTree *tree,
- gpointer origin_tag)
+g_settings_backend_write_changeset (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
{
- return G_SETTINGS_BACKEND_GET_CLASS (backend)
- ->write_tree (backend, tree, origin_tag);
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)->write_changeset (backend, changeset, origin_tag);
}
/*< private >
@@ -891,6 +796,94 @@ g_settings_backend_subscribe (GSettingsBackend *backend,
->subscribe (backend, name);
}
+static GVariant *
+g_settings_backend_real_read_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type,
+ GQueue *read_through,
+ gboolean user_value_only,
+ gboolean default_value)
+{
+ GVariant *value = NULL;
+
+ if (default_value)
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)->read (backend, key, expected_type, TRUE);
+
+ if (g_settings_backend_check_changeset_queue (read_through, key, &value))
+ return value;
+
+ if (user_value_only)
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)->read_user_value (backend, key, expected_type);
+
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)->read (backend, key, expected_type, FALSE);
+}
+
+static gboolean
+g_settings_backend_real_write (GSettingsBackend *backend,
+ const gchar *key,
+ GVariant *value,
+ gpointer origin_tag)
+{
+ GSettingsBackendChangeset *changeset;
+ gboolean success;
+
+ changeset = g_settings_backend_changeset_new_write (key, value);
+ success = g_settings_backend_write_changeset (backend, changeset, origin_tag);
+ g_settings_backend_changeset_unref (changeset);
+
+ return success;
+}
+
+static void
+g_settings_backend_real_reset (GSettingsBackend *backend,
+ const gchar *key,
+ gpointer origin_tag)
+{
+ gboolean success;
+
+ success = g_settings_backend_real_write (backend, key, NULL, origin_tag);
+
+ if (!success)
+ g_critical ("%s is behaving incorrectly: reset() must always succeed",
+ g_type_name (G_TYPE_FROM_INSTANCE (backend)));
+}
+
+static gboolean
+add_to_tree (const gchar *key,
+ GVariant *value,
+ gpointer user_data)
+{
+ g_tree_insert (user_data, (gpointer) key, value);
+
+ return TRUE;
+}
+
+static gboolean
+g_settings_backend_real_write_changeset (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changeset,
+ gpointer origin_tag)
+{
+ gboolean success;
+ GTree *tree;
+
+ tree = g_tree_new ((GCompareFunc) strcmp);
+
+ g_settings_backend_changeset_all (changeset, add_to_tree, tree);
+
+ success = G_SETTINGS_BACKEND_GET_CLASS (backend)->write_tree (backend, tree, origin_tag);
+
+ g_tree_unref (tree);
+
+ return success;
+}
+
+static gboolean
+g_settings_backend_real_get_writable (GSettingsBackend *backend,
+ const gchar *key)
+{
+ return TRUE;
+}
+
static void
g_settings_backend_finalize (GObject *object)
{
@@ -908,14 +901,6 @@ ignore_subscription (GSettingsBackend *backend,
{
}
-static GVariant *
-g_settings_backend_real_read_user_value (GSettingsBackend *backend,
- const gchar *key,
- const GVariantType *expected_type)
-{
- return g_settings_backend_read (backend, key, expected_type, FALSE);
-}
-
static void
g_settings_backend_init (GSettingsBackend *backend)
{
@@ -928,37 +913,17 @@ g_settings_backend_class_init (GSettingsBackendClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ class->reset = g_settings_backend_real_reset;
+ class->write = g_settings_backend_real_write;
+ class->write_changeset = g_settings_backend_real_write_changeset;
+ class->read_value = g_settings_backend_real_read_value;
+ class->get_writable = g_settings_backend_real_get_writable;
class->subscribe = ignore_subscription;
class->unsubscribe = ignore_subscription;
- class->read_user_value = g_settings_backend_real_read_user_value;
-
gobject_class->finalize = g_settings_backend_finalize;
}
-static void
-g_settings_backend_variant_unref0 (gpointer data)
-{
- if (data != NULL)
- g_variant_unref (data);
-}
-
-/*< private >
- * g_settings_backend_create_tree:
- *
- * This is a convenience function for creating a tree that is compatible
- * with g_settings_backend_write(). It merely calls g_tree_new_full()
- * with strcmp(), g_free() and g_variant_unref().
- *
- * Returns: a new #GTree
- */
-GTree *
-g_settings_backend_create_tree (void)
-{
- return g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
- g_free, g_settings_backend_variant_unref0);
-}
-
static gboolean
g_settings_backend_verify (gpointer impl)
{
@@ -1000,31 +965,6 @@ g_settings_backend_get_default (void)
}
/*< private >
- * g_settings_backend_get_permission:
- * @backend: a #GSettingsBackend
- * @path: a path
- *
- * Gets the permission object associated with writing to keys below
- * @path on @backend.
- *
- * If this is not implemented in the backend, then a %TRUE
- * #GSimplePermission is returned.
- *
- * Returns: a non-%NULL #GPermission. Free with g_object_unref()
- */
-GPermission *
-g_settings_backend_get_permission (GSettingsBackend *backend,
- const gchar *path)
-{
- GSettingsBackendClass *class = G_SETTINGS_BACKEND_GET_CLASS (backend);
-
- if (class->get_permission)
- return class->get_permission (backend, path);
-
- return g_simple_permission_new (TRUE);
-}
-
-/*< private >
* g_settings_backend_sync_default:
*
* Syncs the default backend.
@@ -1131,3 +1071,20 @@ g_settings_backend_is_dir (const gchar *string)
return TRUE;
}
+
+gboolean
+g_settings_backend_check_changeset_queue (const GQueue *queue,
+ const gchar *key,
+ GVariant **value)
+{
+ GList *link;
+
+ if (queue == NULL)
+ return FALSE;
+
+ for (link = queue->tail; link; link = link->prev)
+ if (g_settings_backend_changeset_get (link->data, key, value))
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h
index f43ff87..2c9a60b 100644
--- a/gio/gsettingsbackend.h
+++ b/gio/gsettingsbackend.h
@@ -66,6 +66,14 @@ typedef struct _GSettingsBackendClass GSettingsBackendClas
*/
typedef struct _GSettingsBackendChangeset GSettingsBackendChangeset;
+
+typedef enum
+{
+ G_SETTINGS_BACKEND_READ_FLAGS_NONE = 0,
+ G_SETTINGS_BACKEND_READ_DEFAULT_VALUE = (1u << 0),
+ G_SETTINGS_BACKEND_READ_USER_VALUE = (1u << 1)
+} GSettingsBackendReadFlags;
+
/**
* GSettingsBackendClass:
* @read: virtual method to read a key's value
@@ -117,8 +125,23 @@ struct _GSettingsBackendClass
const gchar *key,
const GVariantType *expected_type);
+ /* "new" GSettingsBackendChangeset-enabled API (since 2.48) */
+ GVariant * (*read_simple) (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type);
+
+ GVariant * (*read_value) (GSettingsBackend *backend,
+ const gchar *key,
+ GSettingsBackendReadFlags flags,
+ GQueue *read_through,
+ const GVariantType *expected_type);
+
+ gboolean (*write_changeset) (GSettingsBackend *backend,
+ GSettingsBackendChangeset *changes,
+ gpointer origin_tag);
+
/*< private >*/
- gpointer padding[23];
+ gpointer padding[20];
};
struct _GSettingsBackend
@@ -161,6 +184,10 @@ GLIB_AVAILABLE_IN_ALL
void g_settings_backend_changed_tree (GSettingsBackend *backend,
GTree *tree,
gpointer origin_tag);
+GLIB_AVAILABLE_IN_2_48
+void g_settings_backend_changeset_applied (GSettingsBackend *backend,
+ GSettingsBackendChangeset
*changeset,
+ gpointer origin_tag);
GLIB_AVAILABLE_IN_ALL
GSettingsBackend * g_settings_backend_get_default (void);
@@ -176,6 +203,7 @@ GSettingsBackend * g_null_settings_backend_new (void);
GLIB_AVAILABLE_IN_ALL
GSettingsBackend * g_memory_settings_backend_new (void);
+
GLIB_AVAILABLE_IN_2_48
gboolean g_settings_backend_is_path (const gchar *string);
GLIB_AVAILABLE_IN_2_48
@@ -246,6 +274,12 @@ GSettingsBackendChangeset * g_settings_backend_changeset_diff
GLIB_AVAILABLE_IN_2_48
void g_settings_backend_changeset_seal (GSettingsBackendChangeset
*changeset);
+GLIB_AVAILABLE_IN_2_48
+gboolean g_settings_backend_check_changeset_queue (const GQueue
*queue,
+ const gchar
*key,
+ GSettingsBackendReadFlags
flags,
+ GVariant
**value);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSettingsBackend, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSettingsBackendChangeset, g_settings_backend_changeset_unref)
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
index eef4c7a..146e5fc 100644
--- a/gio/gsettingsbackendinternal.h
+++ b/gio/gsettingsbackendinternal.h
@@ -54,11 +54,11 @@ void g_settings_backend_watch (GSettin
void g_settings_backend_unwatch (GSettingsBackend
*backend,
GObject
*target);
-GTree * g_settings_backend_create_tree (void);
-
-GVariant * g_settings_backend_read (GSettingsBackend
*backend,
+GVariant * g_settings_backend_read_value (GSettingsBackend
*backend,
const gchar *key,
const GVariantType
*expected_type,
+ GQueue
*read_through,
+ gboolean
user_value_only,
gboolean
default_value);
GVariant * g_settings_backend_read_user_value (GSettingsBackend
*backend,
const gchar *key,
@@ -67,8 +67,8 @@ gboolean g_settings_backend_write (GSettin
const gchar *key,
GVariant
*value,
gpointer
origin_tag);
-gboolean g_settings_backend_write_tree (GSettingsBackend
*backend,
- GTree
*tree,
+gboolean g_settings_backend_write_changeset (GSettingsBackend
*backend,
+ GSettingsBackendChangeset
*changeset,
gpointer
origin_tag);
void g_settings_backend_reset (GSettingsBackend
*backend,
const gchar *key,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]