diff options
author | Vincent Untz <vuntz@gnome.org> | 2010-04-15 18:11:05 -0400 |
---|---|---|
committer | Vincent Untz <vuntz@gnome.org> | 2010-04-15 22:20:51 -0400 |
commit | e934a0d85f2d1d85d84c1bef6c8def3501c60b47 (patch) | |
tree | 53c3b7331a530acb727cfef5174c147cdf74e403 | |
parent | 3f1864949e573ef2d264be1fbc0a865f6c6ad52f (diff) | |
download | gconf-e934a0d85f2d1d85d84c1bef6c8def3501c60b47.tar.gz |
[gsettings] Initial push of a GSettings backend using GConf
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | configure.in | 28 | ||||
-rw-r--r-- | gsettings/Makefile.am | 28 | ||||
-rw-r--r-- | gsettings/gconfsettingsbackend.c | 640 | ||||
-rw-r--r-- | gsettings/gconfsettingsbackend.h | 72 |
5 files changed, 774 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index d41ccdd6..6e934816 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 113c081e..bb803f95 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 00000000..74c69fc9 --- /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 00000000..35ec28dc --- /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 00000000..719552e6 --- /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_ */ |