[glib/wip/gsettingsbackendchangeset: 189/191] GSettingsBackend: transition to changesets



commit 82d582270c844e7975f6f36bf88aff6fa8538308
Author: Allison Ryan Lortie <desrt desrt ca>
Date:   Mon Apr 25 14:57:16 2016 +0200

    GSettingsBackend: transition to changesets
    
    Refactor GSettingsBackend to prefer GSettingsBackendChangeset over
    GTree.  Add a new write API based on changesets.
    
    Change our own internal users of this API (really:
    GDelayedSettingsBackend) to use changesets instead of trees.
    
    While we're at it, introduce a 'read_value' API that takes a
    read_through parameter that is a GQueue of changesets.  This is how
    dconf works internally and the other backends will be adapted to that
    soon.  Also add a 'read_simple' API that will useful for trivial
    backends like memory and keyfile as an alternative to implementing the
    full-blown 'read_value' API.
    
    We still leave in place support for backends that implement the old
    API.  If the new vfuncs have not been implemented then we will shim over
    to the old functions (possibly converting to a tree in the process).

 gio/gdelayedsettingsbackend.c  |  469 ++++++++++++++--------------------------
 gio/gdelayedsettingsbackend.h  |   35 +---
 gio/gsettings.c                |   28 +--
 gio/gsettingsbackend.c         |  307 ++++++++++++++++++--------
 gio/gsettingsbackend.h         |   39 ++++-
 gio/gsettingsbackendinternal.h |   14 +-
 6 files changed, 442 insertions(+), 450 deletions(-)
---
diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c
index 22a42eb..917ca9a 100644
--- a/gio/gdelayedsettingsbackend.c
+++ b/gio/gdelayedsettingsbackend.c
@@ -25,107 +25,116 @@
 #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,
+                                       GSettingsBackendReadFlags  flags,
+                                       GQueue                    *read_through,
+                                       const GVariantType        *expected_type)
 {
-  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, flags, read_through, expected_type);
+    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 +143,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 +190,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 +199,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 +269,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 +281,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 +292,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 +302,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 +330,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 +360,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/gsettings.c b/gio/gsettings.c
index e421e0c..cb0852e 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1145,20 +1145,16 @@ g_settings_write_to_backend (GSettings          *settings,
 }
 
 static GVariant *
-g_settings_read_from_backend (GSettings          *settings,
-                              GSettingsSchemaKey *key,
-                              gboolean            user_value_only,
-                              gboolean            default_value)
+g_settings_read_from_backend (GSettings                 *settings,
+                              GSettingsSchemaKey        *key,
+                              GSettingsBackendReadFlags  flags)
 {
   GVariant *value;
   GVariant *fixup;
   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, flags, NULL, key->type);
   g_free (path);
 
   if (value != NULL)
@@ -1198,7 +1194,7 @@ g_settings_get_value (GSettings   *settings,
   g_return_val_if_fail (key != NULL, NULL);
 
   g_settings_schema_key_init (&skey, settings->priv->schema, key);
-  value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
+  value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_FLAGS_NONE);
 
   if (value == NULL)
     value = g_settings_schema_key_get_translated_default (&skey);
@@ -1250,7 +1246,7 @@ g_settings_get_user_value (GSettings   *settings,
   g_return_val_if_fail (key != NULL, NULL);
 
   g_settings_schema_key_init (&skey, settings->priv->schema, key);
-  value = g_settings_read_from_backend (settings, &skey, TRUE, FALSE);
+  value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_USER_VALUE);
   g_settings_schema_key_clear (&skey);
 
   return value;
@@ -1298,7 +1294,7 @@ g_settings_get_default_value (GSettings   *settings,
   g_return_val_if_fail (key != NULL, NULL);
 
   g_settings_schema_key_init (&skey, settings->priv->schema, key);
-  value = g_settings_read_from_backend (settings, &skey, FALSE, TRUE);
+  value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_DEFAULT_VALUE);
 
   if (value == NULL)
     value = g_settings_schema_key_get_translated_default (&skey);
