/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Configuration component listener * * Author: * Rodrigo Moya * * Copyright 2002, Ximian, Inc. */ #include #include #include #include #include #include "e-config-listener.h" #define PARENT_TYPE GTK_TYPE_OBJECT typedef struct { EConfigListener *cl; char *key; GtkFundamentalType type; union { char *v_str; gboolean v_bool; } value; gboolean used_default; } KeyData; struct _EConfigListenerPrivate { Bonobo_ConfigDatabase db; GHashTable *keys; }; static void e_config_listener_class_init (EConfigListenerClass *klass); static void e_config_listener_init (EConfigListener *cl); static void e_config_listener_destroy (GtkObject *object); static GtkObjectClass *parent_class = NULL; static void e_config_listener_class_init (EConfigListenerClass *klass) { GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); parent_class = gtk_type_class (PARENT_TYPE); object_class->destroy = e_config_listener_destroy; } static void e_config_listener_init (EConfigListener *cl) { CORBA_Environment ev; /* allocate internal structure */ cl->priv = g_new0 (EConfigListenerPrivate, 1); cl->priv->keys = g_hash_table_new (g_str_hash, g_str_equal); /* activate the configuration database */ CORBA_exception_init (&ev); cl->priv->db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev); if (BONOBO_EX (&ev) || cl->priv->db == CORBA_OBJECT_NIL) { CORBA_exception_free (&ev); cl->priv->db = CORBA_OBJECT_NIL; } } static void free_key_hash (gpointer key, gpointer value, gpointer user_data) { KeyData *kd = (KeyData *) value; g_return_if_fail (kd != NULL); g_free (kd->key); switch (kd->type) { case GTK_TYPE_STRING : g_free (kd->value.v_str); break; default : } g_free (kd); } static void e_config_listener_destroy (GtkObject *object) { EConfigListener *cl = (EConfigListener *) object; g_return_if_fail (E_IS_CONFIG_LISTENER (cl)); if (cl->priv->db != CORBA_OBJECT_NIL) { bonobo_object_release_unref (cl->priv->db, NULL); cl->priv->db = CORBA_OBJECT_NIL; } g_hash_table_foreach (cl->priv->keys, (GHFunc) free_key_hash, NULL); g_hash_table_destroy (cl->priv->keys); cl->priv->keys = NULL; g_free (cl->priv); cl->priv = NULL; if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } GtkType e_config_listener_get_type (void) { static GtkType type = 0; if (!type) { static const GtkTypeInfo info = { "EConfigListener", sizeof (EConfigListener), sizeof (EConfigListenerClass), (GtkClassInitFunc) e_config_listener_class_init, (GtkObjectInitFunc) e_config_listener_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL }; type = gtk_type_unique (PARENT_TYPE, &info); } return type; } /** * e_config_listener_new * * Create a new configuration listener, which is an object which * allows to listen for changes in the configuration database. It keeps * an updated copy of all requested configuration entries, so that * access is much quicker and instantaneous. * * Returns: the newly created listener. */ EConfigListener * e_config_listener_new (void) { EConfigListener *cl; cl = gtk_type_new (E_CONFIG_LISTENER_TYPE); return cl; } static void property_change_cb (BonoboListener *listener, char *event_name, CORBA_any *any, CORBA_Environment *ev, gpointer user_data) { KeyData *kd = (KeyData *) user_data; g_return_if_fail (any != NULL); g_return_if_fail (kd != NULL); /* free previous value */ if (kd->type == GTK_TYPE_STRING) g_free (kd->value.v_str); /* set new value */ if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_BOOLEAN, NULL)) { kd->type = GTK_TYPE_BOOL; kd->value.v_bool = BONOBO_ARG_GET_BOOLEAN (any); } else if (bonobo_arg_type_is_equal (any->_type, BONOBO_ARG_STRING, NULL)) { kd->type = GTK_TYPE_STRING; kd->value.v_str = g_strdup (BONOBO_ARG_GET_STRING (any)); } else return; } static KeyData * add_key (EConfigListener *cl, const char *key, GtkFundamentalType type, gpointer value, gboolean used_default) { KeyData *kd; char *event_name; CORBA_Environment ev; /* add the key to our hash table */ kd = g_new0 (KeyData, 1); kd->cl = cl; kd->key = g_strdup (key); kd->type = type; switch (type) { case GTK_TYPE_BOOL : memcpy (&kd->value.v_bool, value, sizeof (gboolean)); break; case GTK_TYPE_STRING : kd->value.v_str = (char *) value; break; default : } kd->used_default = used_default; /* add the listener for changes */ event_name = g_strdup_printf ("=Bonobo/ConfigDatabase:change%s", kd->key); CORBA_exception_init (&ev); bonobo_event_source_client_add_listener ( cl->priv->db, property_change_cb, event_name, &ev, kd); if (BONOBO_EX (&ev)) { CORBA_exception_free (&ev); free_key_hash (kd->key, kd, NULL); return NULL; } g_hash_table_insert (cl->priv->keys, kd->key, kd); CORBA_exception_free (&ev); g_free (event_name); return kd; } char * e_config_listener_get_string_with_default (EConfigListener *cl, const char *key, const char *def, gboolean *used_default) { char *str; KeyData *kd; gboolean d; gpointer orig_key, orig_value; g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), NULL); g_return_val_if_fail (key != NULL, NULL); /* search for the key in our hash table */ if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) { /* not found, so retrieve it from the configuration database */ str = bonobo_config_get_string_with_default (cl->priv->db, key, (char *) def, &d); if (str) { kd = add_key (cl, key, GTK_TYPE_STRING, (gpointer) str, d); if (used_default != NULL) *used_default = d; } else return NULL; } else { kd = (KeyData *) orig_value; g_assert (kd != NULL); if (kd->type == GTK_TYPE_STRING) { str = g_strdup (kd->value.v_str); if (used_default != NULL) *used_default = kd->used_default; } else return NULL; } return str; } gboolean e_config_listener_get_boolean_with_default (EConfigListener *cl, const char *key, gboolean def, gboolean *used_default) { gboolean value; KeyData *kd; gboolean d; gpointer orig_key, orig_value; g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), FALSE); g_return_val_if_fail (key != NULL, FALSE); /* search for the key in our hash table */ if (!g_hash_table_lookup_extended (cl->priv->keys, key, &orig_key, &orig_value)) { /* not found, so retrieve it from the configuration database */ value = bonobo_config_get_boolean_with_default (cl->priv->db, key, def, &d); kd = add_key (cl, key, GTK_TYPE_BOOL, &value, d); if (used_default != NULL) *used_default = d; } else { kd = (KeyData *) orig_value; g_assert (kd != NULL); if (kd->type == GTK_TYPE_BOOL) { value = kd->value.v_bool; if (used_default != NULL) *used_default = kd->used_default; } else return FALSE; } return value; } Bonobo_ConfigDatabase e_config_listener_get_db (EConfigListener *cl) { g_return_val_if_fail (E_IS_CONFIG_LISTENER (cl), CORBA_OBJECT_NIL); return cl->priv->db; }