diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac.in | 2 | ||||
-rw-r--r-- | docs/reference/Makefile.am | 5 | ||||
-rw-r--r-- | docs/reference/tmpl/xfconf-binding.sgml | 50 | ||||
-rw-r--r-- | docs/reference/tmpl/xfconf-gtk.sgml | 47 | ||||
-rw-r--r-- | docs/reference/xfconf-docs.sgml | 6 | ||||
-rw-r--r-- | docs/reference/xfconf-sections.txt | 6 | ||||
-rw-r--r-- | xfconf-gtk/Makefile.am | 41 | ||||
-rw-r--r-- | xfconf-gtk/libxfconf-gtk-0.pc.in | 13 | ||||
-rw-r--r-- | xfconf-gtk/xfconf-gtk.c | 225 | ||||
-rw-r--r-- | xfconf-gtk/xfconf-gtk.h | 37 | ||||
-rw-r--r-- | xfconf/Makefile.am | 2 | ||||
-rw-r--r-- | xfconf/xfconf-binding.c | 302 | ||||
-rw-r--r-- | xfconf/xfconf-binding.h | 45 | ||||
-rw-r--r-- | xfconf/xfconf.h | 3 | ||||
-rw-r--r-- | xfconf/xfconf.symbols | 8 |
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 |