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

Revision 19541, 15.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19540, 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#include <string.h>
12#include <gconf/gconf-client.h>
13#include "e-config-listener.h"
14
15#define PARENT_TYPE G_TYPE_OBJECT
16
17typedef struct {
18        EConfigListener *cl;
19        guint lid;
20        char *key;
21        GConfValueType type;
22        union {
23                gboolean v_bool;
24                float v_float;
25                long v_long;
26                char *v_str;
27        } value;
28        gboolean used_default;
29} KeyData;
30
31struct _EConfigListenerPrivate {
32        GConfClient *db;
33        GHashTable *keys;
34};
35
36static void e_config_listener_class_init (EConfigListenerClass *klass);
37static void e_config_listener_init       (EConfigListener *cl, EConfigListenerClass *klass);
38static void e_config_listener_finalize   (GObject *object);
39
40static GObjectClass *parent_class = NULL;
41
42enum {
43        KEY_CHANGED,
44        LAST_SIGNAL
45};
46
47static guint config_listener_signals[LAST_SIGNAL];
48
49static void
50e_config_listener_class_init (EConfigListenerClass *klass)
51{
52        GObjectClass *object_class = G_OBJECT_CLASS (klass);
53
54        parent_class = g_type_class_peek_parent (klass);
55
56        object_class->finalize = e_config_listener_finalize;
57        klass->key_changed = NULL;
58
59        config_listener_signals[KEY_CHANGED] =
60                g_signal_new ("key_changed",
61                              G_TYPE_FROM_CLASS (klass),
62                              G_SIGNAL_RUN_FIRST,
63                              G_STRUCT_OFFSET (EConfigListenerClass, key_changed),
64                              NULL, NULL,
65                              g_cclosure_marshal_VOID__STRING,
66                              G_TYPE_NONE, 1, G_TYPE_STRING);
67
68        /* make sure GConf is initialized */
69        if (!gconf_is_initialized ())
70                gconf_init (0, NULL, NULL);
71}
72
73static void
74e_config_listener_init (EConfigListener *cl, EConfigListenerClass *klass)
75{
76        /* allocate internal structure */
77        cl->priv = g_new0 (EConfigListenerPrivate, 1);
78
79        cl->priv->keys = g_hash_table_new (g_str_hash, g_str_equal);
80        cl->priv->db = gconf_client_get_default ();
81}
82
83static void
84free_key_hash (gpointer key, gpointer value, gpointer user_data)
85{
86        KeyData *kd = (KeyData *) value;
87
88        g_return_if_fail (kd != NULL);
89
90        gconf_client_notify_remove (kd->cl->priv->db, kd->lid);
91
92        g_free (kd->key);
93        switch (kd->type) {
94        case GCONF_VALUE_STRING :
95                g_free (kd->value.v_str);
96                break;
97        default :
98                break;
99        }
100
101        g_free (kd);
102}
103
104static void
105e_config_listener_finalize (GObject *object)
106{
107        EConfigListener *cl = (EConfigListener *) object;
108
109        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
110
111        g_hash_table_foreach (cl->priv->keys, (GHFunc) free_key_hash, NULL);
112        g_hash_table_destroy (cl->priv->keys);
113        cl->priv->keys = NULL;
114
115        if (cl->priv->db != NULL) {
116                g_object_unref (G_OBJECT (cl->priv->db));
117                cl->priv->db = NULL;
118        }
119
120        g_free (cl->priv);
121        cl->priv = NULL;
122
123        if (G_OBJECT_CLASS (parent_class)->finalize)
124                (* G_OBJECT_CLASS (parent_class)->finalize) (object);
125}
126
127GType
128e_config_listener_get_type (void)
129{
130        static GType type = 0;
131
132        if (!type) {
133                static const GTypeInfo info = {
134                        sizeof (EConfigListenerClass),
135                        (GBaseInitFunc) NULL,
136                        (GBaseFinalizeFunc) NULL,
137                        (GClassInitFunc) e_config_listener_class_init,
138                        NULL,
139                        NULL,
140                        sizeof (EConfigListener),
141                        0,
142                        (GInstanceInitFunc) e_config_listener_init
143                };
144                type = g_type_register_static (PARENT_TYPE, "EConfigListener", &info, 0);
145        }
146
147        return type;
148}
149
150/**
151 * e_config_listener_new
152 *
153 * Create a new configuration listener, which is an object which
154 * allows to listen for changes in the configuration database. It keeps
155 * an updated copy of all requested configuration entries, so that
156 * access is much quicker and instantaneous.
157 *
158 * Returns: the newly created listener.
159 */
160EConfigListener *
161e_config_listener_new (void)
162{
163        EConfigListener *cl;
164
165        cl = g_object_new (E_CONFIG_LISTENER_TYPE, NULL);
166        return cl;
167}
168
169static void
170property_change_cb (GConfEngine *engine,
171                    guint cnxn_id,
172                    GConfEntry *entry,
173                    gpointer user_data)
174{
175        KeyData *kd = (KeyData *) user_data;
176
177        g_return_if_fail (entry != NULL);
178        g_return_if_fail (kd != NULL);
179
180        /* free previous value */
181        if (kd->type == GCONF_VALUE_STRING)
182                g_free (kd->value.v_str);
183
184        /* set new value */
185        if (entry->value->type == GCONF_VALUE_BOOL) {
186                kd->type = GCONF_VALUE_BOOL;
187                kd->value.v_bool = gconf_value_get_bool (entry->value);
188        } else if (entry->value->type == GCONF_VALUE_FLOAT) {
189                kd->type = GCONF_VALUE_FLOAT;
190                kd->value.v_float = gconf_value_get_float (entry->value);
191        } else if (entry->value->type == GCONF_VALUE_INT) {
192                kd->type = GCONF_VALUE_INT;
193                kd->value.v_long = gconf_value_get_int (entry->value);
194        } else if (entry->value->type == GCONF_VALUE_STRING) {
195                kd->type = GCONF_VALUE_STRING;
196                kd->value.v_str = g_strdup (gconf_value_get_string (entry->value));
197        } else
198                return;
199
200        g_signal_emit (G_OBJECT (kd->cl), config_listener_signals[KEY_CHANGED], 0, kd->key);
201}
202
203static KeyData *
204add_key (EConfigListener *cl, const char *key, GConfValueType type,
205         gpointer value, gboolean used_default)
206{
207        KeyData *kd;
208
209        /* add the key to our hash table */
210        kd = g_new0 (KeyData, 1);
211        kd->cl = cl;
212        kd->key = g_strdup (key);
213        kd->type = type;
214        switch (type) {
215        case GCONF_VALUE_BOOL :
216                memcpy (&kd->value.v_bool, value, sizeof (gboolean));
217                break;
218        case GCONF_VALUE_FLOAT :
219                memcpy (&kd->value.v_float, value, sizeof (float));
220                break;
221        case GCONF_VALUE_INT :
222                memcpy (&kd->value.v_long, value, sizeof (long));
223                break;
224        case GCONF_VALUE_STRING :
225                kd->value.v_str = g_strdup ((const char *) value);
226                break;
227        default :
228                break;
229        }
230
231        kd->used_default = used_default;
232
233        /* add the listener for changes */
234        gconf_client_add_dir (cl->priv->db, key, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
235        kd->lid = gconf_client_notify_add (cl->priv->db, key,
236                                           (GConfClientNotifyFunc) property_change_cb,
237                                           kd, NULL, NULL);
238
239        g_hash_table_insert (cl->priv->keys, kd->key, kd);
240
241        return kd;
242}
243
244gboolean
245e_config_listener_get_boolean (EConfigListener *cl, const char *key)
246{
247        return e_config_listener_get_boolean_with_default (cl, key, FALSE, NULL);
248}
249
250gboolean
251e_config_listener_get_boolean_with_default (EConfigListener *cl,
252                                            const char *key,
253                                            gboolean def,
254                                            gboolean *used_default)
255{
256        GConfValue *conf_value;
257        gboolean value;
258        KeyData *kd;
259        gpointer orig_key, orig_value;
260
261        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), FALSE);
262        g_return_val_if_fail (key != NULL, FALSE);
263
264        /* search for the key in our hash table */
265        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
266                /* not found, so retrieve it from the configuration database */
267                conf_value = gconf_client_get (cl->priv->db, key, NULL);
268                if (conf_value) {
269                        value = gconf_value_get_bool (conf_value);
270                        kd = add_key (cl, key, GCONF_VALUE_BOOL, &value, FALSE);
271                        gconf_value_free (conf_value);
272
273                        if (used_default != NULL)
274                                *used_default = FALSE;
275                } else {
276                        value = def;
277                        kd = add_key (cl, key, GCONF_VALUE_BOOL, &def, TRUE);
278
279                        if (used_default != NULL)
280                                *used_default = TRUE;
281                }
282        } else {
283                kd = (KeyData *) orig_value;
284                g_assert (kd != NULL);
285
286                if (kd->type == GCONF_VALUE_BOOL) {
287                        value = kd->value.v_bool;
288                        if (used_default != NULL)
289                                *used_default = kd->used_default;
290                } else
291                        return FALSE;
292        }
293
294        return value;
295}
296
297float
298e_config_listener_get_float (EConfigListener *cl, const char *key)
299{
300        return e_config_listener_get_float_with_default (cl, key, 0.0, NULL);
301}
302
303float
304e_config_listener_get_float_with_default (EConfigListener *cl,
305                                          const char *key,
306                                          float def,
307                                          gboolean *used_default)
308{
309        GConfValue *conf_value;
310        float value;
311        KeyData *kd;
312        gpointer orig_key, orig_value;
313
314        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), -1);
315        g_return_val_if_fail (key != NULL, -1);
316
317        /* search for the key in our hash table */
318        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
319                /* not found, so retrieve it from the configuration database */
320                conf_value = gconf_client_get (cl->priv->db, key, NULL);
321                if (conf_value) {
322                        value = gconf_value_get_float (conf_value);
323                        kd = add_key (cl, key, GCONF_VALUE_FLOAT, &value, FALSE);
324                        gconf_value_free (conf_value);
325
326                        if (used_default != NULL)
327                                *used_default = FALSE;
328                } else {
329                        value = def;
330                        kd = add_key (cl, key, GCONF_VALUE_FLOAT, &def, TRUE);
331
332                        if (used_default != NULL)
333                                *used_default = TRUE;
334                }
335        } else {
336                kd = (KeyData *) orig_value;
337                g_assert (kd != NULL);
338
339                if (kd->type == GCONF_VALUE_FLOAT) {
340                        value = kd->value.v_float;
341                        if (used_default != NULL)
342                                *used_default = kd->used_default;
343                } else
344                        return -1;
345        }
346
347        return value;
348}
349
350long
351e_config_listener_get_long (EConfigListener *cl, const char *key)
352{
353        return e_config_listener_get_long_with_default (cl, key, 0, NULL);
354}
355
356long
357e_config_listener_get_long_with_default (EConfigListener *cl,
358                                         const char *key,
359                                         long def,
360                                         gboolean *used_default)
361{
362        GConfValue *conf_value;
363        long value;
364        KeyData *kd;
365        gpointer orig_key, orig_value;
366
367        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), -1);
368        g_return_val_if_fail (key != NULL, -1);
369
370        /* search for the key in our hash table */
371        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
372                /* not found, so retrieve it from the configuration database */
373                conf_value = gconf_client_get (cl->priv->db, key, NULL);
374                if (conf_value) {
375                        value = gconf_value_get_int (conf_value);
376                        kd = add_key (cl, key, GCONF_VALUE_INT, &value, FALSE);
377                        gconf_value_free (conf_value);
378
379                        if (used_default != NULL)
380                                *used_default = FALSE;
381                } else {
382                        value = def;
383                        kd = add_key (cl, key, GCONF_VALUE_INT, &def, TRUE);
384
385                        if (used_default != NULL)
386                                *used_default = TRUE;
387                }
388        } else {
389                kd = (KeyData *) orig_value;
390                g_assert (kd != NULL);
391
392                if (kd->type == GCONF_VALUE_INT) {
393                        value = kd->value.v_long;
394                        if (used_default != NULL)
395                                *used_default = kd->used_default;
396                } else
397                        return -1;
398        }
399
400        return value;
401}
402
403char *
404e_config_listener_get_string (EConfigListener *cl, const char *key)
405{
406        return e_config_listener_get_string_with_default (cl, key, NULL, NULL);
407}
408
409char *
410e_config_listener_get_string_with_default (EConfigListener *cl,
411                                           const char *key,
412                                           const char *def,
413                                           gboolean *used_default)
414{
415        GConfValue *conf_value;
416        char *str;
417        KeyData *kd;
418        gpointer orig_key, orig_value;
419
420        g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), NULL);
421        g_return_val_if_fail (key != NULL, NULL);
422
423        /* search for the key in our hash table */
424        if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
425                /* not found, so retrieve it from the configuration database */
426                conf_value = gconf_client_get (cl->priv->db, key, NULL);
427                if (conf_value) {
428                        str = g_strdup (gconf_value_get_string (conf_value));
429                        kd = add_key (cl, key, GCONF_VALUE_STRING, (gpointer) str, FALSE);
430                        gconf_value_free (conf_value);
431
432                        if (used_default != NULL)
433                                *used_default = FALSE;
434                } else {
435                        str = g_strdup (def);
436                        kd = add_key (cl, key, GCONF_VALUE_STRING, (gpointer) str, TRUE);
437
438                        if (used_default != NULL)
439                                *used_default = TRUE;
440                }
441        } else {
442                kd = (KeyData *) orig_value;
443                g_assert (kd != NULL);
444
445                if (kd->type == GCONF_VALUE_STRING) {
446                        str = g_strdup (kd->value.v_str);
447                        if (used_default != NULL)
448                                *used_default = kd->used_default;
449                } else
450                        return NULL;
451        }
452
453        return str;
454}
455
456void
457e_config_listener_set_boolean (EConfigListener *cl, const char *key, gboolean value)
458{
459        KeyData *kd;
460        GError *err = NULL;
461
462        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
463        g_return_if_fail (key != NULL);
464
465        /* check that the value is not the same */
466        if (value == e_config_listener_get_boolean_with_default (cl, key, 0, NULL))
467                return;
468
469        gconf_client_set_bool (cl->priv->db, key, value, &err);
470        if (err) {
471                g_warning ("e_config_listener_set_bool: %s", err->message);
472                g_error_free (err);
473        } else {
474                /* update the internal copy */
475                kd = g_hash_table_lookup (cl->priv->keys, key);
476                if (kd)
477                        kd->value.v_bool = value;
478        }
479}
480
481void
482e_config_listener_set_float (EConfigListener *cl, const char *key, float value)
483{
484        KeyData *kd;
485        GError *err = NULL;
486
487        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
488        g_return_if_fail (key != NULL);
489
490        /* check that the value is not the same */
491        if (value == e_config_listener_get_float_with_default (cl, key, 0, NULL))
492                return;
493
494        gconf_client_set_float (cl->priv->db, key, value, &err);
495        if (err) {
496                g_warning ("e_config_listener_set_float: %s", err->message);
497                g_error_free (err);
498        } else {
499                /* update the internal copy */
500                kd = g_hash_table_lookup (cl->priv->keys, key);
501                if (kd)
502                        kd->value.v_float = value;
503        }
504}
505
506void
507e_config_listener_set_long (EConfigListener *cl, const char *key, long value)
508{
509        KeyData *kd;
510        GError *err = NULL;
511
512        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
513        g_return_if_fail (key != NULL);
514
515        /* check that the value is not the same */
516        if (value == e_config_listener_get_long_with_default (cl, key, 0, NULL))
517                return;
518
519        gconf_client_set_int (cl->priv->db, key, value, &err);
520        if (err) {
521                g_warning ("e_config_listener_set_long: %s", err->message);
522                g_error_free (err);
523        } else {
524                /* update the internal copy */
525                kd = g_hash_table_lookup (cl->priv->keys, key);
526                if (kd)
527                        kd->value.v_long = value;
528        }
529}
530
531void
532e_config_listener_set_string (EConfigListener *cl, const char *key, const char *value)
533{
534        char *s1, *s2;
535        KeyData *kd;
536        GError *err = NULL;
537
538        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
539        g_return_if_fail (key != NULL);
540
541        /* check that the value is not the same */
542        s1 = (char *) value;
543        s2 = e_config_listener_get_string_with_default (cl, key, NULL, NULL);
544        if (!strcmp (s1 ? s1 : "", s2 ? s2 : "")) {
545                g_free (s2);
546                return;
547        }
548
549        g_free (s2);
550
551        gconf_client_set_string (cl->priv->db, key, value, &err);
552        if (err) {
553                g_warning ("e_config_listener_set_bool: %s", err->message);
554                g_error_free (err);
555        } else {
556                /* update the internal copy */
557                kd = g_hash_table_lookup (cl->priv->keys, key);
558                if (kd) {
559                        g_free (kd->value.v_str);
560                        kd->value.v_str = g_strdup (value);
561                }
562        }
563}
564
565void
566e_config_listener_remove_value (EConfigListener *cl, const char *key)
567{
568        gpointer orig_key, orig_value;
569
570        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
571        g_return_if_fail (key != NULL);
572
573        if (g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) {
574                KeyData *kd = orig_value;
575
576                g_hash_table_remove (cl->priv->keys, key);
577                g_free (kd->key);
578                if (kd->type == GCONF_VALUE_STRING)
579                        g_free (kd->value.v_str);
580                gconf_client_notify_remove (cl->priv->db, kd->lid);
581
582                g_free (kd);
583        }
584
585        gconf_client_unset (cl->priv->db, key, NULL);
586}
587
588void
589e_config_listener_remove_dir (EConfigListener *cl, const char *dir)
590{
591        GSList *slist, *iter;
592        const gchar *key;
593
594        g_return_if_fail (E_IS_CONFIG_LISTENER (cl));
595        g_return_if_fail (dir != NULL);
596
597        slist = gconf_client_all_entries (cl->priv->db, dir, NULL);
598        for (iter = slist; iter != NULL; iter = iter->next) {
599                GConfEntry *entry = iter->data;
600                                                                                               
601                key = gconf_entry_get_key (entry);
602                gconf_client_unset (cl->priv->db, key, NULL);
603                gconf_entry_free (entry);
604        }
605
606        g_slist_free (slist);
607}
Note: See TracBrowser for help on using the repository browser.