summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac.in2
-rw-r--r--docs/reference/Makefile.am5
-rw-r--r--docs/reference/tmpl/xfconf-binding.sgml50
-rw-r--r--docs/reference/tmpl/xfconf-gtk.sgml47
-rw-r--r--docs/reference/xfconf-docs.sgml6
-rw-r--r--docs/reference/xfconf-sections.txt6
-rw-r--r--xfconf-gtk/Makefile.am41
-rw-r--r--xfconf-gtk/libxfconf-gtk-0.pc.in13
-rw-r--r--xfconf-gtk/xfconf-gtk.c225
-rw-r--r--xfconf-gtk/xfconf-gtk.h37
-rw-r--r--xfconf/Makefile.am2
-rw-r--r--xfconf/xfconf-binding.c302
-rw-r--r--xfconf/xfconf-binding.h45
-rw-r--r--xfconf/xfconf.h3
-rw-r--r--xfconf/xfconf.symbols8
16 files changed, 415 insertions, 378 deletions
diff --git a/Makefile.am b/Makefile.am
index 4c092e8..7447f43 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,6 @@ SUBDIRS = \
xfconfd \
xfconf-query \
xfsettingsd \
- xfconf-gtk \
po \
docs \
tests
diff --git a/configure.ac.in b/configure.ac.in
index ec70024..7656ff7 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -196,8 +196,6 @@ tests/remove-properties/Makefile
tests/property-changed-signal/Makefile
xfconf/Makefile
xfconf/libxfconf-0.pc
-xfconf-gtk/Makefile
-xfconf-gtk/libxfconf-gtk-0.pc
xfconf-query/Makefile
xfconfd/Makefile
xfsettingsd/Makefile
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 289fbc7..4ef8479 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -23,12 +23,10 @@ FIXXREF_OPTIONS=
# Used for dependencies
HFILE_GLOB = \
$(top_srcdir)/xfconf/*.h \
- $(top_srcdir)/xfconfd/*.h \
- $(top_srcdir)/xfconf-gtk/*.h
+ $(top_srcdir)/xfconfd/*.h
CFILE_GLOB = \
$(top_srcdir)/xfconf/*.c \
$(top_srcdir)/xfconfd/*.c \
- $(top_srcdir)/xfconf-gtk/*.c \
$(top_srcdir)/common/xfconf-errors.c
# Header files to ignore when scanning
@@ -64,7 +62,6 @@ INCLUDES = \
GTKDOC_LIBS = \
$(top_builddir)/xfconf/libxfconf-$(LIBXFCONF_VERSION_API).la \
- $(top_builddir)/xfconf-gtk/libxfconf-gtk-$(LIBXFCONF_GTK_VERSION_API).la \
$(top_builddir)/xfconfd/xfconfd-xfconf-backend.o
include $(top_srcdir)/gtk-doc.make
diff --git a/docs/reference/tmpl/xfconf-binding.sgml b/docs/reference/tmpl/xfconf-binding.sgml
new file mode 100644
index 0000000..e7dba72
--- /dev/null
+++ b/docs/reference/tmpl/xfconf-binding.sgml
@@ -0,0 +1,50 @@
+<!-- ##### SECTION Title ##### -->
+Xfconf-GObject Binding
+
+<!-- ##### SECTION Short_Description ##### -->
+Functions to bind Xfconf properties to GObject properties
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+Often it may be useful to bind an Xfconf property to a GObject property.
+Settings dialogs often display the current value of an Xfconf property,
+and a user may edit the value to change the value in the Xfconf store.
+If the Xfconf property changes outside the settings dialog, the user will
+usually want to see the settings dialog automatically update to reflect
+the new value.
+
+With a single line of code, Xfconf's binding functionality can automate
+all this.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION xfconf_g_property_bind ##### -->
+<para>
+
+</para>
+
+@channel:
+@xfconf_property:
+@xfconf_property_type:
+@object:
+@object_property:
+
+
+<!-- ##### FUNCTION xfconf_g_property_unbind ##### -->
+<para>
+
+</para>
+
+@channel:
+@xfconf_property:
+@object:
+@object_property:
+
+
diff --git a/docs/reference/tmpl/xfconf-gtk.sgml b/docs/reference/tmpl/xfconf-gtk.sgml
deleted file mode 100644
index 298d3e6..0000000
--- a/docs/reference/tmpl/xfconf-gtk.sgml
+++ /dev/null
@@ -1,47 +0,0 @@
-<!-- ##### SECTION Title ##### -->
-Xfconf-Gtk Library
-
-<!-- ##### SECTION Short_Description ##### -->
-Xfconf Gtk widget binding convenience library
-
-<!-- ##### SECTION Long_Description ##### -->
-<para>
-Often applications will have configuration dialogs that allow users
-to modify settings that are retrieved from and stored to an Xfconf
-configuration store. This library makes creating configuration dialogs
-a breeze by allowing developers to bind a normal Gtk widget (such as a
-GtkEntry or GtkSpinButton) to an Xfconf channel and property string.
-The Gtk widget is automatically populated with the current value in
-Xfconf, and if that value changes, the widget will be automatically
-updated. If the Gtk widget is editable and the user edits the value
-in the widget, the binding will also automatically set the new value
-in the Xfconf store.
-</para>
-
-<!-- ##### SECTION See_Also ##### -->
-<para>
-
-</para>
-
-<!-- ##### SECTION Stability_Level ##### -->
-
-
-<!-- ##### FUNCTION xfconf_gtk_editable_bind_property ##### -->
-<para>
-
-</para>
-
-@editable:
-@channel:
-@property:
-@property_type:
-
-
-<!-- ##### FUNCTION xfconf_gtk_widget_unbind ##### -->
-<para>
-
-</para>
-
-@widget:
-
-
diff --git a/docs/reference/xfconf-docs.sgml b/docs/reference/xfconf-docs.sgml
index afd3c77..24be72f 100644
--- a/docs/reference/xfconf-docs.sgml
+++ b/docs/reference/xfconf-docs.sgml
@@ -21,10 +21,6 @@
<title>Xfconf Client Library</title>
<xi:include href="xml/xfconf.xml"/>
<xi:include href="xml/xfconf-channel.xml"/>
- </chapter>
-
- <chapter>
- <title>Xfconf Gtk Convenience Library</title>
- <xi:include href="xml/xfconf-gtk.xml"/>
+ <xi:include href="xml/xfconf-binding.xml"/>
</chapter>
</book>
diff --git a/docs/reference/xfconf-sections.txt b/docs/reference/xfconf-sections.txt
index 7344342..4049e5e 100644
--- a/docs/reference/xfconf-sections.txt
+++ b/docs/reference/xfconf-sections.txt
@@ -85,7 +85,7 @@ xfconf_g_value_set_uint16
</SECTION>
<SECTION>
-<FILE>xfconf-gtk</FILE>
-xfconf_gtk_editable_bind_property
-xfconf_gtk_widget_unbind
+<FILE>xfconf-binding</FILE>
+xfconf_g_property_bind
+xfconf_g_property_unbind
</SECTION>
diff --git a/xfconf-gtk/Makefile.am b/xfconf-gtk/Makefile.am
deleted file mode 100644
index 62a5a29..0000000
--- a/xfconf-gtk/Makefile.am
+++ /dev/null
@@ -1,41 +0,0 @@
-if BUILD_XFCONF_GTK
-
-lib_LTLIBRARIES = libxfconf-gtk-0.la
-
-libxfconfgtkincludedir = $(includedir)/xfce4/xfconf-gtk-$(LIBXFCONF_GTK_VERSION_API)/xfconf-gtk
-libxfconfgtkinclude_HEADERS = \
- xfconf-gtk.h
-
-libxfconf_gtk_0_la_SOURCES = \
- $(libxfconfgtkinclude_HEADERS) \
- xfconf-gtk.c
-
-libxfconf_gtk_0_la_CFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/common \
- -DLIBXFCONF_COMPILATION \
- -DLIBXFCONF_GTK_COMPILATION \
- -DG_LOG_DOMAIN=\"xfconf-gtk\" \
- $(GTK_CFLAGS)
-
-libxfconf_gtk_0_la_LDFLAGS = \
- -export-dynamic \
- -version-info $(LIBXFCONF_GTK_VERINFO) \
- -export-symbols-regex "^[^_].*" \
- -no-undefined
-
-libxfconf_gtk_0_la_LIBADD = \
- $(top_builddir)/common/libxfconf-gvaluefuncs.la \
- $(top_builddir)/xfconf/libxfconf-$(LIBXFCONF_VERSION_API).la \
- $(GTK_LIBS)
-
-libxfconf_gtk_0_la_DEPENDENCIES = \
- $(top_builddir)/xfconf/libxfconf-$(LIBXFCONF_VERSION_API).la
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libxfconf-gtk-$(LIBXFCONF_GTK_VERSION_API).pc
-
-endif
-
-EXTRA_DIST = \
- libxfconf-gtk-$(LIBXFCONF_GTK_VERSION_API).pc.in
diff --git a/xfconf-gtk/libxfconf-gtk-0.pc.in b/xfconf-gtk/libxfconf-gtk-0.pc.in
deleted file mode 100644
index 8712fe4..0000000
--- a/xfconf-gtk/libxfconf-gtk-0.pc.in
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-libxfconf_gtk_api_version=@LIBXFCONF_GTK_VERSION_API@
-
-Name: @PACKAGE_TARNAME@
-Description: Xfconf Gtk convenience library for Xfce
-Requires: libxfconf-@LIBXFCONF_VERSION_API@ gtk+-2.0
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lxfconf-gtk-${libxfconf_gtk_api_version}
-Cflags: -I${includedir}/xfce4/xfconf-gtk-${libxfconf_gtk_api_version}
diff --git a/xfconf-gtk/xfconf-gtk.c b/xfconf-gtk/xfconf-gtk.c
deleted file mode 100644
index 68e003d..0000000
--- a/xfconf-gtk/xfconf-gtk.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * xfconf
- *
- * Copyright (c) 2007 Brian Tarricone <bjt23@cornell.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License ONLY.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#ifdef GETTEXT_PACKAGE
-#include <glib/gi18n-lib.h>
-#else
-#include <glib/gi18n.h>
-#endif
-
-#include "xfconf-gtk.h"
-#include "xfconf-gvaluefuncs.h"
-
-typedef struct
-{
- GtkWidget *widget;
- XfconfChannel *channel;
- gchar *property;
- GType property_type;
- GCallback xfconf_callback;
- GCallback gtk_callback;
-} XfconfGtkBinding;
-
-
-static void
-xfconf_gtk_channel_freed(gpointer data,
- GObject *where_the_object_was)
-{
- XfconfGtkBinding *binding = data;
- binding->channel = NULL;
- g_object_set_data(G_OBJECT(binding->widget), "--xfconf-gtk-binding",
- NULL);
-}
-
-static void
-xfconf_gtk_binding_free(XfconfGtkBinding *binding)
-{
- if(binding->channel) {
- g_signal_handlers_disconnect_by_func(G_OBJECT(binding->channel),
- binding->xfconf_callback,
- binding);
- g_object_weak_unref(G_OBJECT(binding->channel),
- xfconf_gtk_channel_freed, binding);
- }
-
- if(binding->widget) {
- g_signal_handlers_disconnect_by_func(G_OBJECT(binding->widget),
- binding->gtk_callback,
- binding);
- }
-
- g_free(binding->property);
- g_free(binding);
-}
-
-
-
-static gboolean
-xfconf_gtk_update_property_from_string(XfconfGtkBinding *binding,
- const gchar *value)
-{
- gboolean ret = FALSE;
- GValue val = { 0, };
-
- g_value_init(&val, binding->property_type);
-
- if(_xfconf_gvalue_from_string(&val, value)) {
- ret = xfconf_channel_set_property(binding->channel,
- binding->property,
- &val);
- } else {
- g_warning("Unable to convert string \"%s\" to GType \"%s\"",
- value, G_VALUE_TYPE_NAME(&val));
- }
-
- g_value_unset(&val);
-
- return ret;
-}
-
-static void
-xfconf_gtk_editable_binding(XfconfChannel *channel,
- const gchar *property,
- gpointer user_data)
-{
- XfconfGtkBinding *binding = user_data;
- GValue val = { 0, };
- gchar *cur_val, *new_val;
- gint strpos = 0;
-
- if(strcmp(property, binding->property))
- return;
-
- if(!xfconf_channel_get_property(channel, property, &val))
- return;
-
- new_val = _xfconf_string_from_gvalue(&val);
- g_value_unset(&val);
- if(!new_val)
- return;
-
- cur_val = gtk_editable_get_chars(GTK_EDITABLE(binding->widget), 0, -1);
- if(!strcmp(cur_val, new_val)) {
- g_free(cur_val);
- g_free(new_val);
- return;
- }
- g_free(cur_val);
-
- g_signal_handlers_block_by_func(G_OBJECT(binding->widget),
- binding->gtk_callback, binding);
-
- gtk_editable_delete_text(GTK_EDITABLE(binding->widget), 0, -1);
- gtk_editable_insert_text(GTK_EDITABLE(binding->widget), new_val,
- strlen(new_val), &strpos);
-
- g_signal_handlers_unblock_by_func(G_OBJECT(binding->widget),
- binding->gtk_callback, binding);
-
- g_free(new_val);
-}
-
-static void
-xfconf_gtk_editable_changed(GtkEditable *editable,
- gpointer user_data)
-{
- XfconfGtkBinding *binding = user_data;
- gchar *str;
-
- str = gtk_editable_get_chars(editable, 0, -1);
- xfconf_gtk_update_property_from_string(binding, str);
- g_free(str);
-}
-
-
-
-/**
- * xfconf_gtk_editable_bind_property:
- * @editable: A widget implementing #GtkEditable.
- * @channel: An #XfconfChannel.
- * @property: A string property name.
- * @property_type: The #GType of @property.
- *
- * Binds @editable to @property on @channel such that @editable will
- * always display the value of @property, even if that value changes
- * via any other means. If @widget is editable, the binding will also
- * cause @property to be updated in the Xfconf configuration store.
- *
- * Note: #GtkEntry and #GtkSpinButton (and perhaps others) both
- * implement the #GtkEditable interface and can be used with
- * this function.
- **/
-void
-xfconf_gtk_editable_bind_property(GtkEditable *editable,
- XfconfChannel *channel,
- const gchar *property,
- GType property_type)
-{
- XfconfGtkBinding *binding;
- GtkWidget *widget;
-
- g_return_if_fail(GTK_IS_EDITABLE(editable) && XFCONF_IS_CHANNEL(channel)
- && property && *property);
-
- widget = GTK_WIDGET(editable);
-
- binding = g_new0(XfconfGtkBinding, 1);
- binding->widget = widget;
- binding->channel = channel;
- binding->property = g_strdup(property);
- binding->property_type = property_type;
- binding->xfconf_callback = G_CALLBACK(xfconf_gtk_editable_binding);
- binding->gtk_callback = G_CALLBACK(xfconf_gtk_editable_changed);
-
- /* set initial entry value */
- xfconf_gtk_editable_binding(channel, property, binding);
-
- g_signal_connect(G_OBJECT(widget), "changed",
- binding->gtk_callback, binding);
- g_signal_connect(G_OBJECT(channel), "property-changed",
- binding->xfconf_callback, binding);
-
- g_object_set_data_full(G_OBJECT(widget), "--xfconf-gtk-binding",
- binding,
- (GDestroyNotify)xfconf_gtk_binding_free);
-
- g_object_weak_ref(G_OBJECT(channel), xfconf_gtk_channel_freed,
- binding);
-}
-
-/**
- * xfconf_gtk_widget_unbind:
- * @widget: A #GtkWidget.
- *
- * Causes a widget previously bound to an Xfconf property
- * (via xfconf_gtk_widget_bind_property()) to no longer be bound.
- **/
-void
-xfconf_gtk_widget_unbind(GtkWidget *widget)
-{
- g_object_set_data(G_OBJECT(widget), "--xfconf-gtk-binding", NULL);
-}
diff --git a/xfconf-gtk/xfconf-gtk.h b/xfconf-gtk/xfconf-gtk.h
deleted file mode 100644
index 6a8a94c..0000000
--- a/xfconf-gtk/xfconf-gtk.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * xfconf-gtk
- *
- * Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License ONLY.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __XFCONF_GTK_H__
-#define __XFCONF_GTK_H__
-
-#include <xfconf/xfconf.h>
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-void xfconf_gtk_editable_bind_property(GtkEditable *editable,
- XfconfChannel *channel,
- const gchar *property,
- GType property_type);
-
-void xfconf_gtk_widget_unbind(GtkWidget *widget);
-
-G_END_DECLS
-
-#endif /* __XFCONF_GTK_H__ */
diff --git a/xfconf/Makefile.am b/xfconf/Makefile.am
index 0060ea4..6ddf8f9 100644
--- a/xfconf/Makefile.am
+++ b/xfconf/Makefile.am
@@ -3,6 +3,7 @@ lib_LTLIBRARIES = libxfconf-0.la
libxfconfincludedir = $(includedir)/xfce4/xfconf-$(LIBXFCONF_VERSION_API)/xfconf
libxfconfinclude_HEADERS = \
+ xfconf-binding.h \
xfconf-channel.h \
xfconf-errors.h \
xfconf-types.h \
@@ -10,6 +11,7 @@ libxfconfinclude_HEADERS = \
libxfconf_0_la_SOURCES = \
$(libxfconfinclude_HEADERS) \
+ xfconf-binding.c \
xfconf-channel.c \
xfconf-dbus-bindings.h \
xfconf-private.h \
diff --git a/xfconf/xfconf-binding.c b/xfconf/xfconf-binding.c
new file mode 100644
index 0000000..124e185
--- /dev/null
+++ b/xfconf/xfconf-binding.c
@@ -0,0 +1,302 @@
+/*
+ * xfconf
+ *
+ * Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License ONLY.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "xfconf-binding.h"
+
+
+typedef struct
+{
+ XfconfChannel *channel;
+ gchar *xfconf_property;
+ GType xfconf_property_type;
+
+ GObject *object;
+ gchar *object_property;
+ GType object_property_type;
+} XfconfGBinding;
+
+static void xfconf_g_binding_channel_destroyed(gpointer data,
+ GObject *where_the_object_was);
+static void xfconf_g_binding_object_destroyed(gpointer data,
+ GObject *where_the_object_was);
+static void xfconf_g_binding_channel_property_changed(XfconfChannel *channel,
+ const gchar *property,
+ gpointer user_data);
+static void xfconf_g_binding_object_property_changed(GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data);
+
+static void
+xfconf_g_binding_free(XfconfGBinding *binding)
+{
+ if(G_UNLIKELY(!binding))
+ return;
+
+ if(binding->object) {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(binding->object),
+ G_CALLBACK(xfconf_g_binding_object_property_changed),
+ binding);
+ g_object_weak_unref(G_OBJECT(binding->object),
+ xfconf_g_binding_object_destroyed,
+ binding);
+ }
+
+ if(binding->channel) {
+ g_signal_handlers_disconnect_by_func(G_OBJECT(binding->channel),
+ G_CALLBACK(xfconf_g_binding_channel_property_changed),
+ binding);
+ g_object_weak_unref(G_OBJECT(binding->channel),
+ xfconf_g_binding_channel_destroyed,
+ binding);
+ }
+
+ g_free(binding->xfconf_property);
+ g_free(binding->object_property);
+ g_free(binding);
+}
+
+static void
+xfconf_g_binding_channel_destroyed(gpointer data,
+ GObject *where_the_object_was)
+{
+ XfconfGBinding *binding = data;
+ binding->channel = NULL;
+ xfconf_g_binding_free(binding);
+}
+
+static void
+xfconf_g_binding_object_destroyed(gpointer data,
+ GObject *where_the_object_was)
+{
+ XfconfGBinding *binding = data;
+ binding->object = NULL;
+ xfconf_g_binding_free(binding);
+}
+
+static void
+xfconf_g_binding_channel_property_changed(XfconfChannel *channel,
+ const gchar *property,
+ gpointer user_data)
+{
+ XfconfGBinding *binding = user_data;
+ GValue src_val = { 0, }, dst_val = { 0, };
+
+ if(!xfconf_channel_get_property(channel, property, &src_val))
+ return;
+
+ g_value_init(&dst_val, binding->object_property_type);
+
+ if(g_value_transform(&src_val, &dst_val)) {
+ g_signal_handlers_block_by_func(binding->object,
+ G_CALLBACK(xfconf_g_binding_object_property_changed),
+ binding);
+ g_object_set_property(binding->object, binding->object_property,
+ &dst_val);
+ g_signal_handlers_unblock_by_func(binding->object,
+ G_CALLBACK(xfconf_g_binding_object_property_changed),
+ binding);
+ }
+
+ g_value_unset(&src_val);
+ g_value_unset(&dst_val);
+}
+
+static void
+xfconf_g_binding_object_property_changed(GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ XfconfGBinding *binding = user_data;
+ GValue src_val = { 0, }, dst_val = { 0, };
+
+ /* this can do auto-conversion for us, but we can't easily tell if
+ * the conversion worked */
+ g_value_init(&src_val, G_PARAM_SPEC_VALUE_TYPE(pspec));
+ g_object_get_property(object, g_param_spec_get_name(pspec), &src_val);
+
+ g_value_init(&dst_val, binding->xfconf_property_type);
+
+ if(g_value_transform(&src_val, &dst_val)) {
+ g_signal_handlers_block_by_func(G_OBJECT(binding->channel),
+ G_CALLBACK(xfconf_g_binding_channel_property_changed),
+ binding);
+ xfconf_channel_set_property(binding->channel,
+ binding->xfconf_property,
+ &dst_val);
+ g_signal_handlers_unblock_by_func(G_OBJECT(binding->channel),
+ G_CALLBACK(xfconf_g_binding_channel_property_changed),
+ binding);
+ }
+
+ g_value_unset(&src_val);
+ g_value_unset(&dst_val);
+}
+
+/**
+ * xfconf_g_property_bind:
+ * @channel: An #XfconfChannel.
+ * @xfconf_property: A property on @channel.
+ * @xfconf_property_type: The type of @xfconf_property.
+ * @object: A #GObject.
+ * @object_property: A valid property on @object.
+ *
+ * Binds an Xfconf property to a #GObject property. If the property
+ * is changed via either the #GObject or Xfconf, the corresponding
+ * property will also be updated.
+ *
+ * Note that @xfconf_property_type is required since @xfconf_property
+ * may or may not already exist in the Xfconf store. The type of
+ * @object_property will be determined automatically. If the two
+ * types do not match, a conversion will be attempted.
+ **/
+void
+xfconf_g_property_bind(XfconfChannel *channel,
+ const gchar *xfconf_property,
+ GType xfconf_property_type,
+ GObject *object,
+ const gchar *object_property)
+{
+ XfconfGBinding *binding;
+ GParamSpec *pspec;
+ gchar buf[1024];
+ GList *bindings;
+
+ g_return_if_fail(XFCONF_IS_CHANNEL(channel)
+ && xfconf_property && *xfconf_property
+ && xfconf_property_type != G_TYPE_NONE
+ && xfconf_property_type != G_TYPE_INVALID
+ && G_IS_OBJECT(object)
+ && object_property && *object_property);
+
+ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object),
+ object_property);
+ if(!pspec) {
+ g_warning("Property \"%s\" is not valid for GObject type \"%s\"",
+ object_property, G_OBJECT_TYPE_NAME(object));
+ return;
+ }
+
+ if(!g_value_type_transformable(xfconf_property_type,
+ G_PARAM_SPEC_VALUE_TYPE(pspec)))
+ {
+ g_warning("Converting from type \"%s\" to type \"%s\" is not supported",
+ g_type_name(xfconf_property_type),
+ g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
+ return;
+ }
+
+ if(!g_value_type_transformable(G_PARAM_SPEC_VALUE_TYPE(pspec),
+ xfconf_property_type))
+ {
+ g_warning("Converting from type \"%s\" to type \"%s\" is not supported",
+ g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)),
+ g_type_name(xfconf_property_type));
+ return;
+ }
+
+
+ binding = g_new0(XfconfGBinding, 1);
+ binding->channel = channel;
+ binding->xfconf_property = g_strdup(xfconf_property);
+ binding->xfconf_property_type = xfconf_property_type;
+ binding->object = object;
+ binding->object_property = g_strdup(object_property);
+ binding->object_property_type = G_PARAM_SPEC_VALUE_TYPE(pspec);
+
+ g_object_weak_ref(G_OBJECT(channel),
+ xfconf_g_binding_channel_destroyed,
+ binding);
+ g_object_weak_ref(G_OBJECT(object),
+ xfconf_g_binding_object_destroyed,
+ binding);
+
+ g_snprintf(buf, sizeof(buf), "property-changed::%s", xfconf_property);
+ g_signal_connect(G_OBJECT(channel), buf,
+ G_CALLBACK(xfconf_g_binding_channel_property_changed),
+ binding);
+
+ g_snprintf(buf, sizeof(buf), "notify::%s", object_property);
+ g_signal_connect(G_OBJECT(object), buf,
+ G_CALLBACK(xfconf_g_binding_object_property_changed),
+ binding);
+
+ bindings = g_object_get_data(G_OBJECT(channel), "--xfconf-g-bindings");
+ if(bindings)
+ bindings = g_list_append(bindings, binding);
+ else {
+ bindings = g_list_append(bindings, binding);
+ g_object_set_data_full(G_OBJECT(channel), "--xfconf-g-bindings",
+ bindings, (GDestroyNotify)g_list_free);
+ }
+
+ xfconf_g_binding_channel_property_changed(channel, xfconf_property,
+ binding);
+}
+
+/**
+ * xfconf_g_property_unbind:
+ * @channel: An #XfconfChannel.
+ * @xfconf_property: A bound property on @channel.
+ * @object: A #GObject.
+ * @object_property: A bound property on @object.
+ *
+ * Causes an Xfconf channel previously bound to a #GObject property
+ * (see xfconf_g_property_bind()) to no longer be bound.
+ **/
+void
+xfconf_g_property_unbind(XfconfChannel *channel,
+ const gchar *xfconf_property,
+ GObject *object,
+ const gchar *object_property)
+{
+ GList *bindings = g_object_steal_data(G_OBJECT(channel),
+ "--xfconf-g-bindings");
+ GList *l;
+
+ for(l = bindings; l; l = l->next) {
+ XfconfGBinding *binding = l->data;
+
+ if(object == binding->object
+ && !strcmp(xfconf_property, binding->xfconf_property)
+ && !strcmp(object_property, binding->object_property))
+ {
+ bindings = g_list_delete_link(bindings, l);
+ xfconf_g_binding_free(binding);
+ break;
+ }
+ }
+
+ if(bindings) {
+ g_object_set_data_full(G_OBJECT(channel), "--xfconf-g-bindings",
+ bindings, (GDestroyNotify)g_list_free);
+ }
+}
+
+
+
+#define __XFCONF_BINDING_C__
+#include "common/xfconf-aliasdef.c"
diff --git a/xfconf/xfconf-binding.h b/xfconf/xfconf-binding.h
new file mode 100644
index 0000000..a82bd94
--- /dev/null
+++ b/xfconf/xfconf-binding.h
@@ -0,0 +1,45 @@
+/*
+ * xfconf
+ *
+ * Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License ONLY.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __XFCONF_BINDING_H__
+#define __XFCONF_BINDING_H__
+
+#if !defined(LIBXFCONF_COMPILATION) && !defined(XFCONF_IN_XFCONF_H)
+#error "Do not include xfconf-binding.h, as this file may change or disappear in the future. Include <xfconf/xfconf.h> instead."
+#endif
+
+#include <glib-object.h>
+#include <xfconf/xfconf-channel.h>
+
+G_BEGIN_DECLS
+
+void xfconf_g_property_bind(XfconfChannel *channel,
+ const gchar *xfconf_property,
+ GType xfconf_property_type,
+ GObject *object,
+ const gchar *object_property);
+
+void xfconf_g_property_unbind(XfconfChannel *channel,
+ const gchar *xfconf_property,
+ GObject *object,
+ const gchar *object_property);
+
+G_END_DECLS
+
+#endif /* __XFCONF_BINDING_H__ */
diff --git a/xfconf/xfconf.h b/xfconf/xfconf.h
index 98c3d0d..76b54ad 100644
--- a/xfconf/xfconf.h
+++ b/xfconf/xfconf.h
@@ -25,9 +25,12 @@
#define XFCONF_IN_XFCONF_H
#include <xfconf/xfconf-channel.h>
+#include <xfconf/xfconf-binding.h>
#include <xfconf/xfconf-errors.h>
#include <xfconf/xfconf-types.h>
+#undef XFCONF_IN_XFCONF_H
+
G_BEGIN_DECLS
gboolean xfconf_init(GError **error);
diff --git a/xfconf/xfconf.symbols b/xfconf/xfconf.symbols
index 0d3318d..8c20c24 100644
--- a/xfconf/xfconf.symbols
+++ b/xfconf/xfconf.symbols
@@ -90,3 +90,11 @@ xfconf_channel_set_struct_valist
xfconf_channel_set_structv
#endif
#endif
+
+/* xfconf-binding.h */
+#if IN_HEADER(__XFCONF_BINDING_H__)
+#if IN_SOURCE(__XFCONF_BINDING_C__)
+xfconf_g_object_bind
+xfconf_g_object_unbind
+#endif
+#endif