2
* (C) 2005 OpenedHand Ltd.
4
* Author: Jorn Baayen <jorn@openedhand.com>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Library General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Library General Public License for more details.
16
* You should have received a copy of the GNU Library General Public
17
* License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
24
#include <glib/gi18n-lib.h>
28
#include "gconf-bridge.h"
36
/* The data structures for the different kinds of bindings */
47
gboolean delayed_mode;
51
GSList *val_changes; /* List of changes made to GConf value,
52
that have not received change notification
57
gulong prop_notify_id;
59
guint sync_timeout_id; /* Used in delayed mode */
72
gulong configure_event_id;
73
gulong window_state_event_id;
75
guint sync_timeout_id;
84
GSList *val_changes; /* List of changes made to GConf value,
85
that have not received change notification
88
GtkListStore *list_store;
89
guint row_inserted_id;
92
guint rows_reordered_id;
97
/* Some trickery to be able to treat the data structures generically */
101
PropBinding prop_binding;
102
WindowBinding window_binding;
103
ListStoreBinding list_store_binding;
106
/* Function prototypes */
108
unbind (Binding *binding);
110
#if !HAVE_DECL_GCONF_VALUE_COMPARE /* Not in headers in GConf < 2.13 */
111
int gconf_value_compare (const GConfValue *value_a,
112
const GConfValue *value_b);
115
static GConfBridge *bridge = NULL; /* Global GConfBridge object */
117
/* Free up all resources allocated by the GConfBridge. Called on exit. */
119
destroy_bridge (void)
121
g_hash_table_destroy (bridge->bindings);
122
g_object_unref (bridge->client);
130
* Returns the #GConfBridge. This is a singleton object.
132
* Return value: The #GConfBridge.
135
gconf_bridge_get (void)
140
gconf_bridge_install_default_error_handler ();
142
bridge = g_new (GConfBridge, 1);
144
bridge->client = gconf_client_get_default ();
145
bridge->bindings = g_hash_table_new_full (NULL, NULL, NULL,
146
(GDestroyNotify) unbind);
148
g_atexit (destroy_bridge);
154
* gconf_bridge_get_client
155
* @bridge: A #GConfBridge
157
* Returns the #GConfClient used by @bridge. This is the same #GConfClient
158
* as returned by gconf_client_get_default().
160
* Return value: A #GConfClient.
163
gconf_bridge_get_client (GConfBridge *bridge)
165
g_return_val_if_fail (bridge != NULL, NULL);
167
return bridge->client;
170
/* Generate an ID for a new binding */
174
static guint id_counter = 0;
185
/* Syncs a value from GConf to an object property */
187
prop_binding_sync_pref_to_prop (PropBinding *binding,
188
GConfValue *pref_value)
190
GValue src_value, value;
192
/* Make sure we don't enter an infinite synchronizing loop */
193
g_signal_handler_block (binding->object, binding->prop_notify_id);
195
memset (&src_value, 0, sizeof (GValue));
197
/* First, convert GConfValue to GValue */
198
switch (pref_value->type) {
199
case GCONF_VALUE_STRING:
200
g_value_init (&src_value, G_TYPE_STRING);
201
g_value_set_string (&src_value,
202
gconf_value_get_string (pref_value));
204
case GCONF_VALUE_INT:
205
g_value_init (&src_value, G_TYPE_INT);
206
g_value_set_int (&src_value,
207
gconf_value_get_int (pref_value));
209
case GCONF_VALUE_BOOL:
210
g_value_init (&src_value, G_TYPE_BOOLEAN);
211
g_value_set_boolean (&src_value,
212
gconf_value_get_bool (pref_value));
214
case GCONF_VALUE_FLOAT:
215
g_value_init (&src_value, G_TYPE_FLOAT);
216
g_value_set_float (&src_value,
217
gconf_value_get_float (pref_value));
220
g_warning ("prop_binding_sync_pref_to_prop: Unhandled value "
221
"type '%d'.\n", pref_value->type);
226
/* Then convert to the type expected by the object, if necessary */
227
memset (&value, 0, sizeof (GValue));
228
g_value_init (&value,
229
G_PARAM_SPEC_VALUE_TYPE (binding->prop));
231
if (src_value.g_type != value.g_type) {
232
if (!g_value_transform (&src_value, &value)) {
233
g_warning ("prop_binding_sync_pref_to_prop: Failed to "
234
"transform a \"%s\" to a \"%s\".",
235
g_type_name (src_value.g_type),
236
g_type_name (value.g_type));
241
g_object_set_property (binding->object,
242
binding->prop->name, &value);
244
g_object_set_property (binding->object,
245
binding->prop->name, &src_value);
249
g_value_unset (&src_value);
250
g_value_unset (&value);
252
g_signal_handler_unblock (binding->object, binding->prop_notify_id);
255
/* Syncs an object property to GConf */
257
prop_binding_sync_prop_to_pref (PropBinding *binding)
260
GConfValue *gconf_value;
262
memset (&value, 0, sizeof (GValue));
264
g_value_init (&value,
265
G_PARAM_SPEC_VALUE_TYPE (binding->prop));
266
g_object_get_property (binding->object,
270
switch (value.g_type) {
272
gconf_value = gconf_value_new (GCONF_VALUE_STRING);
273
gconf_value_set_string (gconf_value,
274
g_value_get_string (&value));
277
gconf_value = gconf_value_new (GCONF_VALUE_INT);
278
gconf_value_set_int (gconf_value,
279
g_value_get_int (&value));
282
gconf_value = gconf_value_new (GCONF_VALUE_INT);
283
gconf_value_set_int (gconf_value,
284
g_value_get_uint (&value));
287
gconf_value = gconf_value_new (GCONF_VALUE_INT);
288
gconf_value_set_int (gconf_value,
289
g_value_get_long (&value));
292
gconf_value = gconf_value_new (GCONF_VALUE_INT);
293
gconf_value_set_int (gconf_value,
294
g_value_get_ulong (&value));
297
gconf_value = gconf_value_new (GCONF_VALUE_INT);
298
gconf_value_set_int (gconf_value,
299
g_value_get_int64 (&value));
302
gconf_value = gconf_value_new (GCONF_VALUE_INT);
303
gconf_value_set_int (gconf_value,
304
g_value_get_uint64 (&value));
307
gconf_value = gconf_value_new (GCONF_VALUE_INT);
308
gconf_value_set_int (gconf_value,
309
g_value_get_char (&value));
312
gconf_value = gconf_value_new (GCONF_VALUE_INT);
313
gconf_value_set_int (gconf_value,
314
g_value_get_uchar (&value));
317
gconf_value = gconf_value_new (GCONF_VALUE_INT);
318
gconf_value_set_int (gconf_value,
319
g_value_get_enum (&value));
322
gconf_value = gconf_value_new (GCONF_VALUE_BOOL);
323
gconf_value_set_bool (gconf_value,
324
g_value_get_boolean (&value));
327
gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
328
#ifdef HAVE_CORBA_GCONF
329
/* FIXME we cast to a float explicitly as CORBA GConf
330
* uses doubles in its API, but treats them as floats
331
* when transporting them over CORBA. See #322837 */
332
gconf_value_set_float (gconf_value,
333
(float) g_value_get_double (&value));
335
gconf_value_set_float (gconf_value,
336
g_value_get_double (&value));
340
gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
341
gconf_value_set_float (gconf_value,
342
g_value_get_float (&value));
345
if (g_type_is_a (value.g_type, G_TYPE_ENUM)) {
346
gconf_value = gconf_value_new (GCONF_VALUE_INT);
347
gconf_value_set_int (gconf_value,
348
g_value_get_enum (&value));
350
g_warning ("prop_binding_sync_prop_to_pref: "
351
"Unhandled value type '%s'.\n",
352
g_type_name (value.g_type));
361
gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
363
/* Store until change notification comes in, so that we are able
365
binding->val_changes = g_slist_append (binding->val_changes,
369
g_value_unset (&value);
372
/* Called when a GConf value bound to an object property has changed */
374
prop_binding_pref_changed (GConfClient *client,
379
GConfValue *gconf_value;
380
PropBinding *binding;
383
gconf_value = gconf_entry_get_value (entry);
385
return; /* NULL means that the value has been unset */
387
binding = (PropBinding *) user_data;
389
/* Check that this notification is not caused by sync_prop_to_pref() */
390
l = g_slist_find_custom (binding->val_changes,
392
(GCompareFunc) gconf_value_compare);
394
gconf_value_free (l->data);
396
binding->val_changes = g_slist_delete_link
397
(binding->val_changes, l);
402
prop_binding_sync_pref_to_prop (binding, gconf_value);
405
/* Performs a scheduled prop-to-pref sync for a prop binding in
408
prop_binding_perform_scheduled_sync (PropBinding *binding)
410
prop_binding_sync_prop_to_pref (binding);
412
binding->sync_timeout_id = 0;
414
g_object_unref (binding->object);
419
#define PROP_BINDING_SYNC_DELAY 100 /* Delay for bindings with "delayed"
420
set to TRUE, in ms */
422
/* Called when an object property has changed */
424
prop_binding_prop_changed (GObject *object,
425
GParamSpec *param_spec,
426
PropBinding *binding)
428
if (binding->delayed_mode) {
429
/* Just schedule a sync */
430
if (binding->sync_timeout_id == 0) {
431
/* We keep a reference on the object as long as
432
* we haven't synced yet to make sure we don't
434
g_object_ref (binding->object);
436
binding->sync_timeout_id =
438
(PROP_BINDING_SYNC_DELAY,
440
prop_binding_perform_scheduled_sync,
445
prop_binding_sync_prop_to_pref (binding);
449
/* Called when an object is destroyed */
451
prop_binding_object_destroyed (gpointer user_data,
452
GObject *where_the_object_was)
454
PropBinding *binding;
456
binding = (PropBinding *) user_data;
457
binding->object = NULL; /* Don't do anything with the object
460
g_hash_table_remove (bridge->bindings,
461
GUINT_TO_POINTER (binding->id));
465
* gconf_bridge_bind_property_full
466
* @bridge: A #GConfBridge
467
* @key: A GConf key to be bound
468
* @object: A #GObject
469
* @prop: The property of @object to be bound
470
* @delayed_sync: TRUE if there should be a delay between property changes
471
* and syncs to GConf. Set to TRUE when binding to a rapidly-changing
472
* property, for example the "value" property on a #GtkAdjustment.
474
* Binds @key to @prop, causing them to have the same value at all times.
476
* The types of @key and @prop should be compatible. Floats and doubles, and
477
* ints, uints, longs, unlongs, int64s, uint64s, chars, uchars and enums
478
* can be matched up. Booleans and strings can only be matched to their
481
* On calling this function the current value of @key will be set to @prop.
483
* Return value: The ID of the new binding.
486
gconf_bridge_bind_property_full (GConfBridge *bridge,
490
gboolean delayed_sync)
493
PropBinding *binding;
497
g_return_val_if_fail (bridge != NULL, 0);
498
g_return_val_if_fail (key != NULL, 0);
499
g_return_val_if_fail (G_IS_OBJECT (object), 0);
500
g_return_val_if_fail (prop != NULL, 0);
502
/* First, try to fetch the propertys GParamSpec off the object */
503
pspec = g_object_class_find_property
504
(G_OBJECT_GET_CLASS (object), prop);
505
if (G_UNLIKELY (pspec == NULL)) {
506
g_warning ("gconf_bridge_bind_property_full: A property \"%s\" "
507
"was not found. Please make sure you are passing "
508
"the right property name.", prop);
513
/* GParamSpec found: All good, create new binding. */
514
binding = g_new (PropBinding, 1);
516
binding->type = BINDING_PROP;
517
binding->id = new_id ();
518
binding->delayed_mode = delayed_sync;
519
binding->val_changes = NULL;
520
binding->key = g_strdup (key);
521
binding->object = object;
522
binding->prop = pspec;
523
binding->sync_timeout_id = 0;
525
/* Watch GConf key */
526
binding->val_notify_id =
527
gconf_client_notify_add (bridge->client, key,
528
prop_binding_pref_changed,
529
binding, NULL, NULL);
531
/* Connect to property change notifications */
532
signal = g_strconcat ("notify::", prop, NULL);
533
binding->prop_notify_id =
534
g_signal_connect (object, signal,
535
G_CALLBACK (prop_binding_prop_changed),
539
/* Sync object to value from GConf, if set */
540
val = gconf_client_get (bridge->client, key, NULL);
542
prop_binding_sync_pref_to_prop (binding, val);
543
gconf_value_free (val);
546
/* Handle case where watched object gets destroyed */
547
g_object_weak_ref (object,
548
prop_binding_object_destroyed, binding);
551
g_hash_table_insert (bridge->bindings,
552
GUINT_TO_POINTER (binding->id), binding);
558
/* Unbinds a property binding */
560
prop_binding_unbind (PropBinding *binding)
562
if (binding->delayed_mode && binding->sync_timeout_id > 0) {
563
/* Perform any scheduled syncs */
564
g_source_remove (binding->sync_timeout_id);
566
/* The object will still be around as we have
568
prop_binding_perform_scheduled_sync (binding);
571
gconf_client_notify_remove (bridge->client,
572
binding->val_notify_id);
573
g_free (binding->key);
575
while (binding->val_changes) {
576
gconf_value_free (binding->val_changes->data);
578
binding->val_changes = g_slist_delete_link
579
(binding->val_changes, binding->val_changes);
582
/* The object might have been destroyed .. */
583
if (binding->object) {
584
g_signal_handler_disconnect (binding->object,
585
binding->prop_notify_id);
587
g_object_weak_unref (binding->object,
588
prop_binding_object_destroyed, binding);
596
/* Performs a scheduled dimensions-to-prefs sync for a window binding */
598
window_binding_perform_scheduled_sync (WindowBinding *binding)
600
if (binding->bind_size) {
603
GdkWindowState state;
605
state = gdk_window_get_state (GTK_WIDGET (binding->window)->window);
607
if (state & GDK_WINDOW_STATE_MAXIMIZED) {
608
key = g_strconcat (binding->key_prefix, "_maximized", NULL);
609
gconf_client_set_bool (bridge->client, key, TRUE, NULL);
612
gtk_window_get_size (binding->window, &width, &height);
614
key = g_strconcat (binding->key_prefix, "_width", NULL);
615
gconf_client_set_int (bridge->client, key, width, NULL);
618
key = g_strconcat (binding->key_prefix, "_height", NULL);
619
gconf_client_set_int (bridge->client, key, height, NULL);
622
key = g_strconcat (binding->key_prefix, "_maximized", NULL);
623
gconf_client_set_bool (bridge->client, key, FALSE, NULL);
628
if (binding->bind_pos) {
632
gtk_window_get_position (binding->window, &x, &y);
634
key = g_strconcat (binding->key_prefix, "_x", NULL);
635
gconf_client_set_int (bridge->client, key, x, NULL);
638
key = g_strconcat (binding->key_prefix, "_y", NULL);
639
gconf_client_set_int (bridge->client, key, y, NULL);
643
binding->sync_timeout_id = 0;
648
#define WINDOW_BINDING_SYNC_DELAY 1000 /* Delay before syncing new window
649
dimensions to GConf, in ms */
651
/* Called when the window han been resized or moved */
653
window_binding_configure_event_cb (GtkWindow *window,
654
GdkEventConfigure *event,
655
WindowBinding *binding)
657
/* Schedule a sync */
658
if (binding->sync_timeout_id == 0) {
659
binding->sync_timeout_id =
660
g_timeout_add (WINDOW_BINDING_SYNC_DELAY,
662
window_binding_perform_scheduled_sync,
669
/* Called when the window state is being changed */
671
window_binding_state_event_cb (GtkWindow *window,
672
GdkEventWindowState *event,
673
WindowBinding *binding)
675
window_binding_perform_scheduled_sync (binding);
680
/* Called when the window is being unmapped */
682
window_binding_unmap_cb (GtkWindow *window,
683
WindowBinding *binding)
686
if (binding->sync_timeout_id > 0)
687
g_source_remove (binding->sync_timeout_id);
689
window_binding_perform_scheduled_sync (binding);
694
/* Called when a window is destroyed */
696
window_binding_window_destroyed (gpointer user_data,
697
GObject *where_the_object_was)
699
WindowBinding *binding;
701
binding = (WindowBinding *) user_data;
702
binding->window = NULL; /* Don't do anything with the window
705
g_hash_table_remove (bridge->bindings,
706
GUINT_TO_POINTER (binding->id));
710
* gconf_bridge_bind_window
711
* @bridge: A #GConfBridge
712
* @key_prefix: The prefix of the GConf keys
713
* @window: A #GtkWindow
714
* @bind_size: TRUE to bind the size of @window
715
* @bind_pos: TRUE to bind the position of @window
717
* On calling this function @window will be resized to the values
718
* specified by "@key_prefix<!-- -->_width" and "@key_prefix<!-- -->_height"
719
* and maximixed if "@key_prefix<!-- -->_maximized is TRUE if
720
* @bind_size is TRUE, and moved to the values specified by
721
* "@key_prefix<!-- -->_x" and "@key_prefix<!-- -->_y" if @bind_pos is TRUE.
722
* The respective GConf values will be updated when the window is resized
725
* Return value: The ID of the new binding.
728
gconf_bridge_bind_window (GConfBridge *bridge,
729
const char *key_prefix,
734
WindowBinding *binding;
736
g_return_val_if_fail (bridge != NULL, 0);
737
g_return_val_if_fail (key_prefix != NULL, 0);
738
g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
740
/* Create new binding. */
741
binding = g_new (WindowBinding, 1);
743
binding->type = BINDING_WINDOW;
744
binding->id = new_id ();
745
binding->bind_size = bind_size;
746
binding->bind_pos = bind_pos;
747
binding->key_prefix = g_strdup (key_prefix);
748
binding->window = window;
749
binding->sync_timeout_id = 0;
751
/* Set up GConf keys & sync window to GConf values */
754
GConfValue *width_val, *height_val, *maximized_val;
756
key = g_strconcat (key_prefix, "_width", NULL);
757
width_val = gconf_client_get (bridge->client, key, NULL);
760
key = g_strconcat (key_prefix, "_height", NULL);
761
height_val = gconf_client_get (bridge->client, key, NULL);
764
key = g_strconcat (key_prefix, "_maximized", NULL);
765
maximized_val = gconf_client_get (bridge->client, key, NULL);
768
if (width_val && height_val) {
769
gtk_window_resize (window,
770
gconf_value_get_int (width_val),
771
gconf_value_get_int (height_val));
773
gconf_value_free (width_val);
774
gconf_value_free (height_val);
775
} else if (width_val) {
776
gconf_value_free (width_val);
777
} else if (height_val) {
778
gconf_value_free (height_val);
782
if (gconf_value_get_bool (maximized_val)) {
783
gtk_window_maximize (window);
785
gconf_value_free (maximized_val);
791
GConfValue *x_val, *y_val;
793
key = g_strconcat (key_prefix, "_x", NULL);
794
x_val = gconf_client_get (bridge->client, key, NULL);
797
key = g_strconcat (key_prefix, "_y", NULL);
798
y_val = gconf_client_get (bridge->client, key, NULL);
801
if (x_val && y_val) {
802
gtk_window_move (window,
803
gconf_value_get_int (x_val),
804
gconf_value_get_int (y_val));
806
gconf_value_free (x_val);
807
gconf_value_free (y_val);
809
gconf_value_free (x_val);
811
gconf_value_free (y_val);
815
/* Connect to window size change notifications */
816
binding->configure_event_id =
817
g_signal_connect (window,
820
(window_binding_configure_event_cb),
823
binding->window_state_event_id =
824
g_signal_connect (window,
825
"window_state_event",
827
(window_binding_state_event_cb),
830
g_signal_connect (window,
832
G_CALLBACK (window_binding_unmap_cb),
835
/* Handle case where window gets destroyed */
836
g_object_weak_ref (G_OBJECT (window),
837
window_binding_window_destroyed, binding);
840
g_hash_table_insert (bridge->bindings,
841
GUINT_TO_POINTER (binding->id), binding);
847
/* Unbinds a window binding */
849
window_binding_unbind (WindowBinding *binding)
851
if (binding->sync_timeout_id > 0)
852
g_source_remove (binding->sync_timeout_id);
854
g_free (binding->key_prefix);
856
/* The window might have been destroyed .. */
857
if (binding->window) {
858
g_signal_handler_disconnect (binding->window,
859
binding->configure_event_id);
860
g_signal_handler_disconnect (binding->window,
861
binding->window_state_event_id);
862
g_signal_handler_disconnect (binding->window,
865
g_object_weak_unref (G_OBJECT (binding->window),
866
window_binding_window_destroyed, binding);
871
* List store bindings
874
/* Fills a GtkListStore with the string list from @value */
876
list_store_binding_sync_pref_to_store (ListStoreBinding *binding,
882
/* Make sure we don't enter an infinite synchronizing loop */
883
g_signal_handler_block (binding->list_store,
884
binding->row_inserted_id);
885
g_signal_handler_block (binding->list_store,
886
binding->row_deleted_id);
888
gtk_list_store_clear (binding->list_store);
890
list = gconf_value_get_list (value);
891
for (l = list; l; l = l->next) {
895
l_value = (GConfValue *) l->data;
896
string = gconf_value_get_string (l_value);
898
gtk_list_store_insert_with_values (binding->list_store,
904
g_signal_handler_unblock (binding->list_store,
905
binding->row_inserted_id);
906
g_signal_handler_unblock (binding->list_store,
907
binding->row_deleted_id);
910
/* Sets a GConf value to the contents of a GtkListStore */
912
list_store_binding_sync_store_to_pref (ListStoreBinding *binding)
914
GtkTreeModel *tree_model;
918
GConfValue *gconf_value;
920
tree_model = GTK_TREE_MODEL (binding->list_store);
924
res = gtk_tree_model_get_iter_first (tree_model, &iter);
927
GConfValue *tmp_value;
929
gtk_tree_model_get (tree_model, &iter,
932
tmp_value = gconf_value_new (GCONF_VALUE_STRING);
933
gconf_value_set_string (tmp_value, string);
935
list = g_slist_append (list, tmp_value);
937
res = gtk_tree_model_iter_next (tree_model, &iter);
941
gconf_value = gconf_value_new (GCONF_VALUE_LIST);
942
gconf_value_set_list_type (gconf_value, GCONF_VALUE_STRING);
943
gconf_value_set_list_nocopy (gconf_value, list);
946
gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
948
/* Store until change notification comes in, so that we are able
950
binding->val_changes = g_slist_append (binding->val_changes,
953
binding->sync_idle_id = 0;
955
g_object_unref (binding->list_store);
960
/* Pref changed: sync */
962
list_store_binding_pref_changed (GConfClient *client,
967
GConfValue *gconf_value;
968
ListStoreBinding *binding;
971
gconf_value = gconf_entry_get_value (entry);
973
return; /* NULL means that the value has been unset */
975
binding = (ListStoreBinding *) user_data;
977
/* Check that this notification is not caused by
978
* sync_store_to_pref() */
979
l = g_slist_find_custom (binding->val_changes,
981
(GCompareFunc) gconf_value_compare);
983
gconf_value_free (l->data);
985
binding->val_changes = g_slist_delete_link
986
(binding->val_changes, l);
991
list_store_binding_sync_pref_to_store (binding, gconf_value);
994
/* Called when an object is destroyed */
996
list_store_binding_store_destroyed (gpointer user_data,
997
GObject *where_the_object_was)
999
ListStoreBinding *binding;
1001
binding = (ListStoreBinding *) user_data;
1002
binding->list_store = NULL; /* Don't do anything with the store
1005
g_hash_table_remove (bridge->bindings,
1006
GUINT_TO_POINTER (binding->id));
1009
/* List store changed: Sync */
1011
list_store_binding_store_changed_cb (ListStoreBinding *binding)
1013
if (binding->sync_idle_id == 0) {
1014
g_object_ref (binding->list_store);
1016
binding->sync_idle_id = g_idle_add
1017
((GSourceFunc) list_store_binding_sync_store_to_pref,
1023
* gconf_bridge_bind_string_list_store
1024
* @bridge: A #GConfBridge
1025
* @key: A GConf key to be bound
1026
* @list_store: A #GtkListStore
1028
* On calling this function single string column #GtkListStore @list_store
1029
* will be kept synchronized with the GConf string list value pointed to by
1030
* @key. On calling this function @list_store will be populated with the
1031
* strings specified by the value of @key.
1033
* Return value: The ID of the new binding.
1036
gconf_bridge_bind_string_list_store (GConfBridge *bridge,
1038
GtkListStore *list_store)
1040
GtkTreeModel *tree_model;
1041
gboolean have_one_column, is_string_column;
1042
ListStoreBinding *binding;
1045
g_return_val_if_fail (bridge != NULL, 0);
1046
g_return_val_if_fail (key != NULL, 0);
1047
g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), 0);
1049
/* Check list store suitability */
1050
tree_model = GTK_TREE_MODEL (list_store);
1051
have_one_column = (gtk_tree_model_get_n_columns (tree_model) == 1);
1052
is_string_column = (gtk_tree_model_get_column_type
1053
(tree_model, 0) == G_TYPE_STRING);
1054
if (G_UNLIKELY (!have_one_column || !is_string_column)) {
1055
g_warning ("gconf_bridge_bind_string_list_store: Only "
1056
"GtkListStores with exactly one string column are "
1062
/* Create new binding. */
1063
binding = g_new (ListStoreBinding, 1);
1065
binding->type = BINDING_LIST_STORE;
1066
binding->id = new_id ();
1067
binding->key = g_strdup (key);
1068
binding->val_changes = NULL;
1069
binding->list_store = list_store;
1070
binding->sync_idle_id = 0;
1072
/* Watch GConf key */
1073
binding->val_notify_id =
1074
gconf_client_notify_add (bridge->client, key,
1075
list_store_binding_pref_changed,
1076
binding, NULL, NULL);
1078
/* Connect to ListStore change notifications */
1079
binding->row_inserted_id =
1080
g_signal_connect_swapped (list_store, "row-inserted",
1082
(list_store_binding_store_changed_cb),
1084
binding->row_changed_id =
1085
g_signal_connect_swapped (list_store, "row-changed",
1087
(list_store_binding_store_changed_cb),
1089
binding->row_deleted_id =
1090
g_signal_connect_swapped (list_store, "row-deleted",
1092
(list_store_binding_store_changed_cb),
1094
binding->rows_reordered_id =
1095
g_signal_connect_swapped (list_store, "rows-reordered",
1097
(list_store_binding_store_changed_cb),
1100
/* Sync object to value from GConf, if set */
1101
val = gconf_client_get (bridge->client, key, NULL);
1103
list_store_binding_sync_pref_to_store (binding, val);
1104
gconf_value_free (val);
1107
/* Handle case where watched object gets destroyed */
1108
g_object_weak_ref (G_OBJECT (list_store),
1109
list_store_binding_store_destroyed, binding);
1111
/* Insert binding */
1112
g_hash_table_insert (bridge->bindings,
1113
GUINT_TO_POINTER (binding->id), binding);
1119
/* Unbinds a list store binding */
1121
list_store_binding_unbind (ListStoreBinding *binding)
1123
/* Perform any scheduled syncs */
1124
if (binding->sync_idle_id > 0) {
1125
g_source_remove (binding->sync_idle_id);
1127
/* The store will still be around as we added a reference */
1128
list_store_binding_sync_store_to_pref (binding);
1131
g_free (binding->key);
1133
while (binding->val_changes) {
1134
gconf_value_free (binding->val_changes->data);
1136
binding->val_changes = g_slist_delete_link
1137
(binding->val_changes, binding->val_changes);
1140
/* The store might have been destroyed .. */
1141
if (binding->list_store) {
1142
g_signal_handler_disconnect (binding->list_store,
1143
binding->row_inserted_id);
1144
g_signal_handler_disconnect (binding->list_store,
1145
binding->row_changed_id);
1146
g_signal_handler_disconnect (binding->list_store,
1147
binding->row_deleted_id);
1148
g_signal_handler_disconnect (binding->list_store,
1149
binding->rows_reordered_id);
1151
g_object_weak_unref (G_OBJECT (binding->list_store),
1152
list_store_binding_store_destroyed,
1161
/* Unbinds a binding */
1163
unbind (Binding *binding)
1165
/* Call specialized unbinding function */
1166
switch (binding->type) {
1168
prop_binding_unbind ((PropBinding *) binding);
1170
case BINDING_WINDOW:
1171
window_binding_unbind ((WindowBinding *) binding);
1173
case BINDING_LIST_STORE:
1174
list_store_binding_unbind ((ListStoreBinding *) binding);
1177
g_warning ("Unknown binding type '%d'\n", binding->type);
1185
* gconf_bridge_unbind
1186
* @bridge: A #GConfBridge
1187
* @binding_id: The ID of the binding to be removed
1189
* Removes the binding with ID @binding_id.
1192
gconf_bridge_unbind (GConfBridge *bridge,
1195
g_return_if_fail (bridge != NULL);
1196
g_return_if_fail (binding_id > 0);
1198
/* This will trigger the hash tables value destruction
1199
* function, which will take care of further cleanup */
1200
g_hash_table_remove (bridge->bindings,
1201
GUINT_TO_POINTER (binding_id));
1208
/* This is the same dialog as used in eel */
1210
error_handler (GConfClient *client,
1213
static gboolean shown_dialog = FALSE;
1215
g_warning ("GConf error:\n %s", error->message);
1217
if (!shown_dialog) {
1220
dlg = gtk_message_dialog_new (NULL, 0,
1223
_("GConf error: %s"),
1226
gtk_message_dialog_format_secondary_text
1227
(GTK_MESSAGE_DIALOG (dlg),
1228
_("All further errors shown only on terminal."));
1229
gtk_window_set_title (GTK_WINDOW (dlg), "");
1231
gtk_dialog_run (GTK_DIALOG (dlg));
1233
gtk_widget_destroy (dlg);
1235
shown_dialog = TRUE;
1240
* gconf_bridge_install_default_error_handler
1242
* Sets up the default error handler. Any unhandled GConf errors will
1243
* automatically be handled by presenting the user an error dialog.
1246
gconf_bridge_install_default_error_handler (void)
1248
gconf_client_set_global_default_error_handler (error_handler);