[gconf] [gsettings] Initial push of a GSettings backend using GConf



commit e934a0d85f2d1d85d84c1bef6c8def3501c60b47
Author: Vincent Untz <vuntz gnome org>
Date:   Thu Apr 15 18:11:05 2010 -0400

    [gsettings] Initial push of a GSettings backend using GConf

 Makefile.am                      |    8 +-
 configure.in                     |   28 ++
 gsettings/Makefile.am            |   28 ++
 gsettings/gconfsettingsbackend.c |  640 ++++++++++++++++++++++++++++++++++++++
 gsettings/gconfsettingsbackend.h |   72 +++++
 5 files changed, 774 insertions(+), 2 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index d41ccdd..6e93481 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,12 +1,16 @@
 
 SUBDIRS = gconf backends po doc examples
 
-DIST_SUBDIRS = tests gconf backends po doc examples defaults
+DIST_SUBDIRS = tests gconf backends po doc examples defaults gsettings
 
 if ENABLE_DEFAULTS_SERVICE
 SUBDIRS += defaults
 endif
 
+if ENABLE_GSETTINGS_BACKEND
+SUBDIRS += gsettings
+endif
+
 EXTRA_DIST =                \
 	TODO                \
 	gtk-doc.make        \
@@ -19,7 +23,7 @@ DISTCLEANFILES =          \
 	intltool-merge    \
 	intltool-extract
 
-DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection --enable-defaults-service
+DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection --enable-defaults-service --enable-gsettings-backend
 
 install-data-local:
 	-mkdir -p $(DESTDIR)$(sysgconfdir)/gconf.xml.defaults
diff --git a/configure.in b/configure.in
index 113c081..bb803f9 100644
--- a/configure.in
+++ b/configure.in
@@ -198,6 +198,32 @@ fi
 
 AM_CONDITIONAL(ENABLE_DEFAULTS_SERVICE, [test "x$enable_defaults_service" != "xno"])
 
+AC_ARG_ENABLE(gsettings_backend,
+  AS_HELP_STRING([--enable-gsettings-backend],
+    [build the gsettings backend @<:@default=auto@:>@]),
+  , enable_gsettings_backend=auto)
+
+if test "x$enable_gsettings_backend" != "xno" ; then
+  PKG_CHECK_MODULES(GSETTINGS, gio-2.0, HAVE_GSETTINGS=yes, HAVE_GSETTINGS=no)
+  if test "x$HAVE_GSETTINGS" = "xno"; then
+    if test "x$enable_gsettings_backend" = "xyes" ; then
+      AC_MSG_ERROR([[
+*** Could not find GIO.]])
+    fi
+  else
+    enable_gsettings_backend=yes
+    AC_SUBST(GIO_MODULE_DIR,
+             `pkg-config --variable giomoduledir gio-2.0`)
+    AC_PATH_PROG(GIO_QUERYMODULES, gio-querymodules, no)
+  fi
+fi
+
+if test "x$enable_gsettings_backend" != "xno" ; then
+  AC_DEFINE(ENABLE_GSETTINGS_BACKEND, 1, [enable defaults DBus service])
+fi
+
+AM_CONDITIONAL(ENABLE_GSETTINGS_BACKEND, [test "x$enable_gsettings_backend" != "xno"])
+
 ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
 AC_SUBST(ORBIT_IDL)
 
@@ -288,6 +314,7 @@ doc/gconf/Makefile
 examples/Makefile
 tests/Makefile
 defaults/Makefile
+gsettings/Makefile
 gconf-2.0.pc
 ])
 
@@ -299,6 +326,7 @@ echo "
 	gtk+:		${HAVE_GTK}
 	ldap:		${have_ldap}
 	policykit:	${HAVE_POLKIT}
+	gsettings:	${HAVE_GSETTINGS}
 	introspection:  ${found_introspection}
 
 "
