[glib/wip/settings-backend: 1/14] GSettingsBackend: simplify event handling



commit acd4439e6fdbc80edc39fe366ba6faec44193195
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Dec 29 02:40:01 2011 -0500

    GSettingsBackend: simplify event handling
    
    Drop the 'vtable' business and switch to a single callback that takes a
    new GSettingsEvent structure.
    
    This patch temporarily regresses delayed settings: if a key set within a
    delayed settings backend becomes non-writable, it is no longer removed
    from the changeset.

 gio/Makefile.am                |    2 +-
 gio/gdelayedsettingsbackend.c  |  149 +----------------------
 gio/gio.symbols                |    1 +
 gio/gsettings.c                |  260 +++++++++++++++++++++++-----------------
 gio/gsettingsbackend.c         |  147 +++++++++++------------
 gio/gsettingsbackend.h         |   66 +++++++----
 gio/gsettingsbackendinternal.h |   80 +++++--------
 7 files changed, 298 insertions(+), 407 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 20bcd81..08eb7b2 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -111,7 +111,6 @@ gdbus-daemon-generated.h gdbus-daemon-generated.c: $(srcdir)/dbus-daemon.xml $(s
 		$(NULL)
 
 settings_headers = \
-	gsettingsbackend.h		\
 	gsettingsschema.h		\
 	gsettings.h
 
@@ -624,6 +623,7 @@ gio_headers =			\
 
 gioincludedir=$(includedir)/glib-2.0/gio/
 gioinclude_HEADERS = 		\
+	gsettingsbackend.h	\
 	$(gio_headers)		\
 	gioenumtypes.h
 
diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c
index 6f3c411..b85d724 100644
--- a/gio/gdelayedsettingsbackend.c
+++ b/gio/gdelayedsettingsbackend.c
@@ -264,146 +264,14 @@ g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed)
     }
 }
 
-/* change notification */
 static void
