1 /*
2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2012 Canonical Limited
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 * Author: Ryan Lortie <desrt@desrt.ca>
19 */
20
21 #include "config.h"
22
23 #include "dconf-client.h"
24
25 #include "../engine/dconf-engine.h"
26 #include "../common/dconf-paths.h"
27 #include <glib-object.h>
28
29 /**
30 * SECTION:client
31 * @title: DConfClient
32 * @short_description: Direct read and write access to dconf, based on GDBus
33 *
34 * This is the primary client interface to dconf.
35 *
36 * It allows applications to directly read from and write to the dconf
37 * database. Applications can subscribe to change notifications.
38 *
39 * Most applications probably don't want to access dconf directly and
40 * would be better off using something like #GSettings.
41 *
42 * Please note that the API of libdconf is not stable in any way. It
43 * has changed in incompatible ways in the past and there will be
44 * further changes in the future.
45 **/
46
47 /**
48 * DConfClient:
49 *
50 * The main object for interacting with dconf. This is a #GObject, so
51 * you should manage it with g_object_ref() and g_object_unref().
52 **/
53 struct _DConfClient
54 {
55 GObject parent_instance;
56
57 DConfEngine *engine;
58 GMainContext *context;
59 };
60
61 G_DEFINE_TYPE (DConfClient, dconf_client, G_TYPE_OBJECT)
62
63 enum
64 {
65 SIGNAL_CHANGED,
66 SIGNAL_WRITABILITY_CHANGED,
67 N_SIGNALS
68 };
69 static guint dconf_client_signals[N_SIGNALS];
70
71 static void
dconf_client_finalize(GObject * object)72 dconf_client_finalize (GObject *object)
73 {
74 DConfClient *client = DCONF_CLIENT (object);
75
76 dconf_engine_unref (client->engine);
77 g_main_context_unref (client->context);
78
79 G_OBJECT_CLASS (dconf_client_parent_class)
80 ->finalize (object);
81 }
82
83 static void
dconf_client_init(DConfClient * client)84 dconf_client_init (DConfClient *client)
85 {
86 }
87
88 static void
dconf_client_class_init(DConfClientClass * class)89 dconf_client_class_init (DConfClientClass *class)
90 {
91 GObjectClass *object_class = G_OBJECT_CLASS (class);
92
93 object_class->finalize = dconf_client_finalize;
94
95 /**
96 * DConfClient::changed:
97 * @client: the #DConfClient reporting the change
98 * @prefix: the prefix under which the changes happened
99 * @changes: the list of paths that were changed, relative to @prefix
100 * @tag: the tag for the change, if it originated from the service
101 *
102 * This signal is emitted when the #DConfClient has a possible change
103 * to report. The signal is an indication that a change may have
104 * occurred; it's possible that the keys will still have the same value
105 * as before.
106 *
107 * To ensure that you receive notification about changes to paths that
108 * you are interested in you must call dconf_client_watch_fast() or
109 * dconf_client_watch_sync(). You may still receive notifications for
110 * paths that you did not explicitly watch.
111 *
112 * @prefix will be an absolute dconf path; see dconf_is_path().
113 * @changes is a %NULL-terminated array of dconf rel paths; see
114 * dconf_is_rel_path().
115 *
116 * @tag is an opaque tag string, or %NULL. The only thing you should
117 * do with @tag is to compare it to tag values returned by
118 * dconf_client_write_sync() or dconf_client_change_sync().
119 *
120 * The number of changes being reported is equal to the length of
121 * @changes. Appending each item in @changes to @prefix will give the
122 * absolute path of each changed item.
123 *
124 * If a single key has changed then @prefix will be equal to the key
125 * and @changes will contain a single item: the empty string.
126 *
127 * If a single dir has changed (indicating that any key under the dir
128 * may have changed) then @prefix will be equal to the dir and
129 * @changes will contain a single empty string.
130 *
131 * If more than one change is being reported then @changes will have
132 * more than one item.
133 **/
134 dconf_client_signals[SIGNAL_CHANGED] = g_signal_new ("changed", DCONF_TYPE_CLIENT, G_SIGNAL_RUN_LAST,
135 0, NULL, NULL, NULL, G_TYPE_NONE, 3,
136 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
137 G_TYPE_STRV | G_SIGNAL_TYPE_STATIC_SCOPE,
138 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
139
140 /**
141 * DConfClient::writability-changed:
142 * @client: the #DConfClient reporting the change
143 * @path: the dir or key that changed
144 *
145 * Signal emitted when writability for a key (or all keys in a dir) changes.
146 * It will be immediately followed by #DConfClient::changed signal for
147 * the path.
148 */
149 dconf_client_signals[SIGNAL_WRITABILITY_CHANGED] = g_signal_new ("writability-changed", DCONF_TYPE_CLIENT,
150 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
151 G_TYPE_NONE, 1,
152 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
153 }
154
155 typedef struct
156 {
157 DConfClient *client;
158 gchar *prefix;
159 gchar **changes;
160 gchar *tag;
161 gboolean is_writability;
162 } DConfClientChange;
163
164 static gboolean
dconf_client_dispatch_change_signal(gpointer user_data)165 dconf_client_dispatch_change_signal (gpointer user_data)
166 {
167 DConfClientChange *change = user_data;
168
169 if (change->is_writability)
170 {
171 /* We know that the engine does it this way... */
172 g_assert (change->changes[0][0] == '\0' && change->changes[1] == NULL);
173
174 g_signal_emit (change->client,
175 dconf_client_signals[SIGNAL_WRITABILITY_CHANGED], 0,
176 change->prefix);
177 }
178
179 g_signal_emit (change->client, dconf_client_signals[SIGNAL_CHANGED], 0,
180 change->prefix, change->changes, change->tag);
181
182 g_object_unref (change->client);
183 g_free (change->prefix);
184 g_strfreev (change->changes);
185 g_free (change->tag);
186 g_slice_free (DConfClientChange, change);
187
188 return G_SOURCE_REMOVE;
189 }
190
191 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)192 dconf_engine_change_notify (DConfEngine *engine,
193 const gchar *prefix,
194 const gchar * const *changes,
195 const gchar * tag,
196 gboolean is_writability,
197 gpointer origin_tag,
198 gpointer user_data)
199 {
200 GWeakRef *weak_ref = user_data;
201 DConfClientChange *change;
202 DConfClient *client;
203
204 client = g_weak_ref_get (weak_ref);
205
206 if (client == NULL)
207 return;
208
209 g_return_if_fail (DCONF_IS_CLIENT (client));
210
211 change = g_slice_new (DConfClientChange);
212 change->client = client;
213 change->prefix = g_strdup (prefix);
214 change->changes = g_strdupv ((gchar **) changes);
215 change->tag = g_strdup (tag);
216 change->is_writability = is_writability;
217
218 g_main_context_invoke (client->context, dconf_client_dispatch_change_signal, change);
219 }
220
221 static void
dconf_client_free_weak_ref(gpointer data)222 dconf_client_free_weak_ref (gpointer data)
223 {
224 GWeakRef *weak_ref = data;
225
226 g_weak_ref_clear (weak_ref);
227 g_slice_free (GWeakRef, weak_ref);
228 }
229
230 /**
231 * dconf_client_new:
232 *
233 * Creates a new #DConfClient.
234 *
235 * Returns: (transfer full): a new #DConfClient
236 **/
237 DConfClient *
dconf_client_new(void)238 dconf_client_new (void)
239 {
240 DConfClient *client;
241 GWeakRef *weak_ref;
242
243 client = g_object_new (DCONF_TYPE_CLIENT, NULL);
244 weak_ref = g_slice_new (GWeakRef);
245 g_weak_ref_init (weak_ref, client);
246 client->engine = dconf_engine_new (NULL, weak_ref, dconf_client_free_weak_ref);
247 client->context = g_main_context_ref_thread_default ();
248
249 return client;
250 }
251
252 /**
253 * dconf_client_read:
254 * @client: a #DConfClient
255 * @key: the key to read the value of
256 *
257 * Reads the current value of @key.
258 *
259 * If @key exists, its value is returned. Otherwise, %NULL is returned.
260 *
261 * If there are outstanding "fast" changes in progress they may affect
262 * the result of this call.
263 *
264 * Returns: (transfer full) (nullable): a #GVariant, or %NULL
265 **/
266 GVariant *
dconf_client_read(DConfClient * client,const gchar * key)267 dconf_client_read (DConfClient *client,
268 const gchar *key)
269 {
270 g_return_val_if_fail (DCONF_IS_CLIENT (client), NULL);
271
272 return dconf_engine_read (client->engine, DCONF_READ_FLAGS_NONE, NULL, key);
273 }
274
275 /**
276 * DConfReadFlags:
277 * @DCONF_READ_FLAGS_NONE: no flags
278 * @DCONF_READ_DEFAULT_VALUE: read the default value, ignoring any
279 * values in writable databases or any queued changes. This is
280 * effectively equivalent to asking what value would be read after a
281 * reset was written for the key in question.
282 * @DCONF_READ_USER_VALUE: read the user value, ignoring any system
283 * databases, including ignoring locks. It is even possible to read
284 * "invisible" values in the user database in this way, which would
285 * have normally been ignored because of locks.
286 *
287 * Since: 0.26
288 */
289
290 /**
291 * dconf_client_read_full:
292 * @client: a #DConfClient
293 * @key: the key to read the default value of
294 * @flags: #DConfReadFlags
295 * @read_through: a #GQueue of #DConfChangeset
296 *
297 * Reads the current value of @key.
298 *
299 * If @flags contains %DCONF_READ_USER_VALUE then only the user value
300 * will be read. Locks are ignored, which means that it is possible to
301 * use this API to read "invisible" user values which are hidden by
302 * system locks.
303 *
304 * If @flags contains %DCONF_READ_DEFAULT_VALUE then only non-user
305 * values will be read. The result will be exactly equivalent to the
306 * value that would be read if the current value of the key were to be
307 * reset.
308 *
309 * Flags may not contain both %DCONF_READ_USER_VALUE and
310 * %DCONF_READ_DEFAULT_VALUE.
311 *
312 * If @read_through is non-%NULL, %DCONF_READ_DEFAULT_VALUE is not
313 * given then @read_through is checked for the key in question, subject
314 * to the restriction that the key in question is writable. This
315 * effectively answers the question of "what would happen if these
316 * changes were committed".
317 *
318 * If there are outstanding "fast" changes in progress they may affect
319 * the result of this call.
320 *
321 * If @flags is %DCONF_READ_FLAGS_NONE and @read_through is %NULL then
322 * this call is exactly equivalent to dconf_client_read().
323 *
324 * Returns: (transfer full) (nullable): a #GVariant, or %NULL
325 *
326 * Since: 0.26
327 */
328 GVariant *
dconf_client_read_full(DConfClient * client,const gchar * key,DConfReadFlags flags,const GQueue * read_through)329 dconf_client_read_full (DConfClient *client,
330 const gchar *key,
331 DConfReadFlags flags,
332 const GQueue *read_through)
333 {
334 g_return_val_if_fail (DCONF_IS_CLIENT (client), NULL);
335
336 return dconf_engine_read (client->engine, flags, read_through, key);
337 }
338
339 /**
340 * dconf_client_list:
341 * @client: a #DConfClient
342 * @dir: the dir to list the contents of
343 * @length: the length of the returned list
344 *
345 * Gets the list of all dirs and keys immediately under @dir.
346 *
347 * If @length is non-%NULL then it will be set to the length of the
348 * returned array. In any case, the array is %NULL-terminated.
349 *
350 * IF there are outstanding "fast" changes in progress then this call
351 * may return inaccurate results with respect to those outstanding
352 * changes.
353 *
354 * Returns: (transfer full) (not nullable): an array of strings, never %NULL.
355 **/
356 gchar **
dconf_client_list(DConfClient * client,const gchar * dir,gint * length)357 dconf_client_list (DConfClient *client,
358 const gchar *dir,
359 gint *length)
360 {
361 g_return_val_if_fail (DCONF_IS_CLIENT (client), NULL);
362
363 return dconf_engine_list (client->engine, dir, length);
364 }
365
366 /**
367 * dconf_client_list_locks:
368 * @client: a #DConfClient
369 * @dir: the dir to limit results to
370 * @length: the length of the returned list.
371 *
372 * Lists all locks under @dir in effect for @client.
373 *
374 * If no locks are in effect, an empty list is returned. If no keys are
375 * writable at all then a list containing @dir is returned.
376 *
377 * The returned list will be %NULL-terminated.
378 *
379 * Returns: (transfer full) (not nullable): an array of strings, never %NULL.
380 *
381 * Since: 0.26
382 */
383 gchar **
dconf_client_list_locks(DConfClient * client,const gchar * dir,gint * length)384 dconf_client_list_locks (DConfClient *client,
385 const gchar *dir,
386 gint *length)
387 {
388 g_return_val_if_fail (DCONF_IS_CLIENT (client), NULL);
389 g_return_val_if_fail (dconf_is_dir (dir, NULL), NULL);
390
391 return dconf_engine_list_locks (client->engine, dir, length);
392 }
393
394 /**
395 * dconf_client_is_writable:
396 * @client: a #DConfClient
397 * @key: the key to check for writability
398 *
399 * Checks if @key is writable (ie: the key has no locks).
400 *
401 * This call does not verify that writing to the key will actually be
402 * successful. It only checks that the database is writable and that
403 * there are no locks affecting @key. Other issues (such as a full disk
404 * or an inability to connect to the bus and start the service) may
405 * cause the write to fail.
406 *
407 * Returns: %TRUE if @key is writable
408 **/
409 gboolean
dconf_client_is_writable(DConfClient * client,const gchar * key)410 dconf_client_is_writable (DConfClient *client,
411 const gchar *key)
412 {
413 g_return_val_if_fail (DCONF_IS_CLIENT (client), FALSE);
414
415 return dconf_engine_is_writable (client->engine, key);
416 }
417
418 /**
419 * dconf_client_write_fast:
420 * @client: a #DConfClient
421 * @key: the key to write to
422 * @value: a #GVariant, the value to write. If it has a floating reference it's
423 * consumed.
424 * @error: a pointer to a %NULL #GError, or %NULL
425 *
426 * Writes @value to the given @key, or reset @key to its default value.
427 *
428 * If @value is %NULL then @key is reset to its default value (which may
429 * be completely unset), otherwise @value becomes the new value.
430 *
431 * This call merely queues up the write and returns immediately, without
432 * blocking. The only errors that can be detected or reported at this
433 * point are attempts to write to read-only keys. If the application
434 * exits immediately after this function returns then the queued call
435 * may never be sent; see dconf_client_sync().
436 *
437 * A local copy of the written value is kept so that calls to
438 * dconf_client_read() that occur before the service actually makes the
439 * change will return the new value.
440 *
441 * If the write is queued then a change signal will be directly emitted.
442 * If this function is being called from the main context of @client
443 * then the signal is emitted before this function returns; otherwise it
444 * is scheduled on the main context.
445 *
446 * Returns: %TRUE if the write was queued
447 **/
448 gboolean
dconf_client_write_fast(DConfClient * client,const gchar * key,GVariant * value,GError ** error)449 dconf_client_write_fast (DConfClient *client,
450 const gchar *key,
451 GVariant *value,
452 GError **error)
453 {
454 DConfChangeset *changeset;
455 gboolean success;
456
457 g_return_val_if_fail (DCONF_IS_CLIENT (client), FALSE);
458
459 changeset = dconf_changeset_new_write (key, value);
460 success = dconf_engine_change_fast (client->engine, changeset, NULL, error);
461 dconf_changeset_unref (changeset);
462
463 return success;
464 }
465
466 /**
467 * dconf_client_write_sync:
468 * @client: a #DConfClient
469 * @key: the key to write to
470 * @value: a #GVariant, the value to write. If it has a floating reference it's
471 * consumed.
472 * @tag: (out) (optional) (not nullable) (transfer full): the tag from this write
473 * @cancellable: a #GCancellable, or %NULL
474 * @error: a pointer to a %NULL #GError, or %NULL
475 *
476 * Write @value to the given @key, or reset @key to its default value.
477 *
478 * If @value is %NULL then @key is reset to its default value (which may
479 * be completely unset), otherwise @value becomes the new value.
480 *
481 * This call blocks until the write is complete. This call will
482 * therefore detect and report all cases of failure. If the modified
483 * key is currently being watched then a signal will be emitted from the
484 * main context of @client (once the signal arrives from the service).
485 *
486 * If @tag is non-%NULL then it is set to the unique tag associated with
487 * this write. This is the same tag that will appear in the following
488 * change signal.
489 *
490 * Returns: %TRUE on success, else %FALSE with @error set
491 **/
492 gboolean
dconf_client_write_sync(DConfClient * client,const gchar * key,GVariant * value,gchar ** tag,GCancellable * cancellable,GError ** error)493 dconf_client_write_sync (DConfClient *client,
494 const gchar *key,
495 GVariant *value,
496 gchar **tag,
497 GCancellable *cancellable,
498 GError **error)
499 {
500 DConfChangeset *changeset;
501 gboolean success;
502
503 g_return_val_if_fail (DCONF_IS_CLIENT (client), FALSE);
504
505 changeset = dconf_changeset_new_write (key, value);
506 success = dconf_engine_change_sync (client->engine, changeset, tag, error);
507 dconf_changeset_unref (changeset);
508
509 return success;
510 }
511
512 /**
513 * dconf_client_change_fast:
514 * @client: a #DConfClient
515 * @changeset: the changeset describing the requested change
516 * @error: a pointer to a %NULL #GError, or %NULL
517 *
518 * Performs the change operation described by @changeset.
519 *
520 * Once @changeset is passed to this call it can no longer be modified.
521 *
522 * This call merely queues up the write and returns immediately, without
523 * blocking. The only errors that can be detected or reported at this
524 * point are attempts to write to read-only keys. If the application
525 * exits immediately after this function returns then the queued call
526 * may never be sent; see dconf_client_sync().
527 *
528 * A local copy of the written value is kept so that calls to
529 * dconf_client_read() that occur before the service actually makes the
530 * change will return the new value.
531 *
532 * If the write is queued then a change signal will be directly emitted.
533 * If this function is being called from the main context of @client
534 * then the signal is emitted before this function returns; otherwise it
535 * is scheduled on the main context.
536 *
537 * Returns: %TRUE if the requested changed was queued
538 **/
539 gboolean
dconf_client_change_fast(DConfClient * client,DConfChangeset * changeset,GError ** error)540 dconf_client_change_fast (DConfClient *client,
541 DConfChangeset *changeset,
542 GError **error)
543 {
544 g_return_val_if_fail (DCONF_IS_CLIENT (client), FALSE);
545
546 return dconf_engine_change_fast (client->engine, changeset, NULL, error);
547 }
548
549 /**
550 * dconf_client_change_sync:
551 * @client: a #DConfClient
552 * @changeset: the changeset describing the requested change
553 * @tag: (out) (optional) (not nullable) (transfer full): the tag from this write
554 * @cancellable: a #GCancellable, or %NULL
555 * @error: a pointer to a %NULL #GError, or %NULL
556 *
557 * Performs the change operation described by @changeset.
558 *
559 * Once @changeset is passed to this call it can no longer be modified.
560 *
561 * This call blocks until the change is complete. This call will
562 * therefore detect and report all cases of failure. If any of the
563 * modified keys are currently being watched then a signal will be
564 * emitted from the main context of @client (once the signal arrives
565 * from the service).
566 *
567 * If @tag is non-%NULL then it is set to the unique tag associated with
568 * this change. This is the same tag that will appear in the following
569 * change signal. If @changeset makes no changes then @tag may be
570 * non-unique (eg: the empty string may be used for empty changesets).
571 *
572 * Returns: %TRUE on success, else %FALSE with @error set
573 **/
574 gboolean
dconf_client_change_sync(DConfClient * client,DConfChangeset * changeset,gchar ** tag,GCancellable * cancellable,GError ** error)575 dconf_client_change_sync (DConfClient *client,
576 DConfChangeset *changeset,
577 gchar **tag,
578 GCancellable *cancellable,
579 GError **error)
580 {
581 g_return_val_if_fail (DCONF_IS_CLIENT (client), FALSE);
582
583 return dconf_engine_change_sync (client->engine, changeset, tag, error);
584 }
585
586 /**
587 * dconf_client_watch_fast:
588 * @client: a #DConfClient
589 * @path: a path to watch
590 *
591 * Requests change notifications for @path.
592 *
593 * If @path is a key then the single key is monitored. If @path is a
594 * dir then all keys under the dir are monitored.
595 *
596 * This function queues the watch request with D-Bus and returns
597 * immediately. There is a very slim chance that the dconf database
598 * could change before the watch is actually established. If that is
599 * the case then a synthetic change signal will be emitted.
600 *
601 * Errors are silently ignored.
602 **/
603 void
dconf_client_watch_fast(DConfClient * client,const gchar * path)604 dconf_client_watch_fast (DConfClient *client,
605 const gchar *path)
606 {
607 g_return_if_fail (DCONF_IS_CLIENT (client));
608
609 dconf_engine_watch_fast (client->engine, path);
610 }
611
612 /**
613 * dconf_client_watch_sync:
614 * @client: a #DConfClient
615 * @path: a path to watch
616 *
617 * Requests change notifications for @path.
618 *
619 * If @path is a key then the single key is monitored. If @path is a
620 * dir then all keys under the dir are monitored.
621 *
622 * This function submits each of the various watch requests that are
623 * required to monitor a key and waits until each of them returns. By
624 * the time this function returns, the watch has been established.
625 *
626 * Errors are silently ignored.
627 **/
628 void
dconf_client_watch_sync(DConfClient * client,const gchar * path)629 dconf_client_watch_sync (DConfClient *client,
630 const gchar *path)
631 {
632 g_return_if_fail (DCONF_IS_CLIENT (client));
633
634 dconf_engine_watch_sync (client->engine, path);
635 }
636
637 /**
638 * dconf_client_unwatch_fast:
639 * @client: a #DConfClient
640 * @path: a path previously watched
641 *
642 * Cancels the effect of a previous call to dconf_client_watch_fast().
643 *
644 * This call returns immediately.
645 *
646 * It is still possible that change signals are received after this call
647 * had returned (watching guarantees notification of changes, but
648 * unwatching does not guarantee no notifications).
649 **/
650 void
dconf_client_unwatch_fast(DConfClient * client,const gchar * path)651 dconf_client_unwatch_fast (DConfClient *client,
652 const gchar *path)
653 {
654 g_return_if_fail (DCONF_IS_CLIENT (client));
655
656 dconf_engine_unwatch_fast (client->engine, path);
657 }
658
659 /**
660 * dconf_client_unwatch_sync:
661 * @client: a #DConfClient
662 * @path: a path previously watched
663 *
664 * Cancels the effect of a previous call to dconf_client_watch_sync().
665 *
666 * This function submits each of the various unwatch requests and waits
667 * until each of them returns. It is still possible that change signals
668 * are received after this call has returned (watching guarantees
669 * notification of changes, but unwatching does not guarantee no
670 * notifications).
671 **/
672 void
dconf_client_unwatch_sync(DConfClient * client,const gchar * path)673 dconf_client_unwatch_sync (DConfClient *client,
674 const gchar *path)
675 {
676 g_return_if_fail (DCONF_IS_CLIENT (client));
677
678 dconf_engine_unwatch_sync (client->engine, path);
679 }
680
681 /**
682 * dconf_client_sync:
683 * @client: a #DConfClient
684 *
685 * Blocks until all outstanding "fast" change or write operations have
686 * been submitted to the service.
687 *
688 * Applications should generally call this before exiting on any
689 * #DConfClient that they wrote to.
690 **/
691 void
dconf_client_sync(DConfClient * client)692 dconf_client_sync (DConfClient *client)
693 {
694 g_return_if_fail (DCONF_IS_CLIENT (client));
695
696 dconf_engine_sync (client->engine);
697 }
698