gnome-bluetooth r570 - in trunk: applet properties



Author: hadess
Date: Mon Apr  6 16:26:23 2009
New Revision: 570
URL: http://svn.gnome.org/viewvc/gnome-bluetooth?rev=570&view=rev

Log:
Re-add the icon prefs, simplified


Added:
   trunk/properties/gconf-bridge.c
   trunk/properties/gconf-bridge.h
Modified:
   trunk/applet/main.c
   trunk/properties/Makefile.am
   trunk/properties/bluetooth-manager.schemas.in
   trunk/properties/general.c
   trunk/properties/general.h
   trunk/properties/main.c

Modified: trunk/applet/main.c
==============================================================================
--- trunk/applet/main.c	(original)
+++ trunk/applet/main.c	Mon Apr  6 16:26:23 2009
@@ -43,17 +43,10 @@
 static GtkTreeModel *devices_model;
 static guint num_adapters_present = 0;
 static guint num_adapters_powered = 0;
-
-enum {
-	ICON_POLICY_NEVER,
-	ICON_POLICY_ALWAYS,
-	ICON_POLICY_PRESENT,
-};
-
-static int icon_policy = ICON_POLICY_PRESENT;
+static gboolean show_icon_pref = TRUE;
 
 #define PREF_DIR		"/apps/bluetooth-manager"
-#define PREF_ICON_POLICY	PREF_DIR "/icon_policy"
+#define PREF_SHOW_ICON		PREF_DIR "/icon_policy"
 
 static GConfClient* gconf;
 static BluetoothKillswitch *killswitch = NULL;
@@ -309,16 +302,13 @@
 	else
 		set_icon (TRUE);
 
-	if (icon_policy == ICON_POLICY_NEVER)
-		hide_icon();
-	else if (icon_policy == ICON_POLICY_ALWAYS)
-		show_icon();
-	else if (icon_policy == ICON_POLICY_PRESENT) {
-		if (num_adapters_present > 0 || killswitch != NULL)
-			show_icon();
-		else
-			hide_icon();
+	if (show_icon_pref != FALSE) {
+		if (num_adapters_present > 0 || killswitch != NULL) {
+			show_icon ();
+			return;
+		}
 	}
+	hide_icon ();
 }
 
 static void
@@ -517,13 +507,6 @@
 	device_changed (model, path, NULL, user_data);
 }
 