@@ -1354,7 +1350,7 @@ g_settings_get_enum (GSettings   *settings,
       return -1;
     }
 
-  value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
+  value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_FLAGS_NONE);
 
   if (value == NULL)
     value = g_settings_schema_key_get_translated_default (&skey);
@@ -1467,7 +1463,7 @@ g_settings_get_flags (GSettings   *settings,
       return -1;
     }
 
-  value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
+  value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_FLAGS_NONE);
 
   if (value == NULL)
     value = g_settings_schema_key_get_translated_default (&skey);
@@ -1732,7 +1728,7 @@ g_settings_get_mapped (GSettings           *settings,
 
   g_settings_schema_key_init (&skey, settings->priv->schema, key);
 
-  if ((value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE)))
+  if ((value = g_settings_read_from_backend (settings, &skey, G_SETTINGS_BACKEND_READ_FLAGS_NONE)))
     {
       okay = mapping (value, &result, user_data);
       g_variant_unref (value);
@@ -2514,7 +2510,7 @@ g_settings_binding_key_changed (GSettings   *settings,
 
   g_value_init (&value, binding->property->value_type);
 
-  variant = g_settings_read_from_backend (binding->settings, &binding->key, FALSE, FALSE);
+  variant = g_settings_read_from_backend (binding->settings, &binding->key, 
G_SETTINGS_BACKEND_READ_FLAGS_NONE);
   if (variant && !binding->get_mapping (&value, variant, binding->user_data))
     {
       /* silently ignore errors in the user's config database */
@@ -3060,7 +3056,7 @@ g_settings_action_get_state (GAction *action)
   GSettingsAction *gsa = (GSettingsAction *) action;
   GVariant *value;
 
-  value = g_settings_read_from_backend (gsa->settings, &gsa->key, FALSE, FALSE);
+  value = g_settings_read_from_backend (gsa->settings, &gsa->key, G_SETTINGS_BACKEND_READ_FLAGS_NONE);
 
   if (value == NULL)
     value = g_settings_schema_key_get_translated_default (&gsa->key);
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index cf14fb3..43a350b 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -668,75 +668,80 @@ g_settings_backend_changed_tree (GSettingsBackend *backend,
   g_free (keys);
 }
 
-/*< private >
- * g_settings_backend_read:
+/**
+ * g_settings_backend_changeset_applied:
  * @backend: a #GSettingsBackend implementation
- * @key: the key to read
- * @expected_type: a #GVariantType
- * @default_value: if the default value should be returned
- *
- * Reads a key. This call will never block.
- *
- * If the key exists, the value associated with it will be returned.
- * If the key does not exist, %NULL will be returned.
- *
- * The returned value will be of the type given in @expected_type.  If
- * the backend stored a value of a different type then %NULL will be
- * returned.
+ * @changeset: the #GSettingsBackendChangeset corresponding to the change
+ * @origin_tag: the origin tag
  *
- * 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).
+ * This call is a convenience wrapper.  It gets the list of changes from
+ * the changeset and emits the correct set of change signals.  If the
+ * changeset is not already sealed, then calling this function will seal
+ * it.
  *
- * 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)
+ * Since: 2.26
+ **/
+void
+g_settings_backend_changeset_applied (GSettingsBackend          *backend,
+                                      GSettingsBackendChangeset *changeset,
+                                      gpointer                   origin_tag)
 {
-  GVariant *value;
+  const gchar * const *paths;
+  const gchar *prefix;
+  guint n_items;
 
-  value = G_SETTINGS_BACKEND_GET_CLASS (backend)
-    ->read (backend, key, expected_type, default_value);
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
 
-  if (value != NULL)
-    value = g_variant_take_ref (value);
+  n_items = g_settings_backend_changeset_describe (changeset, &prefix, &paths, NULL);
 
-  if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type))
+  if (n_items == 1)
     {
-      g_variant_unref (value);
-      value = NULL;
+      g_assert (paths[0][0] == '\0');
+      g_settings_backend_changed (backend, prefix, origin_tag);
     }
 
-  return value;
+  else if (n_items > 1)
+    g_settings_backend_keys_changed (backend, prefix, paths, origin_tag);
 }
 
 /*< private >
- * g_settings_backend_read_user_value:
+ * g_settings_backend_read_value:
  * @backend: a #GSettingsBackend implementation
  * @key: the key to read
  * @expected_type: a #GVariantType
+ * @read_through: a #GQueue of #GSettingsBackendChangeset
+ *
+ * Reads a key. This call will never block.
+ *
+ * If the key exists, the value associated with it will be returned.
+ * If the key does not exist, %NULL will be returned.
+ *
+ * The returned value will be of the type given in @expected_type.  If
+ * the backend stored a value of a different type then %NULL will be
+ * returned.
  *
- * Reads the 'user value' of a key.
+ * 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.
  *
- * This is the value of the key that the user has control over and has
- * set for themselves.  Put another way: if the user did not set the
- * value for themselves, then this will return %NULL (even if the
- * sysadmin has provided a default value).
+ * 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_user_value (GSettingsBackend   *backend,
-                                    const gchar        *key,
-                                    const GVariantType *expected_type)
+g_settings_backend_read_value (GSettingsBackend          *backend,
+                               const gchar               *key,
+                               GSettingsBackendReadFlags  flags,
+                               GQueue                    *read_through,
+                               const GVariantType        *expected_type)
 {
   GVariant *value;
 
-  value = G_SETTINGS_BACKEND_GET_CLASS (backend)
-    ->read_user_value (backend, key, expected_type);
+  value = G_SETTINGS_BACKEND_GET_CLASS (backend)->read_value (backend, key, flags, read_through, 
expected_type);
 
   if (value != NULL)
     value = g_variant_take_ref (value);
@@ -788,22 +793,16 @@ g_settings_backend_write (GSettingsBackend *backend,
 }
 
 /*< private >
- * g_settings_backend_write_tree:
+ * g_settings_backend_write_changeset:
  * @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 +810,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 +889,128 @@ g_settings_backend_subscribe (GSettingsBackend *backend,
     ->subscribe (backend, name);
 }
 
+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 GVariant *
+g_settings_backend_real_read_simple (GSettingsBackend          *backend,
+                                     const gchar               *key,
+                                     const GVariantType        *expected_type)
+{
+  return G_SETTINGS_BACKEND_GET_CLASS (backend)->read (backend, key, expected_type, FALSE);
+}
+
+static GVariant *
+g_settings_backend_real_read_value (GSettingsBackend          *backend,
+                                    const gchar               *key,
+                                    GSettingsBackendReadFlags  flags,
+                                    GQueue                    *read_through,
+                                    const GVariantType        *expected_type)
+{
+  GSettingsBackendClass *class = G_SETTINGS_BACKEND_GET_CLASS (backend);
+  GVariant *value = NULL;
+
+  /*
+   * If the class is implementing read_simple then we're handling this
+   * in the new way with a simple backend.
+   *
+   * Otherwise, it's an old backend that hasn't been ported to the new
+   * API and we need to shim it over to the old vfuncs, depending on the
+   * flags.
+   */
+  if (class->read_simple)
+    {
+      if (flags & G_SETTINGS_BACKEND_READ_DEFAULT_VALUE)
+        return NULL;
+
+      if (g_settings_backend_check_changeset_queue (read_through, key, flags, &value))
+        return value;
+
+      return (* class->read_simple) (backend, key, expected_type);
+    }
+  else
+    {
+      if (flags & G_SETTINGS_BACKEND_READ_DEFAULT_VALUE)
+        return (* class->read) (backend, key, expected_type, TRUE);
+
+      if (g_settings_backend_check_changeset_queue (read_through, key, flags, &value))
+        return value;
+
+      if (flags & G_SETTINGS_BACKEND_READ_USER_VALUE)
+        return (* class->read_user_value) (backend, key, expected_type);
+
+      return (* class->read) (backend, key, expected_type, FALSE);
+    }
+}
+
+static gboolean
+g_settings_backend_real_write_changeset (GSettingsBackend          *backend,
+                                         GSettingsBackendChangeset *changeset,
+                                         gpointer                   origin_tag)
+{
+  gboolean success;
+  GTree *tree;
+
+  g_settings_backend_changeset_seal (changeset);
+
+  /* Don't bother memory-management in the tree -- everything here is
+   * owned by the changeset, which has been sealed.
+   */
+  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 +1028,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)
 {
@@ -923,42 +1035,34 @@ g_settings_backend_init (GSettingsBackend *backend)
   g_mutex_init (&backend->priv->lock);
 }
 
