1 /*
2 * Copyright © 2010 Codethink Limited
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Ryan Lortie <desrt@desrt.ca>
18 */
19
20 #include "config.h"
21
22 #define G_SETTINGS_ENABLE_BACKEND
23 #include <gio/gsettingsbackend.h>
24 #include "../engine/dconf-engine.h"
25 #include <gio/gio.h>
26
27 #include <string.h>
28
29 typedef GSettingsBackendClass DConfSettingsBackendClass;
30
31 typedef struct
32 {
33 GSettingsBackend backend;
34 DConfEngine *engine;
35 } DConfSettingsBackend;
36
37 static GType dconf_settings_backend_get_type (void);
G_DEFINE_TYPE(DConfSettingsBackend,dconf_settings_backend,G_TYPE_SETTINGS_BACKEND)38 G_DEFINE_TYPE (DConfSettingsBackend, dconf_settings_backend, G_TYPE_SETTINGS_BACKEND)
39
40 static GVariant *
41 dconf_settings_backend_read (GSettingsBackend *backend,
42 const gchar *key,
43 const GVariantType *expected_type,
44 gboolean default_value)
45 {
46 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
47
48 return dconf_engine_read (dcsb->engine,
49 default_value ? DCONF_READ_DEFAULT_VALUE : 0,
50 NULL, key);
51 }
52
53 static GVariant *
dconf_settings_backend_read_user_value(GSettingsBackend * backend,const gchar * key,const GVariantType * expected_type)54 dconf_settings_backend_read_user_value (GSettingsBackend *backend,
55 const gchar *key,
56 const GVariantType *expected_type)
57 {
58 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
59
60 return dconf_engine_read (dcsb->engine, DCONF_READ_USER_VALUE, NULL, key);
61 }
62
63 static gboolean
dconf_settings_backend_write(GSettingsBackend * backend,const gchar * key,GVariant * value,gpointer origin_tag)64 dconf_settings_backend_write (GSettingsBackend *backend,
65 const gchar *key,
66 GVariant *value,
67 gpointer origin_tag)
68 {
69 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
70 DConfChangeset *change;
71 gboolean success;
72
73 change = dconf_changeset_new ();
74 dconf_changeset_set (change, key, value);
75
76 success = dconf_engine_change_fast (dcsb->engine, change, origin_tag, NULL);
77 dconf_changeset_unref (change);
78
79 return success;
80 }
81
82 static gboolean
dconf_settings_backend_add_to_changeset(gpointer key,gpointer value,gpointer data)83 dconf_settings_backend_add_to_changeset (gpointer key,
84 gpointer value,
85 gpointer data)
86 {
87 dconf_changeset_set (data, key, value);
88
89 return FALSE;
90 }
91
92 static gboolean
dconf_settings_backend_write_tree(GSettingsBackend * backend,GTree * tree,gpointer origin_tag)93 dconf_settings_backend_write_tree (GSettingsBackend *backend,
94 GTree *tree,
95 gpointer origin_tag)
96 {
97 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
98 DConfChangeset *change;
99 gboolean success;
100
101 if (g_tree_nnodes (tree) == 0)
102 return TRUE;
103
104 change = dconf_changeset_new ();
105 g_tree_foreach (tree, dconf_settings_backend_add_to_changeset, change);
106 success = dconf_engine_change_fast (dcsb->engine, change, origin_tag, NULL);
107 dconf_changeset_unref (change);
108
109 return success;
110 }
111
112 static void
dconf_settings_backend_reset(GSettingsBackend * backend,const gchar * key,gpointer origin_tag)113 dconf_settings_backend_reset (GSettingsBackend *backend,
114 const gchar *key,
115 gpointer origin_tag)
116 {
117 dconf_settings_backend_write (backend, key, NULL, origin_tag);
118 }
119
120 static gboolean
dconf_settings_backend_get_writable(GSettingsBackend * backend,const gchar * name)121 dconf_settings_backend_get_writable (GSettingsBackend *backend,
122 const gchar *name)
123 {
124 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
125
126 return dconf_engine_is_writable (dcsb->engine, name);
127 }
128
129 static void
dconf_settings_backend_subscribe(GSettingsBackend * backend,const gchar * name)130 dconf_settings_backend_subscribe (GSettingsBackend *backend,
131 const gchar *name)
132 {
133 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
134
135 dconf_engine_watch_fast (dcsb->engine, name);
136 }
137
138 static void
dconf_settings_backend_unsubscribe(GSettingsBackend * backend,const gchar * name)139 dconf_settings_backend_unsubscribe (GSettingsBackend *backend,
140 const gchar *name)
141 {
142 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
143
144 dconf_engine_unwatch_fast (dcsb->engine, name);
145 }
146
147 static void
dconf_settings_backend_sync(GSettingsBackend * backend)148 dconf_settings_backend_sync (GSettingsBackend *backend)
149 {
150 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
151
152 dconf_engine_sync (dcsb->engine);
153 }
154
155 static void
dconf_settings_backend_free_weak_ref(gpointer data)156 dconf_settings_backend_free_weak_ref (gpointer data)
157 {
158 GWeakRef *weak_ref = data;
159
160 g_weak_ref_clear (weak_ref);
161 g_slice_free (GWeakRef, weak_ref);
162 }
163
164 static void
dconf_settings_backend_init(DConfSettingsBackend * dcsb)165 dconf_settings_backend_init (DConfSettingsBackend *dcsb)
166 {
167 GWeakRef *weak_ref;
168
169 weak_ref = g_slice_new (GWeakRef);
170 g_weak_ref_init (weak_ref, dcsb);
171 dcsb->engine = dconf_engine_new (NULL, weak_ref, dconf_settings_backend_free_weak_ref);
172 }
173
174 static void
dconf_settings_backend_finalize(GObject * object)175 dconf_settings_backend_finalize (GObject *object)
176 {
177 DConfSettingsBackend *dcsb = (DConfSettingsBackend *) object;
178
179 dconf_engine_unref (dcsb->engine);
180
181 G_OBJECT_CLASS (dconf_settings_backend_parent_class)
182 ->finalize (object);
183 }
184
185 static void
dconf_settings_backend_class_init(GSettingsBackendClass * class)186 dconf_settings_backend_class_init (GSettingsBackendClass *class)
187 {
188 GObjectClass *object_class = G_OBJECT_CLASS (class);
189
190 object_class->finalize = dconf_settings_backend_finalize;
191
192 class->read = dconf_settings_backend_read;
193 class->read_user_value = dconf_settings_backend_read_user_value;
194 class->write = dconf_settings_backend_write;
195 class->write_tree = dconf_settings_backend_write_tree;
196 class->reset = dconf_settings_backend_reset;
197 class->get_writable = dconf_settings_backend_get_writable;
198 class->subscribe = dconf_settings_backend_subscribe;
199 class->unsubscribe = dconf_settings_backend_unsubscribe;
200 class->sync = dconf_settings_backend_sync;
201 }
202
203 void
g_io_module_load(GIOModule * module)204 g_io_module_load (GIOModule *module)
205 {
206 g_type_module_use (G_TYPE_MODULE (module));
207 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
208 dconf_settings_backend_get_type (),
209 "dconf", 100);
210 }
211
212 void
g_io_module_unload(GIOModule * module)213 g_io_module_unload (GIOModule *module)
214 {
215 g_assert_not_reached ();
216 }
217
218 gchar **
g_io_module_query(void)219 g_io_module_query (void)
220 {
221 return g_strsplit (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, "!", 0);
222 }
223
224 void
dconf_engine_change_notify(DConfEngine * engine,const gchar * prefix,const gchar * const * changes,const gchar * tag,gboolean is_writability,gpointer origin_tag,gpointer user_data)225 dconf_engine_change_notify (DConfEngine *engine,
226 const gchar *prefix,
227 const gchar * const *changes,
228 const gchar *tag,
229 gboolean is_writability,
230 gpointer origin_tag,
231 gpointer user_data)
232 {
233 GWeakRef *weak_ref = user_data;
234 DConfSettingsBackend *dcsb;
235 g_debug ("change_notify: %s", prefix);
236
237 dcsb = g_weak_ref_get (weak_ref);
238
239 if (dcsb == NULL)
240 return;
241
242 if (changes[0] == NULL)
243 return;
244
245 if (is_writability)
246 {
247 /* We know that the engine does it this way... */
248 g_assert (changes[0][0] == '\0' && changes[1] == NULL);
249
250 if (g_str_has_suffix (prefix, "/"))
251 g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (dcsb), prefix);
252 else
253 g_settings_backend_writable_changed (G_SETTINGS_BACKEND (dcsb), prefix);
254 }
255
256 /* We send the normal change notification even in the event that this
257 * was a writability notification because adding/removing a lock could
258 * impact the value that gets read.
259 */
260 if (changes[1] == NULL)
261 {
262 if (g_str_has_suffix (prefix, "/"))
263 g_settings_backend_path_changed (G_SETTINGS_BACKEND (dcsb), prefix, origin_tag);
264 else
265 g_settings_backend_changed (G_SETTINGS_BACKEND (dcsb), prefix, origin_tag);
266 }
267 else
268 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (dcsb), prefix, changes, origin_tag);
269 }
270