-static GConfEnumStringPair icon_policy_enum_map [] = {
-	{ ICON_POLICY_NEVER,	"never"		},
-	{ ICON_POLICY_ALWAYS,	"always"	},
-	{ ICON_POLICY_PRESENT,	"present"	},
-	{ ICON_POLICY_PRESENT,	NULL		},
-};
-
 static void gconf_callback(GConfClient *client, guint cnxn_id,
 					GConfEntry *entry, gpointer user_data)
 {
@@ -533,15 +516,8 @@
 	if (value == NULL)
 		return;
 
-	if (g_str_equal(entry->key, PREF_ICON_POLICY) == TRUE) {
-		const char *str;
-
-		str = gconf_value_get_string(value);
-		if (!str)
-			return;
-
-		gconf_string_to_enum(icon_policy_enum_map, str, &icon_policy);
-
+	if (g_str_equal(entry->key, PREF_SHOW_ICON) == TRUE) {
+		show_icon_pref = gconf_value_get_bool(value);
 		update_icon_visibility();
 		return;
 	}
@@ -557,7 +533,6 @@
 	GtkStatusIcon *statusicon;
 	GtkWidget *menu;
 	GError *error = NULL;
-	char *str;
 
 	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
@@ -610,11 +585,7 @@
 
 	gconf = gconf_client_get_default();
 
-	str = gconf_client_get_string(gconf, PREF_ICON_POLICY, NULL);
-	if (str) {
-		gconf_string_to_enum(icon_policy_enum_map, str, &icon_policy);
-		g_free(str);
-	}
+	show_icon_pref = gconf_client_get_bool(gconf, PREF_SHOW_ICON, NULL);
 
 	gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
 

Modified: trunk/properties/Makefile.am
==============================================================================
--- trunk/properties/Makefile.am	(original)
+++ trunk/properties/Makefile.am	Mon Apr  6 16:26:23 2009
@@ -1,7 +1,7 @@
 
 bin_PROGRAMS = bluetooth-properties
 
-bluetooth_properties_SOURCES = main.c general.h general.c adapter.h adapter.c
+bluetooth_properties_SOURCES = main.c general.h general.c adapter.h adapter.c gconf-bridge.c gconf-bridge.h
 
 bluetooth_properties_LDADD = $(top_builddir)/common/libgnome-bluetooth.la $(top_builddir)/common/libcommon.la $(PROPS_LIBS)
 

Modified: trunk/properties/bluetooth-manager.schemas.in
==============================================================================
--- trunk/properties/bluetooth-manager.schemas.in	(original)
+++ trunk/properties/bluetooth-manager.schemas.in	Mon Apr  6 16:26:23 2009
@@ -2,14 +2,14 @@
   <schemalist>
 
     <schema>
-      <key>/schemas/apps/bluetooth-manager/icon_policy</key>
-      <applyto>/apps/bluetooth-manager/icon_policy</applyto>
+      <key>/schemas/apps/bluetooth-manager/show_icon</key>
+      <applyto>/apps/bluetooth-manager/show_icon</applyto>
       <owner>bluetooth-manager</owner>
-      <type>string</type>
-      <default>present</default>
+      <type>boolean</type>
+      <default>true</default>
       <locale name="C">
-        <short>When to show the notification icon</short>
-        <long>Display options for the notification icon. Valid options are "never", "present" and "always".</long>
+        <short>Whether to show the notification icon</short>
+        <long>Whether to show the notification icon.</long>
       </locale>
     </schema>
 

Added: trunk/properties/gconf-bridge.c
==============================================================================
--- (empty file)
+++ trunk/properties/gconf-bridge.c	Mon Apr  6 16:26:23 2009
@@ -0,0 +1,1252 @@
+/* 
+ * (C) 2005 OpenedHand Ltd.
+ *
+ * Author: Jorn Baayen <jorn openedhand com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "gconf-bridge.h"
+
+struct _GConfBridge {
+        GConfClient *client;
+        
+        GHashTable *bindings;
+};
+
+/* The data structures for the different kinds of bindings */
+typedef enum {
+        BINDING_PROP,
+        BINDING_WINDOW,
+        BINDING_LIST_STORE
+} BindingType;
+
+typedef struct {
+        BindingType type;
+        guint id;
+        
+        gboolean delayed_mode;
+
+        char *key;
+        guint val_notify_id;
+        GSList *val_changes; /* List of changes made to GConf value,
+                                that have not received change notification
+                                yet. */
+
+        GObject *object;
+        GParamSpec *prop;
+        gulong prop_notify_id;
+
+        guint sync_timeout_id; /* Used in delayed mode */
+} PropBinding;
+
+typedef struct {
+        BindingType type;
+        guint id;
+
+        gboolean bind_size;
+        gboolean bind_pos;
+
+        char *key_prefix;
+
+        GtkWindow *window;
+        gulong configure_event_id;
+	gulong window_state_event_id;
+        gulong unmap_id;
+        guint sync_timeout_id;
+} WindowBinding;
+
+typedef struct {
+        BindingType type;
+        guint id;
+
+        char *key;
+        guint val_notify_id;
+        GSList *val_changes; /* List of changes made to GConf value,
+                                that have not received change notification
+                                yet. */
+
+        GtkListStore *list_store;
+        guint row_inserted_id;
+        guint row_changed_id;
+        guint row_deleted_id;
+        guint rows_reordered_id;
+
+        guint sync_idle_id;
+} ListStoreBinding;
+
+/* Some trickery to be able to treat the data structures generically */
+typedef union {
+        BindingType      type;
+
+        PropBinding      prop_binding;
+        WindowBinding    window_binding;
+        ListStoreBinding list_store_binding;
+} Binding;
+
+/* Function prototypes */
+static void
+unbind (Binding *binding);
+
+#if !HAVE_DECL_GCONF_VALUE_COMPARE /* Not in headers in GConf < 2.13 */
+int gconf_value_compare (const GConfValue *value_a,
+                         const GConfValue *value_b);
+#endif
+
+static GConfBridge *bridge = NULL; /* Global GConfBridge object */
+
+/* Free up all resources allocated by the GConfBridge. Called on exit. */
+static void
+destroy_bridge (void)
+{
+        g_hash_table_destroy (bridge->bindings);
+        g_object_unref (bridge->client);
+
+        g_free (bridge);
+}
+
+/**
+ * gconf_bridge_get
+ *
+ * Returns the #GConfBridge. This is a singleton object.
+ *
+ * Return value: The #GConfBridge.
+ **/
+GConfBridge *
+gconf_bridge_get (void)
+{
+        if (bridge)
+                return bridge;
+
+        gconf_bridge_install_default_error_handler ();
+
+        bridge = g_new (GConfBridge, 1);
+
+        bridge->client = gconf_client_get_default ();
+        bridge->bindings = g_hash_table_new_full (NULL, NULL, NULL,
+                                                  (GDestroyNotify) unbind);
+
+        g_atexit (destroy_bridge);
+
+        return bridge;
+}
+
+/**
+ * gconf_bridge_get_client
+ * @bridge: A #GConfBridge
+ *
+ * Returns the #GConfClient used by @bridge. This is the same #GConfClient 
+ * as returned by gconf_client_get_default().
+ *
+ * Return value: A #GConfClient.
+ **/
+GConfClient *
+gconf_bridge_get_client (GConfBridge *bridge)
+{
+        g_return_val_if_fail (bridge != NULL, NULL);
+
+        return bridge->client;
+}
+
+/* Generate an ID for a new binding */
+static guint
+new_id (void)
+{
+        static guint id_counter = 0;
+
+        id_counter++;
+
+        return id_counter;
+}
+
+/*
+ * Property bindings
+ */
+
+/* Syncs a value from GConf to an object property */
+static void
+prop_binding_sync_pref_to_prop (PropBinding *binding,
+                                GConfValue  *pref_value)
+{
+        GValue src_value, value;
+        
+        /* Make sure we don't enter an infinite synchronizing loop */
+        g_signal_handler_block (binding->object, binding->prop_notify_id);
+
+        memset (&src_value, 0, sizeof (GValue));
+
+        /* First, convert GConfValue to GValue */
+        switch (pref_value->type) {
+        case GCONF_VALUE_STRING:
+                g_value_init (&src_value, G_TYPE_STRING);
+                g_value_set_string (&src_value,
+                                    gconf_value_get_string (pref_value));
+                break;
+        case GCONF_VALUE_INT:
+                g_value_init (&src_value, G_TYPE_INT);
+                g_value_set_int (&src_value,
+                                 gconf_value_get_int (pref_value));
+                break;
+        case GCONF_VALUE_BOOL:
+                g_value_init (&src_value, G_TYPE_BOOLEAN);
+                g_value_set_boolean (&src_value,
+                                     gconf_value_get_bool (pref_value));
+                break;
+        case GCONF_VALUE_FLOAT:
+                g_value_init (&src_value, G_TYPE_FLOAT);
+                g_value_set_float (&src_value,
+                                   gconf_value_get_float (pref_value));
+                break;
+        default:
+                g_warning ("prop_binding_sync_pref_to_prop: Unhandled value "
+                           "type '%d'.\n", pref_value->type);
+
+                return;
+        }
+
+        /* Then convert to the type expected by the object, if necessary */
+        memset (&value, 0, sizeof (GValue));
+        g_value_init (&value,
+                      G_PARAM_SPEC_VALUE_TYPE (binding->prop));
+
+        if (src_value.g_type != value.g_type) {
+                if (!g_value_transform (&src_value, &value)) {
+                        g_warning ("prop_binding_sync_pref_to_prop: Failed to "
+                                   "transform a \"%s\" to a \"%s\".",
+                                   g_type_name (src_value.g_type),
+                                   g_type_name (value.g_type));
+                        
+                        goto done;
+                }
+
+                g_object_set_property (binding->object,
+                                       binding->prop->name, &value);
+        } else {
+                g_object_set_property (binding->object,
+                                       binding->prop->name, &src_value);
+        }
+        
+done:
+        g_value_unset (&src_value);
+        g_value_unset (&value);
+
+        g_signal_handler_unblock (binding->object, binding->prop_notify_id);
+}
+
+/* Syncs an object property to GConf */
+static void
+prop_binding_sync_prop_to_pref (PropBinding *binding)
+{
+        GValue value;
+        GConfValue *gconf_value;
+
+        memset (&value, 0, sizeof (GValue));
+
+        g_value_init (&value,
+                      G_PARAM_SPEC_VALUE_TYPE (binding->prop));
+        g_object_get_property (binding->object,
+                               binding->prop->name,
+                               &value);
+
+        switch (value.g_type) {
+        case G_TYPE_STRING:
+                gconf_value = gconf_value_new (GCONF_VALUE_STRING);
+                gconf_value_set_string (gconf_value,
+                                        g_value_get_string (&value));
+                break;
+        case G_TYPE_INT:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_int (&value));
+                break;
+        case G_TYPE_UINT:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_uint (&value));
+                break;
+        case G_TYPE_LONG:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_long (&value));
+                break;
+        case G_TYPE_ULONG:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_ulong (&value));
+                break;
+        case G_TYPE_INT64:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_int64 (&value));
+                break;
+        case G_TYPE_UINT64:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_uint64 (&value));
+                break;
+        case G_TYPE_CHAR:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_char (&value));
+                break;
+        case G_TYPE_UCHAR:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_uchar (&value));
+                break;
+        case G_TYPE_ENUM:
+                gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                gconf_value_set_int (gconf_value,
+                                     g_value_get_enum (&value));
+                break;
+        case G_TYPE_BOOLEAN:
+                gconf_value = gconf_value_new (GCONF_VALUE_BOOL);
+                gconf_value_set_bool (gconf_value,
+                                      g_value_get_boolean (&value));
+                break;
+        case G_TYPE_DOUBLE:
+                gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
+#ifdef HAVE_CORBA_GCONF
+                /* FIXME we cast to a float explicitly as CORBA GConf
+                 * uses doubles in its API, but treats them as floats
+                 * when transporting them over CORBA. See #322837 */
+                gconf_value_set_float (gconf_value,
+                                       (float) g_value_get_double (&value));
+#else
+                gconf_value_set_float (gconf_value,
+                                       g_value_get_double (&value));
+#endif
+                break;
+        case G_TYPE_FLOAT:
+                gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
+                gconf_value_set_float (gconf_value,
+                                       g_value_get_float (&value));
+                break;
+        default:
+                if (g_type_is_a (value.g_type, G_TYPE_ENUM)) {
+                        gconf_value = gconf_value_new (GCONF_VALUE_INT);
+                        gconf_value_set_int (gconf_value,
+                                             g_value_get_enum (&value));
+                } else {
+                        g_warning ("prop_binding_sync_prop_to_pref: "
+                                   "Unhandled value type '%s'.\n",
+                                   g_type_name (value.g_type));
+
+                        goto done;
+                }
+
+                break;
+        }
+
+        /* Set to GConf */
+        gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
+
+        /* Store until change notification comes in, so that we are able
+         * to ignore it */
+        binding->val_changes = g_slist_append (binding->val_changes,
+                                               gconf_value);
+
+done:
+        g_value_unset (&value);
+}
+
+/* Called when a GConf value bound to an object property has changed */
+static void
+prop_binding_pref_changed (GConfClient *client,
+                           guint        cnxn_id,
+                           GConfEntry  *entry,
+                           gpointer     user_data)
+{
+        GConfValue *gconf_value;
+        PropBinding *binding;
+        GSList *l;
+
+        gconf_value = gconf_entry_get_value (entry);
+        if (!gconf_value)
+                return; /* NULL means that the value has been unset */
+
+        binding = (PropBinding *) user_data;
+
+        /* Check that this notification is not caused by sync_prop_to_pref() */
+        l = g_slist_find_custom (binding->val_changes,
+                                 gconf_value,
+                                 (GCompareFunc) gconf_value_compare);
+        if (l) {
+                gconf_value_free (l->data);
+
+                binding->val_changes = g_slist_delete_link
+                        (binding->val_changes, l);
+
+                return;
+        }
+
+        prop_binding_sync_pref_to_prop (binding, gconf_value);
+}
+
+/* Performs a scheduled prop-to-pref sync for a prop binding in 
+ * delay mode */
+static gboolean
+prop_binding_perform_scheduled_sync (PropBinding *binding)
+{
+        prop_binding_sync_prop_to_pref (binding);
+
+        binding->sync_timeout_id = 0;
+
+        g_object_unref (binding->object);
+        
+        return FALSE;
+}
+
+#define PROP_BINDING_SYNC_DELAY 100 /* Delay for bindings with "delayed"
+                                       set to TRUE, in ms */
+
+/* Called when an object property has changed */
+static void
+prop_binding_prop_changed (GObject     *object,
+                           GParamSpec  *param_spec,
+                           PropBinding *binding)
+{
+        if (binding->delayed_mode) {
+                /* Just schedule a sync */
+                if (binding->sync_timeout_id == 0) {
+                        /* We keep a reference on the object as long as
+                         * we haven't synced yet to make sure we don't
+                         * lose any data */
+                        g_object_ref (binding->object);
+
+                        binding->sync_timeout_id =
+                                g_timeout_add
+                                        (PROP_BINDING_SYNC_DELAY,
+                                         (GSourceFunc)
+                                            prop_binding_perform_scheduled_sync,
+                                         binding);
+                }
+        } else {
+                /* Directly sync */
+                prop_binding_sync_prop_to_pref (binding);
+        }
+}
+
+/* Called when an object is destroyed */
+static void
+prop_binding_object_destroyed (gpointer user_data,
+                               GObject *where_the_object_was)
+{
+        PropBinding *binding;
+
+        binding = (PropBinding *) user_data;
+        binding->object = NULL; /* Don't do anything with the object
+                                   at unbind() */
+        
+        g_hash_table_remove (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id));
+}
+
+/**
+ * gconf_bridge_bind_property_full
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ * @delayed_sync: TRUE if there should be a delay between property changes
+ * and syncs to GConf. Set to TRUE when binding to a rapidly-changing
+ * property, for example the "value" property on a #GtkAdjustment.
+ *
+ * Binds @key to @prop, causing them to have the same value at all times.
+ *
+ * The types of @key and @prop should be compatible. Floats and doubles, and
+ * ints, uints, longs, unlongs, int64s, uint64s, chars, uchars and enums
+ * can be matched up. Booleans and strings can only be matched to their
+ * respective types.
+ *
+ * On calling this function the current value of @key will be set to @prop.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_property_full (GConfBridge *bridge,
+                                 const char  *key,
+                                 GObject     *object,
+                                 const char  *prop,
+                                 gboolean     delayed_sync)
+{
+        GParamSpec *pspec;
+        PropBinding *binding;
+        char *signal;
+        GConfValue *val;
+
+        g_return_val_if_fail (bridge != NULL, 0);
+        g_return_val_if_fail (key != NULL, 0);
+        g_return_val_if_fail (G_IS_OBJECT (object), 0);
+        g_return_val_if_fail (prop != NULL, 0);
+
+        /* First, try to fetch the propertys GParamSpec off the object */
+        pspec = g_object_class_find_property
+                                (G_OBJECT_GET_CLASS (object), prop);
+        if (G_UNLIKELY (pspec == NULL)) {
+                g_warning ("gconf_bridge_bind_property_full: A property \"%s\" "
+                           "was not found. Please make sure you are passing "
+                           "the right property name.", prop);
+
+                return 0;
+        }
+
+        /* GParamSpec found: All good, create new binding. */
+        binding = g_new (PropBinding, 1);
+
+        binding->type = BINDING_PROP;
+        binding->id = new_id ();
+        binding->delayed_mode = delayed_sync;
+        binding->val_changes = NULL;
+        binding->key = g_strdup (key);
+        binding->object = object;
+        binding->prop = pspec;
+        binding->sync_timeout_id = 0;
+        
+        /* Watch GConf key */
+        binding->val_notify_id =
+                gconf_client_notify_add (bridge->client, key,
+                                         prop_binding_pref_changed,
+                                         binding, NULL, NULL);
+
+        /* Connect to property change notifications */
+        signal = g_strconcat ("notify::", prop, NULL);
+        binding->prop_notify_id =
+                g_signal_connect (object, signal,
+                                  G_CALLBACK (prop_binding_prop_changed),
+                                  binding);
+        g_free (signal);
+
+        /* Sync object to value from GConf, if set */
+        val = gconf_client_get (bridge->client, key, NULL);
+        if (val) {
+                prop_binding_sync_pref_to_prop (binding, val);
+                gconf_value_free (val);
+        }
+
+        /* Handle case where watched object gets destroyed */
+        g_object_weak_ref (object,
+                           prop_binding_object_destroyed, binding);
+
+        /* Insert binding */
+        g_hash_table_insert (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id), binding);
+
+        /* Done */
+        return binding->id;
+}
+
+/* Unbinds a property binding */
+static void
+prop_binding_unbind (PropBinding *binding)
+{
+        if (binding->delayed_mode && binding->sync_timeout_id > 0) {
+                /* Perform any scheduled syncs */
+                g_source_remove (binding->sync_timeout_id);
+                        
+                /* The object will still be around as we have
+                 * a reference */
+                prop_binding_perform_scheduled_sync (binding);
+        }
+
+        gconf_client_notify_remove (bridge->client,
+                                    binding->val_notify_id);
+        g_free (binding->key);
+
+        while (binding->val_changes) {
+                gconf_value_free (binding->val_changes->data);
+
+                binding->val_changes = g_slist_delete_link
+                        (binding->val_changes, binding->val_changes);
+        }
+
+        /* The object might have been destroyed .. */
+        if (binding->object) {
+                g_signal_handler_disconnect (binding->object,
+                                             binding->prop_notify_id);
+
+                g_object_weak_unref (binding->object,
+                                     prop_binding_object_destroyed, binding);
+        }
+}
+
+/*
+ * Window bindings
+ */
+
+/* Performs a scheduled dimensions-to-prefs sync for a window binding */
+static gboolean
+window_binding_perform_scheduled_sync (WindowBinding *binding)
+{
+        if (binding->bind_size) {
+                int width, height;
+                char *key;
+                GdkWindowState state;
+
+                state = gdk_window_get_state (GTK_WIDGET (binding->window)->window);
+
+                if (state & GDK_WINDOW_STATE_MAXIMIZED) {
+                        key = g_strconcat (binding->key_prefix, "_maximized", NULL);
+                        gconf_client_set_bool (bridge->client, key, TRUE, NULL);
+                        g_free (key);
+                } else {
+                        gtk_window_get_size (binding->window, &width, &height);
+
+                        key = g_strconcat (binding->key_prefix, "_width", NULL);
+                        gconf_client_set_int (bridge->client, key, width, NULL);
+                        g_free (key);
+
+                        key = g_strconcat (binding->key_prefix, "_height", NULL);
+                        gconf_client_set_int (bridge->client, key, height, NULL);
+                        g_free (key);
+
+                        key = g_strconcat (binding->key_prefix, "_maximized", NULL);
+                        gconf_client_set_bool (bridge->client, key, FALSE, NULL);
+                        g_free (key);
+                }
+        }
+
+        if (binding->bind_pos) {
+                int x, y;
+                char *key;
+
+                gtk_window_get_position (binding->window, &x, &y);
+
+                key = g_strconcat (binding->key_prefix, "_x", NULL);
+                gconf_client_set_int (bridge->client, key, x, NULL);
+                g_free (key);
+
+                key = g_strconcat (binding->key_prefix, "_y", NULL);
+                gconf_client_set_int (bridge->client, key, y, NULL);
+                g_free (key);
+        }
+
+        binding->sync_timeout_id = 0;
+
+        return FALSE;
+}
+
+#define WINDOW_BINDING_SYNC_DELAY 1000 /* Delay before syncing new window
+                                          dimensions to GConf, in ms */
+
+/* Called when the window han been resized or moved */
+static gboolean
+window_binding_configure_event_cb (GtkWindow         *window,
+                                   GdkEventConfigure *event,
+                                   WindowBinding     *binding)
+{
+        /* Schedule a sync */
+        if (binding->sync_timeout_id == 0) {
+                binding->sync_timeout_id =
+                        g_timeout_add (WINDOW_BINDING_SYNC_DELAY,
+                                       (GSourceFunc)
+                                          window_binding_perform_scheduled_sync,
+                                       binding);
+        }
+
+        return FALSE;
+}
+
+/* Called when the window state is being changed */
+static gboolean
+window_binding_state_event_cb (GtkWindow           *window,
+                               GdkEventWindowState *event,
+                               WindowBinding       *binding)
+{
+        window_binding_perform_scheduled_sync (binding);
+
+        return FALSE;
+}
+
+/* Called when the window is being unmapped */
+static gboolean
+window_binding_unmap_cb (GtkWindow     *window,
+                         WindowBinding *binding)
+{
+        /* Force sync */
+        if (binding->sync_timeout_id > 0)
+                g_source_remove (binding->sync_timeout_id);
+
+        window_binding_perform_scheduled_sync (binding);
+
+        return FALSE;
+}
+
+/* Called when a window is destroyed */
+static void
+window_binding_window_destroyed (gpointer user_data,
+                                 GObject *where_the_object_was)
+{
+        WindowBinding *binding;
+
+        binding = (WindowBinding *) user_data;
+        binding->window = NULL; /* Don't do anything with the window
+                                   at unbind() */
+        
+        g_hash_table_remove (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id));
+}
+
+/**
+ * gconf_bridge_bind_window
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ * @bind_size: TRUE to bind the size of @window
+ * @bind_pos: TRUE to bind the position of @window
+ * 
+ * On calling this function @window will be resized to the values
+ * specified by "@key_prefix<!-- -->_width" and "@key_prefix<!-- -->_height"
+ * and maximixed if "@key_prefix<!-- -->_maximized is TRUE if
+ * @bind_size is TRUE, and moved to the values specified by
+ * "@key_prefix<!-- -->_x" and "@key_prefix<!-- -->_y" if @bind_pos is TRUE.
+ * The respective GConf values will be updated when the window is resized
+ * and/or moved.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_window (GConfBridge *bridge,
+                          const char  *key_prefix,
+                          GtkWindow   *window,
+                          gboolean     bind_size,
+                          gboolean     bind_pos)
+{
+        WindowBinding *binding;
+
+        g_return_val_if_fail (bridge != NULL, 0);
+        g_return_val_if_fail (key_prefix != NULL, 0);
+        g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
+
+        /* Create new binding. */
+        binding = g_new (WindowBinding, 1);
+
+        binding->type = BINDING_WINDOW;
+        binding->id = new_id ();
+        binding->bind_size = bind_size;
+        binding->bind_pos = bind_pos;
+        binding->key_prefix = g_strdup (key_prefix);
+        binding->window = window;
+        binding->sync_timeout_id = 0;
+
+        /* Set up GConf keys & sync window to GConf values */
+        if (bind_size) {
+                char *key;
+                GConfValue *width_val, *height_val, *maximized_val;
+
+                key = g_strconcat (key_prefix, "_width", NULL);
+                width_val = gconf_client_get (bridge->client, key, NULL);
+                g_free (key);
+
+                key = g_strconcat (key_prefix, "_height", NULL);
+                height_val = gconf_client_get (bridge->client, key, NULL);
+                g_free (key);
+
+                key = g_strconcat (key_prefix, "_maximized", NULL);
+                maximized_val = gconf_client_get (bridge->client, key, NULL);
+                g_free (key);
+
+                if (width_val && height_val) {
+                        gtk_window_resize (window,
+                                           gconf_value_get_int (width_val),
+                                           gconf_value_get_int (height_val));
+
+                        gconf_value_free (width_val);
+                        gconf_value_free (height_val);
+                } else if (width_val) {
+                        gconf_value_free (width_val);
+                } else if (height_val) {
+                        gconf_value_free (height_val);
+                }
+
+                if (maximized_val) {
+                        if (gconf_value_get_bool (maximized_val)) {
+                                gtk_window_maximize (window);
+                        }
+                        gconf_value_free (maximized_val);
+                }
+        }
+
+        if (bind_pos) {
+                char *key;
+                GConfValue *x_val, *y_val;
+                
+                key = g_strconcat (key_prefix, "_x", NULL);
+                x_val = gconf_client_get (bridge->client, key, NULL);
+                g_free (key);
+
+                key = g_strconcat (key_prefix, "_y", NULL);
+                y_val = gconf_client_get (bridge->client, key, NULL);
+                g_free (key);
+
+                if (x_val && y_val) {
+                        gtk_window_move (window,
+                                         gconf_value_get_int (x_val),
+                                         gconf_value_get_int (y_val));
+
+                        gconf_value_free (x_val);
+                        gconf_value_free (y_val);
+                } else if (x_val) {
+                        gconf_value_free (x_val);
+                } else if (y_val) {
+                        gconf_value_free (y_val);
+                }
+        }
+
+        /* Connect to window size change notifications */
+        binding->configure_event_id =
+                g_signal_connect (window,
+                                  "configure-event",
+                                  G_CALLBACK
+                                        (window_binding_configure_event_cb),
+                                  binding);
+
+        binding->window_state_event_id =
+                g_signal_connect (window,
+                                  "window_state_event",
+                                  G_CALLBACK
+                                        (window_binding_state_event_cb),
+                                  binding);
+        binding->unmap_id =
+                g_signal_connect (window,
+                                  "unmap",
+                                  G_CALLBACK (window_binding_unmap_cb),
+                                  binding);
+
+        /* Handle case where window gets destroyed */
+        g_object_weak_ref (G_OBJECT (window),
+                           window_binding_window_destroyed, binding);
+
+        /* Insert binding */
+        g_hash_table_insert (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id), binding);
+
+        /* Done */
+        return binding->id;
+}
+
+/* Unbinds a window binding */
+static void
+window_binding_unbind (WindowBinding *binding)
+{
+        if (binding->sync_timeout_id > 0)
+                g_source_remove (binding->sync_timeout_id);
+
+        g_free (binding->key_prefix);
+
+        /* The window might have been destroyed .. */
+        if (binding->window) {
+                g_signal_handler_disconnect (binding->window,
+                                             binding->configure_event_id);
+                g_signal_handler_disconnect (binding->window,
+					     binding->window_state_event_id);
+                g_signal_handler_disconnect (binding->window,
+                                             binding->unmap_id);
+
+                g_object_weak_unref (G_OBJECT (binding->window),
+                                     window_binding_window_destroyed, binding);
+        }
+}
+
+/*
+ * List store bindings
+ */
+
+/* Fills a GtkListStore with the string list from @value */
+static void
+list_store_binding_sync_pref_to_store (ListStoreBinding *binding,
+                                       GConfValue       *value)
+{
+        GSList *list, *l;
+        GtkTreeIter iter;
+
+        /* Make sure we don't enter an infinite synchronizing loop */
+        g_signal_handler_block (binding->list_store,
+                                binding->row_inserted_id);
+        g_signal_handler_block (binding->list_store,
+                                binding->row_deleted_id);
+        
+        gtk_list_store_clear (binding->list_store);
+
+        list = gconf_value_get_list (value);
+        for (l = list; l; l = l->next) {
+                GConfValue *l_value;
+                const char *string;
+
+                l_value = (GConfValue *) l->data;
+                string = gconf_value_get_string (l_value);
+
+                gtk_list_store_insert_with_values (binding->list_store,
+                                                   &iter, -1,
+                                                   0, string,
+                                                   -1);
+        }
+
+        g_signal_handler_unblock (binding->list_store,
+                                  binding->row_inserted_id);
+        g_signal_handler_unblock (binding->list_store,
+                                  binding->row_deleted_id);
+}
+
+/* Sets a GConf value to the contents of a GtkListStore */
+static gboolean
+list_store_binding_sync_store_to_pref (ListStoreBinding *binding)
+{
+        GtkTreeModel *tree_model;
+        GtkTreeIter iter;
+        GSList *list;
+        int res;
+        GConfValue *gconf_value;
+
+        tree_model = GTK_TREE_MODEL (binding->list_store);
+
+        /* Build list */
+        list = NULL;
+        res = gtk_tree_model_get_iter_first (tree_model, &iter);
+        while (res) {
+                char *string;
+                GConfValue *tmp_value;
+
+                gtk_tree_model_get (tree_model, &iter,
+                                    0, &string, -1);
+
+                tmp_value = gconf_value_new (GCONF_VALUE_STRING);
+                gconf_value_set_string (tmp_value, string);
+
+                list = g_slist_append (list, tmp_value);
+
+                res = gtk_tree_model_iter_next (tree_model, &iter);
+        }
+
+        /* Create value */
+        gconf_value = gconf_value_new (GCONF_VALUE_LIST);
+        gconf_value_set_list_type (gconf_value, GCONF_VALUE_STRING);
+        gconf_value_set_list_nocopy (gconf_value, list);
+
+        /* Set */
+        gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
+
+        /* Store until change notification comes in, so that we are able
+         * to ignore it */
+        binding->val_changes = g_slist_append (binding->val_changes,
+                                               gconf_value);
+
+        binding->sync_idle_id = 0;
+
+        g_object_unref (binding->list_store);
+
+        return FALSE;
+}
+
+/* Pref changed: sync */
+static void
+list_store_binding_pref_changed (GConfClient *client,
+                                 guint        cnxn_id,
+                                 GConfEntry  *entry,
+                                 gpointer     user_data)
+{
+        GConfValue *gconf_value;
+        ListStoreBinding *binding;
+        GSList *l;
+
+        gconf_value = gconf_entry_get_value (entry);
+        if (!gconf_value)
+                return; /* NULL means that the value has been unset */
+
+        binding = (ListStoreBinding *) user_data;
+
+        /* Check that this notification is not caused by
+         * sync_store_to_pref() */
+        l = g_slist_find_custom (binding->val_changes,
+                                 gconf_value,
+                                 (GCompareFunc) gconf_value_compare);
+        if (l) {
+                gconf_value_free (l->data);
+
+                binding->val_changes = g_slist_delete_link
+                        (binding->val_changes, l);
+
+                return;
+        }
+
+        list_store_binding_sync_pref_to_store (binding, gconf_value);
+}
+
+/* Called when an object is destroyed */
+static void
+list_store_binding_store_destroyed (gpointer user_data,
+                                    GObject *where_the_object_was)
+{
+        ListStoreBinding *binding;
+
+        binding = (ListStoreBinding *) user_data;
+        binding->list_store = NULL; /* Don't do anything with the store
+                                       at unbind() */
+        
+        g_hash_table_remove (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id));
+}
+
+/* List store changed: Sync */
+static void
+list_store_binding_store_changed_cb (ListStoreBinding *binding)
+{
+        if (binding->sync_idle_id == 0) {
+                g_object_ref (binding->list_store);
+
+                binding->sync_idle_id = g_idle_add
+                        ((GSourceFunc) list_store_binding_sync_store_to_pref,
+                         binding);
+        }
+}
+
+/**
+ * gconf_bridge_bind_string_list_store
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @list_store: A #GtkListStore
+ * 
+ * On calling this function single string column #GtkListStore @list_store
+ * will be kept synchronized with the GConf string list value pointed to by
+ * @key. On calling this function @list_store will be populated with the
+ * strings specified by the value of @key.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_string_list_store (GConfBridge  *bridge,
+                                     const char   *key,
+                                     GtkListStore *list_store)
+{
+        GtkTreeModel *tree_model;
+        gboolean have_one_column, is_string_column;
+        ListStoreBinding *binding;
+        GConfValue *val;
+
+        g_return_val_if_fail (bridge != NULL, 0);
+        g_return_val_if_fail (key != NULL, 0);
+        g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), 0);
+
+        /* Check list store suitability */
+        tree_model = GTK_TREE_MODEL (list_store);
+        have_one_column = (gtk_tree_model_get_n_columns (tree_model) == 1);
+        is_string_column = (gtk_tree_model_get_column_type
+                                        (tree_model, 0) == G_TYPE_STRING);
+        if (G_UNLIKELY (!have_one_column || !is_string_column)) {
+                g_warning ("gconf_bridge_bind_string_list_store: Only "
+                           "GtkListStores with exactly one string column are "
+                           "supported.");
+
+                return 0;
+        }
+
+        /* Create new binding. */
+        binding = g_new (ListStoreBinding, 1);
+
+        binding->type = BINDING_LIST_STORE;
+        binding->id = new_id ();
+        binding->key = g_strdup (key);
+        binding->val_changes = NULL;
+        binding->list_store = list_store;
+        binding->sync_idle_id = 0;
+
+        /* Watch GConf key */
+        binding->val_notify_id =
+                gconf_client_notify_add (bridge->client, key,
+                                         list_store_binding_pref_changed,
+                                         binding, NULL, NULL);
+
+        /* Connect to ListStore change notifications */
+        binding->row_inserted_id =
+                g_signal_connect_swapped (list_store, "row-inserted",
+                                          G_CALLBACK
+                                          (list_store_binding_store_changed_cb),
+                                          binding);
+        binding->row_changed_id =
+                g_signal_connect_swapped (list_store, "row-changed",
+                                          G_CALLBACK
+                                          (list_store_binding_store_changed_cb),
+                                          binding);
+        binding->row_deleted_id =
+                g_signal_connect_swapped (list_store, "row-deleted",
+                                          G_CALLBACK
+                                          (list_store_binding_store_changed_cb),
+                                          binding);
+        binding->rows_reordered_id =
+                g_signal_connect_swapped (list_store, "rows-reordered",
+                                          G_CALLBACK
+                                          (list_store_binding_store_changed_cb),
+                                          binding);
+
+        /* Sync object to value from GConf, if set */
+        val = gconf_client_get (bridge->client, key, NULL);
+        if (val) {
+                list_store_binding_sync_pref_to_store (binding, val);
+                gconf_value_free (val);
+        }
+
+        /* Handle case where watched object gets destroyed */
+        g_object_weak_ref (G_OBJECT (list_store),
+                           list_store_binding_store_destroyed, binding);
+
+        /* Insert binding */
+        g_hash_table_insert (bridge->bindings,
+                             GUINT_TO_POINTER (binding->id), binding);
+
+        /* Done */
+        return binding->id;
+}
+
+/* Unbinds a list store binding */
+static void
+list_store_binding_unbind (ListStoreBinding *binding)
+{
+        /* Perform any scheduled syncs */
+        if (binding->sync_idle_id > 0) {
+                g_source_remove (binding->sync_idle_id);
+
+                /* The store will still be around as we added a reference */
+                list_store_binding_sync_store_to_pref (binding);
+        }
+
+        g_free (binding->key);
+
+        while (binding->val_changes) {
+                gconf_value_free (binding->val_changes->data);
+
+                binding->val_changes = g_slist_delete_link
+                        (binding->val_changes, binding->val_changes);
+        }
+
+        /* The store might have been destroyed .. */
+        if (binding->list_store) {
+                g_signal_handler_disconnect (binding->list_store,
+                                             binding->row_inserted_id);
+                g_signal_handler_disconnect (binding->list_store,
+                                             binding->row_changed_id);
+                g_signal_handler_disconnect (binding->list_store,
+                                             binding->row_deleted_id);
+                g_signal_handler_disconnect (binding->list_store,
+                                             binding->rows_reordered_id);
+
+                g_object_weak_unref (G_OBJECT (binding->list_store),
+                                     list_store_binding_store_destroyed,
+                                     binding);
+        }
+}
+
+/*
+ * Generic unbinding
+ */
+
+/* Unbinds a binding */
+static void
+unbind (Binding *binding)
+{
+        /* Call specialized unbinding function */
+        switch (binding->type) {
+        case BINDING_PROP:
+                prop_binding_unbind ((PropBinding *) binding);
+                break;
+        case BINDING_WINDOW:
+                window_binding_unbind ((WindowBinding *) binding);
+                break;
+        case BINDING_LIST_STORE:
+                list_store_binding_unbind ((ListStoreBinding *) binding);
+                break;
+        default:
+                g_warning ("Unknown binding type '%d'\n", binding->type);
+                break;
+        }
+
+        g_free (binding);
+}
+
+/**
+ * gconf_bridge_unbind
+ * @bridge: A #GConfBridge
+ * @binding_id: The ID of the binding to be removed
+ *
+ * Removes the binding with ID @binding_id.
+ **/
+void
+gconf_bridge_unbind (GConfBridge *bridge,
+                     guint        binding_id)
+{
+        g_return_if_fail (bridge != NULL);
+        g_return_if_fail (binding_id > 0);
+
+        /* This will trigger the hash tables value destruction
+         * function, which will take care of further cleanup */
+        g_hash_table_remove (bridge->bindings, 
+                             GUINT_TO_POINTER (binding_id));
+}
+
+/*
+ * Error handling
+ */
+
+/* This is the same dialog as used in eel */
+static void
+error_handler (GConfClient *client,
+               GError      *error)
+{
+        static gboolean shown_dialog = FALSE;
+
+        g_warning ("GConf error:\n  %s", error->message);
+
+        if (!shown_dialog) {
+                char *message;
+                GtkWidget *dlg;
+
+                message = g_strdup_printf (_("GConf error: %s"),
+                                           error->message);
+                dlg = gtk_message_dialog_new (NULL, 0,
+                                              GTK_MESSAGE_ERROR,
+                                              GTK_BUTTONS_OK,
+                                              message);
+                g_free (message);
+
+                gtk_message_dialog_format_secondary_text
+                        (GTK_MESSAGE_DIALOG (dlg),
+                         _("All further errors shown only on terminal."));
+                gtk_window_set_title (GTK_WINDOW (dlg), "");
+
+                gtk_dialog_run (GTK_DIALOG (dlg));
+
+                gtk_widget_destroy (dlg);
+
+                shown_dialog = TRUE;
+	}
+}
+
+/**
+ * gconf_bridge_install_default_error_handler
+ *
+ * Sets up the default error handler. Any unhandled GConf errors will
+ * automatically be handled by presenting the user an error dialog.
+ **/
+void
+gconf_bridge_install_default_error_handler (void)
+{
+        gconf_client_set_global_default_error_handler (error_handler);
+}

