summaryrefslogtreecommitdiff
path: root/common/dconf-changeset.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/dconf-changeset.c')
-rw-r--r--common/dconf-changeset.c100
1 files changed, 85 insertions, 15 deletions
diff --git a/common/dconf-changeset.c b/common/dconf-changeset.c
index c80c88c..cea34c1 100644
--- a/common/dconf-changeset.c
+++ b/common/dconf-changeset.c
@@ -772,6 +772,87 @@ dconf_changeset_change (DConfChangeset *changeset,
}
/**
+ * dconf_changeset_filter_changes:
+ * @base: a database mode changeset
+ * @changes: a changeset
+ *
+ * Produces a changeset that contains all the changes in @changes that
+ * are not already present in @base
+ *
+ * If there are no such changes, %NULL is returned
+ *
+ * Applying the result to @base will yield the same result as applying
+ * @changes to @base
+ *
+ * Returns: (transfer full) (nullable): the minimal changes, or %NULL
+ *
+ * Since: 0.35.1
+ */
+DConfChangeset *
+dconf_changeset_filter_changes (DConfChangeset *base,
+ DConfChangeset *changes)
+{
+ DConfChangeset *result = NULL;
+ GHashTableIter iter_changes;
+ gpointer key, val;
+
+ g_return_val_if_fail (base->is_database, NULL);
+
+ /* We create the list of changes by iterating the 'changes' changeset
+ * and noting any keys that are not in the 'base' changeset or do not
+ * have the same value in the 'base' changeset
+ *
+ * Note: because 'base' is a database changeset we don't have to
+ * worry about it containing NULL values (dir resets).
+ */
+ g_hash_table_iter_init (&iter_changes, changes->table);
+ while (g_hash_table_iter_next (&iter_changes, &key, &val))
+ {
+ GVariant *base_val = g_hash_table_lookup (base->table, key);
+
+ if (g_str_has_suffix (key, "/"))
+ {
+ // Path reset
+ gboolean reset_is_effective = FALSE;
+ GHashTableIter iter_base;
+ gpointer base_key = NULL;
+
+ g_return_val_if_fail (val == NULL, NULL);
+
+ // First we check whether there are any keys in base that would be reset
+ g_hash_table_iter_init (&iter_base, base->table);
+ while (g_hash_table_iter_next (&iter_base, &base_key, NULL))
+ if (g_str_has_prefix (base_key, key) && !g_str_equal (base_key, key))
+ {
+ reset_is_effective = TRUE;
+ break;
+ }
+
+ if (reset_is_effective)
+ {
+ if (!result)
+ result = dconf_changeset_new ();
+
+ dconf_changeset_set (result, key, val);
+ }
+ }
+ else if (base_val == NULL && val == NULL)
+ continue; // Resetting a key that wasn't set
+ else if (val == NULL || base_val == NULL || !g_variant_equal (val, base_val))
+ {
+ // Resetting an existing key, inserting a value under a key that was not
+ // set, or replacing an existing value with a different one.
+ if (!result)
+ result = dconf_changeset_new ();
+
+ dconf_changeset_set (result, key, val);
+ }
+ }
+
+ return result;
+}
+
+/**
* dconf_changeset_diff:
* @from: a database mode changeset
* @to: a database mode changeset
@@ -793,7 +874,7 @@ DConfChangeset *
dconf_changeset_diff (DConfChangeset *from,
DConfChangeset *to)
{
- DConfChangeset *changeset = NULL;
+ DConfChangeset *changeset;
GHashTableIter iter;
gpointer key, val;
@@ -806,8 +887,8 @@ dconf_changeset_diff (DConfChangeset *from,
*
* We create our list of changes in two steps:
*
- * - iterate the 'to' changeset and note any keys that do not have
- * the same value in the 'from' changeset
+ * - call dconf_changeset_filter_changes to find values from 'to'
+ * which are not present in 'from' or hold different values to 'to'
*
* - iterate the 'from' changeset and note any keys not present in
* the 'to' changeset, recording resets for them
@@ -817,19 +898,8 @@ dconf_changeset_diff (DConfChangeset *from,
* Note: because 'from' and 'to' are database changesets we don't have
* to worry about seeing NULL values or dirs.
*/
- g_hash_table_iter_init (&iter, to->table);
- while (g_hash_table_iter_next (&iter, &key, &val))
- {
- GVariant *from_val = g_hash_table_lookup (from->table, key);
-
- if (from_val == NULL || !g_variant_equal (val, from_val))
- {
- if (!changeset)
- changeset = dconf_changeset_new ();
- dconf_changeset_set (changeset, key, val);
- }
- }
+ changeset = dconf_changeset_filter_changes (from, to);
g_hash_table_iter_init (&iter, from->table);
while (g_hash_table_iter_next (&iter, &key, &val))