+static GVariant *
+g_settings_backend_real_read_user_value (GSettingsBackend   *backend,
+                                         const gchar        *key,
+                                         const GVariantType *expected_type)
+{
+  return G_SETTINGS_BACKEND_GET_CLASS (backend)->read (backend, key, expected_type, FALSE);
+}
+
 static void
 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->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;
+  class->read_value = g_settings_backend_real_read_value;
+  class->read_simple = g_settings_backend_real_read_simple;
+  class->write_changeset = g_settings_backend_real_write_changeset;
 
   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)
 {
@@ -1131,3 +1235,24 @@ g_settings_backend_is_dir (const gchar *string)
 
   return TRUE;
 }
+
+gboolean
+g_settings_backend_check_changeset_queue (const GQueue               *queue,
+                                          const gchar                *key,
+                                          GSettingsBackendReadFlags   flags,
+                                          GVariant                  **value)
+{
+  GList *link;
+
+  if (flags & G_SETTINGS_BACKEND_READ_DEFAULT_VALUE)
+    return FALSE;
+
+  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..537446b 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
@@ -85,6 +93,7 @@ struct _GSettingsBackendClass
 {
   GObjectClass parent_class;
 
+  /* Deprecated.  Implement ::read_value and ::read_simple instead */
   GVariant *    (*read)             (GSettingsBackend    *backend,
                                      const gchar         *key,
                                      const GVariantType  *expected_type,
@@ -97,6 +106,7 @@ struct _GSettingsBackendClass
                                      const gchar         *key,
                                      GVariant            *value,
                                      gpointer             origin_tag);
+  /* Deprecated.  Implement ::write_changeset instead. */
   gboolean      (*write_tree)       (GSettingsBackend    *backend,
                                      GTree               *tree,
                                      gpointer             origin_tag);
@@ -113,12 +123,28 @@ struct _GSettingsBackendClass
   GPermission * (*get_permission)   (GSettingsBackend    *backend,
                                      const gchar         *path);
 
+  /* Deprecated.  Implement ::read_value and ::read_simple instead */
   GVariant *    (*read_user_value)  (GSettingsBackend    *backend,
                                      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 +187,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 +206,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 +277,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..53f2bf7 100644
--- a/gio/gsettingsbackendinternal.h
+++ b/gio/gsettingsbackendinternal.h
@@ -54,21 +54,17 @@ 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,
-                                                                         const gchar                    *key,
-                                                                         const GVariantType             
*expected_type,
-                                                                         gboolean                        
default_value);
-GVariant *              g_settings_backend_read_user_value              (GSettingsBackend               
*backend,
+GVariant *              g_settings_backend_read_value                   (GSettingsBackend               
*backend,
                                                                          const gchar                    *key,
+                                                                         GSettingsBackendReadFlags       
flags,
+                                                                         GQueue                         
*read_through,
                                                                          const GVariantType             
*expected_type);
 gboolean                g_settings_backend_write                        (GSettingsBackend               
*backend,
                                                                          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]