Added: trunk/properties/gconf-bridge.h
==============================================================================
--- (empty file)
+++ trunk/properties/gconf-bridge.h	Mon Apr  6 16:26:23 2009
@@ -0,0 +1,116 @@
+/* 
+ * (C) 2005 OpenedHand Ltd.
+ *
+ * Author: Jorn Baayen <jorn openedhand com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#ifndef __GCONF_BRIDGE_H__
+#define __GCONF_BRIDGE_H__
+
+#include <gconf/gconf-client.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void gconf_bridge_install_default_error_handler (void);
+
+typedef struct _GConfBridge GConfBridge;
+
+GConfBridge *gconf_bridge_get                    (void);
+
+GConfClient *gconf_bridge_get_client             (GConfBridge  *bridge);
+
+guint        gconf_bridge_bind_property_full     (GConfBridge  *bridge,
+                                                  const char   *key,
+                                                  GObject      *object,
+                                                  const char   *prop,
+                                                  gboolean      delayed_sync);
+
+/**
+ * gconf_bridge_bind_property
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ *
+ * Binds @key to @prop without delays, causing them to have the same value at all times. See
+ * #gconf_bridge_bind_property_full for more details.
+ *
+ **/
+#define gconf_bridge_bind_property(bridge, key, object, prop) \
+        gconf_bridge_bind_property_full ((bridge), (key), \
+                                         (object), (prop), FALSE)
+
+/**
+ * gconf_bridge_bind_property_delayed
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ *
+ * Binds @key to @prop with a delay, causing them to have the same value at all
+ * times. See #gconf_bridge_bind_property_full for more details.
+ **/
+#define gconf_bridge_bind_property_delayed(bridge, key, object, prop) \
+        gconf_bridge_bind_property_full ((bridge), (key), \
+                                         (object), (prop), TRUE)
+
+guint        gconf_bridge_bind_window            (GConfBridge  *bridge,
+                                                  const char   *key_prefix,
+                                                  GtkWindow    *window,
+                                                  gboolean      bind_size,
+                                                  gboolean      bind_pos);
+
+/**
+ * gconf_bridge_bind_window_size
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ * 
+ * On calling this function @window will be resized to the values specified by
+ * "@key_prefix<!-- -->_width" and "@key_prefix<!-- -->_height".  The respective
+ * GConf values will be updated when the window is resized. See
+ * #gconf_bridge_bind_window for more details.
+ **/
+#define gconf_bridge_bind_window_size(bridge, key_prefix, window) \
+        gconf_bridge_bind_window ((bridge), (key_prefix), (window), TRUE, FALSE)
+
+/**
+ * gconf_bridge_bind_window_pos
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ * 
+ * On calling this function @window will be moved to the values specified by
+ * "@key_prefix<!-- -->_x" and "@key_prefix<!-- -->_y". The respective GConf
+ * values will be updated when the window is moved. See
+ * #gconf_bridge_bind_window for more details.
+ **/
+#define gconf_bridge_bind_window_pos(bridge, key_prefix, window) \
+        gconf_bridge_bind_window ((bridge), (key_prefix), (window), FALSE, TRUE)
+
+guint        gconf_bridge_bind_string_list_store (GConfBridge  *bridge,
+                                                  const char   *key,
+                                                  GtkListStore *list_store);
+
+void         gconf_bridge_unbind                 (GConfBridge  *bridge,
+                                                  guint         binding_id);
+
+G_END_DECLS
+
+#endif /* __GCONF_BRIDGE_H__ */