-delayed_backend_changed (GObject          *target,
-                         GSettingsBackend *backend,
-                         const gchar      *key,
-                         gpointer          origin_tag)
+g_delayed_settings_got_event (GObject              *target,
+                              const GSettingsEvent *event)
 {
   GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
 
-  if (origin_tag != delayed->priv)
-    g_settings_backend_changed (G_SETTINGS_BACKEND (delayed),
-                                key, origin_tag);
-}
-
-static void
-delayed_backend_keys_changed (GObject             *target,
-                              GSettingsBackend    *backend,
-                              const gchar         *path,
-                              const gchar * const *items,
-                              gpointer             origin_tag)
-{
-  GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
-
-  if (origin_tag != delayed->priv)
-    g_settings_backend_keys_changed (G_SETTINGS_BACKEND (delayed),
-                                     path, items, origin_tag);
-}
-
-static void
-delayed_backend_path_changed (GObject          *target,
-                              GSettingsBackend *backend,
-                              const gchar      *path,
-                              gpointer          origin_tag)
-{
-  GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
-
-  if (origin_tag != delayed->priv)
-    g_settings_backend_path_changed (G_SETTINGS_BACKEND (delayed),
-                                     path, origin_tag);
-}
-
-static void
-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;
-
-  if (g_str_has_prefix (key, state->path))
-    state->keys[state->index++] = key;
-
-  return FALSE;
-}
-
-static void
-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);
-
-      /* 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);
+  if (event->origin_tag != delayed->priv)
+    g_settings_backend_report_event (G_SETTINGS_BACKEND (delayed), event);
 }
 
 static void
@@ -470,13 +338,6 @@ g_delayed_settings_backend_new (GSettingsBackend *backend,
                                 gpointer          owner,
                                 GMainContext     *owner_context)
 {
-  static GSettingsListenerVTable vtable = {
-    delayed_backend_changed,
-    delayed_backend_path_changed,
-    delayed_backend_keys_changed,
-    delayed_backend_writable_changed,
-    delayed_backend_path_writable_changed
-  };
   GDelayedSettingsBackend *delayed;
 
   delayed = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL);
@@ -487,7 +348,7 @@ g_delayed_settings_backend_new (GSettingsBackend *backend,
   g_object_weak_ref (owner, g_delayed_settings_backend_disown, delayed);
 
   g_settings_backend_watch (delayed->priv->backend,
-                            &vtable, G_OBJECT (delayed), NULL);
+                            g_delayed_settings_got_event, G_OBJECT (delayed), NULL);
 
   return delayed;
 }
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 6db9bbd..3c7cc0c 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1132,6 +1132,7 @@ g_file_descriptor_based_get_type
 g_file_descriptor_based_get_fd
 #endif
 g_settings_backend_get_type
+g_settings_backend_report_event
 g_settings_backend_changed
 g_settings_backend_flatten_tree
 g_settings_backend_keys_changed
diff --git a/gio/gsettings.c b/gio/gsettings.c
index a6ee776..f0f5c1d 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -316,124 +316,175 @@ g_settings_real_writable_change_event (GSettings *settings,
 }
 
 static void
-settings_backend_changed (GObject             *target,
-                          GSettingsBackend    *backend,
-                          const gchar         *key,
-                          gpointer             origin_tag)
+g_settings_emit_signal (GSettings          *settings,
+                        GSettingsEventType  type,
+                        const GQuark       *quarks,
+                        gint                n_items)
 {
-  GSettings *settings = G_SETTINGS (target);
   gboolean ignore_this;
-  gint i;
+  guint signal_id;
 
-  /* We used to assert here:
-   *
-   *   settings->priv->backend == backend
-   *
-   * but it could be the case that a notification is queued for delivery
-   * while someone calls g_settings_delay() (which changes the backend).
-   *
-   * Since the delay backend would just pass that straight through
-   * anyway, it doesn't make sense to try to detect this case.
-   * Therefore, we just accept it.
-   */
+  switch (type)
+    {
+    case G_SETTINGS_EVENT_CHANGE:
+      signal_id = g_settings_signals[SIGNAL_CHANGE_EVENT];
+      break;
 
-  for (i = 0; key[i] == settings->priv->path[i]; i++);
+    case G_SETTINGS_EVENT_WRITABLE_CHANGE:
+      signal_id = g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT];
+      break;
 
-  if (settings->priv->path[i] == '\0' &&
-      g_settings_schema_has_key (settings->priv->schema, key + i))
+    default:
+      g_assert_not_reached ();
+    }
+
+  /* writable-change-event signals are emitted in a different way */
+  if (signal_id == g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT])
     {
-      GQuark quark;
+      if (n_items > 0)
+        {
+          gint i;
+
+          for (i = 0; i < n_items; i++)
+            g_signal_emit (settings, signal_id, 0, quarks[i], &ignore_this);
+        }
+      else
+        g_signal_emit (settings, signal_id, 0, (GQuark) 0, &ignore_this);
 
-      quark = g_quark_from_string (key + i);
-      g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
-                     0, &quark, 1, &ignore_this);
+      return;
     }
+
+  g_signal_emit (settings, signal_id, 0, quarks, n_items, &ignore_this);
 }
 
 static void
-settings_backend_path_changed (GObject          *target,
-                               GSettingsBackend *backend,
-                               const gchar      *path,
-                               gpointer          origin_tag)
+g_settings_got_event (GObject              *target,
+                      const GSettingsEvent *event)
 {
   GSettings *settings = G_SETTINGS (target);
-  gboolean ignore_this;
+  const gchar *prefix;
+  const gchar *path;
+  gint prefix_len;
+  gint path_len;
 
-  if (g_str_has_prefix (settings->priv->path, path))
-    g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
-                   0, NULL, 0, &ignore_this);
-}
+  /* The path of the GSettings always ends with '/'.
+   *
+   * For path '/a/b/', consider these prefixes:
+   *
+   *   - /x/           does not match
+   *   - /a/b/         want to match -- this is us directly
+   *   - /a/           want to match -- this may impact us
+   *   - /a/b/c        want to match -- 'c' may be a key
+   *   - /a/b/c/       does not match
+   *
+   * We can quickly determine if we are in a 'want to match' situation
+   * by fast-forwarding the common part of the GSettings path and the
+   * event prefix.
+   */
+  path = settings->priv->path;
+  prefix = event->prefix;
 
