[glib/new-gsettings] some GSettings stuff
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/new-gsettings] some GSettings stuff
- Date: Tue, 13 Apr 2010 13:20:45 +0000 (UTC)
commit e06ca1fae6b2e77ac9d7641842e30d77cfb4dcc0
Author: Ryan Lortie <desrt desrt ca>
Date: Sat Apr 10 21:57:55 2010 -0400
some GSettings stuff
gio/Makefile.am | 5 +
gio/gdelayedsettingsbackend.c | 329 ++++++++++++++++++++++++++++++++++++++++
gio/gdelayedsettingsbackend.h | 59 ++++++++
gio/gio-marshal.list | 2 +
gio/gmemorysettingsbackend.c | 98 ++++++++++++
gio/gmemorysettingsbackend.h | 51 +++++++
gio/gsettingsbackend.c | 332 +++++++++++++++++++++++++++++++++++++++++
gio/gsettingsbackend.h | 108 +++++++++++++
8 files changed, 984 insertions(+), 0 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fd42438..80368cf 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -250,6 +250,11 @@ libgio_2_0_la_SOURCES = \
gpollfilemonitor.h \
gresolver.c \
gseekable.c \
+ gsettings.c \
+ gsettingsschema.c \
+ gdelayedsettingsbackend.c\
+ gsettingsbackend.c \
+ gmemorysettingsbackend.c\
gsimpleasyncresult.c \
gsocket.c \
gsocketaddress.c \
diff --git a/gio/gdelayedsettingsbackend.c b/gio/gdelayedsettingsbackend.c
new file mode 100644
index 0000000..6128268
--- /dev/null
+++ b/gio/gdelayedsettingsbackend.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "gdelayedsettingsbackend.h"
+
+#include <string.h>
+
+#include "gioalias.h"
+
+enum
+{
+ PROP_NONE,
+ PROP_BACKEND,
+ PROP_BASE_PATH,
+ PROP_HAS_UNAPPLIED
+};
+
+struct _GDelayedSettingsBackendPrivate {
+ GSettingsBackend *backend;
+ guint handler_id;
+ gchar *base_path;
+ GTree *delayed;
+};
+
+G_DEFINE_TYPE (GDelayedSettingsBackend,
+ g_delayed_settings_backend,
+ G_TYPE_SETTINGS_BACKEND)
+
+static gboolean
+g_delayed_settings_backend_add_to_tree (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ gpointer *args = user_data;
+
+ g_tree_insert (args[0],
+ g_strjoin (NULL, args[1], key, NULL),
+ g_variant_ref (value));
+
+ return FALSE;
+}
+
+static void
+g_delayed_settings_backend_write (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *tree,
+ gpointer origin_tag)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
+ gconstpointer args[2] = { delayed->priv->delayed, prefix };
+ gboolean was_empty;
+
+ was_empty = g_tree_nnodes (delayed->priv->delayed) == 0;
+
+ g_tree_foreach (tree, g_delayed_settings_backend_add_to_tree, args);
+
+ g_settings_backend_changed_tree (backend, prefix, tree, origin_tag);
+
+ if (was_empty)
+ g_object_notify (G_OBJECT (delayed), "has-unapplied");
+}
+
+static GVariant *
+g_delayed_settings_backend_read (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
+ GVariant *result = NULL;
+ gchar *path;
+
+ if ((result = g_tree_lookup (delayed->priv->delayed, key)))
+ return g_variant_ref (result);
+
+ path = g_strconcat (delayed->priv->base_path, key, NULL);
+ result = g_settings_backend_read (delayed->priv->backend,
+ path, expected_type);
+ g_free (path);
+
+ return result;
+}
+
+gboolean
+g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *delayed)
+{
+ return g_tree_nnodes (delayed->priv->delayed) > 0;
+}
+
+void
+g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed)
+{
+ if (g_tree_nnodes (delayed->priv->delayed))
+ {
+ GTree *tmp;
+
+ tmp = delayed->priv->delayed;
+ delayed->priv->delayed = g_settings_backend_create_tree ();
+
+ g_settings_backend_write (delayed->priv->backend,
+ delayed->priv->base_path,
+ tmp, delayed->priv);
+ g_tree_unref (tmp);
+
+ g_object_notify (G_OBJECT (delayed), "has-unapplied");
+ }
+}
+
+void
+g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed)
+{
+ if (g_tree_nnodes (delayed->priv->delayed))
+ {
+ GTree *tmp;
+
+ tmp = delayed->priv->delayed;
+ delayed->priv->delayed = g_settings_backend_create_tree ();
+ g_settings_backend_changed_tree (G_SETTINGS_BACKEND (delayed),
+ "", tmp, NULL);
+ g_tree_destroy (tmp);
+
+ g_object_notify (G_OBJECT (delayed), "has-unapplied");
+ }
+}
+
+static gboolean
+g_delayed_settings_backend_get_writable (GSettingsBackend *backend,
+ const gchar *name)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (backend);
+ gboolean sensitive;
+ gchar *path;
+
+ path = g_strconcat (delayed->priv->base_path, name, NULL);
+ sensitive = g_settings_backend_get_writable (delayed->priv->backend, path);
+ g_free (path);
+
+ return sensitive;
+}
+
+static void
+g_delayed_settings_backend_subscribe (GSettingsBackend *base,
+ const char *name)
+{
+}
+
+static void
+g_delayed_settings_backend_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object);
+
+ switch (prop_id)
+ {
+ gboolean has;
+
+ case PROP_HAS_UNAPPLIED:
+ has = g_delayed_settings_backend_get_has_unapplied (delayed);
+ g_value_set_boolean (value, has);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+g_delayed_settings_backend_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object);
+
+ switch (prop_id)
+ {
+ case PROP_BACKEND:
+ g_assert (delayed->priv->backend == NULL);
+ delayed->priv->backend = g_value_dup_object (value);
+ break;
+
+ case PROP_BASE_PATH:
+ g_assert (delayed->priv->base_path == NULL);
+ delayed->priv->base_path = g_value_dup_string (value);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+g_delayed_settings_backend_backend_changed (GSettingsBackend *backend,
+ const gchar *prefix,
+ const gchar * const *items,
+ gint n_items,
+ gpointer origin_tag,
+ gpointer user_data)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (user_data);
+
+ if (origin_tag == delayed->priv)
+ return;
+
+ if (g_str_has_prefix (prefix, delayed->priv->base_path))
+ {
+ g_settings_backend_changed (G_SETTINGS_BACKEND (delayed),
+ prefix + strlen (delayed->priv->base_path),
+ items, n_items, origin_tag);
+ }
+
+ else if (g_str_has_prefix (delayed->priv->base_path, prefix))
+ {
+ const gchar **my_items;
+ const gchar *relative;
+ gint relative_length;
+ gint i, j;
+
+ relative = delayed->priv->base_path + strlen (prefix);
+ relative_length = strlen (relative);
+
+ my_items = g_new (const gchar *, n_items + 1);
+
+ for (i = j = 0; i < n_items; i++)
+ if (g_str_has_prefix (items[i], relative))
+ my_items[j++] = items[i] + relative_length;
+ my_items[j] = NULL;
+
+ if (j > 0)
+ g_settings_backend_changed (G_SETTINGS_BACKEND (delayed),
+ "", my_items, j, origin_tag);
+ g_free (my_items);
+ }
+
+ else
+ /* do nothing */;
+}
+
+static void
+g_delayed_settings_backend_constructed (GObject *object)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object);
+
+ g_assert (delayed->priv->backend != NULL);
+ g_assert (delayed->priv->base_path != NULL);
+
+ delayed->priv->handler_id =
+ g_signal_connect (delayed->priv->backend, "changed",
+ G_CALLBACK (g_delayed_settings_backend_backend_changed),
+ delayed);
+
+ g_settings_backend_subscribe (delayed->priv->backend,
+ delayed->priv->base_path);
+}
+
+static void
+g_delayed_settings_backend_finalize (GObject *object)
+{
+ GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (object);
+
+ g_signal_handler_disconnect (delayed->priv->backend,
+ delayed->priv->handler_id);
+ g_settings_backend_unsubscribe (delayed->priv->backend,
+ delayed->priv->base_path);
+ g_object_unref (delayed->priv->backend);
+ g_free (delayed->priv->base_path);
+}
+
+static void
+g_delayed_settings_backend_class_init (GDelayedSettingsBackendClass *class)
+{
+ GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ g_type_class_add_private (class, sizeof (GDelayedSettingsBackendPrivate));
+
+ backend_class->write = g_delayed_settings_backend_write;
+ backend_class->read = g_delayed_settings_backend_read;
+ backend_class->get_writable = g_delayed_settings_backend_get_writable;
+ backend_class->subscribe = g_delayed_settings_backend_subscribe;
+ backend_class->unsubscribe = g_delayed_settings_backend_subscribe;
+
+ object_class->get_property = g_delayed_settings_backend_get_property;
+ object_class->set_property = g_delayed_settings_backend_set_property;
+ object_class->constructed = g_delayed_settings_backend_constructed;
+ object_class->finalize = g_delayed_settings_backend_finalize;
+
+ g_object_class_install_property (object_class, PROP_BACKEND,
+ g_param_spec_object ("backend", "backend backend", "backend",
+ G_TYPE_SETTINGS_BACKEND, G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_BASE_PATH,
+ g_param_spec_string ("base-path", "base path", "base",
+ "", G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_HAS_UNAPPLIED,
+ g_param_spec_boolean ("has-unapplied", "has unapplied", "unapplied",
+ FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+}
+
+static void
+g_delayed_settings_backend_init (GDelayedSettingsBackend *delayed)
+{
+ delayed->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (delayed, G_TYPE_DELAYED_SETTINGS_BACKEND,
+ GDelayedSettingsBackendPrivate);
+
+ delayed->priv->delayed = g_settings_backend_create_tree ();
+}
+
+GSettingsBackend *
+g_delayed_settings_backend_new (GSettingsBackend *backend,
+ const gchar *base_path)
+{
+ return g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND,
+ "backend", backend,
+ "base-path", base_path,
+ NULL);
+}
+
+#define _gsettingsdelayedbackend_c_
+#include "gioaliasdef.c"
diff --git a/gio/gdelayedsettingsbackend.h b/gio/gdelayedsettingsbackend.h
new file mode 100644
index 0000000..e7dedf1
--- /dev/null
+++ b/gio/gdelayedsettingsbackend.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#ifndef _gsettingsdelayedbackend_h_
+#define _gsettingsdelayedbackend_h_
+
+#include <glib-object.h>
+
+#include <gio/gsettingsbackend.h>
+
+#define G_TYPE_DELAYED_SETTINGS_BACKEND (g_delayed_settings_backend_get_type ())
+#define G_DELAYED_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_DELAYED_SETTINGS_BACKEND, \
+ GDelayedSettingsBackend))
+#define G_DELAYED_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_DELAYED_SETTINGS_BACKEND, \
+ GDelayedSettingsBackendClass))
+#define G_IS_DELAYED_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_DELAYED_SETTINGS_BACKEND))
+#define G_IS_DELAYED_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_DELAYED_SETTINGS_BACKEND))
+#define G_DELAYED_SETTINGS_BACKEND_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_DELAYED_SETTINGS_BACKEND, \
+ GDelayedSettingsBackendClass))
+
+typedef struct _GDelayedSettingsBackendPrivate GDelayedSettingsBackendPrivate;
+typedef struct _GDelayedSettingsBackendClass GDelayedSettingsBackendClass;
+typedef struct _GDelayedSettingsBackend GDelayedSettingsBackend;
+
+struct _GDelayedSettingsBackendClass
+{
+ GSettingsBackendClass parent_class;
+};
+
+struct _GDelayedSettingsBackend
+{
+ GSettingsBackend parent_instance;
+ GDelayedSettingsBackendPrivate *priv;
+};
+
+G_BEGIN_DECLS
+
+GType g_delayed_settings_backend_get_type (void);
+GSettingsBackend * g_delayed_settings_backend_new (GSettingsBackend *backend,
+ const gchar *base_path);
+void g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed);
+void g_delayed_settings_backend_apply (GDelayedSettingsBackend *delayed);
+gboolean g_delayed_settings_backend_get_has_unapplied (GDelayedSettingsBackend *delayed);
+
+G_END_DECLS
+
+#endif /* _gsettingsdelayedbackend_h_ */
diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list
index 269ec35..49c2916 100644
--- a/gio/gio-marshal.list
+++ b/gio/gio-marshal.list
@@ -4,3 +4,5 @@ VOID:BOOLEAN,POINTER
VOID:OBJECT,OBJECT,ENUM
BOOLEAN:OBJECT,OBJECT
VOID:STRING,BOXED,BOXED
+VOID:STRING,BOXED,INT,POINTER
+VOID:POINTER,INT
diff --git a/gio/gmemorysettingsbackend.c b/gio/gmemorysettingsbackend.c
new file mode 100644
index 0000000..4548414
--- /dev/null
+++ b/gio/gmemorysettingsbackend.c
@@ -0,0 +1,98 @@
+#include "gmemorysettingsbackend.h"
+
+G_DEFINE_TYPE_WITH_CODE (GMemorySettingsBackend,
+ g_memory_settings_backend,
+ G_TYPE_SETTINGS_BACKEND,
+ g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
+ g_define_type_id, "memory", 0))
+
+struct _GMemorySettingsBackendPrivate
+{
+ GHashTable *table;
+};
+
+static GVariant *
+g_memory_settings_backend_read (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type)
+{
+ GVariant *value;
+
+ GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (backend);
+
+ value = g_hash_table_lookup (memory->priv->table, key);
+
+ if (value != NULL)
+ g_variant_ref (value);
+
+ return value;
+}
+
+static gboolean
+g_memory_settings_backend_write_one (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ GMemorySettingsBackend *memory = ((gpointer *) data)[0];
+ const gchar *prefix = ((gpointer *) data)[1];
+
+ g_hash_table_insert (memory->priv->table,
+ g_strjoin ("", prefix, key, NULL),
+ g_variant_ref (value));
+
+ return FALSE;
+}
+
+static void
+g_memory_settings_backend_write (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *tree,
+ gpointer origin_tag)
+{
+ gpointer write_info[] = { backend, (gpointer) prefix };
+ g_tree_foreach (tree, g_memory_settings_backend_write_one, write_info);
+ g_settings_backend_changed_tree (backend, prefix, tree, origin_tag);
+}
+
+static gboolean
+g_memory_settings_backend_get_writable (GSettingsBackend *backend,
+ const gchar *name)
+{
+ return TRUE;
+}
+
+static void
+g_memory_settings_backend_finalize (GObject *object)
+{
+ GMemorySettingsBackend *memory = G_MEMORY_SETTINGS_BACKEND (object);
+
+ g_hash_table_unref (memory->priv->table);
+
+ G_OBJECT_CLASS (g_memory_settings_backend_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_memory_settings_backend_init (GMemorySettingsBackend *memory)
+{
+ memory->priv = G_TYPE_INSTANCE_GET_PRIVATE (memory,
+ G_TYPE_MEMORY_SETTINGS_BACKEND,
+ GMemorySettingsBackendPrivate);
+ memory->priv->table =
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) g_variant_unref);
+}
+
+static void
+g_memory_settings_backend_class_init (GMemorySettingsBackendClass *class)
+{
+ GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ backend_class->read = g_memory_settings_backend_read;
+ backend_class->write = g_memory_settings_backend_write;
+ backend_class->get_writable = g_memory_settings_backend_get_writable;
+ object_class->finalize = g_memory_settings_backend_finalize;
+
+ g_type_class_add_private (class, sizeof (GMemorySettingsBackendPrivate));
+}
diff --git a/gio/gmemorysettingsbackend.h b/gio/gmemorysettingsbackend.h
new file mode 100644
index 0000000..a765175
--- /dev/null
+++ b/gio/gmemorysettingsbackend.h
@@ -0,0 +1,51 @@
+#ifndef _gmemorysettingsbackend_h_
+#define _gmemorysettingsbackend_h_
+
+#include <gio/gsettingsbackend.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_MEMORY_SETTINGS_BACKEND (g_memory_settings_backend_get_type ())
+#define G_MEMORY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MEMORY_SETTINGS_BACKEND, \
+ GMemorySettingsBackend))
+#define G_MEMORY_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MEMORY_SETTINGS_BACKEND, \
+ GMemorySettingsBackendClass))
+#define G_IS_MEMORY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MEMORY_SETTINGS_BACKEND))
+#define G_IS_MEMORY_SETTINGS_BACKEND_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MEMORY_SETTINGS_BACKEND))
+#define G_MEMORY_SETTINGS_BACKEND_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MEMORY_SETTINGS_BACKEND, \
+ GMemorySettingsBackendClass))
+
+#define G_MEMORY_SETTINGS_BACKEND_EXTENSION_POINT_NAME "gsettings-backend"
+
+/**
+ * GMemorySettingsBackend:
+ *
+ * A backend to GSettings that stores the settings in memory.
+ **/
+typedef struct _GMemorySettingsBackendPrivate GMemorySettingsBackendPrivate;
+typedef struct _GMemorySettingsBackendClass GMemorySettingsBackendClass;
+typedef struct _GMemorySettingsBackend GMemorySettingsBackend;
+
+struct _GMemorySettingsBackendClass
+{
+ GSettingsBackendClass parent_class;
+};
+
+struct _GMemorySettingsBackend
+{
+ GSettingsBackend parent_instance;
+
+ /*< private >*/
+ GMemorySettingsBackendPrivate *priv;
+};
+
+GType g_memory_settings_backend_get_type (void);
+
+G_END_DECLS
+
+#endif /* _gmemorysettingsbackend_h_ */
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
new file mode 100644
index 0000000..b0da255
--- /dev/null
+++ b/gio/gsettingsbackend.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "gsettingsbackend.h"
+
+#include "giomodule-priv.h"
+#include "gio-marshal.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "gioalias.h"
+
+G_DEFINE_ABSTRACT_TYPE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
+
+static guint changed_signal;
+
+/**
+ * SECTION:gsettingsbackend
+ * @short_description: an interface for settings backend implementations
+ *
+ * The #GSettingsBackend inteface defines a generic interface for
+ * non-strictly-typed data backend in a hierarchy.
+ *
+ * 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 signal.
+ *
+ * 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.
+ **/
+
+/**
+ * g_settings_backend_changed:
+ * @backend: a #GSettingsBackend implementation
+ * @prefix: the longest common prefix
+ * @items: the NULL-terminated list of changed keys
+ * @n_items: the number of items in @items
+ * @origin_tag: the origin tag
+ *
+ * Emits the changed signal on @backend. This function should only be
+ * called by the implementation itself, to indicate that a change has
+ * occurred.
+ *
+ * The list of changed keys, relative to the root of the settings store,
+ * is @prefix prepended to each of the @items. It must either be the
+ * case that @prefix is equal to "" or ends in "/" or that @items
+ * contains exactly one item: "". @prefix need not be the largest
+ * possible prefix.
+ *
+ * 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). 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.
+ **/
+void
+g_settings_backend_changed (GSettingsBackend *backend,
+ const gchar *prefix,
+ gchar const * const *items,
+ gint n_items,
+ gpointer origin_tag)
+{
+ if (n_items == -1)
+ for (n_items = 0; items[n_items]; n_items++);
+
+ g_assert (items[n_items] == NULL);
+
+ g_signal_emit (backend, changed_signal, 0,
+ prefix, items, n_items, origin_tag);
+}
+
+static gboolean
+g_settings_backend_append_to_list (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ return (*((*((gchar ***) user_data))++) = key, FALSE);
+}
+
+/**
+ * g_settings_backend_changed_tree:
+ * @backend: a #GSettingsBackend implementation
+ * @prefix: the longest common prefix
+ * @tree: a #GTree
+ * @origin_tag: the origin tag
+ *
+ * This call is a convenience wrapper around
+ * g_settings_backend_changed(). It gets the list of changes from
+ * @tree.
+ **/
+void
+g_settings_backend_changed_tree (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *tree,
+ gpointer origin_tag)
+{
+ gchar **list;
+
+ list = g_new (gchar *, g_tree_nnodes (tree) + 1);
+
+ {
+ gchar **ptr = list;
+ g_tree_foreach (tree, g_settings_backend_append_to_list, &ptr);
+ *ptr = NULL;
+
+ g_assert (list + g_tree_nnodes (tree) == ptr);
+ }
+
+ g_signal_emit (backend, changed_signal, 0,
+ prefix, list, g_tree_nnodes (tree), origin_tag);
+ g_free (list);
+}
+
+/**
+ * g_settings_backend_read:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the key to read
+ * @expected_type: a #GVariantType hint
+ * @returns: the values that was read, or %NULL
+ *
+ * Reads a keys. This call will never block.
+ *
+ * If the key exists, 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);
+}
+
+/**
+ * g_settings_backend_write:
+ * @backend: a #GSettingsBackend implementation
+ * @prefix: the longest common prefix
+ * @values: a #GTree containing values to write
+ * @origin_tag: the origin tag
+ *
+ * Writes one or more keys. This call will never block.
+ *
+ * For each item in @values, a key is written. The key to be written is
+ * @prefix prepended to the key used in the tree. The value stored in
+ * the tree is expected to be a #GVariant instance. It must either be
+ * the case that @prefix is equal to "" or ends in "/" or that @values
+ * contains exactly one item, with a key of "". @prefix need not be the
+ * largest possible prefix.
+ *
+ * This call does not fail. During this call a "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 "backend-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 *prefix,
+ GTree *values,
+ gpointer origin_tag)
+{
+ G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->write (backend, prefix, values, origin_tag);
+}
+
+/**
+ * g_settings_backend_get_writable:
+ * @backend: a #GSettingsBackend implementation
+ * @name: the name of a key, relative to the root of the backend
+ * @returns: %TRUE if the key is writable
+ *
+ * Ensures that 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);
+}
+
+/**
+ * g_settings_backend_subscribe:
+ * @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);
+}
+
+/**
+ * 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_class_init (GSettingsBackendClass *class)
+{
+ changed_signal =
+ g_signal_new ("changed", G_TYPE_SETTINGS_BACKEND,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GSettingsBackendClass, changed),
+ NULL, NULL,
+ _gio_marshal_VOID__STRING_BOXED_INT_POINTER, G_TYPE_NONE,
+ 4, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_INT, G_TYPE_POINTER);
+}
+
+/**
+ * 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 (gpointer user_data)
+{
+ 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;
+ }
+
+ type = g_io_extension_get_type (extension);
+
+ return g_object_new (type, NULL);
+}
+
+/**
+ * g_settings_backend_get_default:
+ * @returns: the default #GSettingsBackend
+ *
+ * Returns the default #GSettingsBackend.
+ *
+ * The user does not own the return value and it must not be freed.
+ **/
+GSettingsBackend *
+g_settings_backend_get_default (void)
+{
+ static GOnce once = G_ONCE_INIT;
+
+ return g_once (&once, get_default_backend, NULL);
+}
+
+static void
+g_settings_backend_init (GSettingsBackend *backend)
+{
+}
diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h
new file mode 100644
index 0000000..6c2bd10
--- /dev/null
+++ b/gio/gsettingsbackend.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#ifndef _gsettingsbackend_h_
+#define _gsettingsbackend_h_
+
+#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))
+
+#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;
+
+ void (*changed) (GSettingsBackend *backend,
+ const gchar *prefix,
+ gchar const * const *names,
+ gint names_len,
+ gpointer origin_tag);
+
+ GVariant * (*read) (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type);
+ void (*write) (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *tree,
+ 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);
+GSettingsBackend * g_settings_backend_get_default (void);
+void g_settings_backend_set_default (GSettingsBackend *backend);
+GTree * g_settings_backend_create_tree (void);
+
+GVariant * g_settings_backend_read (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type);
+
+void g_settings_backend_write (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *values,
+ gpointer origin_tag);
+
+gboolean g_settings_backend_get_writable (GSettingsBackend *backend,
+ const char *name);
+
+void g_settings_backend_unsubscribe (GSettingsBackend *backend,
+ const char *name);
+void g_settings_backend_subscribe (GSettingsBackend *backend,
+ const char *name);
+
+void g_settings_backend_changed (GSettingsBackend *backend,
+ const gchar *prefix,
+ gchar const * const *items,
+ gint n_items,
+ gpointer origin_tag);
+void g_settings_backend_changed_tree (GSettingsBackend *backend,
+ const gchar *prefix,
+ GTree *tree,
+ gpointer origin_tag);
+
+G_END_DECLS
+
+#endif /* _gsettingsbackend_h_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]