[glib] merge GSettingsBackend



commit 18ba085d0ad28e7edbe575addacbaa2bb13d9f1c
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Apr 15 14:59:41 2010 -0400

    merge GSettingsBackend

 docs/reference/gio/Makefile.am |    1 +
 gio/Makefile.am                |    9 +
 gio/gio.symbols                |   14 +
 gio/gsettingsbackend.c         |  877 ++++++++++++++++++++++++++++++++++++++++
 gio/gsettingsbackend.h         |  122 ++++++
 gio/gsettingsbackendinternal.h |  100 +++++
 gio/pltcheck.sh                |    2 +-
 7 files changed, 1124 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/gio/Makefile.am b/docs/reference/gio/Makefile.am
index 2c51c7e..d9cd55b 100644
--- a/docs/reference/gio/Makefile.am
+++ b/docs/reference/gio/Makefile.am
@@ -50,6 +50,7 @@ IGNORE_HFILES=				\
 	gnativevolumemonitor.h		\
 	gnetworkingprivate.h		\
 	gpollfilemonitor.h		\
+	gsettingsbackendinternal.h	\
 	gthreadedresolver.h		\
 	gunionvolumemonitor.h		\
 	gunixdrive.h			\
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fd42438..e0c2090 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -79,6 +79,13 @@ gio-marshal.c: gio-marshal.h gio-marshal.list
 	$(glib_genmarshal) --prefix=_gio_marshal $(srcdir)/gio-marshal.list --body --internal) > $  tmp && \
 	  mv $  tmp $@
 
+settings_sources = \
+	gsettingsbackendinternal.h	\
+	gsettingsbackend.c
+
+settings_headers = \
+	gsettingsbackend.h
+
 local_sources = \
 	glocaldirectorymonitor.c 	\
 	glocaldirectorymonitor.h 	\
@@ -285,6 +292,7 @@ libgio_2_0_la_SOURCES =		\
 	$(appinfo_sources) 	\
 	$(unix_sources) 	\
 	$(win32_sources) 	\
+	$(settings_sources) 	\
 	$(local_sources) 	\
 	$(marshal_sources) 	\
 	$(NULL)
@@ -411,6 +419,7 @@ gio_headers =			\
 	gvolumemonitor.h 	\
 	gzlibcompressor.h	\
 	gzlibdecompressor.h	\
+	$(settings_headers) 	\
 	$(NULL)
 
 gioincludedir=$(includedir)/glib-2.0/gio/
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 62a99d7..e74d328 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1340,3 +1340,17 @@ g_file_descriptor_based_get_type G_GNUC_CONST
 g_file_descriptor_based_get_fd
 #endif
 #endif
