1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4 * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5 * Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
6 * Copyright (C) 2008-2011 Red Hat, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
28 #define DCONF_PREFIX "/desktop/ibus"
29 #define DCONF_PRESERVE_NAME_PREFIXES_KEY \
30 DCONF_PREFIX"/general/dconf-preserve-name-prefixes"
32 struct _IBusConfigDConf {
33 IBusConfigService parent;
36 /* if a dconf path matches one of preserve_name_prefixes, don't convert
37 key names from/to GSettings key names (see _to_gsettings_name
38 and _from_gsettings_name) */
39 GSList *preserve_name_prefixes;
42 struct _IBusConfigDConfClass {
43 IBusConfigServiceClass parent;
46 /* functions prototype */
47 static void ibus_config_dconf_class_init (IBusConfigDConfClass *class);
48 static void ibus_config_dconf_init (IBusConfigDConf *config);
49 static void ibus_config_dconf_destroy (IBusConfigDConf *config);
50 static gboolean ibus_config_dconf_set_value (IBusConfigService *config,
55 static GVariant *ibus_config_dconf_get_value (IBusConfigService *config,
59 static GVariant *ibus_config_dconf_get_values (IBusConfigService *config,
62 static gboolean ibus_config_dconf_unset_value (IBusConfigService *config,
67 G_DEFINE_TYPE (IBusConfigDConf, ibus_config_dconf, IBUS_TYPE_CONFIG_SERVICE)
70 ibus_config_dconf_class_init (IBusConfigDConfClass *class)
72 IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
73 IBusConfigServiceClass *config_class = IBUS_CONFIG_SERVICE_CLASS (class);
75 object_class->destroy = (IBusObjectDestroyFunc) ibus_config_dconf_destroy;
76 config_class->set_value = ibus_config_dconf_set_value;
77 config_class->get_value = ibus_config_dconf_get_value;
78 config_class->get_values = ibus_config_dconf_get_values;
79 config_class->unset_value = ibus_config_dconf_unset_value;
83 _has_prefixes (const gchar *path, GSList *prefixes)
85 GSList *head = prefixes;
86 for (; head; head = head->next) {
87 if (g_str_has_prefix (path, head->data)) {
94 /* Convert key names from/to GSettings names. While GSettings only
95 * accepts lowercase letters / numbers / and dash ('-'), IBus uses
96 * underscore ('_') and some engines even use uppercase letters.
98 * To minimize the gap, we do the following conversion:
100 * - when converting from IBus names to GSettings names, first convert
101 * all letters to lowercase and then replace underscores with dashes.
102 * - when converting from GSettings names to IBus names, simply
103 * replace dashes with underscores.
105 * Note that though the conversion does not always roundtrip, it does
109 _to_gsettings_name (const gchar *name)
111 return g_strcanon (g_ascii_strdown (name, -1),
112 "abcdefghijklmnopqrstuvwxyz0123456789-",
117 _from_gsettings_name (const gchar *name)
119 gchar *retval = g_strdup (name), *p;
120 for (p = retval; *p != '\0'; p++)
126 typedef gchar *(* NameConvFunc) (const gchar *);
129 _conv_path (const gchar *path, NameConvFunc conv_func)
131 gchar **strv = g_strsplit (path, "/", -1), **p;
134 for (p = strv; *p; p++) {
136 canon = (*conv_func) (*p);
141 retval = g_strjoinv ("/", strv);
147 _to_gsettings_path (const gchar *path)
149 return _conv_path (path, _to_gsettings_name);
153 _from_gsettings_path (const gchar *gpath)
155 return _conv_path (gpath, _from_gsettings_name);
159 _watch_func (DConfClient *client,
161 const gchar * const *items,
164 IBusConfigDConf *config)
166 gchar **gkeys = NULL;
169 g_return_if_fail (gpath != NULL);
170 g_return_if_fail (n_items >= 0);
172 if (dconf_is_key (gpath, NULL)) {
173 /* If path is a key, the notification should be taken to mean
174 that one key may have changed. */
176 gkeys = g_malloc0_n (n_items + 1, sizeof (gchar *));
177 gkeys[0] = g_strdup (gpath);
180 /* If path is a dir and items is empty then it is an
181 indication that any key under path may have
183 gkeys = dconf_client_list (config->client, gpath, &n_items);
185 gkeys = g_boxed_copy (G_TYPE_STRV, items);
187 for (i = 0; i < n_items; i++) {
188 gchar *gname = gkeys[i];
189 gkeys[i] = g_strdup_printf ("%s/%s", gpath, gname);
194 for (i = 0; i < n_items; i++) {
195 gchar *gname, *path, *name;
196 GVariant *variant = dconf_client_read (config->client, gkeys[i]);
198 if (variant == NULL) {
199 /* Use a empty tuple for a unset value */
200 variant = g_variant_new_tuple (NULL, 0);
203 gname = strrchr (gkeys[i], '/');
207 if (_has_prefixes (gkeys[i], config->preserve_name_prefixes)) {
211 path = _from_gsettings_path (gkeys[i]);
212 name = _from_gsettings_name (gname);
215 ibus_config_service_value_changed ((IBusConfigService *) config,
216 path + sizeof (DCONF_PREFIX),
219 if (path != gkeys[i]) {
225 g_variant_unref (variant);
231 ibus_config_dconf_init (IBusConfigDConf *config)
236 config->client = dconf_client_new ("ibus",
237 (DConfWatchFunc)_watch_func,
242 if (!dconf_client_watch (config->client, DCONF_PREFIX"/", NULL, &error))
243 g_warning ("Can not watch dconf path %s", DCONF_PREFIX"/");
245 config->preserve_name_prefixes = NULL;
246 variant = dconf_client_read (config->client,
247 DCONF_PRESERVE_NAME_PREFIXES_KEY);
248 if (variant != NULL) {
252 g_variant_iter_init (&iter, variant);
253 while ((child = g_variant_iter_next_value (&iter))) {
254 char *prefix = g_variant_dup_string (child, NULL);
255 config->preserve_name_prefixes =
256 g_slist_prepend (config->preserve_name_prefixes,
258 g_variant_unref (child);
260 g_variant_unref (variant);
265 ibus_config_dconf_destroy (IBusConfigDConf *config)
267 if (config->client) {
268 GError *error = NULL;
269 if (!dconf_client_unwatch (config->client, DCONF_PREFIX"/", NULL, &error))
270 g_warning ("Can not unwatch dconf path %s", DCONF_PREFIX"/");
272 g_object_unref (config->client);
273 config->client = NULL;
276 g_slist_free_full (config->preserve_name_prefixes, (GDestroyNotify) g_free);
277 config->preserve_name_prefixes = NULL;
279 IBUS_OBJECT_CLASS (ibus_config_dconf_parent_class)->
280 destroy ((IBusObject *)config);
284 ibus_config_dconf_set_value (IBusConfigService *config,
285 const gchar *section,
290 IBusConfigDConf *dconf = IBUS_CONFIG_DCONF (config);
291 DConfClient *client = dconf->client;
292 gchar *path, *gpath, *gname, *gkey;
295 path = g_strdup_printf (DCONF_PREFIX"/%s", section);
296 gpath = _to_gsettings_path (path);
299 if (_has_prefixes (gpath, dconf->preserve_name_prefixes)) {
300 gname = (char *) name;
302 gname = _to_gsettings_name (name);
304 gkey = g_strconcat (gpath, "/", gname, NULL);
310 retval = dconf_client_write (client,
314 NULL, /* cancellable */
318 /* notify the caller that the value has changed, as dconf does not
319 call watch_func when the caller is the process itself */
322 /* Use a empty tuple for a unset value */
323 value = g_variant_new_tuple (NULL, 0);
325 ibus_config_service_value_changed (config, section, name, value);
331 ibus_config_dconf_get_value (IBusConfigService *config,
332 const gchar *section,
336 IBusConfigDConf *dconf = IBUS_CONFIG_DCONF (config);
337 DConfClient *client = dconf->client;
338 gchar *path, *gpath, *gname, *gkey;
341 path = g_strdup_printf (DCONF_PREFIX"/%s", section);
342 gpath = _to_gsettings_path (path);
345 if (_has_prefixes (gpath, dconf->preserve_name_prefixes)) {
346 gname = (char *) name;
348 gname = _to_gsettings_name (name);
350 gkey = g_strconcat (gpath, "/", gname, NULL);
356 variant = dconf_client_read (client, gkey);
359 if (variant == NULL) {
360 *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
361 "Config value [%s:%s] does not exist.", section, name);
369 ibus_config_dconf_get_values (IBusConfigService *config,
370 const gchar *section,
373 IBusConfigDConf *dconf = IBUS_CONFIG_DCONF (config);
374 DConfClient *client = dconf->client;
377 gchar **entries, **p;
378 GVariantBuilder *builder;
379 gboolean preserve_name;
381 dir = g_strdup_printf (DCONF_PREFIX"/%s/", section);
382 gdir = _to_gsettings_path (dir);
385 preserve_name = _has_prefixes (gdir, dconf->preserve_name_prefixes);
387 entries = dconf_client_list (client, gdir, &len);
388 builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
389 for (p = entries; *p != NULL; p++) {
390 gchar *gkey = g_strconcat (gdir, *p, NULL);
391 GVariant *value = dconf_client_read (client, gkey);
395 if (!preserve_name) {
396 name = _from_gsettings_name (*p);
398 g_variant_builder_add (builder, "{sv}", name, value);
402 g_variant_unref (value);
405 g_strfreev (entries);
408 return g_variant_builder_end (builder);
412 ibus_config_dconf_unset_value (IBusConfigService *config,
413 const gchar *section,
417 return ibus_config_dconf_set_value (config, section, name, NULL, error);
421 ibus_config_dconf_new (GDBusConnection *connection)
423 IBusConfigDConf *config;
424 config = (IBusConfigDConf *) g_object_new (IBUS_TYPE_CONFIG_DCONF,
425 "object-path", IBUS_PATH_CONFIG,
426 "connection", connection,