Modified: trunk/properties/general.c
==============================================================================
--- trunk/properties/general.c	(original)
+++ trunk/properties/general.c	Mon Apr  6 16:26:23 2009
@@ -26,84 +26,10 @@
 #include <config.h>
 #endif
 
-#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-#include <gconf/gconf-client.h>
-
-#include <bluetooth-client.h>
-
 #include "general.h"
 
-typedef enum {
-	ICON_POLICY_NEVER,
-	ICON_POLICY_ALWAYS,
-	ICON_POLICY_PRESENT,
-} EnumIconPolicy;
-
-static int icon_policy = ICON_POLICY_PRESENT;
-
-#define PREF_DIR		"/apps/bluetooth-manager"
-#define PREF_ICON_POLICY	PREF_DIR "/icon_policy"
-
-static GConfEnumStringPair icon_policy_enum_map [] = {
-	{ ICON_POLICY_NEVER,	"never"		},
-	{ ICON_POLICY_ALWAYS,	"always"	},
-	{ ICON_POLICY_PRESENT,	"present"	},
-	{ ICON_POLICY_PRESENT,	NULL		},
-};
-
-static GConfClient* gconf;
-
-static GtkWidget *button_never;
-static GtkWidget *button_always;
-static GtkWidget *button_present;
-
-static void update_icon_policy(GtkWidget *button)
-{
-	GtkWidget *widget;
-	const char *str;
-
-	if (button == NULL) {
-		switch (icon_policy) {
-		case ICON_POLICY_NEVER:
-			widget = button_never;
-			break;
-		case ICON_POLICY_ALWAYS:
-			widget = button_always;
-			break;
-		case ICON_POLICY_PRESENT:
-		default:
-			widget = button_present;
-			break;
-		}
-
-		if (!widget)
-			return;
-
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
-
-		return;
-	}
-
-	if (button == button_always)
-		icon_policy = ICON_POLICY_ALWAYS;
-	else if (button == button_never)
-		icon_policy = ICON_POLICY_NEVER;
-	else if (button == button_present)
-		icon_policy = ICON_POLICY_PRESENT;
-
-	str = gconf_enum_to_string(icon_policy_enum_map, icon_policy);
-
-	gconf_client_set_string(gconf, PREF_ICON_POLICY, str, NULL);
-}
-
-static void policy_callback(GtkWidget *button, gpointer user_data)
-{
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == TRUE)
-		update_icon_policy(button);
-}
-
 GtkWidget *create_label(const gchar *str)
 {
 	GtkWidget *label;
@@ -120,88 +46,3 @@
 	return label;
 }
 