+
+#if IN_HEADER(__G_SETTINGS_BACKEND_H__)
+#if IN_FILE(__G_SETTINGS_BACKEND_C__)
+g_settings_backend_get_type
+
+g_settings_backend_changed
+g_settings_backend_keys_changed
+g_settings_backend_path_changed
+g_settings_backend_path_writable_changed
+g_settings_backend_writable_changed
+
+g_settings_backend_changed_tree
+#endif
+#endif
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
new file mode 100644
index 0000000..e818daf
--- /dev/null
+++ b/gio/gsettingsbackend.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright © 2009, 2010 Codethink Limited
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gsettingsbackendinternal.h"
+#include "giomodule-priv.h"
+#include "gio-marshal.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glibintl.h>
+
+#include "gioalias.h"
+
+G_DEFINE_ABSTRACT_TYPE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
+
+typedef struct _GSettingsBackendWatch GSettingsBackendWatch;
+
+struct _GSettingsBackendPrivate
+{
+  GSettingsBackendWatch *watches;
+  gchar *context;
+};
+
+enum
+{
+  PROP_0,
+  PROP_CONTEXT
+};
+
+/**
+ * SECTION:gsettingsbackend
+ * @title: GSettingsBackend
+ * @short_description: an interface for settings backend implementations
+ * @include: gio/gsettingsbackend.h
+ * @see_also: #GSettings, #GIOExtensionPoint
+ *
+ * The #GSettingsBackend interface defines a generic interface for
+ * non-strictly-typed data that is stored in a hierarchy. To implement
+ * an alternative storage backend for #GSettings, you need to implement
+ * the #GSettingsBackend interface and then make it implement the
+ * extension point #G_SETTINGS_BACKEND_EXTENSION_POINT_NAME.
+ *
+ * The interface defines methods for reading and writing values, a
+ * method for determining if writing of certain values will fail
+ * (lockdown) and a change notification mechanism.
+ *
+ * The semantics of the interface are very precisely defined and
+ * implementations must carefully adhere to the expectations of
+ * callers that are documented on each of the interface methods.
+ *
+ * Some of the GSettingsBackend functions accept or return a #GTree.
+ * These trees always have strings as keys and #GVariant as values.
+ * g_settings_backend_create_tree() is a convenience function to create
+ * suitable trees.
+ *
+ * <note><para>
+ * The #GSettingsBackend API is exported to allow third-party
+ * implementations, but does not carry the same stability guarantees
+ * as the public GIO API. For this reason, you have to define the
+ * C preprocessor symbol #G_SETTINGS_ENABLE_BACKEND before including
+ * <filename>gio/gsettingsbackend.h</filename>
+ * </para></note>
+ **/
+
+struct _GSettingsBackendWatch
+{
+  GSettingsBackendChangedFunc              changed;
+  GSettingsBackendPathChangedFunc          path_changed;
+  GSettingsBackendKeysChangedFunc          keys_changed;
+  GSettingsBackendWritableChangedFunc      writable_changed;
+  GSettingsBackendPathWritableChangedFunc  path_writable_changed;
+  gpointer                                 user_data;
+
+  GSettingsBackendWatch                   *next;
+};
+
+void
+g_settings_backend_watch (GSettingsBackend                        *backend,
+                          GSettingsBackendChangedFunc              changed,
+                          GSettingsBackendPathChangedFunc          path_changed,
+                          GSettingsBackendKeysChangedFunc          keys_changed,
+                          GSettingsBackendWritableChangedFunc      writable_changed,
+                          GSettingsBackendPathWritableChangedFunc  path_writable_changed,
+                          gpointer                                 user_data)
+{
+  GSettingsBackendWatch *watch;
+
+  watch = g_slice_new (GSettingsBackendWatch);
+  watch->changed = changed;
+  watch->path_changed = path_changed;
+  watch->keys_changed = keys_changed;
+  watch->writable_changed = writable_changed;
+  watch->path_writable_changed = path_writable_changed;
+  watch->user_data = user_data;
+
+  watch->next = backend->priv->watches;
+  backend->priv->watches = watch;
+}
+
+void
+g_settings_backend_unwatch (GSettingsBackend *backend,
+                            gpointer          user_data)
+{
+  GSettingsBackendWatch **ptr;
+
+  for (ptr = &backend->priv->watches; *ptr; ptr = &(*ptr)->next)
+    if ((*ptr)->user_data == user_data)
+      {
+        GSettingsBackendWatch *tmp = *ptr;
+
+        *ptr = tmp->next;
+        g_slice_free (GSettingsBackendWatch, tmp);
+
+        return;
+      }
+
+  g_assert_not_reached ();
+}
+
+static gboolean
+is_key (const gchar *key)
+{
+  gint length;
+  gint i;
+
+  g_return_val_if_fail (key != NULL, FALSE);
+  g_return_val_if_fail (key[0] == '/', FALSE);
+
+  for (i = 1; key[i]; i++)
+    g_return_val_if_fail (key[i] != '/' || key[i + 1] != '/', FALSE);
+
+  length = i;
+
+  g_return_val_if_fail (key[length - 1] != '/', FALSE);
+
+  return TRUE;
+}
+
+static gboolean
+is_path (const gchar *path)
+{
+  gint length;
+  gint i;
+
+  g_return_val_if_fail (path != NULL, FALSE);
+  g_return_val_if_fail (path[0] == '/', FALSE);
+
+  for (i = 1; path[i]; i++)
+    g_return_val_if_fail (path[i] != '/' || path[i + 1] != '/', FALSE);
+
+  length = i;
+
+  g_return_val_if_fail (path[length - 1] == '/', FALSE);
+
+  return TRUE;
+}
+
+/**
+ * g_settings_backend_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the name of the key
+ * @origin_tag: the origin tag
+ *
+ * Signals that a single key has possibly changed.  Backend
+ * implementations should call this if a key has possibly changed its
+ * value.
+ *
+ * @key must be a valid key (ie: starting with a slash, not containing
+ * '//', and not ending with a slash).
+ *
+ * The implementation must call this function during any call to
+ * g_settings_backend_write(), before the call returns (except in the
+ * case that no keys are actually changed and it cares to detect this
+ * fact).  It may not rely on the existence of a mainloop for
+ * dispatching the signal later.
+ *
+ * The implementation may call this function at any other time it likes
+ * in response to other events (such as changes occuring outside of the
+ * program).  These calls may originate from a mainloop or may originate
+ * in response to any other action (including from calls to
+ * g_settings_backend_write()).
+ *
+ * In the case that this call is in response to a call to
+ * g_settings_backend_write() then @origin_tag must be set to the same
+ * value that was passed to that call.
+ *
+ * Since: 2.26
+ **/
+void
+g_settings_backend_changed (GSettingsBackend *backend,
+                            const gchar      *key,
+                            gpointer          origin_tag)
+{
+  GSettingsBackendWatch *watch;
+
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
+  g_return_if_fail (is_key (key));
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->changed (backend, key, origin_tag, watch->user_data);
+}
+
+/**
+ * g_settings_backend_keys_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @path: the path containing the changes
+ * @items: the %NULL-terminated list of changed keys
+ * @origin_tag: the origin tag
+ *
+ * Signals that a list of keys have possibly changed.  Backend
+ * implementations should call this if keys have possibly changed their
+ * values.
+ *
+ * @path must be a valid path (ie: starting and ending with a slash and
+ * not containing '//').  Each string in @items must form a valid key
+ * name when @path is prefixed to it (ie: each item must not start or
+ * end with '/' and must not contain '//').
+ *
+ * The meaning of this signal is that any of the key names resulting
+ * from the contatenation of @path with each item in @items may have
+ * changed.
+ *
+ * The same rules for when notifications must occur apply as per
+ * g_settings_backend_changed().  These two calls can be used
+ * interchangeably if exactly one item has changed (although in that
+ * case g_settings_backend_changed() is definitely preferred).
+ *
+ * For efficiency reasons, the implementation should strive for @path to
+ * be as long as possible (ie: the longest common prefix of all of the
+ * keys that were changed) but this is not strictly required.
+ *
+ * Since: 2.26
+ */
+void
+g_settings_backend_keys_changed (GSettingsBackend    *backend,
+                                 const gchar         *path,
+                                 gchar const * const *items,
+                                 gpointer             origin_tag)
+{
+  GSettingsBackendWatch *watch;
+
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
+  g_return_if_fail (path[0] == '\0' || is_path (path));
+  g_return_if_fail (items != NULL);
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->keys_changed (backend, path, items, origin_tag, watch->user_data);
+}
+
+/**
+ * g_settings_backend_keys_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @path: the path containing the changes
+ * @origin_tag: the origin tag
+ *
+ * Signals that all keys below a given path may have possibly changed.
+ * Backend implementations should call this if an entire path of keys
+ * have possibly changed their values.
+ *
+ * @path must be a valid path (ie: starting and ending with a slash and
+ * not containing '//').
+ *
+ * The meaning of this signal is that any of the key which has a name
+ * starting with @path may have changed.
+ *
+ * The same rules for when notifications must occur apply as per
+ * g_settings_backend_changed().  This call might be an appropriate
+ * reasponse to a 'reset' call but implementations are also free to
+ * explicitly list the keys that were affected by that call if they can
+ * easily do so.
+ *
+ * For efficiency reasons, the implementation should strive for @path to
+ * be as long as possible (ie: the longest common prefix of all of the
+ * keys that were changed) but this is not strictly required.  As an
+ * example, if this function is called with the path of "/" then every
+ * single key in the application will be notified of a possible change.
+ *
+ * Since: 2.26
+ */
+void
+g_settings_backend_path_changed (GSettingsBackend *backend,
+                                 const gchar      *path,
+                                 gpointer          origin_tag)
+{
+  GSettingsBackendWatch *watch;
+
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
+  g_return_if_fail (is_path (path));
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->path_changed (backend, path, origin_tag, watch->user_data);
+}
+
+/**
+ * g_settings_backend_writable_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the name of the key
+ *
+ * Signals that the writability of a single key has possibly changed.
+ *
+ * Since GSettings performs no locking operations for itself, this call
+ * will always be made in response to external events.
+ *
+ * Since: 2.26
+ **/
+void
+g_settings_backend_writable_changed (GSettingsBackend *backend,
+                                     const gchar      *key)
+{
+  GSettingsBackendWatch *watch;
+
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
+  g_return_if_fail (is_key (key));
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->writable_changed (backend, key, watch->user_data);
+}
+
+/**
+ * g_settings_backend_writable_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @path: the name of the path
+ *
+ * Signals that the writability of all keys below a given path may have
+ * changed.
+ *
+ * Since GSettings performs no locking operations for itself, this call
+ * will always be made in response to external events.
+ *
+ * Since: 2.26
+ **/
+void
+g_settings_backend_path_writable_changed (GSettingsBackend *backend,
+                                          const gchar      *path)
+{
+  GSettingsBackendWatch *watch;
+
+  g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
+  g_return_if_fail (is_path (path));
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->path_writable_changed (backend, path, watch->user_data);
+}
+
+typedef struct
+{
+  gint prefix_len;
+  gchar *prefix;
+  gchar **items;
+} GetKeysState;
+
+static gboolean
+tree_get_keys (gpointer key,
+               gpointer value,
+               gpointer user_data)
+{
+  GetKeysState *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->items++ = key;
+
+  return FALSE;
+}
+
+/**
+ * g_settings_backend_changed_tree:
+ * @backend: a #GSettingsBackend implementation
+ * @tree: a #GTree containing the changes
+ * @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().
+ *
+ * Since: 2.26
+ **/
+void
+g_settings_backend_changed_tree (GSettingsBackend *backend,
+                                 GTree            *tree,
+                                 gpointer          origin_tag)
+{
+  GSettingsBackendWatch *watch;
+  GetKeysState state = { 0, };
+  gchar **list;
+
+  list = g_new (gchar *, g_tree_nnodes (tree) + 1);
+  state.items = list;
+
+  g_tree_foreach (tree, tree_get_keys, &state);
+  g_return_if_fail (list + g_tree_nnodes (tree) == state.items);
+  *state.items = NULL;
+
+  while (state.items-- != list)
+    *state.items += state.prefix_len;
+
+  for (watch = backend->priv->watches; watch; watch = watch->next)
+    watch->keys_changed (backend, state.prefix,
+                         (const gchar * const *) list,
+                         origin_tag, watch->user_data);
+
+  g_free (list);
+  g_free (state.prefix);
+}
+
+/*< private >
+ * g_settings_backend_read:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the key to read
+ * @expected_type: a #GVariantType hint
+ * @returns: the value that was read, or %NULL
+ *
+ * Reads a key. This call will never block.
+ *
+ * If the key exists, the value associated with it will be returned.
+ * If the key does not exist, %NULL will be returned.
+ *
+ * If @expected_type is given, it serves as a type hint to the backend.
+ * If you expect a key of a certain type then you should give
+ * @expected_type to increase your chances of getting it.  Some backends
+ * may ignore this argument and return values of a different type; it is
+ * mostly used by backends that don't store strong type information.
+ */
+GVariant *
+g_settings_backend_read (GSettingsBackend   *backend,
+                         const gchar        *key,
+                         const GVariantType *expected_type)
+{
+  return G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->read (backend, key, expected_type);
+}
+
+/*< private >
+ * g_settings_backend_write:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the name of the key
+ * @value: a #GVariant value to write to this key
+ * @origin_tag: the origin tag
+ *
+ * Writes exactly one key.
+ *
+ * This call does not fail.  During this call a
+ * #GSettingsBackend::changed signal will be emitted if the value of the
+ * key has changed.  The updated key value 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)
+ * to indicate that the affected keys have suddenly "changed back" to their
+ * old values.
+ */
+void
+g_settings_backend_write (GSettingsBackend *backend,
+                          const gchar      *key,
+                          GVariant         *value,
+                          gpointer          origin_tag)
+{
+  G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->write (backend, key, value, origin_tag);
+}
+
+/*< private >
+ * g_settings_backend_write_keys:
+ * @backend: a #GSettingsBackend implementation
+ * @values: a #GTree containing key-value pairs to write
+ * @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.
+ *
+ * One possible method that an implementation might deal with failures is
+ * to emit a second "changed" signal (either during this call, or later)
+ * to indicate that the affected keys have suddenly "changed back" to their
+ * old values.
+ */
+void
+g_settings_backend_write_keys (GSettingsBackend *backend,
+                               GTree            *tree,
+                               gpointer          origin_tag)
+{
+  G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->write_keys (backend, tree, origin_tag);
+}
+
+/*< private >
+ * g_settings_backend_reset:
+ * @backend: a #GSettingsBackend implementation
+ * @name: the name of a key or path
+ * @origin_tag: the origin tag
+ *
+ * "Resets" the named key or path.  For a key this means that it is
+ * reverted to its "default" value (ie: after system-wide defaults,
+ * mandatory keys, etc. have been taken into account) or possibly unsets
+ * it.
+ *
+ * For paths, it means that every key under the path is reset.
+ */
+void
+g_settings_backend_reset (GSettingsBackend *backend,
+                          const gchar      *name,
+                          gpointer          origin_tag)
+{
+  G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->reset (backend, name, origin_tag);
+}
+
+/*< private >
+ * g_settings_backend_get_writable:
+ * @backend: a #GSettingsBackend implementation
+ * @name: the name of a key
+ * @returns: %TRUE if the key is writable
+ *
+ * Finds out if a key is available for writing to.  This is the
+ * interface through which 'lockdown' is implemented.  Locked down
+ * keys will have %FALSE returned by this call.
+ *
+ * You should not write to locked-down keys, but if you do, the
+ * implementation will deal with it.
+ */
+gboolean
+g_settings_backend_get_writable (GSettingsBackend *backend,
+                                 const gchar      *name)
+{
+  return G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->get_writable (backend, name);
+}
+
+/*< private >
+ * g_settings_backend_unsubscribe:
+ * @backend: a #GSettingsBackend
+ * @name: a key or path to subscribe to
+ *
+ * Reverses the effect of a previous call to
+ * g_settings_backend_subscribe().
+ */
+void
+g_settings_backend_unsubscribe (GSettingsBackend *backend,
+                                const char       *name)
+{
+  G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->unsubscribe (backend, name);
+}
+
+/*< private >
+ * g_settings_backend_subscribe:
+ * @backend: a #GSettingsBackend
+ * @name: a key or path to subscribe to
+ *
+ * Requests that change signals be emitted for events on @name.
+ */
+void
+g_settings_backend_subscribe (GSettingsBackend *backend,
+                              const gchar      *name)
+{
+  G_SETTINGS_BACKEND_GET_CLASS (backend)
+    ->subscribe (backend, name);
+}
+
+static void
+g_settings_backend_set_property (GObject         *object,
+                                 guint            prop_id,
+                                 const GValue    *value,
+                                 GParamSpec      *pspec)
+{
+  GSettingsBackend *backend = G_SETTINGS_BACKEND (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTEXT:
+      backend->priv->context = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+g_settings_backend_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GSettingsBackend *backend = G_SETTINGS_BACKEND (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTEXT:
+      g_value_set_string (value, backend->priv->context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+g_settings_backend_finalize (GObject *object)
+{
+  GSettingsBackend *backend = G_SETTINGS_BACKEND (object);
+
+  g_free (backend->priv->context);
+
+  G_OBJECT_CLASS (g_settings_backend_parent_class)->finalize (object);
+}
+
+static void
+ignore_subscription (GSettingsBackend *backend,
+                     const gchar      *key)
+{
+}
+
+static void
+g_settings_backend_init (GSettingsBackend *backend)
+{
+  backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
+                                               G_TYPE_SETTINGS_BACKEND,
+                                               GSettingsBackendPrivate);
+}
+
+static void
+g_settings_backend_class_init (GSettingsBackendClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  class->subscribe = ignore_subscription;
+  class->unsubscribe = ignore_subscription;
+
+  gobject_class->get_property = g_settings_backend_get_property;
+  gobject_class->set_property = g_settings_backend_set_property;
+  gobject_class->finalize = g_settings_backend_finalize;
+
+  g_type_class_add_private (class, sizeof (GSettingsBackendPrivate));
+
+  /**
+   * GSettingsBackend:context:
+   *
+   * The "context" property gives a hint to the backend as to
+   * what storage to use. It is up to the implementation to make
+   * use of this information.
+   *
+   * E.g. DConf supports "user", "system", "defaults" and "login"
+   * contexts.
+   *
+   * If your backend supports different contexts, you should also
+   * provide an implementation of the supports_context() class
+   * function in #GSettingsBackendClass.
+   *
+   * Since: 2.26
+   */
+  g_object_class_install_property (gobject_class, PROP_CONTEXT,
+    g_param_spec_string ("context", P_("Context"),
+                         P_("An identifier to decide which storage to use"),
+                         NULL, G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+}
+
+/*< private >
+ * g_settings_backend_create_tree:
+ * @returns: a new #GTree
+ *
+ * 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().
+ */
+GTree *
+g_settings_backend_create_tree (void)
+{
+  return g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
+                          g_free, (GDestroyNotify) g_variant_unref);
+}
+
+
+static gpointer
+get_default_backend (const gchar *context)
+{
+  GIOExtension *extension = NULL;
+  GIOExtensionPoint *point;
+  GList *extensions;
+  const gchar *env;
+  GType type;
+
+  _g_io_modules_ensure_loaded ();
+
+  point = g_io_extension_point_lookup (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME);
+
+  if ((env = getenv ("GSETTINGS_BACKEND")))
+    {
+      extension = g_io_extension_point_get_extension_by_name (point, env);
+
+      if (extension == NULL)
+        g_warning ("Can't find GSettings backend '%s' given in "
+                   "GSETTINGS_BACKEND environment variable", env);
+    }
+
+  if (extension == NULL)
+    {
+      extensions = g_io_extension_point_get_extensions (point);
+
+      if (extensions == NULL)
+        g_error ("No GSettingsBackend implementations exist.");
+
+      extension = extensions->data;
+    }
+
+  if (context)
+    {
+      GSettingsBackendClass *backend_class;
+      GTypeClass *class;
+
+      class = g_io_extension_ref_class (extension);
+      backend_class = G_SETTINGS_BACKEND_CLASS (class);
+
+      if (backend_class->supports_context != NULL &&
+          !backend_class->supports_context (context))
+        {
+          g_type_class_unref (class);
+          return NULL;
+        }
+
+      g_type_class_unref (class);
+    }
+
+  type = g_io_extension_get_type (extension);
+
+  return g_object_new (type, "context", context, NULL);
+}
+
+/*< private >
+ * g_settings_backend_get_with_context:
+ * @context: a context that might be used by the backend to determine
+ *     which storage to use, or %NULL to use the default storage
+ * @returns: the default #GSettingsBackend
+ *
+ * Returns the default #GSettingsBackend. It is possible to override
+ * the default by setting the <envar>GSETTINGS_BACKEND</envar>
+ * environment variable to the name of a settings backend.
+ *
+ * The @context parameter can be used to indicate that a different
+ * than the default storage is desired. E.g. the DConf backend lets
+ * you use "user", "system", "defaults" and "login" as contexts.
+ *
+ * If @context is not supported by the implementation, this function
+ * returns an instance of the #GSettingsMemoryBackend.
+ * See g_settings_backend_supports_context(),
+ *
+ * The user does not own the return value and it must not be freed.
+ */
+GSettingsBackend *
+g_settings_backend_get_with_context (const gchar *context)
+{
+  static GHashTable *backends;
+  GSettingsBackend *backend;
+
+  g_return_val_if_fail (context != NULL, NULL);
+
+  _g_io_modules_ensure_extension_points_registered ();
+
+  if (!backends)
+    backends = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  backend = g_hash_table_lookup (backends, context);
+
+  if (!backend)
+    {
+      backend = get_default_backend (context);
+
+      if (!backend)
+        {
+          /* FIXME: create an instance of the const backend */
+        }
+
+      g_hash_table_insert (backends, g_strdup (context), backend);
+    }
+
+  return g_object_ref (backend);
+}
+
+/*< private >
+ * g_settings_backend_supports_context:
+ * @context: a context string that might be passed to
+ *     g_settings_backend_new_with_context()
+ * @returns: #TRUE if @context is supported
+ *
+ * Determines if the given context is supported by the default
+ * GSettingsBackend implementation.
+ */
+gboolean
+g_settings_backend_supports_context (const gchar *context)
+{
+  GSettingsBackend *backend;
+
+  backend = get_default_backend (context);
+
+  if (backend)
+    {
+      g_object_unref (backend);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+#define __G_SETTINGS_BACKEND_C__
+#include "gioaliasdef.c"
diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h
new file mode 100644
index 0000000..ecdf51b
--- /dev/null
+++ b/gio/gsettingsbackend.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2009, 2010 Codethink Limited
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __G_SETTINGS_BACKEND_H__
+#define __G_SETTINGS_BACKEND_H__
+
+#if !defined (G_SETTINGS_ENABLE_BACKEND) && !defined (GIO_COMPILATION)
+#error "You must define G_SETTINGS_ENABLE_BACKEND before including <gio/gsettingsbackend.h>."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SETTINGS_BACKEND                             (g_settings_backend_get_type ())
+#define G_SETTINGS_BACKEND(inst)                            (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SETTINGS_BACKEND, GSettingsBackend))
+#define G_SETTINGS_BACKEND_CLASS(class)                     (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SETTINGS_BACKEND, GSettingsBackendClass))
+#define G_IS_SETTINGS_BACKEND(inst)                         (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SETTINGS_BACKEND))
+#define G_IS_SETTINGS_BACKEND_CLASS(class)                  (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SETTINGS_BACKEND))
+#define G_SETTINGS_BACKEND_GET_CLASS(inst)                  (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SETTINGS_BACKEND, GSettingsBackendClass))
+
+/**
+ * G_SETTINGS_BACKEND_EXTENSION_POINT_NAME:
+ *
+ * Extension point for #GSettingsBackend functionality.
+ **/
+#define G_SETTINGS_BACKEND_EXTENSION_POINT_NAME "gsettings-backend"
+
+/**
+ * GSettingsBackend:
+ *
+ * An implementation of a settings storage repository.
+ **/
+typedef struct _GSettingsBackendPrivate                     GSettingsBackendPrivate;
+typedef struct _GSettingsBackendClass                       GSettingsBackendClass;
+typedef struct _GSettingsBackend                            GSettingsBackend;
+
+
+struct _GSettingsBackendClass
+{
+  GObjectClass parent_class;
+
+  gboolean    (*supports_context) (const gchar         *context);
+
+  GVariant *  (*read)             (GSettingsBackend    *backend,
+                                   const gchar         *key,
+                                   const GVariantType  *expected_type);
+  void        (*write)            (GSettingsBackend    *backend,
+                                   const gchar         *key,
+                                   GVariant            *value,
+                                   gpointer             origin_tag);
+  void        (*write_keys)       (GSettingsBackend    *backend,
+                                   GTree               *tree,
+                                   gpointer             origin_tag);
+  void        (*reset)            (GSettingsBackend    *backend,
+                                   const gchar         *name,
+                                   gpointer             origin_tag);
+  gboolean    (*get_writable)     (GSettingsBackend    *backend,
+                                   const gchar         *name);
+  void        (*subscribe)        (GSettingsBackend    *backend,
+                                   const gchar         *name);
+  void        (*unsubscribe)      (GSettingsBackend    *backend,
+                                   const gchar         *name);
+};
+
+struct _GSettingsBackend
+{
+  GObject parent_instance;
+
+  /*< private >*/
+  GSettingsBackendPrivate *priv;
+};
+
+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_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);
+
+G_END_DECLS
+
+#endif /* __G_SETTINGS_BACKEND_H__ */
diff --git a/gio/gsettingsbackendinternal.h b/gio/gsettingsbackendinternal.h
new file mode 100644
index 0000000..3e4c5e9
--- /dev/null
+++ b/gio/gsettingsbackendinternal.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2009, 2010 Codethink Limited
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __G_SETTINGS_BACKEND_INTERNAL_H__
+#define __G_SETTINGS_BACKEND_INTERNAL_H__
+
+#include "gsettingsbackend.h"
+
+G_BEGIN_DECLS
+
+typedef void          (*GSettingsBackendChangedFunc)                    (GSettingsBackend    *backend,
+                                                                         const gchar         *key,
+                                                                         gpointer             origin_tag,
+                                                                         gpointer             user_data);
+typedef void          (*GSettingsBackendPathChangedFunc)                (GSettingsBackend    *backend,
+                                                                         const gchar         *path,
+                                                                         gpointer             origin_tag,
+                                                                         gpointer             user_data);
+typedef void          (*GSettingsBackendKeysChangedFunc)                (GSettingsBackend    *backend,
+                                                                         const gchar         *prefix,
+                                                                         const gchar * const *names,
+                                                                         gpointer             origin_tag,
+                                                                         gpointer             user_data);
+typedef void          (*GSettingsBackendWritableChangedFunc)            (GSettingsBackend    *backend,
+                                                                         const gchar         *key,
+                                                                         gpointer             user_data);
+typedef void          (*GSettingsBackendPathWritableChangedFunc)        (GSettingsBackend    *backend,
+                                                                         const gchar         *path,
+                                                                         gpointer             user_data);
+
+G_GNUC_INTERNAL
+void                    g_settings_backend_watch                        (GSettingsBackend                        *backend,
+                                                                         GSettingsBackendChangedFunc              changed,
+                                                                         GSettingsBackendPathChangedFunc          path_changed,
+                                                                         GSettingsBackendKeysChangedFunc          keys_changed,
+                                                                         GSettingsBackendWritableChangedFunc      writable_changed,
+                                                                         GSettingsBackendPathWritableChangedFunc  path_writable_changed,
+                                                                         gpointer                                 user_data);
+G_GNUC_INTERNAL
+void                    g_settings_backend_unwatch                      (GSettingsBackend                     *backend,
+                                                                         gpointer                              user_data);
+
+G_GNUC_INTERNAL
+gboolean                        g_settings_backend_supports_context     (const gchar                          *context);
+G_GNUC_INTERNAL
+GSettingsBackend *              g_settings_backend_get_with_context     (const gchar                          *context);
+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);
+G_GNUC_INTERNAL
+void                            g_settings_backend_write                (GSettingsBackend                     *backend,
+                                                                         const gchar                          *key,
+                                                                         GVariant                             *value,
+                                                                         gpointer                              origin_tag);
+G_GNUC_INTERNAL
+void                            g_settings_backend_write_keys           (GSettingsBackend                     *backend,
+                                                                         GTree                                *tree,
+                                                                         gpointer                              origin_tag);
+G_GNUC_INTERNAL
+void                            g_settings_backend_reset                (GSettingsBackend                     *backend,
+                                                                         const gchar                          *name,
+                                                                         gpointer                              origin_tag);
+
+G_GNUC_INTERNAL
+gboolean                        g_settings_backend_get_writable         (GSettingsBackend                     *backend,
+                                                                         const char                           *name);
+
+G_GNUC_INTERNAL
+void                            g_settings_backend_unsubscribe          (GSettingsBackend                     *backend,
+                                                                         const char                           *name);
+G_GNUC_INTERNAL
+void                            g_settings_backend_subscribe            (GSettingsBackend                     *backend,
+                                                                         const char                           *name);
+
+G_END_DECLS
+
+#endif  /* __G_SETTINGS_BACKEND_INTERNAL_H__ */
diff --git a/gio/pltcheck.sh b/gio/pltcheck.sh
index ae2b9b6..a0244bf 100755
--- a/gio/pltcheck.sh
+++ b/gio/pltcheck.sh
@@ -9,7 +9,7 @@ if ! which readelf 2>/dev/null >/dev/null; then
 	exit 0
 fi
 
-SKIP='\<g_access\|\<g_array_\|\<g_ascii\|\<g_list_\|\<g_assertion_message\|\<g_warn_message\|\<g_atomic\|\<g_bit_\|\<g_boxed\|\<g_build_filename\|\<g_byte_array\|\<g_checksum\|\<g_child_watch\|\<g_clear_error\|\<g_convert\|\<g_dir_\|\<g_enum_\|\<g_error_\|\<g_prefix_error\|\<g_file_error_quark\|\<g_file_get_contents\|\<g_file_set_contents\|\<g_file_test\|\<g_file_read_link\|\<g_filename_\|\<g_find_program_in_path\|\<g_flags_\|\<g_free\|\<g_get_\|\<g_getenv\|\<g_setenv\|\<g_hash_table_\|\<g_hostname_\|\<g_iconv\|\<g_idle_\|\<g_intern_static_string\|\<g_io_add_watch\|\<g_io_channel_\|\<g_io_create_watch\|\<g_key_file_\|\<g_listenv\|\<g_locale_to_utf8\|\<g_log\|\<g_main_context_\|\<g_main_current_source\|\<g_main_loop_\|\<g_malloc\|\<g_markup_\|\<g_mkdir_\|\<g_mkstemp\|\<g_module_\|\<g_object_\|\<g_once_\|\<g_param_spec_\|\<g_path_\|\<g_poll\|\<g_printerr\|\<g_propagate_error\|\<g_ptr_array_\|\<g_qsort_\|\<g_quark_\|\<g_queue_\|\<g_random_int_range\|\<g_realloc\|\<g_return_if_f
 ail\|\<g_set_error\|\<g_shell_\|\<g_signal_\|\<g_slice_\|\<g_slist_\|\<g_snprintf\|\<g_source_\|\<g_spawn_\|\<g_static_\|\<g_str\|\<g_thread_pool_\|\<g_time_val_add\|\<g_timeout_\|\<g_type_\|\<g_unlink\|\<g_uri_\|\<g_utf8_\|\<g_value_'
+SKIP='\<g_access\|\<g_array_\|\<g_ascii\|\<g_list_\|\<g_assertion_message\|\<g_warn_message\|\<g_atomic\|\<g_bit_\|\<g_boxed\|\<g_build_filename\|\<g_byte_array\|\<g_checksum\|\<g_child_watch\|\<g_clear_error\|\<g_convert\|\<g_dir_\|\<g_enum_\|\<g_error_\|\<g_prefix_error\|\<g_file_error_quark\|\<g_file_get_contents\|\<g_file_set_contents\|\<g_file_test\|\<g_file_read_link\|\<g_filename_\|\<g_find_program_in_path\|\<g_flags_\|\<g_free\|\<g_get_\|\<g_getenv\|\<g_setenv\|\<g_hash_table_\|\<g_hostname_\|\<g_iconv\|\<g_idle_\|\<g_intern_static_string\|\<g_io_add_watch\|\<g_io_channel_\|\<g_io_create_watch\|\<g_key_file_\|\<g_listenv\|\<g_locale_to_utf8\|\<g_log\|\<g_main_context_\|\<g_main_current_source\|\<g_main_loop_\|\<g_malloc\|\<g_markup_\|\<g_mkdir_\|\<g_mkstemp\|\<g_module_\|\<g_object_\|\<g_once_\|\<g_param_spec_\|\<g_path_\|\<g_poll\|\<g_printerr\|\<g_propagate_error\|\<g_ptr_array_\|\<g_qsort_\|\<g_quark_\|\<g_queue_\|\<g_random_int_range\|\<g_realloc\|\<g_return_if_f
 ail\|\<g_set_error\|\<g_shell_\|\<g_signal_\|\<g_slice_\|\<g_slist_\|\<g_snprintf\|\<g_source_\|\<g_spawn_\|\<g_static_\|\<g_str\|\<g_thread_pool_\|\<g_time_val_add\|\<g_timeout_\|\<g_type_\|\<g_unlink\|\<g_uri_\|\<g_utf8_\|\<g_value_\|\<g_tree_'
 
 for so in .libs/lib*.so; do
 	echo Checking $so for local PLT entries



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