source: trunk/third/evolution/e-util/e-config-listener.c @ 19195

Revision 19195, 13.6 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19194, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * Configuration component listener
4 *
5 * Author:
6 *   Rodrigo Moya <rodrigo@ximian.com>
7 *
8 * Copyright 2002, Ximian, Inc.
9 */
10
11#ifdef HAVE_CONFIG_H
12#include <config.h>
13#endif
14
15#include <gtk/gtksignal.h>
16#include <gtk/gtktypeutils.h>
17#include <bonobo/bonobo-exception.h>
18#include <bonobo/bonobo-event-source.h>
19#include <bonobo/bonobo-moniker-util.h>
20#include <bonobo/bonobo-object.h>
21#include "e-config-listener.h"
22
23#define PARENT_TYPE GTK_TYPE_OBJECT
24
25typedef struct {
26        EConfigListener *cl;
27        Bonobo_EventSource_ListenerId lid;
28        char *key;
29        GtkFundamentalType type;
30        union {
31                gboolean v_bool;
32                float v_float;
33                long v_long;
34                char *v_str;
35        } value;
36        gboolean used_default;
37} KeyData;
38
39struct _EConfigListenerPrivate {
40        Bonobo_ConfigDatabase db;
41        GHashTable *keys;
42};
43
44static void e_config_listener_class_init (EConfigListenerClass *klass);
45static void e_config_listener_init       (EConfigListener *cl);
46static void e_config_listener_destroy    (GtkObject *object);
47
48static GtkObjectClass *parent_class = NULL;
49
50enum {
51        KEY_CHANGED,
52        LAST_SIGNAL
53};
54
55static guint config_listener_signals[LAST_SIGNAL];
56
57static void
58e_config_listener_class_init (EConfigListenerClass *klass)
59{
60        GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
61
62        parent_class = gtk_type_class (PARENT_TYPE);
63
64        object_class->destroy = e_config_listener_destroy;
65        klass->key_changed = NULL;
66
67        config_listener_signals[KEY_CHANGED] =
68                gtk_signal_new ("key_changed",
69                                GTK_RUN_FIRST,
70                                object_class->type,
71                                GTK_SIGNAL_OFFSET (EConfigListenerClass, key_changed),
72                                gtk_marshal_NONE__STRING,
73                                GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
74        gtk_object_class_add_signals (object_class, config_listener_signals, LAST_SIGNAL);
75}
76
77static void
78e_config_listener_init (EConfigListener *cl)
79{
80        CORBA_Environment ev;
81
82        /* allocate internal structure */
83        cl->priv = g_new0 (EConfigListenerPrivate, 1);
84
85        cl->priv->keys = g_hash_table_new (g_str_hash, g_str_equal);
86
87        /* activate the configuration database */
88        CORBA_exception_init (&ev);
89        cl->priv->db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev);
90
91        if (BONOBO_EX (&ev) || cl->priv->db == CORBA_OBJECT_NIL) {
92                CORBA_exception_free (&ev);
93                cl->priv->db = CORBA_OBJECT_NIL;
94        }
95}
96
97static void
98free_key_hash (gpointer key, gpointer value, gpointer user_data)
99{
100        KeyData *kd = (KeyData *) value;
101
102        g_return_if_fail (kd != NULL);
103
104        bonobo_event_source_client_remove_listener (kd->cl->priv->db, kd->lid, NULL);
105
106        g_free (kd->key);
107        switch (kd->type) {
108        case GTK_TYPE_STRING :
109                g_free (kd->value.v_str);
110                break;
111        default :
112                break;
113        }
114
115        g_free (kd);
116}
117
118static void
119e_config_listener_destroy (GtkObject *object)
120{
121        EConfigListener *cl = (EConfigListener *) object;
122
123        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
124
125        g_hash_table_foreach (cl->priv->keys, (GHFunc) free_key_hash, NULL);
126        g_hash_table_destroy (cl->priv->keys);
127        cl->priv->keys = NULL;
128
129        if (cl->priv->db != CORBA_OBJECT_NIL) {
130                bonobo_object_release_unref (cl->priv->db, NULL);
131                cl->priv->db = CORBA_OBJECT_NIL;
132        }
133
134        g_free (cl->priv);
135        cl->priv = NULL;
136
137        if (GTK_OBJECT_CLASS (parent_class)->destroy)
138                (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
139}
140
141GtkType
142e_config_listener_get_type (void)
143{
144        static GtkType type = 0;
145
146        if (!type) {
147                static const GtkTypeInfo info = {
148                        "EConfigListener",
149                        sizeof (EConfigListener),
150                        sizeof (EConfigListenerClass),
151                        (GtkClassInitFunc) e_config_listener_class_init,
152                        (GtkObjectInitFunc) e_config_listener_init,
153                        NULL, /* reserved_1 */
154                        NULL, /* reserved_2 */
155                        (GtkClassInitFunc) NULL
156                };
157
158                type = gtk_type_unique (PARENT_TYPE, &info);
159        }
160
161        return type;
162}
163
164/**
165 * e_config_listener_new
166 *
167 * Create a new configuration listener, which is an object which
168 * allows to listen for changes in the configuration database. It keeps
169 * an updated copy of all requested configuration entries, so that
170 * access is much quicker and instantaneous.
171 *
172 * Returns: the newly created listener.
173 */
174EConfigListener *
175e_config_listener_new (void)
176{
177        EConfigListener *cl;
178
179        cl = gtk_type_new (E_CONFIG_LISTENER_TYPE);
180        return cl;
181}
182
183static void
184property_change_cb (BonoboListener *listener,
185                    char *event_name,
186                    CORBA_any *any,
187                    CORBA_Environment *ev,
188                    gpointer user_data)
189{
190        KeyData *kd = (KeyData *) user_data;
191
192        g_return_if_fail (any != NULL);
193        g_return_if_fail (kd != NULL);
194
195        /* free previous value */
196        if (kd->type == GTK_TYPE_STRING)
197                g_free (kd->value.v_str);
198
199        /* set new value */
200        if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_BOOLEAN, NULL)) {
201                kd->type = GTK_TYPE_BOOL;
202                kd->value.v_bool = BONOBO_ARG_GET_BOOLEAN (any);
203        } else if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_FLOAT, NULL)) {
204                kd->type = GTK_TYPE_FLOAT;
205                kd->value.v_float = BONOBO_ARG_GET_FLOAT (any);
206        } else if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_LONG, NULL)) {
207                kd->type = GTK_TYPE_LONG;
208                kd->value.v_long = BONOBO_ARG_GET_LONG (any);
209        } else if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_STRING, NULL)) {
210                kd->type = GTK_TYPE_STRING;
211                kd->value.v_str = g_strdup (BONOBO_ARG_GET_STRING (any));
212        } else
213                return;
214
215        gtk_signal_emit (GTK_OBJECT (kd->cl), config_listener_signals[KEY_CHANGED], kd->key);
216}
217
218static KeyData *
219add_key (EConfigListener *cl, const char *key, GtkFundamentalType type,
220         gpointer value, gboolean used_default)
221{
222        KeyData *kd;
223        char *event_name;
224        char *ch;
225        CORBA_Environment ev;
226
227        /* add the key to our hash table */
228        kd = g_new0 (KeyData, 1);
229        kd->cl = cl;
230        kd->key = g_strdup (key);
231        kd->type = type;
232        switch (type) {
233        case GTK_TYPE_BOOL :
234                memcpy (&kd->value.v_bool, value, sizeof (gboolean));
235                break;
236        case GTK_TYPE_FLOAT :
237                memcpy (&kd->value.v_float, value, sizeof (float));
238                break;
239        case GTK_TYPE_LONG :
240                memcpy (&kd->value.v_long, value, sizeof (long));
241                break;
242        case GTK_TYPE_STRING :
243                kd->value.v_str = (char *) value;
244                break;
245        default :
246                break;
247        }
248
249        kd->used_default = used_default;
250
251        /* add the listener for changes */
252        event_name = g_strdup_printf ("=Bonobo/ConfigDatabase:change%s",
253                                      kd->key);
254        ch = strrchr (event_name, '/');
255        if (ch)
256                *ch = ':';
257
258        CORBA_exception_init (&ev);
259        kd->lid = bonobo_event_source_client_add_listener (
260                cl->priv->db,
261                property_change_cb,
262                event_name,
263                &ev, kd);
264        if (BONOBO_EX (&ev)) {
265                CORBA_exception_free (&ev);
266                g_free (event_name);
267                free_key_hash (kd->key, kd, NULL);
268                return NULL;
269        }
270
271        g_hash_table_insert (cl->priv->keys, kd->key, kd);
272
273        CORBA_exception_free (&ev);
274        g_free (event_name);
275
276        return kd;
277}
278
279gboolean
280e_config_listener_get_boolean_with_default (EConfigListener *cl,
281                                            const char *key,
282                                            gboolean def,
283                                            gboolean *used_default)
284{
285        gboolean value;
286        KeyData *kd;
287        gboolean d;
288        gpointer orig_key, orig_value;
289
290        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), FALSE);
291        g_return_val_if_fail (key != NULL, FALSE);
292
293        /* search for the key in our hash table */
294        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
295                /* not found, so retrieve it from the configuration database */
296                value = bonobo_config_get_boolean_with_default (cl->priv->db, key, def, &d);
297                kd = add_key (cl, key, GTK_TYPE_BOOL, &value, d);
298
299                if (used_default != NULL)
300                        *used_default = d;
301        } else {
302                kd = (KeyData *) orig_value;
303                g_assert (kd != NULL);
304
305                if (kd->type == GTK_TYPE_BOOL) {
306                        value = kd->value.v_bool;
307                        if (used_default != NULL)
308                                *used_default = kd->used_default;
309                } else
310                        return FALSE;
311        }
312
313        return value;
314}
315
316float
317e_config_listener_get_float_with_default (EConfigListener *cl,
318                                          const char *key,
319                                          float def,
320                                          gboolean *used_default)
321{
322        float value;
323        KeyData *kd;
324        gboolean d;
325        gpointer orig_key, orig_value;
326
327        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), -1);
328        g_return_val_if_fail (key != NULL, -1);
329
330        /* search for the key in our hash table */
331        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
332                /* not found, so retrieve it from the configuration database */
333                value = bonobo_config_get_float_with_default (cl->priv->db, key, def, &d);
334                kd = add_key (cl, key, GTK_TYPE_FLOAT, &value, d);
335
336                if (used_default != NULL)
337                        *used_default = d;
338        } else {
339                kd = (KeyData *) orig_value;
340                g_assert (kd != NULL);
341
342                if (kd->type == GTK_TYPE_FLOAT) {
343                        value = kd->value.v_float;
344                        if (used_default != NULL)
345                                *used_default = kd->used_default;
346                } else
347                        return -1;
348        }
349
350        return value;
351}
352
353long
354e_config_listener_get_long_with_default (EConfigListener *cl,
355                                         const char *key,
356                                         long def,
357                                         gboolean *used_default)
358{
359        long value;
360        KeyData *kd;
361        gboolean d;
362        gpointer orig_key, orig_value;
363
364        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), -1);
365        g_return_val_if_fail (key != NULL, -1);
366
367        /* search for the key in our hash table */
368        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
369                /* not found, so retrieve it from the configuration database */
370                value = bonobo_config_get_long_with_default (cl->priv->db, key, def, &d);
371                kd = add_key (cl, key, GTK_TYPE_LONG, &value, d);
372
373                if (used_default != NULL)
374                        *used_default = d;
375        } else {
376                kd = (KeyData *) orig_value;
377                g_assert (kd != NULL);
378
379                if (kd->type == GTK_TYPE_LONG) {
380                        value = kd->value.v_long;
381                        if (used_default != NULL)
382                                *used_default = kd->used_default;
383                } else
384                        return -1;
385        }
386
387        return value;
388}
389
390char *
391e_config_listener_get_string_with_default (EConfigListener *cl,
392                                           const char *key,
393                                           const char *def,
394                                           gboolean *used_default)
395{
396        char *str;
397        KeyData *kd;
398        gboolean d;
399        gpointer orig_key, orig_value;
400
401        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), NULL);
402        g_return_val_if_fail (key != NULL, NULL);
403
404        /* search for the key in our hash table */
405        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
406                /* not found, so retrieve it from the configuration database */
407                str = bonobo_config_get_string_with_default (cl->priv->db, key, (char *) def, &d);
408                if (str) {
409                        kd = add_key (cl, key, GTK_TYPE_STRING, (gpointer) str, d);
410
411                        if (used_default != NULL)
412                                *used_default = d;
413                } else
414                        return NULL;
415        } else {
416                kd = (KeyData *) orig_value;
417                g_assert (kd != NULL);
418
419                if (kd->type == GTK_TYPE_STRING) {
420                        str = kd->value.v_str;
421                        if (used_default != NULL)
422                                *used_default = kd->used_default;
423                } else
424                        return NULL;
425        }
426
427        return g_strdup (str);
428}
429
430void
431e_config_listener_set_boolean (EConfigListener *cl, const char *key, gboolean value)
432{
433        CORBA_Environment ev;
434        KeyData *kd;
435
436        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
437        g_return_if_fail (key != NULL);
438
439        /* check that the value is not the same */
440        if (value == e_config_listener_get_boolean_with_default (cl, key, 0, NULL))
441                return;
442
443        CORBA_exception_init (&ev);
444
445        bonobo_config_set_boolean (cl->priv->db, key, value, &ev);
446        if (BONOBO_EX (&ev))
447                g_warning ("Cannot save config key %s -- %s", key, BONOBO_EX_ID (&ev));
448        else {
449                /* update the internal copy */
450                kd = g_hash_table_lookup (cl->priv->keys, key);
451                if (kd)
452                        kd->value.v_bool = value;
453        }
454
455        CORBA_exception_free (&ev);
456}
457
458void
459e_config_listener_set_float (EConfigListener *cl, const char *key, float value)
460{
461        CORBA_Environment ev;
462        KeyData *kd;
463
464        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
465        g_return_if_fail (key != NULL);
466
467        /* check that the value is not the same */
468        if (value == e_config_listener_get_float_with_default (cl, key, 0, NULL))
469                return;
470
471        CORBA_exception_init (&ev);
472
473        bonobo_config_set_float (cl->priv->db, key, value, &ev);
474        if (BONOBO_EX (&ev))
475                g_warning ("Cannot save config key %s -- %s", key, BONOBO_EX_ID (&ev));
476        else {
477                /* update the internal copy */
478                kd = g_hash_table_lookup (cl->priv->keys, key);
479                if (kd)
480                        kd->value.v_float = value;
481        }
482
483        CORBA_exception_free (&ev);
484}
485
486void
487e_config_listener_set_long (EConfigListener *cl, const char *key, long value)
488{
489        CORBA_Environment ev;
490        KeyData *kd;
491
492        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
493        g_return_if_fail (key != NULL);
494
495        /* check that the value is not the same */
496        if (value == e_config_listener_get_long_with_default (cl, key, 0, NULL))
497                return;
498
499        CORBA_exception_init (&ev);
500
501        bonobo_config_set_long (cl->priv->db, key, value, &ev);
502        if (BONOBO_EX (&ev))
503                g_warning ("Cannot save config key %s -- %s", key, BONOBO_EX_ID (&ev));
504        else {
505                /* update the internal copy */
506                kd = g_hash_table_lookup (cl->priv->keys, key);
507                if (kd)
508                        kd->value.v_long = value;
509        }
510
511        CORBA_exception_free (&ev);
512}
513
514void
515e_config_listener_set_string (EConfigListener *cl, const char *key, const char *value)
516{
517        CORBA_Environment ev;
518        char *s1, *s2;
519        KeyData *kd;
520
521        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
522        g_return_if_fail (key != NULL);
523
524        /* check that the value is not the same */
525        s1 = (char *) value;
526        s2 = e_config_listener_get_string_with_default (cl, key, NULL, NULL);
527        if (!strcmp (s1 ? s1 : "", s2 ? s2 : "")) {
528                g_free (s2);
529                return;
530        }
531
532        g_free (s2);
533
534        CORBA_exception_init (&ev);
535
536        bonobo_config_set_string (cl->priv->db, key, value, &ev);
537        if (BONOBO_EX (&ev))
538                g_warning ("Cannot save config key %s -- %s", key, BONOBO_EX_ID (&ev));
539        else {
540                /* update the internal copy */
541                kd = g_hash_table_lookup (cl->priv->keys, key);
542                if (kd) {
543                        g_free (kd->value.v_str);
544                        kd->value.v_str = g_strdup (value);
545                }
546        }
547
548        CORBA_exception_free (&ev);
549}
550
551void
552e_config_listener_remove_dir (EConfigListener *cl, const char *dir)
553{
554        CORBA_Environment ev;
555
556        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
557        g_return_if_fail (dir != NULL);
558
559        CORBA_exception_init (&ev);
560        Bonobo_ConfigDatabase_removeDir (cl->priv->db, dir, &ev);
561        if (BONOBO_EX (&ev)) {
562                g_warning ("Cannot remove config dir %s -- %s", dir, BONOBO_EX_ID (&ev));
563        }
564
565        CORBA_exception_free (&ev);
566}
567
568Bonobo_ConfigDatabase
569e_config_listener_get_db (EConfigListener *cl)
570{
571        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), CORBA_OBJECT_NIL);
572        return cl->priv->db;
573}
Note: See TracBrowser for help on using the repository browser.