summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2012-11-08 12:50:22 -0500
committerRyan Lortie <desrt@desrt.ca>2012-11-08 13:44:01 -0500
commita088be7c43575620309c952798c8c40cd3fa1f20 (patch)
tree337dd1a42e33b9844da50e4a6dc336dd8e97e23b
parent19bca1d807d47b7b28f1343aa7ed980ddc6cbe96 (diff)
downloaddconf-a088be7c43575620309c952798c8c40cd3fa1f20.tar.gz
DConfChangeset: add "database mode" and change()
Add a new mode for DConfChangeset to represent the entire contents of a dconf database. Also add a dconf_changeset_change() call to either merge changesets or apply a changeset to a database-mode changeset. Doing this allows us to have only one instance of the algorithm to deal with resets (ie: when resetting '/a/' we must reset all keys starting with '/a/').
-rw-r--r--common/dconf-changeset.c131
-rw-r--r--common/dconf-changeset.h4
2 files changed, 131 insertions, 4 deletions
diff --git a/common/dconf-changeset.c b/common/dconf-changeset.c
index a5c98da..4c56b93 100644
--- a/common/dconf-changeset.c
+++ b/common/dconf-changeset.c
@@ -54,6 +54,7 @@
struct _DConfChangeset
{
GHashTable *table;
+ gboolean is_database;
gint ref_count;
gchar *prefix;
@@ -88,6 +89,57 @@ dconf_changeset_new (void)
}
/**
+ * dconf_changeset_new_database:
+ * @copy_of: (allow none): a #DConfChangeset to copy
+ *
+ * Creates a new #DConfChangeset in "database" mode, possibly
+ * initialising it with the values of another changeset.
+ *
+ * In a certain sense it's possible to imagine that a #DConfChangeset
+ * could express the contents of an entire dconf database -- the
+ * contents are the database are what you would have if you applied the
+ * changeset to an empty database. One thing that fails to map in this
+ * analogy are reset operations -- if we start with an empty database
+ * then reset operations are meaningless.
+ *
+ * A "database" mode changeset is therefore a changeset which is
+ * incapable of containing reset operations.
+ *
+ * It is not permitted to use a database-mode changeset for most
+ * operations (such as the @change argument to dconf_changeset_change()
+ * or the @changeset argument to #DConfClient APIs).
+ *
+ * If @copy_of is non-%NULL then its contents will be copied into the
+ * created changeset. @copy_of must be a database-mode changeset.
+ *
+ * Returns: a new #DConfChangeset in "database" mode
+ *
+ * Since: 0.16
+ */
+DConfChangeset *
+dconf_changeset_new_database (DConfChangeset *copy_of)
+{
+ DConfChangeset *changeset;
+
+ g_return_val_if_fail (copy_of == NULL || copy_of->is_database, NULL);
+
+ changeset = dconf_changeset_new ();
+ changeset->is_database = TRUE;
+
+ if (copy_of)
+ {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, copy_of->table);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ g_hash_table_insert (changeset->table, g_strdup (key), g_variant_ref (value));
+ }
+
+ return changeset;
+}
+
+/**
* dconf_changeset_unref:
* @changeset: a #DConfChangeset
*
@@ -162,13 +214,26 @@ dconf_changeset_set (DConfChangeset *changeset,
if (g_str_has_prefix (key, path))
g_hash_table_iter_remove (&iter);
- /* Record the reset itself. */
- g_hash_table_insert (changeset->table, g_strdup (path), NULL);
+ /* If this is a non-database then record the reset itself. */
+ if (!changeset->is_database)
+ g_hash_table_insert (changeset->table, g_strdup (path), NULL);
+ }
+
+ /* ...or a value reset */
+ else if (value == NULL)
+ {
+ /* If we're a non-database, record the reset explicitly.
+ * Otherwise, just reset whatever may be there already.
+ */
+ if (!changeset->is_database)
+ g_hash_table_insert (changeset->table, g_strdup (path), NULL);
+ else
+ g_hash_table_remove (changeset->table, path);
}
- /* else, just a normal value write or reset */
+ /* ...or a normal write. */
else
- g_hash_table_insert (changeset->table, g_strdup (path), value ? g_variant_ref_sink (value) : NULL);
+ g_hash_table_insert (changeset->table, g_strdup (path), g_variant_ref_sink (value));
}
/**
@@ -574,3 +639,61 @@ dconf_changeset_is_empty (DConfChangeset *changeset)
{
return !g_hash_table_size (changeset->table);
}
+
+/**
+ * dconf_changeset_change:
+ * @changeset: a #DConfChangeset (to be changed)
+ * @changes: the changes to make to @changeset
+ *
+ * Applies @changes to @changeset.
+ *
+ * If @changeset is a normal changeset then reset requests in @changes
+ * will be allied to @changeset and then copied down into it. In this
+ * case the two changesets are effectively being merged.
+ *
+ * If @changeset is in database mode then the reset operations in
+ * @changes will simply be applied to @changeset.
+ *
+ * Since: 0.16
+ **/
+void
+dconf_changeset_change (DConfChangeset *changeset,
+ DConfChangeset *changes)
+{
+ gsize prefix_len;
+ gint i;
+
+ /* Handling resets is a little bit tricky...
+ *
+ * Consider the case that we have @changeset containing a key /a/b and
+ * @changes containing a reset request for /a/ and a set request for
+ * /a/c.
+ *
+ * It's clear that at the end of this all, we should have only /a/c
+ * but in order for that to be the case, we need to make sure that we
+ * process the reset of /a/ before we process the set of /a/c.
+ *
+ * The easiest way to do this is to visit the strings in sorted order.
+ * That removes the possibility of iterating over the hash table, but
+ * dconf_changeset_build_description() makes the list in the order we
+ * need so just call it and then iterate over the result.
+ */
+
+ if (!dconf_changeset_describe (changes, NULL, NULL, NULL))
+ return;
+
+ prefix_len = strlen (changes->prefix);
+ for (i = 0; changes->paths[i]; i++)
+ {
+ const gchar *path;
+ GVariant *value;
+
+ /* The changes->paths are just pointers into the keys of the
+ * hashtable, fast-forwarded past the prefix. Rewind a bit.
+ */
+ path = changes->paths[i] - prefix_len;
+ value = changes->values[i];
+
+ dconf_changeset_set (changeset, path, value);
+ }
+}
diff --git a/common/dconf-changeset.h b/common/dconf-changeset.h
index 1aecabe..eb8dde1 100644
--- a/common/dconf-changeset.h
+++ b/common/dconf-changeset.h
@@ -31,6 +31,7 @@ typedef gboolean (* DConfChangesetPredicate) (const g
gpointer user_data);
DConfChangeset * dconf_changeset_new (void);
+DConfChangeset * dconf_changeset_new_database (DConfChangeset *copy_of);
DConfChangeset * dconf_changeset_new_write (const gchar *path,
GVariant *value);
@@ -63,4 +64,7 @@ guint dconf_changeset_describe (DConfCh
GVariant * dconf_changeset_serialise (DConfChangeset *changeset);
DConfChangeset * dconf_changeset_deserialise (GVariant *serialised);
+void dconf_changeset_change (DConfChangeset *changeset,
+ DConfChangeset *changes);
+
#endif /* __dconf_changeset_h__ */