64f1c47db402e1434646fc16a83d8323eb66f377
[platform/upstream/ibus.git] / gconf / config.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3
4 #include <string.h>
5 #include <ibus.h>
6 #include "config.h"
7
8 #define GCONF_PREFIX "/desktop/ibus"
9
10 struct _IBusConfigGConf {
11     IBusConfigService parent;
12     GConfClient *client;
13 };
14
15 struct _IBusConfigGConfClass {
16     IBusConfigServiceClass parent;
17
18 };
19
20 /* functions prototype */
21 static void         ibus_config_gconf_class_init    (IBusConfigGConfClass   *class);
22 static void         ibus_config_gconf_init          (IBusConfigGConf        *config);
23 static void         ibus_config_gconf_destroy       (IBusConfigGConf        *config);
24 static gboolean     ibus_config_gconf_set_value     (IBusConfigService      *config,
25                                                      const gchar            *section,
26                                                      const gchar            *name,
27                                                      GVariant               *value,
28                                                      GError                **error);
29 static GVariant    *ibus_config_gconf_get_value     (IBusConfigService      *config,
30                                                      const gchar            *section,
31                                                      const gchar            *name,
32                                                      GError                **error);
33 static GVariant    *ibus_config_gconf_get_values    (IBusConfigService      *config,
34                                                      const gchar            *section,
35                                                      GError                **error);
36 static gboolean     ibus_config_gconf_unset_value   (IBusConfigService      *config,
37                                                      const gchar            *section,
38                                                      const gchar            *name,
39                                                      GError                **error);
40 static GConfValue   *_to_gconf_value                (GVariant               *value);
41 static GVariant     *_from_gconf_value              (const GConfValue       *gvalue);
42
43 G_DEFINE_TYPE (IBusConfigGConf, ibus_config_gconf, IBUS_TYPE_CONFIG_SERVICE)
44
45 static void
46 ibus_config_gconf_class_init (IBusConfigGConfClass *class)
47 {
48     GObjectClass *object_class = G_OBJECT_CLASS (class);
49
50     IBUS_OBJECT_CLASS (object_class)->destroy = (IBusObjectDestroyFunc) ibus_config_gconf_destroy;
51     IBUS_CONFIG_SERVICE_CLASS (object_class)->set_value   = ibus_config_gconf_set_value;
52     IBUS_CONFIG_SERVICE_CLASS (object_class)->get_value   = ibus_config_gconf_get_value;
53     IBUS_CONFIG_SERVICE_CLASS (object_class)->get_values  = ibus_config_gconf_get_values;
54     IBUS_CONFIG_SERVICE_CLASS (object_class)->unset_value = ibus_config_gconf_unset_value;
55 }
56
57 static void
58 _value_changed_cb (GConfClient     *client,
59                    const gchar     *key,
60                    GConfValue      *value,
61                    IBusConfigGConf *config)
62 {
63     gchar *p, *section, *name;
64
65     g_return_if_fail (key != NULL);
66
67     p = g_strdup (key);
68     section = p + sizeof (GCONF_PREFIX);
69     name = rindex (p, '/') + 1;
70     *(name - 1) = '\0';
71     
72     GVariant *variant;
73     if (value) {
74         variant = _from_gconf_value (value);
75     }
76     else {
77         /* Use a empty typle for a unset value */
78         variant = g_variant_new_tuple (NULL, 0);
79     }
80     g_return_if_fail (variant != NULL);
81     ibus_config_service_value_changed ((IBusConfigService *) config,
82                                        section,
83                                        name,
84                                        variant);
85     g_variant_unref (variant);
86     g_free (p);
87 }
88
89 static void
90 ibus_config_gconf_init (IBusConfigGConf *config)
91 {
92     config->client = gconf_client_get_default ();
93     gconf_client_add_dir (config->client,
94                           GCONF_PREFIX,
95                           GCONF_CLIENT_PRELOAD_RECURSIVE,
96                           NULL);
97     g_signal_connect (config->client, "value-changed", G_CALLBACK (_value_changed_cb), config);
98 }
99
100 static void
101 ibus_config_gconf_destroy (IBusConfigGConf *config)
102 {
103     if (config->client) {
104         g_signal_handlers_disconnect_by_func (config->client, G_CALLBACK (_value_changed_cb), config);
105         g_object_unref (config->client);
106         config->client = NULL;
107     }
108
109     IBUS_OBJECT_CLASS (ibus_config_gconf_parent_class)->destroy ((IBusObject *)config);
110 }
111
112 static GConfValue *
113 _to_gconf_value (GVariant *value)
114 {
115     GConfValue *gv = NULL;
116
117     switch (g_variant_classify (value)) {
118     case G_VARIANT_CLASS_STRING:
119         {
120             gv = gconf_value_new (GCONF_VALUE_STRING);
121             gconf_value_set_string (gv, g_variant_get_string (value, NULL));
122         }
123         break;
124     case G_VARIANT_CLASS_INT32:
125         {
126             gv = gconf_value_new (GCONF_VALUE_INT);
127             gconf_value_set_int (gv, g_variant_get_int32 (value));
128         }
129         break;
130     case G_VARIANT_CLASS_BOOLEAN:
131         {
132             gv = gconf_value_new (GCONF_VALUE_BOOL);
133             gconf_value_set_bool (gv, g_variant_get_boolean (value));
134         }
135         break;
136     case G_VARIANT_CLASS_DOUBLE:
137         {
138             gv = gconf_value_new (GCONF_VALUE_FLOAT);
139             gconf_value_set_float (gv, g_variant_get_double (value));
140         }
141         break;
142     case G_VARIANT_CLASS_ARRAY:
143         {
144             const GVariantType *element_type = g_variant_type_element (g_variant_get_type (value));
145
146             GConfValueType type = GCONF_VALUE_INVALID;
147             if (g_variant_type_equal (element_type, G_VARIANT_TYPE_STRING))
148                 type = GCONF_VALUE_STRING;
149             else if (g_variant_type_equal (element_type, G_VARIANT_TYPE_INT32))
150                 type = GCONF_VALUE_INT;
151             else if (g_variant_type_equal (element_type, G_VARIANT_TYPE_BOOLEAN))
152                 type = GCONF_VALUE_BOOL;
153             else if (g_variant_type_equal (element_type, G_VARIANT_TYPE_DOUBLE))
154                 type = GCONF_VALUE_FLOAT;
155             else
156                 g_return_val_if_reached (NULL);
157
158             gv = gconf_value_new (GCONF_VALUE_LIST);
159             gconf_value_set_list_type (gv, type);
160
161             GSList *elements = NULL;
162             GVariantIter iter;
163             GVariant *child;
164             g_variant_iter_init (&iter, value);
165             while ((child = g_variant_iter_next_value (&iter)) != NULL) {
166                 elements = g_slist_append (elements, _to_gconf_value (child));
167                 g_variant_unref (child);
168             }
169             gconf_value_set_list_nocopy (gv, elements);
170         }
171         break;
172     default:
173         g_return_val_if_reached (NULL);
174     }
175
176     return gv;
177 }
178
179 static GVariant *
180 _from_gconf_value (const GConfValue *gv)
181 {
182     g_assert (gv != NULL);
183
184     switch (gv->type) {
185     case GCONF_VALUE_STRING:
186         return g_variant_new_string (gconf_value_get_string (gv));
187     case GCONF_VALUE_INT:
188         return g_variant_new_int32 (gconf_value_get_int (gv));
189     case GCONF_VALUE_FLOAT:
190         return g_variant_new_double (gconf_value_get_float (gv));
191     case GCONF_VALUE_BOOL:
192         return g_variant_new_boolean (gconf_value_get_bool (gv));
193     case GCONF_VALUE_LIST:
194         {
195             GVariantBuilder builder;
196             switch (gconf_value_get_list_type (gv)) {
197             case GCONF_VALUE_STRING:
198                 g_variant_builder_init (&builder, G_VARIANT_TYPE("as")); break;
199             case GCONF_VALUE_INT:
200                 g_variant_builder_init (&builder, G_VARIANT_TYPE("ai")); break;
201             case GCONF_VALUE_FLOAT:
202                 g_variant_builder_init (&builder, G_VARIANT_TYPE("ad")); break;
203             case GCONF_VALUE_BOOL:
204                 g_variant_builder_init (&builder, G_VARIANT_TYPE("ab")); break;
205                 break;
206             default:
207                 g_assert_not_reached ();
208             }
209
210             GSList *list = gconf_value_get_list (gv);
211             GSList *p = list;
212             while (p != NULL) {
213                 switch (gconf_value_get_list_type (gv)) {
214                 case GCONF_VALUE_STRING:
215                     g_variant_builder_add (&builder, "s", gconf_value_get_string ((GConfValue *)p->data));
216                     break;
217                 case GCONF_VALUE_INT:
218                     g_variant_builder_add (&builder, "i", gconf_value_get_int ((GConfValue *)p->data));
219                     break;
220                 case GCONF_VALUE_FLOAT:
221                     g_variant_builder_add (&builder, "d", gconf_value_get_float ((GConfValue *)p->data));
222                     break;
223                 case GCONF_VALUE_BOOL:
224                     g_variant_builder_add (&builder, "b", gconf_value_get_bool ((GConfValue *)p->data));
225                     break;
226                 default:
227                     g_assert_not_reached ();
228                 }
229                 p = p->next;
230             }
231             return g_variant_builder_end (&builder);
232         }
233     default:
234         g_assert_not_reached ();
235     }
236 }
237
238
239 static gboolean
240 ibus_config_gconf_set_value (IBusConfigService      *config,
241                              const gchar            *section,
242                              const gchar            *name,
243                              GVariant               *value,
244                              GError                **error)
245 {
246     gchar *key;
247     GConfValue *gv;
248
249     gv = _to_gconf_value (value);
250     if (gv == NULL) {
251         gchar *str = g_variant_print (value, TRUE);
252         *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
253                         "Can not set config value [%s:%s] to %s.",
254                         section, name, str);
255         g_free (str);
256         return FALSE;
257     }
258     key = g_strdup_printf (GCONF_PREFIX"/%s/%s", section, name);
259     gconf_client_set (((IBusConfigGConf *)config)->client, key, gv, error);
260
261     g_free (key);
262     gconf_value_free (gv);
263
264     if (*error != NULL) {
265         return FALSE;
266     }
267     return TRUE;
268 }
269
270 static GVariant *
271 ibus_config_gconf_get_value (IBusConfigService      *config,
272                              const gchar            *section,
273                              const gchar            *name,
274                              GError                **error)
275 {
276     gchar *key = g_strdup_printf (GCONF_PREFIX"/%s/%s", section, name);
277
278     GConfValue *gv = gconf_client_get (((IBusConfigGConf *) config)->client, key, NULL);
279
280     g_free (key);
281
282     if (gv == NULL) {
283         *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
284                         "Config value [%s:%s] does not exist.", section, name);
285         return NULL;
286     }
287
288     GVariant *variant = _from_gconf_value (gv);
289     gconf_value_free (gv);
290
291     return variant;
292 }
293
294 static GVariant *
295 ibus_config_gconf_get_values (IBusConfigService      *config,
296                               const gchar            *section,
297                               GError                **error)
298 {
299     gchar *dir = g_strdup_printf (GCONF_PREFIX"/%s", section);
300     gint len = strlen(dir) + 1;
301     GSList *entries = gconf_client_all_entries (((IBusConfigGConf *) config)->client, dir, NULL);
302     g_free (dir);
303
304     GSList *p;
305     GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
306     for (p = entries; p != NULL; p = p->next) {
307         GConfEntry *entry = (GConfEntry *)p->data;
308         if (entry->key != NULL && entry->value != NULL) {
309             const gchar *name = entry->key + len;
310             GVariant *value = _from_gconf_value (entry->value);
311             g_variant_builder_add (builder, "{sv}", name, value);
312         }
313         gconf_entry_free (entry);
314     }
315     g_slist_free (entries);
316
317     return g_variant_builder_end (builder);
318 }
319
320 static gboolean
321 ibus_config_gconf_unset_value (IBusConfigService      *config,
322                                const gchar            *section,
323                                const gchar            *name,
324                                GError                **error)
325 {
326     gchar *key = g_strdup_printf (GCONF_PREFIX"/%s/%s", section, name);
327
328     gconf_client_unset (((IBusConfigGConf *)config)->client, key, error);
329     g_free (key);
330
331     if (*error != NULL) {
332         return FALSE;
333     }
334     return TRUE;
335 }
336
337 IBusConfigGConf *
338 ibus_config_gconf_new (GDBusConnection *connection)
339 {
340     IBusConfigGConf *config;
341     config = (IBusConfigGConf *) g_object_new (IBUS_TYPE_CONFIG_GCONF,
342                                                "object-path", IBUS_PATH_CONFIG,
343                                                "connection", connection,
344                                                NULL);
345     return config;
346 }