-GtkWidget *create_general(void)
-{
-	GtkWidget *mainbox;
-	GtkWidget *vbox;
-	GtkWidget *label;
-	GSList *group = NULL;
-
-	mainbox = gtk_vbox_new(FALSE, 24);
-	gtk_container_set_border_width(GTK_CONTAINER(mainbox), 12);
-
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_box_pack_start(GTK_BOX(mainbox), vbox, FALSE, FALSE, 0);
-
-	label = create_label(_("Notification area"));
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-	button_never = gtk_radio_button_new_with_label(group,
-						_("Never display icon"));
-	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_never));
-	gtk_box_pack_start(GTK_BOX(vbox), button_never, FALSE, FALSE, 0);
-	g_signal_connect(G_OBJECT(button_never), "toggled",
-					G_CALLBACK(policy_callback), NULL);
-
-	button_present = gtk_radio_button_new_with_label(group,
-				_("Only display when adapter present"));
-	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_present));
-	gtk_box_pack_start(GTK_BOX(vbox), button_present, FALSE, FALSE, 0);
-	g_signal_connect(G_OBJECT(button_present), "toggled",
-					G_CALLBACK(policy_callback), NULL);
-
-	button_always = gtk_radio_button_new_with_label(group,
-						_("Always display icon"));
-	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_always));
-	gtk_box_pack_start(GTK_BOX(vbox), button_always, FALSE, FALSE, 0);
-	g_signal_connect(G_OBJECT(button_always), "toggled",
-					G_CALLBACK(policy_callback), NULL);
-
-	update_icon_policy(NULL);
-
-	return mainbox;
-}
-
-static void gconf_callback(GConfClient *client, guint cnxn_id,
-					GConfEntry *entry, gpointer user_data)
-{
-	GConfValue *value;
-
-	value = gconf_entry_get_value(entry);
-	if (value == NULL)
-		return;
-
-	if (g_str_equal(entry->key, PREF_ICON_POLICY) == TRUE) {
-		const char *str;
-
-		str = gconf_value_get_string(value);
-		if (str)
-			gconf_string_to_enum(icon_policy_enum_map,
-							str, &icon_policy);
-
-		update_icon_policy(NULL);
-	}
-}
-
-void setup_general(void)
-{
-	char *str;
-
-	gconf = gconf_client_get_default();
-
-	str = gconf_client_get_string(gconf, PREF_ICON_POLICY, NULL);
-	if (str) {
-		gconf_string_to_enum(icon_policy_enum_map, str, &icon_policy);
-		g_free(str);
-	}
-
-	gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
-
-	gconf_client_notify_add(gconf, PREF_DIR,
-					gconf_callback, NULL, NULL, NULL);
-}
-
-void cleanup_general(void)
-{
-	g_object_unref(gconf);
-}