-static void
-settings_backend_keys_changed (GObject             *target,
-                               GSettingsBackend    *backend,
-                               const gchar         *path,
-                               const gchar * const *items,
-                               gpointer             origin_tag)
-{
-  GSettings *settings = G_SETTINGS (target);
-  gboolean ignore_this;
-  gint i;
+  while (*prefix && *prefix == *path)
+    {
+      prefix++;
+      path++;
+    }
+  prefix_len = strlen (prefix);
+  path_len = strlen (path);
+
+  /* If after removing the common prefix, we are left with characters in
+   * both then it is clear that we are in a non-matching situation.
+   */
+  if (prefix_len && path_len)
+    return;
 
-  for (i = 0; settings->priv->path[i] &&
-              settings->priv->path[i] == path[i]; i++);
+  if (prefix_len)
+    {
+      /* If part of the prefix is remaining then the only possibility is
+       * that we are emitting a change notification for a single key
+       * belonging to this settings object.  The remainder of that
+       * prefix (after stripping our path) is exactly the name of that
+       * key.
+       *
+       * Necessarily, this key must not contain a slash in any part of
+       * it.  This is a somewhat common case, so we explicitly check
+       * that before attempting to do a lookup of the key.
+       */
+      if (strchr (prefix, '/'))
+        return;
+
+      /* If the prefix doesn't end with a slash (as we just verified)
+       * then it had better be the case that the keys array is empty.
+       * We don't bother verifying that, though.
+       *
+       * We just check if the prefix is the name of one of our keys.
+       */
+      if (g_settings_schema_has_key (settings->priv->schema, prefix))
+        {
+          GQuark quark;
 
-  if (path[i] == '\0')
+          quark = g_quark_from_string (prefix);
+          g_settings_emit_signal (settings, event->type, &quark, 1);
+        }
+    }
+  else
     {
-      GQuark quarks[256];
-      gint j, l = 0;
+      /* The entire prefix is consumed.  This means that the prefix
+       * ended with a slash and matched our path.
+       *
+       * We may still have some remaining part of the path, however.  If
+       * that is true, we need to verify that each item in the keys
+       * array has this component as a prefix.
+       */
 
-      for (j = 0; items[j]; j++)
-         {
-           const gchar *item = items[j];
-           gint k;
+      /* If the key array is empty then all items under this path have
+       * changed.  We don't care about any remaining part of our path in
+       * this case since everything has changed.
+       */
+      if (event->keys[0] == NULL)
+        g_settings_emit_signal (settings, event->type, NULL, 0);
 
-           for (k = 0; item[k] == settings->priv->path[i + k]; k++);
+      else
+        {
+          GQuark *quarks;
+          gint n, i, j;
 
-           if (settings->priv->path[i + k] == '\0' &&
-               g_settings_schema_has_key (settings->priv->schema, item + k))
-             quarks[l++] = g_quark_from_string (item + k);
+          n = g_strv_length (event->keys);
 
-           /* "256 quarks ought to be enough for anybody!"
-            * If this bites you, I'm sorry.  Please file a bug.
-            */
-           g_assert (l < 256);
-         }
+          if (20 < n)
+            quarks = g_new (GQuark, n);
+          else
+            quarks = g_newa (GQuark, n);
 
-      if (l > 0)
-        g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
-                       0, quarks, l, &ignore_this);
-    }
-}
+          j = 0;
+          for (i = 0; event->keys[i]; i++)
+            {
+              gchar *key = event->keys[i];
 
-static void
-settings_backend_writable_changed (GObject          *target,
-                                   GSettingsBackend *backend,
-                                   const gchar      *key)
-{
-  GSettings *settings = G_SETTINGS (target);
-  gboolean ignore_this;
-  gint i;
+              /* Check the prefix */
+              if (!g_str_has_prefix (key, path))
+                continue;
 
-  for (i = 0; key[i] == settings->priv->path[i]; i++);
+              /* Remove that component from the key */
+              key += path_len;
 
-  if (settings->priv->path[i] == '\0' &&
-      g_settings_schema_has_key (settings->priv->schema, key + i))
-    g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT],
-                   0, g_quark_from_string (key + i), &ignore_this);
-}
+              /* Do the slash check as above, and for the same reason */
+              if (strchr (key, '/'))
+                continue;
 
