2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2012 Canonical Limited
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.
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.
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/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
23 #include "dconf-client.h"
25 #include "../engine/dconf-engine.h"
26 #include "../common/dconf-paths.h"
27 #include <glib-object.h>
32 * @short_description: Direct read and write access to dconf, based on GDBus
34 * This is the primary client interface to dconf.
36 * It allows applications to directly read from and write to the dconf
37 * database. Applications can subscribe to change notifications.
39 * Most applications probably don't want to access dconf directly and
40 * would be better off using something like #GSettings.
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.
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().
55 GObject parent_instance
;
58 GMainContext
*context
;
61 G_DEFINE_TYPE (DConfClient
, dconf_client
, G_TYPE_OBJECT
)
66 SIGNAL_WRITABILITY_CHANGED
,
69 static guint dconf_client_signals
[N_SIGNALS
];
72 dconf_client_finalize (GObject
*object
)
74 DConfClient
*client
= DCONF_CLIENT (object
);
76 dconf_engine_unref (client
->engine
);
77 g_main_context_unref (client
->context
);
79 G_OBJECT_CLASS (dconf_client_parent_class
)
84 dconf_client_init (DConfClient
*client
)
89 dconf_client_class_init (DConfClientClass
*class)
91 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
93 object_class
->finalize
= dconf_client_finalize
;
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
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
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.
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().
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().
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.
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.
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.
131 * If more than one change is being reported then @changes will have
132 * more than one item.
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
);
141 * DConfClient::writability-changed:
142 * @client: the #DConfClient reporting the change
143 * @path: the dir or key that changed
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
149 dconf_client_signals
[SIGNAL_WRITABILITY_CHANGED
] = g_signal_new ("writability-changed", DCONF_TYPE_CLIENT
,
150 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, NULL
,
152 G_TYPE_STRING
| G_SIGNAL_TYPE_STATIC_SCOPE
);
161 gboolean is_writability
;
165 dconf_client_dispatch_change_signal (gpointer user_data
)
167 DConfClientChange
*change
= user_data
;
169 if (change
->is_writability
)
171 /* We know that the engine does it this way... */
172 g_assert (change
->changes
[0][0] == '\0' && change
->changes
[1] == NULL
);
174 g_signal_emit (change
->client
,
175 dconf_client_signals
[SIGNAL_WRITABILITY_CHANGED
], 0,
179 g_signal_emit (change
->client
, dconf_client_signals
[SIGNAL_CHANGED
], 0,
180 change
->prefix
, change
->changes
, change
->tag
);
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
);
188 return G_SOURCE_REMOVE
;
192 dconf_engine_change_notify (DConfEngine
*engine
,
194 const gchar
* const *changes
,
196 gboolean is_writability
,
200 GWeakRef
*weak_ref
= user_data
;
201 DConfClientChange
*change
;
204 client
= g_weak_ref_get (weak_ref
);
209 g_return_if_fail (DCONF_IS_CLIENT (client
));
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
;
218 g_main_context_invoke (client
->context
, dconf_client_dispatch_change_signal
, change
);
222 dconf_client_free_weak_ref (gpointer data
)
224 GWeakRef
*weak_ref
= data
;
226 g_weak_ref_clear (weak_ref
);
227 g_slice_free (GWeakRef
, weak_ref
);
233 * Creates a new #DConfClient.
235 * Returns: (transfer full): a new #DConfClient
238 dconf_client_new (void)
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 ();
254 * @client: a #DConfClient
255 * @key: the key to read the value of
257 * Reads the current value of @key.
259 * If @key exists, its value is returned. Otherwise, %NULL is returned.
261 * If there are outstanding "fast" changes in progress they may affect
262 * the result of this call.
264 * Returns: (transfer full) (nullable): a #GVariant, or %NULL
267 dconf_client_read (DConfClient
*client
,
270 g_return_val_if_fail (DCONF_IS_CLIENT (client
), NULL
);
272 return dconf_engine_read (client
->engine
, DCONF_READ_FLAGS_NONE
, NULL
, key
);
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.
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
297 * Reads the current value of @key.
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
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
309 * Flags may not contain both %DCONF_READ_USER_VALUE and
310 * %DCONF_READ_DEFAULT_VALUE.
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".
318 * If there are outstanding "fast" changes in progress they may affect
319 * the result of this call.
321 * If @flags is %DCONF_READ_FLAGS_NONE and @read_through is %NULL then
322 * this call is exactly equivalent to dconf_client_read().
324 * Returns: (transfer full) (nullable): a #GVariant, or %NULL
329 dconf_client_read_full (DConfClient
*client
,
331 DConfReadFlags flags
,
332 const GQueue
*read_through
)
334 g_return_val_if_fail (DCONF_IS_CLIENT (client
), NULL
);
336 return dconf_engine_read (client
->engine
, flags
, read_through
, key
);
341 * @client: a #DConfClient
342 * @dir: the dir to list the contents of
343 * @length: the length of the returned list
345 * Gets the list of all dirs and keys immediately under @dir.
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.
350 * IF there are outstanding "fast" changes in progress then this call
351 * may return inaccurate results with respect to those outstanding
354 * Returns: (transfer full) (not nullable): an array of strings, never %NULL.
357 dconf_client_list (DConfClient
*client
,
361 g_return_val_if_fail (DCONF_IS_CLIENT (client
), NULL
);
363 return dconf_engine_list (client
->engine
, dir
, length
);
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.
372 * Lists all locks under @dir in effect for @client.
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.
377 * The returned list will be %NULL-terminated.
379 * Returns: (transfer full) (not nullable): an array of strings, never %NULL.
384 dconf_client_list_locks (DConfClient
*client
,
388 g_return_val_if_fail (DCONF_IS_CLIENT (client
), NULL
);
389 g_return_val_if_fail (dconf_is_dir (dir
, NULL
), NULL
);
391 return dconf_engine_list_locks (client
->engine
, dir
, length
);
395 * dconf_client_is_writable:
396 * @client: a #DConfClient
397 * @key: the key to check for writability
399 * Checks if @key is writable (ie: the key has no locks).
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.
407 * Returns: %TRUE if @key is writable
410 dconf_client_is_writable (DConfClient
*client
,
413 g_return_val_if_fail (DCONF_IS_CLIENT (client
), FALSE
);
415 return dconf_engine_is_writable (client
->engine
, key
);
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
424 * @error: a pointer to a %NULL #GError, or %NULL
426 * Writes @value to the given @key, or reset @key to its default value.
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.
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().
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.
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.
446 * Returns: %TRUE if the write was queued
449 dconf_client_write_fast (DConfClient
*client
,
454 DConfChangeset
*changeset
;
457 g_return_val_if_fail (DCONF_IS_CLIENT (client
), FALSE
);
459 changeset
= dconf_changeset_new_write (key
, value
);
460 success
= dconf_engine_change_fast (client
->engine
, changeset
, NULL
, error
);
461 dconf_changeset_unref (changeset
);
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
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
476 * Write @value to the given @key, or reset @key to its default value.
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.
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).
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
490 * Returns: %TRUE on success, else %FALSE with @error set
493 dconf_client_write_sync (DConfClient
*client
,
497 GCancellable
*cancellable
,
500 DConfChangeset
*changeset
;
503 g_return_val_if_fail (DCONF_IS_CLIENT (client
), FALSE
);
505 changeset
= dconf_changeset_new_write (key
, value
);
506 success
= dconf_engine_change_sync (client
->engine
, changeset
, tag
, error
);
507 dconf_changeset_unref (changeset
);
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
518 * Performs the change operation described by @changeset.
520 * Once @changeset is passed to this call it can no longer be modified.
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().
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.
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.
537 * Returns: %TRUE if the requested changed was queued
540 dconf_client_change_fast (DConfClient
*client
,
541 DConfChangeset
*changeset
,
544 g_return_val_if_fail (DCONF_IS_CLIENT (client
), FALSE
);
546 return dconf_engine_change_fast (client
->engine
, changeset
, NULL
, error
);
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
557 * Performs the change operation described by @changeset.
559 * Once @changeset is passed to this call it can no longer be modified.
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
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).
572 * Returns: %TRUE on success, else %FALSE with @error set
575 dconf_client_change_sync (DConfClient
*client
,
576 DConfChangeset
*changeset
,
578 GCancellable
*cancellable
,
581 g_return_val_if_fail (DCONF_IS_CLIENT (client
), FALSE
);
583 return dconf_engine_change_sync (client
->engine
, changeset
, tag
, error
);
587 * dconf_client_watch_fast:
588 * @client: a #DConfClient
589 * @path: a path to watch
591 * Requests change notifications for @path.
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.
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.
601 * Errors are silently ignored.
604 dconf_client_watch_fast (DConfClient
*client
,
607 g_return_if_fail (DCONF_IS_CLIENT (client
));
609 dconf_engine_watch_fast (client
->engine
, path
);
613 * dconf_client_watch_sync:
614 * @client: a #DConfClient
615 * @path: a path to watch
617 * Requests change notifications for @path.
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.
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.
626 * Errors are silently ignored.
629 dconf_client_watch_sync (DConfClient
*client
,
632 g_return_if_fail (DCONF_IS_CLIENT (client
));
634 dconf_engine_watch_sync (client
->engine
, path
);
638 * dconf_client_unwatch_fast:
639 * @client: a #DConfClient
640 * @path: a path previously watched
642 * Cancels the effect of a previous call to dconf_client_watch_fast().
644 * This call returns immediately.
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).
651 dconf_client_unwatch_fast (DConfClient
*client
,
654 g_return_if_fail (DCONF_IS_CLIENT (client
));
656 dconf_engine_unwatch_fast (client
->engine
, path
);
660 * dconf_client_unwatch_sync:
661 * @client: a #DConfClient
662 * @path: a path previously watched
664 * Cancels the effect of a previous call to dconf_client_watch_sync().
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
673 dconf_client_unwatch_sync (DConfClient
*client
,
676 g_return_if_fail (DCONF_IS_CLIENT (client
));
678 dconf_engine_unwatch_sync (client
->engine
, path
);
683 * @client: a #DConfClient
685 * Blocks until all outstanding "fast" change or write operations have
686 * been submitted to the service.
688 * Applications should generally call this before exiting on any
689 * #DConfClient that they wrote to.
692 dconf_client_sync (DConfClient
*client
)
694 g_return_if_fail (DCONF_IS_CLIENT (client
));
696 dconf_engine_sync (client
->engine
);