nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright © 2009, 2010 Codethink Limited |
||
3 | * Copyright © 2010 Red Hat, Inc. |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it under the terms of the GNU Lesser General Public |
||
7 | * License as published by the Free Software Foundation; either |
||
8 | * version 2 of the licence, or (at your option) any later version. |
||
9 | * |
||
10 | * This library is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
13 | * Lesser General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU Lesser General Public |
||
16 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
||
17 | * |
||
18 | * Authors: Ryan Lortie <desrt@desrt.ca> |
||
19 | * Matthias Clasen <mclasen@redhat.com> |
||
20 | */ |
||
21 | |||
22 | #include "config.h" |
||
23 | |||
24 | #include "gsettingsbackendinternal.h" |
||
25 | #include "gsimplepermission.h" |
||
26 | #include "giomodule-priv.h" |
||
27 | |||
28 | #include <string.h> |
||
29 | #include <stdlib.h> |
||
30 | #include <glib.h> |
||
31 | #include <glibintl.h> |
||
32 | |||
33 | |||
34 | typedef struct _GSettingsBackendClosure GSettingsBackendClosure; |
||
35 | typedef struct _GSettingsBackendWatch GSettingsBackendWatch; |
||
36 | |||
37 | struct _GSettingsBackendPrivate |
||
38 | { |
||
39 | GSettingsBackendWatch *watches; |
||
40 | GMutex lock; |
||
41 | }; |
||
42 | |||
43 | G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT) |
||
44 | |||
45 | /* For g_settings_backend_sync_default(), we only want to actually do |
||
46 | * the sync if the backend already exists. This avoids us creating an |
||
47 | * entire GSettingsBackend in order to call a do-nothing sync() |
||
48 | * operation on it. This variable lets us avoid that. |
||
49 | */ |
||
50 | static gboolean g_settings_has_backend; |
||
51 | |||
52 | /** |
||
53 | * SECTION:gsettingsbackend |
||
54 | * @title: GSettingsBackend |
||
55 | * @short_description: Interface for settings backend implementations |
||
56 | * @include: gio/gsettingsbackend.h |
||
57 | * @see_also: #GSettings, #GIOExtensionPoint |
||
58 | * |
||
59 | * The #GSettingsBackend interface defines a generic interface for |
||
60 | * non-strictly-typed data that is stored in a hierarchy. To implement |
||
61 | * an alternative storage backend for #GSettings, you need to implement |
||
62 | * the #GSettingsBackend interface and then make it implement the |
||
63 | * extension point #G_SETTINGS_BACKEND_EXTENSION_POINT_NAME. |
||
64 | * |
||
65 | * The interface defines methods for reading and writing values, a |
||
66 | * method for determining if writing of certain values will fail |
||
67 | * (lockdown) and a change notification mechanism. |
||
68 | * |
||
69 | * The semantics of the interface are very precisely defined and |
||
70 | * implementations must carefully adhere to the expectations of |
||
71 | * callers that are documented on each of the interface methods. |
||
72 | * |
||
73 | * Some of the GSettingsBackend functions accept or return a #GTree. |
||
74 | * These trees always have strings as keys and #GVariant as values. |
||
75 | * g_settings_backend_create_tree() is a convenience function to create |
||
76 | * suitable trees. |
||
77 | * |
||
78 | * The GSettingsBackend API is exported to allow third-party |
||
79 | * implementations, but does not carry the same stability guarantees |
||
80 | * as the public GIO API. For this reason, you have to define the |
||
81 | * C preprocessor symbol %G_SETTINGS_ENABLE_BACKEND before including |
||
82 | * `gio/gsettingsbackend.h`. |
||
83 | **/ |
||
84 | |||
85 | static gboolean |
||
86 | is_key (const gchar *key) |
||
87 | { |
||
88 | gint length; |
||
89 | gint i; |
||
90 | |||
91 | g_return_val_if_fail (key != NULL, FALSE); |
||
92 | g_return_val_if_fail (key[0] == '/', FALSE); |
||
93 | |||
94 | for (i = 1; key[i]; i++) |
||
95 | g_return_val_if_fail (key[i] != '/' || key[i + 1] != '/', FALSE); |
||
96 | |||
97 | length = i; |
||
98 | |||
99 | g_return_val_if_fail (key[length - 1] != '/', FALSE); |
||
100 | |||
101 | return TRUE; |
||
102 | } |
||
103 | |||
104 | static gboolean |
||
105 | is_path (const gchar *path) |
||
106 | { |
||
107 | gint length; |
||
108 | gint i; |
||
109 | |||
110 | g_return_val_if_fail (path != NULL, FALSE); |
||
111 | g_return_val_if_fail (path[0] == '/', FALSE); |
||
112 | |||
113 | for (i = 1; path[i]; i++) |
||
114 | g_return_val_if_fail (path[i] != '/' || path[i + 1] != '/', FALSE); |
||
115 | |||
116 | length = i; |
||
117 | |||
118 | g_return_val_if_fail (path[length - 1] == '/', FALSE); |
||
119 | |||
120 | return TRUE; |
||
121 | } |
||
122 | |||
123 | struct _GSettingsBackendWatch |
||
124 | { |
||
125 | GObject *target; |
||
126 | const GSettingsListenerVTable *vtable; |
||
127 | GMainContext *context; |
||
128 | GSettingsBackendWatch *next; |
||
129 | }; |
||
130 | |||
131 | struct _GSettingsBackendClosure |
||
132 | { |
||
133 | void (*function) (GObject *target, |
||
134 | GSettingsBackend *backend, |
||
135 | const gchar *name, |
||
136 | gpointer origin_tag, |
||
137 | gchar **names); |
||
138 | |||
139 | GMainContext *context; |
||
140 | GObject *target; |
||
141 | GSettingsBackend *backend; |
||
142 | gchar *name; |
||
143 | gpointer origin_tag; |
||
144 | gchar **names; |
||
145 | }; |
||
146 | |||
147 | static void |
||
148 | g_settings_backend_watch_weak_notify (gpointer data, |
||
149 | GObject *where_the_object_was) |
||
150 | { |
||
151 | GSettingsBackend *backend = data; |
||
152 | GSettingsBackendWatch **ptr; |
||
153 | |||
154 | /* search and remove */ |
||
155 | g_mutex_lock (&backend->priv->lock); |
||
156 | for (ptr = &backend->priv->watches; *ptr; ptr = &(*ptr)->next) |
||
157 | if ((*ptr)->target == where_the_object_was) |
||
158 | { |
||
159 | GSettingsBackendWatch *tmp = *ptr; |
||
160 | |||
161 | *ptr = tmp->next; |
||
162 | g_slice_free (GSettingsBackendWatch, tmp); |
||
163 | |||
164 | g_mutex_unlock (&backend->priv->lock); |
||
165 | return; |
||
166 | } |
||
167 | |||
168 | /* we didn't find it. that shouldn't happen. */ |
||
169 | g_assert_not_reached (); |
||
170 | } |
||
171 | |||
172 | /*< private > |
||
173 | * g_settings_backend_watch: |
||
174 | * @backend: a #GSettingsBackend |
||
175 | * @target: the GObject (typically GSettings instance) to call back to |
||
176 | * @context: (allow-none): a #GMainContext, or %NULL |
||
177 | * ...: callbacks... |
||
178 | * |
||
179 | * Registers a new watch on a #GSettingsBackend. |
||
180 | * |
||
181 | * note: %NULL @context does not mean "default main context" but rather, |
||
182 | * "it is okay to dispatch in any context". If the default main context |
||
183 | * is specifically desired then it must be given. |
||
184 | * |
||
185 | * note also: if you want to get meaningful values for the @origin_tag |
||
186 | * that appears as an argument to some of the callbacks, you *must* have |
||
187 | * @context as %NULL. Otherwise, you are subject to cross-thread |
||
188 | * dispatching and whatever owned @origin_tag at the time that the event |
||
189 | * occurred may no longer own it. This is a problem if you consider that |
||
190 | * you may now be the new owner of that address and mistakenly think |
||
191 | * that the event in question originated from yourself. |
||
192 | * |
||
193 | * tl;dr: If you give a non-%NULL @context then you must ignore the |
||
194 | * value of @origin_tag given to any callbacks. |
||
195 | **/ |
||
196 | void |
||
197 | g_settings_backend_watch (GSettingsBackend *backend, |
||
198 | const GSettingsListenerVTable *vtable, |
||
199 | GObject *target, |
||
200 | GMainContext *context) |
||
201 | { |
||
202 | GSettingsBackendWatch *watch; |
||
203 | |||
204 | /* For purposes of discussion, we assume that our target is a |
||
205 | * GSettings instance. |
||
206 | * |
||
207 | * Our strategy to defend against the final reference dropping on the |
||
208 | * GSettings object in a thread other than the one that is doing the |
||
209 | * dispatching is as follows: |
||
210 | * |
||
211 | * 1) hold a GObject reference on the GSettings during an outstanding |
||
212 | * dispatch. This ensures that the delivery is always possible. |
||
213 | * |
||
214 | * 2) hold a weak reference on the GSettings at other times. This |
||
215 | * allows us to receive early notification of pending destruction |
||
216 | * of the object. At this point, it is still safe to obtain a |
||
217 | * reference on the GObject to keep it alive, so #1 will work up |
||
218 | * to that point. After that point, we'll have been able to drop |
||
219 | * the watch from the list. |
||
220 | * |
||
221 | * Note, in particular, that it's not possible to simply have an |
||
222 | * "unwatch" function that gets called from the finalize function of |
||
223 | * the GSettings instance because, by that point it is no longer |
||
224 | * possible to keep the object alive using g_object_ref() and we would |
||
225 | * have no way of knowing this. |
||
226 | * |
||
227 | * Note also that we do not need to hold a reference on the main |
||
228 | * context here since the GSettings instance does that for us and we |
||
229 | * will receive the weak notify long before it is dropped. We don't |
||
230 | * even need to hold it during dispatches because our reference on the |
||
231 | * GSettings will prevent the finalize from running and dropping the |
||
232 | * ref on the context. |
||
233 | * |
||
234 | * All access to the list holds a mutex. We have some strategies to |
||
235 | * avoid some of the pain that would be associated with that. |
||
236 | */ |
||
237 | |||
238 | watch = g_slice_new (GSettingsBackendWatch); |
||
239 | watch->context = context; |
||
240 | watch->vtable = vtable; |
||
241 | watch->target = target; |
||
242 | g_object_weak_ref (target, g_settings_backend_watch_weak_notify, backend); |
||
243 | |||
244 | /* linked list prepend */ |
||
245 | g_mutex_lock (&backend->priv->lock); |
||
246 | watch->next = backend->priv->watches; |
||
247 | backend->priv->watches = watch; |
||
248 | g_mutex_unlock (&backend->priv->lock); |
||
249 | } |
||
250 | |||
251 | void |
||
252 | g_settings_backend_unwatch (GSettingsBackend *backend, |
||
253 | GObject *target) |
||
254 | { |
||
255 | /* Our caller surely owns a reference on 'target', so the order of |
||
256 | * these two calls is unimportant. |
||
257 | */ |
||
258 | g_object_weak_unref (target, g_settings_backend_watch_weak_notify, backend); |
||
259 | g_settings_backend_watch_weak_notify (backend, target); |
||
260 | } |
||
261 | |||
262 | static gboolean |
||
263 | g_settings_backend_invoke_closure (gpointer user_data) |
||
264 | { |
||
265 | GSettingsBackendClosure *closure = user_data; |
||
266 | |||
267 | closure->function (closure->target, closure->backend, closure->name, |
||
268 | closure->origin_tag, closure->names); |
||
269 | |||
270 | g_object_unref (closure->backend); |
||
271 | g_object_unref (closure->target); |
||
272 | g_strfreev (closure->names); |
||
273 | g_free (closure->name); |
||
274 | |||
275 | g_slice_free (GSettingsBackendClosure, closure); |
||
276 | |||
277 | return FALSE; |
||
278 | } |
||
279 | |||
280 | static void |
||
281 | g_settings_backend_dispatch_signal (GSettingsBackend *backend, |
||
282 | gsize function_offset, |
||
283 | const gchar *name, |
||
284 | gpointer origin_tag, |
||
285 | const gchar * const *names) |
||
286 | { |
||
287 | GSettingsBackendWatch *watch; |
||
288 | GSList *closures = NULL; |
||
289 | |||
290 | /* We're in a little bit of a tricky situation here. We need to hold |
||
291 | * a lock while traversing the list, but we don't want to hold the |
||
292 | * lock while calling back into user code. |
||
293 | * |
||
294 | * We work around this by creating a bunch of GSettingsBackendClosure |
||
295 | * objects while holding the lock and dispatching them after. We |
||
296 | * never touch the list without holding the lock. |
||
297 | */ |
||
298 | g_mutex_lock (&backend->priv->lock); |
||
299 | for (watch = backend->priv->watches; watch; watch = watch->next) |
||
300 | { |
||
301 | GSettingsBackendClosure *closure; |
||
302 | |||
303 | closure = g_slice_new (GSettingsBackendClosure); |
||
304 | closure->context = watch->context; |
||
305 | closure->backend = g_object_ref (backend); |
||
306 | closure->target = g_object_ref (watch->target); |
||
307 | closure->function = G_STRUCT_MEMBER (void *, watch->vtable, |
||
308 | function_offset); |
||
309 | closure->name = g_strdup (name); |
||
310 | closure->origin_tag = origin_tag; |
||
311 | closure->names = g_strdupv ((gchar **) names); |
||
312 | |||
313 | closures = g_slist_prepend (closures, closure); |
||
314 | } |
||
315 | g_mutex_unlock (&backend->priv->lock); |
||
316 | |||
317 | while (closures) |
||
318 | { |
||
319 | GSettingsBackendClosure *closure = closures->data; |
||
320 | |||
321 | if (closure->context) |
||
322 | g_main_context_invoke (closure->context, |
||
323 | g_settings_backend_invoke_closure, |
||
324 | closure); |
||
325 | else |
||
326 | g_settings_backend_invoke_closure (closure); |
||
327 | |||
328 | closures = g_slist_delete_link (closures, closures); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | /** |
||
333 | * g_settings_backend_changed: |
||
334 | * @backend: a #GSettingsBackend implementation |
||
335 | * @key: the name of the key |
||
336 | * @origin_tag: the origin tag |
||
337 | * |
||
338 | * Signals that a single key has possibly changed. Backend |
||
339 | * implementations should call this if a key has possibly changed its |
||
340 | * value. |
||
341 | * |
||
342 | * @key must be a valid key (ie starting with a slash, not containing |
||
343 | * '//', and not ending with a slash). |
||
344 | * |
||
345 | * The implementation must call this function during any call to |
||
346 | * g_settings_backend_write(), before the call returns (except in the |
||
347 | * case that no keys are actually changed and it cares to detect this |
||
348 | * fact). It may not rely on the existence of a mainloop for |
||
349 | * dispatching the signal later. |
||
350 | * |
||
351 | * The implementation may call this function at any other time it likes |
||
352 | * in response to other events (such as changes occurring outside of the |
||
353 | * program). These calls may originate from a mainloop or may originate |
||
354 | * in response to any other action (including from calls to |
||
355 | * g_settings_backend_write()). |
||
356 | * |
||
357 | * In the case that this call is in response to a call to |
||
358 | * g_settings_backend_write() then @origin_tag must be set to the same |
||
359 | * value that was passed to that call. |
||
360 | * |
||
361 | * Since: 2.26 |
||
362 | **/ |
||
363 | void |
||
364 | g_settings_backend_changed (GSettingsBackend *backend, |
||
365 | const gchar *key, |
||
366 | gpointer origin_tag) |
||
367 | { |
||
368 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
369 | g_return_if_fail (is_key (key)); |
||
370 | |||
371 | g_settings_backend_dispatch_signal (backend, |
||
372 | G_STRUCT_OFFSET (GSettingsListenerVTable, |
||
373 | changed), |
||
374 | key, origin_tag, NULL); |
||
375 | } |
||
376 | |||
377 | /** |
||
378 | * g_settings_backend_keys_changed: |
||
379 | * @backend: a #GSettingsBackend implementation |
||
380 | * @path: the path containing the changes |
||
381 | * @items: (array zero-terminated=1): the %NULL-terminated list of changed keys |
||
382 | * @origin_tag: the origin tag |
||
383 | * |
||
384 | * Signals that a list of keys have possibly changed. Backend |
||
385 | * implementations should call this if keys have possibly changed their |
||
386 | * values. |
||
387 | * |
||
388 | * @path must be a valid path (ie starting and ending with a slash and |
||
389 | * not containing '//'). Each string in @items must form a valid key |
||
390 | * name when @path is prefixed to it (ie: each item must not start or |
||
391 | * end with '/' and must not contain '//'). |
||
392 | * |
||
393 | * The meaning of this signal is that any of the key names resulting |
||
394 | * from the contatenation of @path with each item in @items may have |
||
395 | * changed. |
||
396 | * |
||
397 | * The same rules for when notifications must occur apply as per |
||
398 | * g_settings_backend_changed(). These two calls can be used |
||
399 | * interchangeably if exactly one item has changed (although in that |
||
400 | * case g_settings_backend_changed() is definitely preferred). |
||
401 | * |
||
402 | * For efficiency reasons, the implementation should strive for @path to |
||
403 | * be as long as possible (ie: the longest common prefix of all of the |
||
404 | * keys that were changed) but this is not strictly required. |
||
405 | * |
||
406 | * Since: 2.26 |
||
407 | */ |
||
408 | void |
||
409 | g_settings_backend_keys_changed (GSettingsBackend *backend, |
||
410 | const gchar *path, |
||
411 | gchar const * const *items, |
||
412 | gpointer origin_tag) |
||
413 | { |
||
414 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
415 | g_return_if_fail (is_path (path)); |
||
416 | |||
417 | /* XXX: should do stricter checking (ie: inspect each item) */ |
||
418 | g_return_if_fail (items != NULL); |
||
419 | |||
420 | g_settings_backend_dispatch_signal (backend, |
||
421 | G_STRUCT_OFFSET (GSettingsListenerVTable, |
||
422 | keys_changed), |
||
423 | path, origin_tag, items); |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * g_settings_backend_path_changed: |
||
428 | * @backend: a #GSettingsBackend implementation |
||
429 | * @path: the path containing the changes |
||
430 | * @origin_tag: the origin tag |
||
431 | * |
||
432 | * Signals that all keys below a given path may have possibly changed. |
||
433 | * Backend implementations should call this if an entire path of keys |
||
434 | * have possibly changed their values. |
||
435 | * |
||
436 | * @path must be a valid path (ie starting and ending with a slash and |
||
437 | * not containing '//'). |
||
438 | * |
||
439 | * The meaning of this signal is that any of the key which has a name |
||
440 | * starting with @path may have changed. |
||
441 | * |
||
442 | * The same rules for when notifications must occur apply as per |
||
443 | * g_settings_backend_changed(). This call might be an appropriate |
||
444 | * reasponse to a 'reset' call but implementations are also free to |
||
445 | * explicitly list the keys that were affected by that call if they can |
||
446 | * easily do so. |
||
447 | * |
||
448 | * For efficiency reasons, the implementation should strive for @path to |
||
449 | * be as long as possible (ie: the longest common prefix of all of the |
||
450 | * keys that were changed) but this is not strictly required. As an |
||
451 | * example, if this function is called with the path of "/" then every |
||
452 | * single key in the application will be notified of a possible change. |
||
453 | * |
||
454 | * Since: 2.26 |
||
455 | */ |
||
456 | void |
||
457 | g_settings_backend_path_changed (GSettingsBackend *backend, |
||
458 | const gchar *path, |
||
459 | gpointer origin_tag) |
||
460 | { |
||
461 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
462 | g_return_if_fail (is_path (path)); |
||
463 | |||
464 | g_settings_backend_dispatch_signal (backend, |
||
465 | G_STRUCT_OFFSET (GSettingsListenerVTable, |
||
466 | path_changed), |
||
467 | path, origin_tag, NULL); |
||
468 | } |
||
469 | |||
470 | /** |
||
471 | * g_settings_backend_writable_changed: |
||
472 | * @backend: a #GSettingsBackend implementation |
||
473 | * @key: the name of the key |
||
474 | * |
||
475 | * Signals that the writability of a single key has possibly changed. |
||
476 | * |
||
477 | * Since GSettings performs no locking operations for itself, this call |
||
478 | * will always be made in response to external events. |
||
479 | * |
||
480 | * Since: 2.26 |
||
481 | **/ |
||
482 | void |
||
483 | g_settings_backend_writable_changed (GSettingsBackend *backend, |
||
484 | const gchar *key) |
||
485 | { |
||
486 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
487 | g_return_if_fail (is_key (key)); |
||
488 | |||
489 | g_settings_backend_dispatch_signal (backend, |
||
490 | G_STRUCT_OFFSET (GSettingsListenerVTable, |
||
491 | writable_changed), |
||
492 | key, NULL, NULL); |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * g_settings_backend_path_writable_changed: |
||
497 | * @backend: a #GSettingsBackend implementation |
||
498 | * @path: the name of the path |
||
499 | * |
||
500 | * Signals that the writability of all keys below a given path may have |
||
501 | * changed. |
||
502 | * |
||
503 | * Since GSettings performs no locking operations for itself, this call |
||
504 | * will always be made in response to external events. |
||
505 | * |
||
506 | * Since: 2.26 |
||
507 | **/ |
||
508 | void |
||
509 | g_settings_backend_path_writable_changed (GSettingsBackend *backend, |
||
510 | const gchar *path) |
||
511 | { |
||
512 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
513 | g_return_if_fail (is_path (path)); |
||
514 | |||
515 | g_settings_backend_dispatch_signal (backend, |
||
516 | G_STRUCT_OFFSET (GSettingsListenerVTable, |
||
517 | path_writable_changed), |
||
518 | path, NULL, NULL); |
||
519 | } |
||
520 | |||
521 | typedef struct |
||
522 | { |
||
523 | const gchar **keys; |
||
524 | GVariant **values; |
||
525 | gint prefix_len; |
||
526 | gchar *prefix; |
||
527 | } FlattenState; |
||
528 | |||
529 | static gboolean |
||
530 | g_settings_backend_flatten_one (gpointer key, |
||
531 | gpointer value, |
||
532 | gpointer user_data) |
||
533 | { |
||
534 | FlattenState *state = user_data; |
||
535 | const gchar *skey = key; |
||
536 | gint i; |
||
537 | |||
538 | g_return_val_if_fail (is_key (key), TRUE); |
||
539 | |||
540 | /* calculate longest common prefix */ |
||
541 | if (state->prefix == NULL) |
||
542 | { |
||
543 | gchar *last_byte; |
||
544 | |||
545 | /* first key? just take the prefix up to the last '/' */ |
||
546 | state->prefix = g_strdup (skey); |
||
547 | last_byte = strrchr (state->prefix, '/') + 1; |
||
548 | state->prefix_len = last_byte - state->prefix; |
||
549 | *last_byte = '\0'; |
||
550 | } |
||
551 | else |
||
552 | { |
||
553 | /* find the first character that does not match. we will |
||
554 | * definitely find one because the prefix ends in '/' and the key |
||
555 | * does not. also: no two keys in the tree are the same. |
||
556 | */ |
||
557 | for (i = 0; state->prefix[i] == skey[i]; i++); |
||
558 | |||
559 | /* check if we need to shorten the prefix */ |
||
560 | if (state->prefix[i] != '\0') |
||
561 | { |
||
562 | /* find the nearest '/', terminate after it */ |
||
563 | while (state->prefix[i - 1] != '/') |
||
564 | i--; |
||
565 | |||
566 | state->prefix[i] = '\0'; |
||
567 | state->prefix_len = i; |
||
568 | } |
||
569 | } |
||
570 | |||
571 | |||
572 | /* save the entire item into the array. |
||
573 | * the prefixes will be removed later. |
||
574 | */ |
||
575 | *state->keys++ = key; |
||
576 | |||
577 | if (state->values) |
||
578 | *state->values++ = value; |
||
579 | |||
580 | return FALSE; |
||
581 | } |
||
582 | |||
583 | /** |
||
584 | * g_settings_backend_flatten_tree: |
||
585 | * @tree: a #GTree containing the changes |
||
586 | * @path: (out): the location to save the path |
||
587 | * @keys: (out) (transfer container) (array zero-terminated=1): the |
||
588 | * location to save the relative keys |
||
589 | * @values: (out) (allow-none) (transfer container) (array zero-terminated=1): |
||
590 | * the location to save the values, or %NULL |
||
591 | * |
||
592 | * Calculate the longest common prefix of all keys in a tree and write |
||
593 | * out an array of the key names relative to that prefix and, |
||
594 | * optionally, the value to store at each of those keys. |
||
595 | * |
||
596 | * You must free the value returned in @path, @keys and @values using |
||
597 | * g_free(). You should not attempt to free or unref the contents of |
||
598 | * @keys or @values. |
||
599 | * |
||
600 | * Since: 2.26 |
||
601 | **/ |
||
602 | void |
||
603 | g_settings_backend_flatten_tree (GTree *tree, |
||
604 | gchar **path, |
||
605 | const gchar ***keys, |
||
606 | GVariant ***values) |
||
607 | { |
||
608 | FlattenState state = { 0, }; |
||
609 | gsize nnodes; |
||
610 | |||
611 | nnodes = g_tree_nnodes (tree); |
||
612 | |||
613 | *keys = state.keys = g_new (const gchar *, nnodes + 1); |
||
614 | state.keys[nnodes] = NULL; |
||
615 | |||
616 | if (values != NULL) |
||
617 | { |
||
618 | *values = state.values = g_new (GVariant *, nnodes + 1); |
||
619 | state.values[nnodes] = NULL; |
||
620 | } |
||
621 | |||
622 | g_tree_foreach (tree, g_settings_backend_flatten_one, &state); |
||
623 | g_return_if_fail (*keys + nnodes == state.keys); |
||
624 | |||
625 | *path = state.prefix; |
||
626 | while (nnodes--) |
||
627 | *--state.keys += state.prefix_len; |
||
628 | } |
||
629 | |||
630 | /** |
||
631 | * g_settings_backend_changed_tree: |
||
632 | * @backend: a #GSettingsBackend implementation |
||
633 | * @tree: a #GTree containing the changes |
||
634 | * @origin_tag: the origin tag |
||
635 | * |
||
636 | * This call is a convenience wrapper. It gets the list of changes from |
||
637 | * @tree, computes the longest common prefix and calls |
||
638 | * g_settings_backend_changed(). |
||
639 | * |
||
640 | * Since: 2.26 |
||
641 | **/ |
||
642 | void |
||
643 | g_settings_backend_changed_tree (GSettingsBackend *backend, |
||
644 | GTree *tree, |
||
645 | gpointer origin_tag) |
||
646 | { |
||
647 | const gchar **keys; |
||
648 | gchar *path; |
||
649 | |||
650 | g_return_if_fail (G_IS_SETTINGS_BACKEND (backend)); |
||
651 | |||
652 | g_settings_backend_flatten_tree (tree, &path, &keys, NULL); |
||
653 | |||
654 | #ifdef DEBUG_CHANGES |
||
655 | { |
||
656 | gint i; |
||
657 | |||
658 | g_print ("----\n"); |
||
659 | g_print ("changed_tree(): prefix %s\n", path); |
||
660 | for (i = 0; keys[i]; i++) |
||
661 | g_print (" %s\n", keys[i]); |
||
662 | g_print ("----\n"); |
||
663 | } |
||
664 | #endif |
||
665 | |||
666 | g_settings_backend_keys_changed (backend, path, keys, origin_tag); |
||
667 | g_free (path); |
||
668 | g_free (keys); |
||
669 | } |
||
670 | |||
671 | /*< private > |
||
672 | * g_settings_backend_read: |
||
673 | * @backend: a #GSettingsBackend implementation |
||
674 | * @key: the key to read |
||
675 | * @expected_type: a #GVariantType |
||
676 | * @default_value: if the default value should be returned |
||
677 | * |
||
678 | * Reads a key. This call will never block. |
||
679 | * |
||
680 | * If the key exists, the value associated with it will be returned. |
||
681 | * If the key does not exist, %NULL will be returned. |
||
682 | * |
||
683 | * The returned value will be of the type given in @expected_type. If |
||
684 | * the backend stored a value of a different type then %NULL will be |
||
685 | * returned. |
||
686 | * |
||
687 | * If @default_value is %TRUE then this gets the default value from the |
||
688 | * backend (ie: the one that the backend would contain if |
||
689 | * g_settings_reset() were called). |
||
690 | * |
||
691 | * Returns: the value that was read, or %NULL |
||
692 | */ |
||
693 | GVariant * |
||
694 | g_settings_backend_read (GSettingsBackend *backend, |
||
695 | const gchar *key, |
||
696 | const GVariantType *expected_type, |
||
697 | gboolean default_value) |
||
698 | { |
||
699 | GVariant *value; |
||
700 | |||
701 | value = G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
702 | ->read (backend, key, expected_type, default_value); |
||
703 | |||
704 | if (value != NULL) |
||
705 | value = g_variant_take_ref (value); |
||
706 | |||
707 | if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type)) |
||
708 | { |
||
709 | g_variant_unref (value); |
||
710 | value = NULL; |
||
711 | } |
||
712 | |||
713 | return value; |
||
714 | } |
||
715 | |||
716 | /*< private > |
||
717 | * g_settings_backend_read_user_value: |
||
718 | * @backend: a #GSettingsBackend implementation |
||
719 | * @key: the key to read |
||
720 | * @expected_type: a #GVariantType |
||
721 | * |
||
722 | * Reads the 'user value' of a key. |
||
723 | * |
||
724 | * This is the value of the key that the user has control over and has |
||
725 | * set for themselves. Put another way: if the user did not set the |
||
726 | * value for themselves, then this will return %NULL (even if the |
||
727 | * sysadmin has provided a default value). |
||
728 | * |
||
729 | * Returns: the value that was read, or %NULL |
||
730 | */ |
||
731 | GVariant * |
||
732 | g_settings_backend_read_user_value (GSettingsBackend *backend, |
||
733 | const gchar *key, |
||
734 | const GVariantType *expected_type) |
||
735 | { |
||
736 | GVariant *value; |
||
737 | |||
738 | value = G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
739 | ->read_user_value (backend, key, expected_type); |
||
740 | |||
741 | if (value != NULL) |
||
742 | value = g_variant_take_ref (value); |
||
743 | |||
744 | if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type)) |
||
745 | { |
||
746 | g_variant_unref (value); |
||
747 | value = NULL; |
||
748 | } |
||
749 | |||
750 | return value; |
||
751 | } |
||
752 | |||
753 | /*< private > |
||
754 | * g_settings_backend_write: |
||
755 | * @backend: a #GSettingsBackend implementation |
||
756 | * @key: the name of the key |
||
757 | * @value: a #GVariant value to write to this key |
||
758 | * @origin_tag: the origin tag |
||
759 | * |
||
760 | * Writes exactly one key. |
||
761 | * |
||
762 | * This call does not fail. During this call a |
||
763 | * #GSettingsBackend::changed signal will be emitted if the value of the |
||
764 | * key has changed. The updated key value will be visible to any signal |
||
765 | * callbacks. |
||
766 | * |
||
767 | * One possible method that an implementation might deal with failures is |
||
768 | * to emit a second "changed" signal (either during this call, or later) |
||
769 | * to indicate that the affected keys have suddenly "changed back" to their |
||
770 | * old values. |
||
771 | * |
||
772 | * Returns: %TRUE if the write succeeded, %FALSE if the key was not writable |
||
773 | */ |
||
774 | gboolean |
||
775 | g_settings_backend_write (GSettingsBackend *backend, |
||
776 | const gchar *key, |
||
777 | GVariant *value, |
||
778 | gpointer origin_tag) |
||
779 | { |
||
780 | gboolean success; |
||
781 | |||
782 | g_variant_ref_sink (value); |
||
783 | success = G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
784 | ->write (backend, key, value, origin_tag); |
||
785 | g_variant_unref (value); |
||
786 | |||
787 | return success; |
||
788 | } |
||
789 | |||
790 | /*< private > |
||
791 | * g_settings_backend_write_tree: |
||
792 | * @backend: a #GSettingsBackend implementation |
||
793 | * @tree: a #GTree containing key-value pairs to write |
||
794 | * @origin_tag: the origin tag |
||
795 | * |
||
796 | * Writes one or more keys. This call will never block. |
||
797 | * |
||
798 | * The key of each item in the tree is the key name to write to and the |
||
799 | * value is a #GVariant to write. The proper type of #GTree for this |
||
800 | * call can be created with g_settings_backend_create_tree(). This call |
||
801 | * might take a reference to the tree; you must not modified the #GTree |
||
802 | * after passing it to this call. |
||
803 | * |
||
804 | * This call does not fail. During this call a #GSettingsBackend::changed |
||
805 | * signal will be emitted if any keys have been changed. The new values of |
||
806 | * all updated keys will be visible to any signal callbacks. |
||
807 | * |
||
808 | * One possible method that an implementation might deal with failures is |
||
809 | * to emit a second "changed" signal (either during this call, or later) |
||
810 | * to indicate that the affected keys have suddenly "changed back" to their |
||
811 | * old values. |
||
812 | */ |
||
813 | gboolean |
||
814 | g_settings_backend_write_tree (GSettingsBackend *backend, |
||
815 | GTree *tree, |
||
816 | gpointer origin_tag) |
||
817 | { |
||
818 | return G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
819 | ->write_tree (backend, tree, origin_tag); |
||
820 | } |
||
821 | |||
822 | /*< private > |
||
823 | * g_settings_backend_reset: |
||
824 | * @backend: a #GSettingsBackend implementation |
||
825 | * @key: the name of a key |
||
826 | * @origin_tag: the origin tag |
||
827 | * |
||
828 | * "Resets" the named key to its "default" value (ie: after system-wide |
||
829 | * defaults, mandatory keys, etc. have been taken into account) or possibly |
||
830 | * unsets it. |
||
831 | */ |
||
832 | void |
||
833 | g_settings_backend_reset (GSettingsBackend *backend, |
||
834 | const gchar *key, |
||
835 | gpointer origin_tag) |
||
836 | { |
||
837 | G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
838 | ->reset (backend, key, origin_tag); |
||
839 | } |
||
840 | |||
841 | /*< private > |
||
842 | * g_settings_backend_get_writable: |
||
843 | * @backend: a #GSettingsBackend implementation |
||
844 | * @key: the name of a key |
||
845 | * |
||
846 | * Finds out if a key is available for writing to. This is the |
||
847 | * interface through which 'lockdown' is implemented. Locked down |
||
848 | * keys will have %FALSE returned by this call. |
||
849 | * |
||
850 | * You should not write to locked-down keys, but if you do, the |
||
851 | * implementation will deal with it. |
||
852 | * |
||
853 | * Returns: %TRUE if the key is writable |
||
854 | */ |
||
855 | gboolean |
||
856 | g_settings_backend_get_writable (GSettingsBackend *backend, |
||
857 | const gchar *key) |
||
858 | { |
||
859 | return G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
860 | ->get_writable (backend, key); |
||
861 | } |
||
862 | |||
863 | /*< private > |
||
864 | * g_settings_backend_unsubscribe: |
||
865 | * @backend: a #GSettingsBackend |
||
866 | * @name: a key or path to subscribe to |
||
867 | * |
||
868 | * Reverses the effect of a previous call to |
||
869 | * g_settings_backend_subscribe(). |
||
870 | */ |
||
871 | void |
||
872 | g_settings_backend_unsubscribe (GSettingsBackend *backend, |
||
873 | const char *name) |
||
874 | { |
||
875 | G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
876 | ->unsubscribe (backend, name); |
||
877 | } |
||
878 | |||
879 | /*< private > |
||
880 | * g_settings_backend_subscribe: |
||
881 | * @backend: a #GSettingsBackend |
||
882 | * @name: a key or path to subscribe to |
||
883 | * |
||
884 | * Requests that change signals be emitted for events on @name. |
||
885 | */ |
||
886 | void |
||
887 | g_settings_backend_subscribe (GSettingsBackend *backend, |
||
888 | const gchar *name) |
||
889 | { |
||
890 | G_SETTINGS_BACKEND_GET_CLASS (backend) |
||
891 | ->subscribe (backend, name); |
||
892 | } |
||
893 | |||
894 | static void |
||
895 | g_settings_backend_finalize (GObject *object) |
||
896 | { |
||
897 | GSettingsBackend *backend = G_SETTINGS_BACKEND (object); |
||
898 | |||
899 | g_mutex_clear (&backend->priv->lock); |
||
900 | |||
901 | G_OBJECT_CLASS (g_settings_backend_parent_class) |
||
902 | ->finalize (object); |
||
903 | } |
||
904 | |||
905 | static void |
||
906 | ignore_subscription (GSettingsBackend *backend, |
||
907 | const gchar *key) |
||
908 | { |
||
909 | } |
||
910 | |||
911 | static GVariant * |
||
912 | g_settings_backend_real_read_user_value (GSettingsBackend *backend, |
||
913 | const gchar *key, |
||
914 | const GVariantType *expected_type) |
||
915 | { |
||
916 | return g_settings_backend_read (backend, key, expected_type, FALSE); |
||
917 | } |
||
918 | |||
919 | static void |
||
920 | g_settings_backend_init (GSettingsBackend *backend) |
||
921 | { |
||
922 | backend->priv = g_settings_backend_get_instance_private (backend); |
||
923 | g_mutex_init (&backend->priv->lock); |
||
924 | } |
||
925 | |||
926 | static void |
||
927 | g_settings_backend_class_init (GSettingsBackendClass *class) |
||
928 | { |
||
929 | GObjectClass *gobject_class = G_OBJECT_CLASS (class); |
||
930 | |||
931 | class->subscribe = ignore_subscription; |
||
932 | class->unsubscribe = ignore_subscription; |
||
933 | |||
934 | class->read_user_value = g_settings_backend_real_read_user_value; |
||
935 | |||
936 | gobject_class->finalize = g_settings_backend_finalize; |
||
937 | } |
||
938 | |||
939 | static void |
||
940 | g_settings_backend_variant_unref0 (gpointer data) |
||
941 | { |
||
942 | if (data != NULL) |
||
943 | g_variant_unref (data); |
||
944 | } |
||
945 | |||
946 | /*< private > |
||
947 | * g_settings_backend_create_tree: |
||
948 | * |
||
949 | * This is a convenience function for creating a tree that is compatible |
||
950 | * with g_settings_backend_write(). It merely calls g_tree_new_full() |
||
951 | * with strcmp(), g_free() and g_variant_unref(). |
||
952 | * |
||
953 | * Returns: a new #GTree |
||
954 | */ |
||
955 | GTree * |
||
956 | g_settings_backend_create_tree (void) |
||
957 | { |
||
958 | return g_tree_new_full ((GCompareDataFunc) strcmp, NULL, |
||
959 | g_free, g_settings_backend_variant_unref0); |
||
960 | } |
||
961 | |||
962 | static gboolean |
||
963 | g_settings_backend_verify (gpointer impl) |
||
964 | { |
||
965 | GSettingsBackend *backend = impl; |
||
966 | |||
967 | if (strcmp (G_OBJECT_TYPE_NAME (backend), "GMemorySettingsBackend") == 0 && |
||
968 | g_strcmp0 (g_getenv ("GSETTINGS_BACKEND"), "memory") != 0) |
||
969 | { |
||
970 | g_message ("Using the 'memory' GSettings backend. Your settings " |
||
971 | "will not be saved or shared with other applications."); |
||
972 | } |
||
973 | |||
974 | g_settings_has_backend = TRUE; |
||
975 | return TRUE; |
||
976 | } |
||
977 | |||
978 | /** |
||
979 | * g_settings_backend_get_default: |
||
980 | * |
||
981 | * Returns the default #GSettingsBackend. It is possible to override |
||
982 | * the default by setting the `GSETTINGS_BACKEND` environment variable |
||
983 | * to the name of a settings backend. |
||
984 | * |
||
985 | * The user gets a reference to the backend. |
||
986 | * |
||
987 | * Returns: (transfer full): the default #GSettingsBackend |
||
988 | * |
||
989 | * Since: 2.28 |
||
990 | */ |
||
991 | GSettingsBackend * |
||
992 | g_settings_backend_get_default (void) |
||
993 | { |
||
994 | GSettingsBackend *backend; |
||
995 | |||
996 | backend = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, |
||
997 | "GSETTINGS_BACKEND", |
||
998 | g_settings_backend_verify); |
||
999 | return g_object_ref (backend); |
||
1000 | } |
||
1001 | |||
1002 | /*< private > |
||
1003 | * g_settings_backend_get_permission: |
||
1004 | * @backend: a #GSettingsBackend |
||
1005 | * @path: a path |
||
1006 | * |
||
1007 | * Gets the permission object associated with writing to keys below |
||
1008 | * @path on @backend. |
||
1009 | * |
||
1010 | * If this is not implemented in the backend, then a %TRUE |
||
1011 | * #GSimplePermission is returned. |
||
1012 | * |
||
1013 | * Returns: a non-%NULL #GPermission. Free with g_object_unref() |
||
1014 | */ |
||
1015 | GPermission * |
||
1016 | g_settings_backend_get_permission (GSettingsBackend *backend, |
||
1017 | const gchar *path) |
||
1018 | { |
||
1019 | GSettingsBackendClass *class = G_SETTINGS_BACKEND_GET_CLASS (backend); |
||
1020 | |||
1021 | if (class->get_permission) |
||
1022 | return class->get_permission (backend, path); |
||
1023 | |||
1024 | return g_simple_permission_new (TRUE); |
||
1025 | } |
||
1026 | |||
1027 | /*< private > |
||
1028 | * g_settings_backend_sync_default: |
||
1029 | * |
||
1030 | * Syncs the default backend. |
||
1031 | */ |
||
1032 | void |
||
1033 | g_settings_backend_sync_default (void) |
||
1034 | { |
||
1035 | if (g_settings_has_backend) |
||
1036 | { |
||
1037 | GSettingsBackendClass *class; |
||
1038 | GSettingsBackend *backend; |
||
1039 | |||
1040 | backend = g_settings_backend_get_default (); |
||
1041 | class = G_SETTINGS_BACKEND_GET_CLASS (backend); |
||
1042 | |||
1043 | if (class->sync) |
||
1044 | class->sync (backend); |
||
1045 | } |
||
1046 | } |