-static void
-settings_backend_path_writable_changed (GObject          *target,
-                                        GSettingsBackend *backend,
-                                        const gchar      *path)
-{
-  GSettings *settings = G_SETTINGS (target);
-  gboolean ignore_this;
+              /* Check if it's actually a key */
+              if (g_settings_schema_has_key (settings->priv->schema, key))
+                quarks[j++] = g_quark_from_string (key);
+            }
+
+          /* Only signal if we actually had a match. */
+          if (j > 0)
+            g_settings_emit_signal (settings, event->type, quarks, j);
 
-  if (g_str_has_prefix (settings->priv->path, path))
-    g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT],
-                   0, (GQuark) 0, &ignore_this);
+          if (20 < n)
+            g_free (quarks);
+        }
+    }
 }
 
 /* Properties, Construction, Destruction {{{1 */
@@ -546,14 +597,6 @@ g_settings_get_property (GObject    *object,
     }
 }
 
-static const GSettingsListenerVTable listener_vtable = {
-  settings_backend_changed,
-  settings_backend_path_changed,
-  settings_backend_keys_changed,
-  settings_backend_writable_changed,
-  settings_backend_path_writable_changed
-};
-
 static void
 g_settings_constructed (GObject *object)
 {
@@ -579,7 +622,8 @@ g_settings_constructed (GObject *object)
     settings->priv->backend = g_settings_backend_get_default ();
 
   g_settings_backend_watch (settings->priv->backend,
-                            &listener_vtable, G_OBJECT (settings),
+                            g_settings_got_event,
+                            G_OBJECT (settings),
                             settings->priv->main_context);
   g_settings_backend_subscribe (settings->priv->backend,
                                 settings->priv->path);
@@ -1907,7 +1951,7 @@ g_settings_delay (GSettings *settings)
 
   settings->priv->backend = G_SETTINGS_BACKEND (settings->priv->delayed);
   g_settings_backend_watch (settings->priv->backend,
-                            &listener_vtable, G_OBJECT (settings),
+                            g_settings_got_event, G_OBJECT (settings),
                             settings->priv->main_context);
 
   g_object_notify (G_OBJECT (settings), "delay-apply");
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index c89531a..76485a5 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -126,26 +126,18 @@ is_path (const gchar *path)
 
 struct _GSettingsBackendWatch
 {
-  GObject                       *target;
-  const GSettingsListenerVTable *vtable;
-  GMainContext                  *context;
-  GSettingsBackendWatch         *next;
+  GObject               *target;
+  GSettingsEventFunc     function;
+  GMainContext          *context;
+  GSettingsBackendWatch *next;
 };
 
 struct _GSettingsBackendClosure
 {
-  void (*function) (GObject          *target,
-                    GSettingsBackend *backend,
-                    const gchar      *name,
-                    gpointer          data1,
-                    gpointer          data2);
-
-  GSettingsBackend *backend;
-  GObject          *target;
-  gchar            *name;
-  gpointer          data1;
-  GBoxedFreeFunc    data1_free;
-  gpointer          data2;
+  GSettingsEventFunc  function;
+  GSettingsBackend   *backend;
+  GObject            *target;
+  GSettingsEvent      event;
 };
 
 static void
@@ -198,10 +190,10 @@ g_settings_backend_watch_weak_notify (gpointer  data,
  * value of @origin_tag given to any callbacks.
  **/
 void
-g_settings_backend_watch (GSettingsBackend              *backend,
-                          const GSettingsListenerVTable *vtable,
-                          GObject                       *target,
-                          GMainContext                  *context)
+g_settings_backend_watch (GSettingsBackend   *backend,
+                          GSettingsEventFunc  callback,
+                          GObject            *target,
+                          GMainContext       *context)
 {
   GSettingsBackendWatch *watch;
 
@@ -241,7 +233,7 @@ g_settings_backend_watch (GSettingsBackend              *backend,
 
   watch = g_slice_new (GSettingsBackendWatch);
   watch->context = context;
-  watch->vtable = vtable;
+  watch->function = callback;
   watch->target = target;
   g_object_weak_ref (target, g_settings_backend_watch_weak_notify, backend);
 
@@ -268,47 +260,24 @@ g_settings_backend_invoke_closure (gpointer user_data)
 {
   GSettingsBackendClosure *closure = user_data;
 
-  closure->function (closure->target, closure->backend, closure->name,
-                     closure->data1, closure->data2);
+  closure->function (closure->target, &closure->event);
 
-  closure->data1_free (closure->data1);
   g_object_unref (closure->backend);
   g_object_unref (closure->target);
-  g_free (closure->name);
+  g_strfreev (closure->event.keys);
+  g_free (closure->event.prefix);
 
   g_slice_free (GSettingsBackendClosure, closure);
 
   return FALSE;
 }
 
-static gpointer
-pointer_id (gpointer a)
-{
-  return a;
-}
-
-static void
-pointer_ignore (gpointer a)
-{
-}
-
-static void
-g_settings_backend_dispatch_signal (GSettingsBackend *backend,
-                                    gsize             function_offset,
-                                    const gchar      *name,
-                                    gpointer          data1,
-                                    GBoxedCopyFunc    data1_copy,
-                                    GBoxedFreeFunc    data1_free,
-                                    gpointer          data2)
+void
+g_settings_backend_report_event (GSettingsBackend     *backend,
+                                 const GSettingsEvent *event)
 {
   GSettingsBackendWatch *suffix, *watch, *next;
 
-  if (data1_copy == NULL)
-    data1_copy = pointer_id;
-
-  if (data1_free == NULL)
-    data1_free = pointer_ignore;
-
   /* We're in a little bit of a tricky situation here.  We need to hold
    * a lock while traversing the list, but we don't want to hold the
    * lock while calling back into user code.
@@ -337,12 +306,11 @@ g_settings_backend_dispatch_signal (GSettingsBackend *backend,
       closure = g_slice_new (GSettingsBackendClosure);
       closure->backend = g_object_ref (backend);
       closure->target = watch->target; /* we took our ref above */
-      closure->function = G_STRUCT_MEMBER (void *, watch->vtable,
-                                           function_offset);
-      closure->name = g_strdup (name);
-      closure->data1 = data1_copy (data1);
-      closure->data1_free = data1_free;
-      closure->data2 = data2;
+      closure->function = watch->function;
+      closure->event.type = event->type;
+      closure->event.prefix = g_strdup (event->prefix);
+      closure->event.keys = g_strdupv (event->keys);
+      closure->event.origin_tag = event->origin_tag;
 
       /* we do this here because 'watch' may not live to the end of this
        * iteration of the loop (since we may unref the target below).
@@ -394,13 +362,18 @@ g_settings_backend_changed (GSettingsBackend *backend,
                             const gchar      *key,
                             gpointer          origin_tag)
 {
+  GSettingsEvent event;
+  gchar *null = NULL;
+
   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
   g_return_if_fail (is_key (key));
 
-  g_settings_backend_dispatch_signal (backend,
-                                      G_STRUCT_OFFSET (GSettingsListenerVTable,
-                                                       changed),
-                                      key, origin_tag, NULL, NULL, NULL);
+  event.type = G_SETTINGS_EVENT_CHANGE;
+  event.prefix = (gchar *) key;
+  event.keys = &null;
+  event.origin_tag = origin_tag;
+
+  g_settings_backend_report_event (backend, &event);
 }
 
 /**
@@ -440,19 +413,20 @@ g_settings_backend_keys_changed (GSettingsBackend    *backend,
                                  gchar const * const *items,
                                  gpointer             origin_tag)
 {
+  GSettingsEvent event;
+
   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
   g_return_if_fail (is_path (path));
 
   /* XXX: should do stricter checking (ie: inspect each item) */
   g_return_if_fail (items != NULL);
 
-  g_settings_backend_dispatch_signal (backend,
-                                      G_STRUCT_OFFSET (GSettingsListenerVTable,
-                                                       keys_changed),
-                                      path, (gpointer) items,
-                                      (GBoxedCopyFunc) g_strdupv,
-                                      (GBoxedFreeFunc) g_strfreev,
-                                      origin_tag);
+  event.type = G_SETTINGS_EVENT_CHANGE;
+  event.prefix = (gchar *) path;
+  event.keys = (gchar **) items;
+  event.origin_tag = origin_tag;
+
+  g_settings_backend_report_event (backend, &event);
 }
 
 /**
@@ -490,13 +464,18 @@ g_settings_backend_path_changed (GSettingsBackend *backend,
                                  const gchar      *path,
                                  gpointer          origin_tag)
 {
+  GSettingsEvent event;
+  gchar *null = NULL;
+
   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
   g_return_if_fail (is_path (path));
 
-  g_settings_backend_dispatch_signal (backend,
-                                      G_STRUCT_OFFSET (GSettingsListenerVTable,
-                                                       path_changed),
-                                      path, origin_tag, NULL, NULL, NULL);
+  event.type = G_SETTINGS_EVENT_CHANGE;
+  event.prefix = (gchar *) path;
+  event.keys = &null;
+  event.origin_tag = origin_tag;
+
+  g_settings_backend_report_event (backend, &event);
 }
 
 /**
@@ -515,13 +494,18 @@ void
 g_settings_backend_writable_changed (GSettingsBackend *backend,
                                      const gchar      *key)
 {
+  GSettingsEvent event;
+  gchar *null = NULL;
+
   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
   g_return_if_fail (is_key (key));
 
-  g_settings_backend_dispatch_signal (backend,
-                                      G_STRUCT_OFFSET (GSettingsListenerVTable,
-                                                       writable_changed),
-                                      key, NULL, NULL, NULL, NULL);
+  event.type = G_SETTINGS_EVENT_WRITABLE_CHANGE;
+  event.prefix = (gchar *) key;
+  event.keys = &null;
+  event.origin_tag = NULL;
+
+  g_settings_backend_report_event (backend, &event);
 }
 
 /**
@@ -541,13 +525,18 @@ void
 g_settings_backend_path_writable_changed (GSettingsBackend *backend,
                                           const gchar      *path)
 {
+  GSettingsEvent event;
+  gchar *null = NULL;
+
   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
   g_return_if_fail (is_path (path));
 
-  g_settings_backend_dispatch_signal (backend,
-                                      G_STRUCT_OFFSET (GSettingsListenerVTable,
-                                                       path_writable_changed),
-                                      path, NULL, NULL, NULL, NULL);
+  event.type = G_SETTINGS_EVENT_WRITABLE_CHANGE;
+  event.prefix = (gchar *) path;
+  event.keys = &null;
+  event.origin_tag = NULL;
+
+  g_settings_backend_report_event (backend, &event);
 }
 
 typedef struct
diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h
index e674187..f75136f 100644
--- a/gio/gsettingsbackend.h
+++ b/gio/gsettingsbackend.h
@@ -104,36 +104,52 @@ struct _GSettingsBackend
   GSettingsBackendPrivate *priv;
 };
 
+typedef enum
+{
+  G_SETTINGS_EVENT_CHANGE,
+  G_SETTINGS_EVENT_WRITABLE_CHANGE
+} GSettingsEventType;
+
+typedef struct
+{
+  GSettingsEventType   type;
+  gchar               *prefix;
+  gchar              **keys;
+  gpointer             origin_tag;
+} GSettingsEvent;
+
 GType                   g_settings_backend_get_type                     (void);
 
-void                    g_settings_backend_changed                      (GSettingsBackend    *backend,
-                                                                         const gchar         *key,
-                                                                         gpointer             origin_tag);
-void                    g_settings_backend_path_changed                 (GSettingsBackend    *backend,
-                                                                         const gchar         *path,
-                                                                         gpointer             origin_tag);
-void                    g_settings_backend_flatten_tree                 (GTree               *tree,
-                                                                         gchar              **path,
-                                                                         const gchar       ***keys,
-                                                                         GVariant          ***values);
-void                    g_settings_backend_keys_changed                 (GSettingsBackend    *backend,
-                                                                         const gchar         *path,
-                                                                         gchar const * const *items,
-                                                                         gpointer             origin_tag);
-
-void                    g_settings_backend_path_writable_changed        (GSettingsBackend    *backend,
-                                                                         const gchar         *path);
-void                    g_settings_backend_writable_changed             (GSettingsBackend    *backend,
-                                                                         const gchar         *key);
-void                    g_settings_backend_changed_tree                 (GSettingsBackend    *backend,
-                                                                         GTree               *tree,
-                                                                         gpointer             origin_tag);
+void                    g_settings_backend_report_event                 (GSettingsBackend     *backend,
+                                                                         const GSettingsEvent *event);
+void                    g_settings_backend_changed                      (GSettingsBackend     *backend,
+                                                                         const gchar          *key,
+                                                                         gpointer              origin_tag);
+void                    g_settings_backend_path_changed                 (GSettingsBackend     *backend,
+                                                                         const gchar          *path,
+                                                                         gpointer              origin_tag);
+void                    g_settings_backend_flatten_tree                 (GTree                *tree,
+                                                                         gchar               **path,
+                                                                         const gchar        ***keys,
+                                                                         GVariant           ***values);
+void                    g_settings_backend_keys_changed                 (GSettingsBackend     *backend,
+                                                                         const gchar          *path,
+                                                                         gchar const * const  *items,
+                                                                         gpointer              origin_tag);
+
+void                    g_settings_backend_path_writable_changed        (GSettingsBackend     *backend,
+                                                                         const gchar          *path);
+void                    g_settings_backend_writable_changed             (GSettingsBackend     *backend,
+                                                                         const gchar          *key);
+void                    g_settings_backend_changed_tree                 (GSettingsBackend     *backend,
+                                                                         GTree                *tree,
+                                                                         gpointer              origin_tag);
 
 GSettingsBackend *      g_settings_backend_get_default                  (void);
 
-GSettingsBackend *      g_keyfile_settings_backend_new                  (const gchar         *filename,
-                                                                         const gchar         *root_path,
-                                                                         const gchar         *root_group);
+GSettingsBackend *      g_keyfile_settings_backend_new                  (const gchar          *filename,
+                                                                         const gchar          *root_path,
+                                                                         const gchar          *root_group);
 
 GSettingsBackend *      g_null_settings_backend_new                     (void);
 
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
index 368c54b..2b2d8f2 100644
--- a/gio/gsettingsbackendinternal.h
+++ b/gio/gsettingsbackendinternal.h
@@ -26,71 +26,51 @@
 
 #include "gsettingsbackend.h"
 
-typedef struct
-{
-  void (* changed)               (GObject             *target,
-                                  GSettingsBackend    *backend,
-                                  const gchar         *key,
-                                  gpointer             origin_tag);
-  void (* path_changed)          (GObject             *target,
-                                  GSettingsBackend    *backend,
-                                  const gchar         *path,
-                                  gpointer             origin_tag);
-  void (* keys_changed)          (GObject             *target,
-                                  GSettingsBackend    *backend,
-                                  const gchar         *prefix,
-                                  const gchar * const *names,
-                                  gpointer             origin_tag);
-  void (* writable_changed)      (GObject             *target,
-                                  GSettingsBackend    *backend,
-                                  const gchar         *key);
-  void (* path_writable_changed) (GObject             *target,
-                                  GSettingsBackend    *backend,
-                                  const gchar         *path);
-} GSettingsListenerVTable;
+typedef void         (* GSettingsEventFunc)                             (GObject              *target,
+                                                                         const GSettingsEvent *event);
 
 G_GNUC_INTERNAL
-void                    g_settings_backend_watch                        (GSettingsBackend               *backend,
-                                                                         const GSettingsListenerVTable  *vtable,
-                                                                         GObject                        *target,
-                                                                         GMainContext                   *context);
+void                    g_settings_backend_watch                        (GSettingsBackend     *backend,
+                                                                         GSettingsEventFunc    callback,
+                                                                         GObject              *target,
+                                                                         GMainContext         *context);
 G_GNUC_INTERNAL
-void                    g_settings_backend_unwatch                      (GSettingsBackend               *backend,
-                                                                         GObject                        *target);
+void                    g_settings_backend_unwatch                      (GSettingsBackend     *backend,
+                                                                         GObject              *target);
 
 G_GNUC_INTERNAL
 GTree *                 g_settings_backend_create_tree                  (void);
 
 G_GNUC_INTERNAL
-GVariant *              g_settings_backend_read                         (GSettingsBackend               *backend,
-                                                                         const gchar                    *key,
-                                                                         const GVariantType             *expected_type,
-                                                                         gboolean                        default_value);
+GVariant *              g_settings_backend_read                         (GSettingsBackend     *backend,
+                                                                         const gchar          *key,
+                                                                         const GVariantType   *expected_type,
+                                                                         gboolean              default_value);
 G_GNUC_INTERNAL
-gboolean                g_settings_backend_write                        (GSettingsBackend               *backend,
-                                                                         const gchar                    *key,
-                                                                         GVariant                       *value,
-                                                                         gpointer                        origin_tag);
+gboolean                g_settings_backend_write                        (GSettingsBackend     *backend,
+                                                                         const gchar          *key,
+                                                                         GVariant             *value,
+                                                                         gpointer              origin_tag);
 G_GNUC_INTERNAL
-gboolean                g_settings_backend_write_tree                   (GSettingsBackend               *backend,
-                                                                         GTree                          *tree,
-                                                                         gpointer                        origin_tag);
+gboolean                g_settings_backend_write_tree                   (GSettingsBackend     *backend,
+                                                                         GTree                *tree,
+                                                                         gpointer              origin_tag);
 G_GNUC_INTERNAL
-void                    g_settings_backend_reset                        (GSettingsBackend               *backend,
-                                                                         const gchar                    *key,
-                                                                         gpointer                        origin_tag);
+void                    g_settings_backend_reset                        (GSettingsBackend     *backend,
+                                                                         const gchar          *key,
+                                                                         gpointer              origin_tag);
 G_GNUC_INTERNAL
-gboolean                g_settings_backend_get_writable                 (GSettingsBackend               *backend,
-                                                                         const char                     *key);
+gboolean                g_settings_backend_get_writable                 (GSettingsBackend     *backend,
+                                                                         const char           *key);
 G_GNUC_INTERNAL
-void                    g_settings_backend_unsubscribe                  (GSettingsBackend               *backend,
-                                                                         const char                     *name);
+void                    g_settings_backend_unsubscribe                  (GSettingsBackend     *backend,
+                                                                         const char           *name);
 G_GNUC_INTERNAL
-void                    g_settings_backend_subscribe                    (GSettingsBackend               *backend,
-                                                                         const char                     *name);
+void                    g_settings_backend_subscribe                    (GSettingsBackend     *backend,
+                                                                         const char           *name);
 G_GNUC_INTERNAL
-GPermission *           g_settings_backend_get_permission               (GSettingsBackend               *backend,
-                                                                         const gchar                    *path);
+GPermission *           g_settings_backend_get_permission               (GSettingsBackend     *backend,
+                                                                         const gchar          *path);
 G_GNUC_INTERNAL
 void                    g_settings_backend_sync_default                 (void);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]