diff --git a/gsettings/Makefile.am b/gsettings/Makefile.am
new file mode 100644
index 0000000..74c69fc
--- /dev/null
+++ b/gsettings/Makefile.am
@@ -0,0 +1,28 @@
+module_flags = -export_dynamic -avoid-version -module -no-undefined -export-symbols-regex '^g_io_module_(load|unload|query)'
+
+giomodule_LTLIBRARIES = libgsettingsgconfbackend.la
+giomoduledir = $(GIO_MODULE_DIR)
+
+libgsettingsgconfbackend_la_SOURCES = \
+	gconfsettingsbackend-module.c \
+	gconfsettingsbackend.c        \
+	gconfsettingsbackend.h
+
+libgsettingsgconfbackend_la_CFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_builddir) \
+	$(GSETTINGS_CFLAGS)
+
+libgsettingsgconfbackend_la_LDFLAGS = \
+	$(module_flags)               \
+	$(NULL)
+
+libgsettingsgconfbackend_la_LIBADD =        \
+	$(top_builddir)/gconf/libgconf-2.la \
+	$(GSETTINGS_LIBS)                   \
+	$(NULL)
+
+install-data-hook:
+	if test -z "$(DESTDIR)" -a "$(GIO_QUERYMODULES)" != "no" ; then                         \
+		$(GIO_QUERYMODULES) $(GIO_MODULE_DIR) ;                                         \
+	fi
diff --git a/gsettings/gconfsettingsbackend.c b/gsettings/gconfsettingsbackend.c
new file mode 100644
index 0000000..35ec28d
--- /dev/null
+++ b/gsettings/gconfsettingsbackend.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2010 Novell, 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 License, 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.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gconf/gconf-client.h>
+
+#include "gconfsettingsbackend.h"
+
+G_DEFINE_DYNAMIC_TYPE (GConfSettingsBackend, gconf_settings_backend, G_TYPE_SETTINGS_BACKEND);
+
+struct _GConfSettingsBackendPrivate
+{
+  GConfClient *client;
+};
+
+static gboolean
+gconf_settings_backend_simple_gconf_value_type_is_compatible (GConfValueType      type,
+                                                              const GVariantType *expected_type)
+{
+  switch (type)
+    {
+    case GCONF_VALUE_STRING:
+      return (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING)      ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH) ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE));
+    case GCONF_VALUE_INT:
+      return (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE)   ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16)  ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16) ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32)  ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32) ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64)  ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64) ||
+              g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE));
+    case GCONF_VALUE_FLOAT:
+      return g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE);
+    case GCONF_VALUE_BOOL:
+      return g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN);
+    case GCONF_VALUE_LIST:
+    case GCONF_VALUE_PAIR:
+      return FALSE;
+    default:
+      return FALSE;
+    }
+}
+
+static GVariant *
+gconf_settings_backend_simple_gconf_value_type_to_gvariant (GConfValue         *gconf_value,
+                                                            const GVariantType *expected_type)
+{
+  /* Note: it's guaranteed that the types are compatible */
+  GVariant *variant = NULL;
+
+  if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN))
+    variant = g_variant_new_boolean (gconf_value_get_bool (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE))
+    {
+      int value = gconf_value_get_int (gconf_value);
+      if (value < 0 || value > 255)
+        return NULL;
+      variant = g_variant_new_byte (value);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+    {
+      int value = gconf_value_get_int (gconf_value);
+      if (value < G_MINSHORT || value > G_MAXSHORT)
+        return NULL;
+      variant = g_variant_new_int16 (value);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+    {
+      int value = gconf_value_get_int (gconf_value);
+      if (value < 0 || value > G_MAXUSHORT)
+        return NULL;
+      variant = g_variant_new_uint16 (value);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+    variant = g_variant_new_int32 (gconf_value_get_int (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+    {
+      int value = gconf_value_get_int (gconf_value);
+      if (value < 0)
+        return NULL;
+      variant = g_variant_new_uint32 (value);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+    variant = g_variant_new_int64 ((gint64) gconf_value_get_int (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+    {
+      int value = gconf_value_get_int (gconf_value);
+      if (value < 0)
+        return NULL;
+      variant = g_variant_new_uint64 (value);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+    variant = g_variant_new_handle (gconf_value_get_int (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+    variant = g_variant_new_double (gconf_value_get_float (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING))
+    variant = g_variant_new_string (gconf_value_get_string (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
+    variant = g_variant_new_object_path (gconf_value_get_string (gconf_value));
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE))
+    variant = g_variant_new_signature (gconf_value_get_string (gconf_value));
+
+  return variant;
+}
+
+static GVariant *
+gconf_settings_backend_gconf_value_to_gvariant (GConfValue         *gconf_value,
+                                                const GVariantType *expected_type)
+{
+  switch (gconf_value->type)
+    {
+    case GCONF_VALUE_STRING:
+    case GCONF_VALUE_INT:
+    case GCONF_VALUE_FLOAT:
+    case GCONF_VALUE_BOOL:
+      if (!gconf_settings_backend_simple_gconf_value_type_is_compatible (gconf_value->type, expected_type))
+        return NULL;
+      return gconf_settings_backend_simple_gconf_value_type_to_gvariant (gconf_value, expected_type);
+    case GCONF_VALUE_LIST:
+      {
+        GConfValueType      list_type;
+        const GVariantType *array_type;
+        GSList             *list;
+        GPtrArray          *array;
+        GVariant           *result;
+
+        if (!g_variant_type_is_array (expected_type))
+          return NULL;
+
+        list_type = gconf_value_get_list_type (gconf_value);
+        array_type = g_variant_type_element (expected_type);
+        if (!gconf_settings_backend_simple_gconf_value_type_is_compatible (list_type, array_type))
+          return NULL;
+
+        array = g_ptr_array_new ();
+        for (list = gconf_value_get_list (gconf_value); list != NULL; list = list->next)
+          {
+            GVariant *variant;
+            variant = gconf_settings_backend_simple_gconf_value_type_to_gvariant (list->data, array_type);
+            g_ptr_array_add (array, variant);
+          }
+
+        result = g_variant_new_array (array_type, (GVariant **) array->pdata, array->len);
+        g_ptr_array_free (array, TRUE);
+
+        return result;
+      }
+      break;
+    case GCONF_VALUE_PAIR:
+      {
+        GConfValue         *car;
+        GConfValue         *cdr;
+        const GVariantType *first_type;
+        const GVariantType *second_type;
+        GVariant           *tuple[2];
+        GVariant           *result;
+
+        if (!g_variant_type_is_tuple (expected_type) ||
+            g_variant_type_n_items (expected_type) != 2)
+          return NULL;
+
+        car = gconf_value_get_car (gconf_value);
+        cdr = gconf_value_get_cdr (gconf_value);
+        first_type = g_variant_type_first (expected_type);
+        second_type = g_variant_type_next (first_type);
+
+        if (!gconf_settings_backend_simple_gconf_value_type_is_compatible (car->type, first_type) ||
+            !gconf_settings_backend_simple_gconf_value_type_is_compatible (cdr->type, second_type))
+          return NULL;
+
+        tuple[0] = gconf_settings_backend_simple_gconf_value_type_to_gvariant (car, first_type);
+        tuple[1] = gconf_settings_backend_simple_gconf_value_type_to_gvariant (cdr, second_type);
+
+        result = g_variant_new_tuple (tuple, 2);
+        return result;
+      }
+      break;
+    default:
+      return NULL;
+    }
+
+  g_assert_not_reached ();
+
+  return NULL;
+}
+
+static GConfValueType
+gconf_settings_backend_simple_gvariant_type_to_gconf_value_type (const GVariantType *type)
+{
+  if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
+      return GCONF_VALUE_BOOL;
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)     ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_INT16)    ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)   ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_INT32)    ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)   ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_INT64)    ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)   ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
+      return GCONF_VALUE_INT;
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
+      return GCONF_VALUE_FLOAT;
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)      ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
+      return GCONF_VALUE_STRING;
+
+  return GCONF_VALUE_INVALID;
+}
+
+static GConfValue *
+gconf_settings_backend_simple_gvariant_to_gconf_value (GVariant           *value,
+                                                       const GVariantType *type)
+{
+  GConfValue *gconf_value = NULL;
+
+  if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
+    {
+      gconf_value = gconf_value_new (GCONF_VALUE_BOOL);
+      gconf_value_set_bool (gconf_value, g_variant_get_boolean (value));
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
+    {
+      guchar i = g_variant_get_byte (value);
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
+    {
+      gint16 i = g_variant_get_int16 (value);
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
+    {
+      guint16 i = g_variant_get_uint16 (value);
+      if (i > G_MAXINT)
+        return NULL;
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
+    {
+      gint32 i = g_variant_get_int32 (value);
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
+    {
+      guint32 i = g_variant_get_uint32 (value);
+      if (i > G_MAXINT)
+        return NULL;
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
+    {
+      gint64 i = g_variant_get_int64 (value);
+      if (i < G_MININT || i > G_MAXINT)
+        return NULL;
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
+    {
+      guint64 i = g_variant_get_uint64 (value);
+      if (i > G_MAXINT)
+        return NULL;
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
+    {
+      gint32 i = g_variant_get_handle (value);
+      gconf_value = gconf_value_new (GCONF_VALUE_INT);
+      gconf_value_set_int (gconf_value, i);
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
+    {
+      gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
+      gconf_value_set_float (gconf_value, g_variant_get_double (value));
+    }
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)      ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
+           g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
+    {
+      gconf_value = gconf_value_new (GCONF_VALUE_STRING);
+      gconf_value_set_string (gconf_value, g_variant_get_string (value, NULL));
+    }
+
+  return gconf_value;
+}
+
+static GConfValue *
+gconf_settings_backend_gvariant_to_gconf_value (GVariant *value)
+{
+  const GVariantType *type;
+  GConfValue         *gconf_value = NULL;
+
+  type = g_variant_get_type (value);
+  if (g_variant_type_is_basic (type) &&
+      !g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
+    gconf_value = gconf_settings_backend_simple_gvariant_to_gconf_value (value, type);
+  else if (g_variant_type_is_array (type))
+    {
+      const GVariantType *array_type;
+      array_type = g_variant_type_element (type);
+
+      if (g_variant_type_is_basic (array_type) &&
+          !g_variant_type_equal (array_type, G_VARIANT_TYPE_BASIC))
+        {
+          GConfValueType  value_type;
+          int             i;
+          GSList        *list = NULL;
+
+          for (i = 0; i < g_variant_n_children (value); i++)
+            {
+              GConfValue *l;
+
+              l = gconf_settings_backend_simple_gvariant_to_gconf_value (g_variant_get_child_value (value, i),
+                                                                         array_type);
+              list = g_slist_prepend (list, l);
+            }
+
+          list = g_slist_reverse (list);
+
+          value_type = gconf_settings_backend_simple_gvariant_type_to_gconf_value_type (array_type);
+          gconf_value = gconf_value_new (GCONF_VALUE_LIST);
+          gconf_value_set_list_type (gconf_value, value_type);
+          gconf_value_set_list (gconf_value, list);
+
+          g_slist_foreach (list, (GFunc) gconf_value_free, NULL);
+          g_slist_free (list);
+        }
+    }
+  else if (g_variant_type_is_tuple (type) &&
+            g_variant_type_n_items (type) == 2)
+    {
+      const GVariantType *first_type;
+      const GVariantType *second_type;
+
+      first_type = g_variant_type_first (type);
+      second_type = g_variant_type_next (first_type);
+
+      if (g_variant_type_is_basic (first_type) &&
+          !g_variant_type_equal (first_type, G_VARIANT_TYPE_BASIC) &&
+          g_variant_type_is_basic (second_type) &&
+          !g_variant_type_equal (second_type, G_VARIANT_TYPE_BASIC))
+        {
+          GConfValue *car;
+          GConfValue *cdr;
+
+          gconf_value = gconf_value_new (GCONF_VALUE_PAIR);
+
+          car = gconf_settings_backend_simple_gvariant_to_gconf_value (g_variant_get_child_value (value, 0), first_type);
+          cdr = gconf_settings_backend_simple_gvariant_to_gconf_value (g_variant_get_child_value (value, 1), second_type);
+
+          if (car)
+            gconf_value_set_car_nocopy (gconf_value, car);
+          if (cdr)
+            gconf_value_set_cdr_nocopy (gconf_value, cdr);
+
+          if (car == NULL || cdr == NULL)
+            {
+              gconf_value_free (gconf_value);
+              gconf_value = NULL;
+            }
+        }
+    }
+
+  return gconf_value;
+}
+
+static GVariant *
+gconf_settings_backend_read (GSettingsBackend   *backend,
+                             const gchar        *key,
+                             const GVariantType *expected_type)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+  GConfValue *gconf_value;
+  GVariant *value;
+
+  gconf_value = gconf_client_get_without_default (gconf->priv->client,
+                                                  key, NULL);
+  if (gconf_value == NULL)
+    return NULL;
+
+  value = gconf_settings_backend_gconf_value_to_gvariant (gconf_value, expected_type);
+  gconf_value_free (gconf_value);
+
+  if (value != NULL)
+    g_variant_ref_sink (value);
+
+  return value;
+}
+
+static gboolean
+gconf_settings_backend_write_one (const gchar          *key,
+                                  GVariant             *value,
+                                  GConfSettingsBackend *gconf)
+{
+  GConfValue *gconf_value;
+  GError     *error;
+
+  gconf_value = gconf_settings_backend_gvariant_to_gconf_value (value);
+  if (gconf_value == NULL)
+    return FALSE;
+
+  error = NULL;
+  gconf_client_set (gconf->priv->client, key, gconf_value, &error);
+  if (error != NULL)
+    {
+      g_error_free (error);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+typedef struct {
+  GConfSettingsBackend *gconf;
+  GTree                *failed_keys;
+} GConfSettingsBackendWriteHelper;
+
+static gboolean
+gconf_settings_backend_write_one_helper (const gchar *key,
+                                         GVariant    *value,
+                                         GConfSettingsBackendWriteHelper *helper)
+{
+  gboolean success;
+
+  success = gconf_settings_backend_write_one (key, value, helper->gconf);
+
+  if (!success)
+    g_tree_insert (helper->failed_keys, (gpointer) key, GINT_TO_POINTER(1));
+
+  return FALSE;
+}
+
+static void
+gconf_settings_backend_write (GSettingsBackend *backend,
+                              const gchar      *key,
+                              GVariant         *value,
+                              gpointer          origin_tag)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+  gboolean success;
+
+  success = gconf_settings_backend_write_one (key, value, gconf);
+
+  //FIXME: need to keep failed value in memory so we can return it if it's being requested before we do the second event
+  //FIXME: eat gconf notification for the change we just did
+  g_settings_backend_changed (backend, key, origin_tag);
+
+  if (!success)
+    g_settings_backend_changed (backend, key, NULL);
+}
+
+static void
+gconf_settings_backend_write_keys (GSettingsBackend *backend,
+                                   GTree            *tree,
+                                   gpointer          origin_tag)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+  GConfSettingsBackendWriteHelper helper;
+
+  helper.gconf = gconf;
+  helper.failed_keys = g_tree_new ((GCompareFunc) g_strcmp0);
+
+  g_tree_foreach (tree, (GTraverseFunc) gconf_settings_backend_write_one_helper, &helper);
+  g_settings_backend_changed_tree (backend, tree, origin_tag);
+
+  if (g_tree_nnodes (helper.failed_keys) > 0)
+    g_settings_backend_changed_tree (backend, helper.failed_keys, NULL);
+
+  g_tree_unref (helper.failed_keys);
+}
+
+static void
+gconf_settings_backend_reset (GSettingsBackend *backend,
+                              const gchar      *name,
+                              gpointer          origin_tag)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+
+  if (name[strlen(name) - 1] == '/')
+    {
+      /* We have no way to know if it was completely successful or if it
+       * completely failed, or if only some keys were unset, so we just send
+       * one big changed signal. */
+      gconf_client_recursive_unset (gconf->priv->client, name, 0, NULL);
+      g_settings_backend_path_changed (backend, name, origin_tag);
+    }
+  else
+    {
+      if (gconf_client_unset (gconf->priv->client, name, NULL))
+        g_settings_backend_changed (backend, name, origin_tag);
+    }
+}
+
+static gboolean
+gconf_settings_backend_get_writable (GSettingsBackend *backend,
+                                     const gchar      *name)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+
+  /* we don't support checking writabality for a whole subpath */
+  if (name[strlen(name) - 1] == '/')
+    return FALSE;
+
+  return gconf_client_key_is_writable (gconf->priv->client, name, NULL);
+}
+
+static char *
+gconf_settings_backend_get_gconf_path_from_name (const gchar *name)
+{
+  /* Note: we don't want trailing slash */
+  if (name[strlen(name) - 1] != '/')
+    {
+      const gchar *slash;
+      slash = strrchr (name, '/');
+      g_assert (slash != NULL);
+      return g_strndup (name, slash - name);
+    }
+  else
+    return g_strndup (name, strlen(name) - 1);
+}
+
+static void
+gconf_settings_backend_subscribe (GSettingsBackend *backend,
+                                  const gchar      *name)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+  gchar                *path;
+
+  path = gconf_settings_backend_get_gconf_path_from_name (name);
+  gconf_client_add_dir (gconf->priv->client, path, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+  g_free (path);
+  //FIXME notify
+}
+
+static void
+gconf_settings_backend_unsubscribe (GSettingsBackend *backend,
+                                    const gchar      *name)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (backend);
+  gchar                *path;
+
+  path = gconf_settings_backend_get_gconf_path_from_name (name);
+  gconf_client_remove_dir (gconf->priv->client, path, NULL);
+  g_free (path);
+}
+
+static gboolean
+gconf_settings_backend_supports_context (const gchar *context)
+{
+  return FALSE;
+}
+
+static void
+gconf_settings_backend_finalize (GObject *object)
+{
+  GConfSettingsBackend *gconf = GCONF_SETTINGS_BACKEND (object);
+
+  g_object_unref (gconf->priv->client);
+  gconf->priv->client = NULL;
+
+  G_OBJECT_CLASS (gconf_settings_backend_parent_class)
+    ->finalize (object);
+}
+
+static void
+gconf_settings_backend_init (GConfSettingsBackend *gconf)
+{
+  gconf->priv = G_TYPE_INSTANCE_GET_PRIVATE (gconf,
+                                             GCONF_TYPE_SETTINGS_BACKEND,
+                                             GConfSettingsBackendPrivate);
+  gconf->priv->client = gconf_client_get_default ();
+}
+
+static void
+gconf_settings_backend_class_finalize (GConfSettingsBackendClass *class)
+{                               
+}
+
+static void
+gconf_settings_backend_class_init (GConfSettingsBackendClass *class)
+{
+  GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = gconf_settings_backend_finalize;
+
+  backend_class->read = gconf_settings_backend_read;
+  backend_class->write = gconf_settings_backend_write;
+  backend_class->write_keys = gconf_settings_backend_write_keys;
+  backend_class->reset = gconf_settings_backend_reset;
+  backend_class->get_writable = gconf_settings_backend_get_writable;
+  backend_class->subscribe = gconf_settings_backend_subscribe;
+  backend_class->unsubscribe = gconf_settings_backend_unsubscribe;
+  backend_class->supports_context = gconf_settings_backend_supports_context;
+
+  g_type_class_add_private (class, sizeof (GConfSettingsBackendPrivate));
+}
+
+void 
+gconf_settings_backend_register (GIOModule *module)
+{
+  gconf_settings_backend_register_type (G_TYPE_MODULE (module));
+  g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
+				  GCONF_TYPE_SETTINGS_BACKEND,
+				  "gconf",
+				  -1);
+}
diff --git a/gsettings/gconfsettingsbackend.h b/gsettings/gconfsettingsbackend.h
new file mode 100644
index 0000000..719552e
--- /dev/null
+++ b/gsettings/gconfsettingsbackend.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Novell, 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 License, 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.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#ifndef _gconfsettingsbackend_h_
+#define _gconfsettingsbackend_h_
+
+#define G_SETTINGS_ENABLE_BACKEND
+#include <gio/gsettingsbackend.h>
+
+G_BEGIN_DECLS
+
+#define GCONF_TYPE_SETTINGS_BACKEND                   (gconf_settings_backend_get_type ())
+#define GCONF_SETTINGS_BACKEND(inst)                  (G_TYPE_CHECK_INSTANCE_CAST ((inst),    \
+                                                       GCONF_TYPE_SETTINGS_BACKEND,           \
+                                                       GConfSettingsBackend))
+#define GCONF_SETTINGS_BACKEND_CLASS(class)           (G_TYPE_CHECK_CLASS_CAST ((class),      \
+                                                       GCONF_TYPE_SETTINGS_BACKEND,           \
+                                                       GConfSettingsBackendClass))
+#define GCONF_IS_SETTINGS_BACKEND(inst)               (G_TYPE_CHECK_INSTANCE_TYPE ((inst),    \
+                                                       GCONF_TYPE_SETTINGS_BACKEND))
+#define GCONF_IS_SETTINGS_BACKEND_CLASS(class)        (G_TYPE_CHECK_CLASS_TYPE ((class),      \
+                                                       GCONF_TYPE_SETTINGS_BACKEND))
+#define GCONF_SETTINGS_BACKEND_GET_CLASS(inst)        (G_TYPE_INSTANCE_GET_CLASS ((inst),     \
+                                                       GCONF_TYPE_SETTINGS_BACKEND,           \
+                                                       GConfSettingsBackendClass))
+
+/**
+ * GConfSettingsBackend:
+ *
+ * A backend to GSettings that stores the settings in gconf.
+ **/
+typedef struct _GConfSettingsBackendPrivate               GConfSettingsBackendPrivate;
+typedef struct _GConfSettingsBackendClass                 GConfSettingsBackendClass;
+typedef struct _GConfSettingsBackend                      GConfSettingsBackend;
+
+struct _GConfSettingsBackendClass
+{
+  GSettingsBackendClass parent_class;
+};
+
+struct _GConfSettingsBackend
+{
+  GSettingsBackend parent_instance;
+
+  /*< private >*/
+  GConfSettingsBackendPrivate *priv;
+};
+
+GType gconf_settings_backend_get_type (void);
+void  gconf_settings_backend_register (GIOModule *module);
+
+G_END_DECLS
+
+#endif /* _gconfsettingsbackend_h_ */



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