[glib/wip/gsettingsbackendchangeset: 5/5] more stuff



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]