Modified: trunk/properties/general.h
==============================================================================
--- trunk/properties/general.h	(original)
+++ trunk/properties/general.h	Mon Apr  6 16:26:23 2009
@@ -23,6 +23,4 @@
  */
 
 GtkWidget *create_label(const gchar *str);
-GtkWidget *create_general(void);
-void setup_general(void);
-void cleanup_general(void);
+

Modified: trunk/properties/main.c
==============================================================================
--- trunk/properties/main.c	(original)
+++ trunk/properties/main.c	Mon Apr  6 16:26:23 2009
@@ -30,9 +30,13 @@
 #include <gtk/gtk.h>
 #include <unique/uniqueapp.h>
 
+#include "gconf-bridge.h"
 #include "general.h"
 #include "adapter.h"
 
+#define PREF_DIR		"/apps/bluetooth-manager"
+#define PREF_SHOW_ICON		PREF_DIR "/show_icon"
+
 static gboolean delete_callback(GtkWidget *window, GdkEvent *event,
 							gpointer user_data)
 {
@@ -118,10 +122,10 @@
 static GtkWidget *create_window(GtkWidget *notebook)
 {
 	GtkWidget *window;
-/*	GtkWidget *widget; */
 	GtkWidget *vbox;
 	GtkWidget *buttonbox;
 	GtkWidget *button;
+	GConfBridge *bridge;
 
 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 	gtk_window_set_title(GTK_WINDOW(window), _("Bluetooth Preferences"));
@@ -136,6 +140,12 @@
 
 	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
 
+	button = gtk_check_button_new_with_mnemonic (_("_Show Bluetooth icon"));
+	bridge = gconf_bridge_get ();
+	gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+	gconf_bridge_bind_property_full (bridge, PREF_SHOW_ICON, G_OBJECT (button),
+					 "active", FALSE);
+
 	buttonbox = gtk_hbutton_box_new();
 	gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonbox), GTK_BUTTONBOX_END);
 	gtk_box_pack_start(GTK_BOX(vbox), buttonbox, FALSE, FALSE, 0);
@@ -158,12 +168,6 @@
 	gtk_container_add(GTK_CONTAINER(buttonbox), button);
 #endif
 
-#if 0
-	widget = create_general();
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL);
-	gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook),
-						widget, _("General"));
-#endif
 	gtk_widget_show_all(window);
 
 	return window;



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