Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-context"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libpeas.h>
10 : :
11 : : #include "valent-context.h"
12 : : #include "valent-debug.h"
13 : : #include "valent-macros.h"
14 : : #include "valent-object.h"
15 : :
16 : :
17 : : /**
18 : : * ValentContext:
19 : : *
20 : : * A class representing a abstract data context.
21 : : *
22 : : * `ValentContext` is an abstraction of a data context, with a loose hierarchy
23 : : * expressed as a virtual path (e.g. `device/0123456789abcdef/plugin/battery`).
24 : : * It can be used to coordinate persistent data of various types by mapping onto
25 : : * existing hierarchies like [class@Gio.Settings] (i.e. relocatable schemas),
26 : : * on-disk caches and configuration files (i.e. XDG data dirs) and user files
27 : : * (i.e. XDG user dirs).
28 : : *
29 : : * Since: 1.0
30 : : */
31 : :
32 : : typedef struct
33 : : {
34 : : ValentContext *parent;
35 : :
36 : : char *domain;
37 : : char *id;
38 : : char *path;
39 : :
40 : : GFile *cache;
41 : : GFile *config;
42 : : GFile *data;
43 : : } ValentContextPrivate;
44 : :
45 [ + + + - ]: 7293 : G_DEFINE_TYPE_WITH_PRIVATE (ValentContext, valent_context, VALENT_TYPE_OBJECT)
46 : :
47 : : enum {
48 : : PROP_0,
49 : : PROP_DOMAIN,
50 : : PROP_ID,
51 : : PROP_PARENT,
52 : : N_PROPERTIES
53 : : };
54 : :
55 : : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
56 : :
57 : :
58 : : static inline gboolean
59 : 77 : ensure_directory (GFile *dir)
60 : : {
61 [ + - + - : 77 : g_assert (G_IS_FILE (dir));
+ - - + ]
62 : :
63 [ - + ]: 77 : if (g_mkdir_with_parents (g_file_peek_path (dir), 0700) == -1)
64 : : {
65 : 0 : VALENT_NOTE ("Failed to create \"%s\": %s",
66 : : g_file_peek_path (dir),
67 : : g_strerror (errno));
68 : 0 : return FALSE;
69 : : }
70 : :
71 : : return TRUE;
72 : : }
73 : :
74 : : static gboolean
75 : 30 : remove_directory (GFile *file,
76 : : GCancellable *cancellable,
77 : : GError **error)
78 : : {
79 : 60 : g_autoptr (GFileEnumerator) iter = NULL;
80 : :
81 [ + - + - : 30 : g_assert (G_IS_FILE (file));
+ - - + ]
82 [ - + - - : 30 : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
83 [ + - - + ]: 30 : g_assert (error == NULL || *error == NULL);
84 : :
85 : 30 : iter = g_file_enumerate_children (file,
86 : : G_FILE_ATTRIBUTE_STANDARD_NAME,
87 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
88 : : cancellable,
89 : : NULL);
90 : :
91 [ + + ]: 42 : while (iter != NULL)
92 : : {
93 : 21 : GFile *child;
94 : :
95 [ + - ]: 21 : if (!g_file_enumerator_iterate (iter, NULL, &child, cancellable, error))
96 : 0 : return FALSE;
97 : :
98 [ + + ]: 21 : if (child == NULL)
99 : : break;
100 : :
101 [ + - ]: 12 : if (!remove_directory (child, cancellable, error))
102 : : return FALSE;
103 : : }
104 : :
105 : 30 : return g_file_delete (file, cancellable, error);
106 : : }
107 : :
108 : : /*
109 : : * GObject
110 : : */
111 : : static void
112 : 688 : valent_context_constructed (GObject *object)
113 : : {
114 : 688 : ValentContext *self = VALENT_CONTEXT (object);
115 : 688 : ValentContextPrivate *priv = valent_context_get_instance_private (self);
116 : :
117 [ + + ]: 688 : if (priv->parent != NULL)
118 : : {
119 : 458 : const char *base_path;
120 : :
121 : 458 : base_path = valent_context_get_path (priv->parent);
122 : 458 : priv->path = g_build_filename (base_path, priv->domain, priv->id, NULL);
123 : : }
124 : : else
125 : : {
126 : 230 : priv->path = g_build_filename (priv->domain, priv->id, NULL);
127 : : }
128 : :
129 : 688 : priv->cache = g_file_new_build_filename (g_get_user_cache_dir (),
130 : : PACKAGE_NAME,
131 : : priv->path,
132 : : NULL);
133 : 688 : priv->config = g_file_new_build_filename (g_get_user_config_dir (),
134 : : PACKAGE_NAME,
135 : : priv->path,
136 : : NULL);
137 : 688 : priv->data = g_file_new_build_filename (g_get_user_data_dir (),
138 : : PACKAGE_NAME,
139 : : priv->path,
140 : : NULL);
141 : :
142 : 688 : G_OBJECT_CLASS (valent_context_parent_class)->constructed (object);
143 : 688 : }
144 : :
145 : : static void
146 : 643 : valent_context_finalize (GObject *object)
147 : : {
148 : 643 : ValentContext *self = VALENT_CONTEXT (object);
149 : 643 : ValentContextPrivate *priv = valent_context_get_instance_private (self);
150 : :
151 [ + - ]: 643 : g_clear_object (&priv->cache);
152 [ + - ]: 643 : g_clear_object (&priv->config);
153 [ + - ]: 643 : g_clear_object (&priv->data);
154 [ + - ]: 643 : g_clear_pointer (&priv->path, g_free);
155 [ + + ]: 643 : g_clear_pointer (&priv->domain, g_free);
156 [ + + ]: 643 : g_clear_pointer (&priv->id, g_free);
157 : :
158 : 643 : G_OBJECT_CLASS (valent_context_parent_class)->finalize (object);
159 : 643 : }
160 : :
161 : : static void
162 : 0 : valent_context_get_property (GObject *object,
163 : : guint prop_id,
164 : : GValue *value,
165 : : GParamSpec *pspec)
166 : : {
167 : 0 : ValentContext *self = VALENT_CONTEXT (object);
168 : :
169 [ # # # # ]: 0 : switch (prop_id)
170 : : {
171 : 0 : case PROP_DOMAIN:
172 : 0 : g_value_set_string (value, valent_context_get_domain (self));
173 : 0 : break;
174 : :
175 : 0 : case PROP_ID:
176 : 0 : g_value_set_string (value, valent_context_get_id (self));
177 : 0 : break;
178 : :
179 : 0 : case PROP_PARENT:
180 : 0 : g_value_set_object (value, valent_context_get_parent (self));
181 : 0 : break;
182 : :
183 : 0 : default:
184 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185 : : }
186 : 0 : }
187 : :
188 : : static void
189 : 2064 : valent_context_set_property (GObject *object,
190 : : guint prop_id,
191 : : const GValue *value,
192 : : GParamSpec *pspec)
193 : : {
194 : 2064 : ValentContext *self = VALENT_CONTEXT (object);
195 : 2064 : ValentContextPrivate *priv = valent_context_get_instance_private (self);
196 : :
197 [ + + + - ]: 2064 : switch (prop_id)
198 : : {
199 : 688 : case PROP_DOMAIN:
200 : 688 : priv->domain = g_value_dup_string (value);
201 : 688 : break;
202 : :
203 : 688 : case PROP_ID:
204 : 688 : priv->id = g_value_dup_string (value);
205 : 688 : break;
206 : :
207 : 688 : case PROP_PARENT:
208 : 688 : priv->parent = g_value_get_object (value);
209 : 688 : break;
210 : :
211 : 0 : default:
212 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213 : : }
214 : 2064 : }
215 : :
216 : : static void
217 : 51 : valent_context_class_init (ValentContextClass *klass)
218 : : {
219 : 51 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
220 : :
221 : 51 : object_class->constructed = valent_context_constructed;
222 : 51 : object_class->finalize = valent_context_finalize;
223 : 51 : object_class->get_property = valent_context_get_property;
224 : 51 : object_class->set_property = valent_context_set_property;
225 : :
226 : : /**
227 : : * ValentContext:domain: (getter get_domain)
228 : : *
229 : : * The domain for this context.
230 : : *
231 : : * Since: 1.0
232 : : */
233 : 102 : properties [PROP_DOMAIN] =
234 : 51 : g_param_spec_string ("domain", NULL, NULL,
235 : : NULL,
236 : : (G_PARAM_READWRITE |
237 : : G_PARAM_CONSTRUCT_ONLY |
238 : : G_PARAM_EXPLICIT_NOTIFY |
239 : : G_PARAM_STATIC_STRINGS));
240 : :
241 : : /**
242 : : * ValentContext:id: (getter get_id)
243 : : *
244 : : * The ID for this context.
245 : : *
246 : : * Since: 1.0
247 : : */
248 : 102 : properties [PROP_ID] =
249 : 51 : g_param_spec_string ("id", NULL, NULL,
250 : : NULL,
251 : : (G_PARAM_READWRITE |
252 : : G_PARAM_CONSTRUCT_ONLY |
253 : : G_PARAM_EXPLICIT_NOTIFY |
254 : : G_PARAM_STATIC_STRINGS));
255 : :
256 : : /**
257 : : * ValentContext:parent: (getter get_parent)
258 : : *
259 : : * The parent context.
260 : : *
261 : : * Since: 1.0
262 : : */
263 : 102 : properties [PROP_PARENT] =
264 : 51 : g_param_spec_object ("parent", NULL, NULL,
265 : : VALENT_TYPE_CONTEXT,
266 : : (G_PARAM_READWRITE |
267 : : G_PARAM_CONSTRUCT_ONLY |
268 : : G_PARAM_EXPLICIT_NOTIFY |
269 : : G_PARAM_STATIC_STRINGS));
270 : :
271 : 51 : g_object_class_install_properties (object_class, N_PROPERTIES, properties);
272 : 51 : }
273 : :
274 : : static void
275 : 688 : valent_context_init (ValentContext *self)
276 : : {
277 : 688 : }
278 : :
279 : : /**
280 : : * valent_context_new:
281 : : * @parent: (nullable): a parent context
282 : : * @domain: (nullable): a domain
283 : : * @id: (nullable): a unique identifier
284 : : *
285 : : * Create a new `ValentContext`.
286 : : *
287 : : * If given, @parent will be taken into consideration when building paths.
288 : : *
289 : : * If given, @domain should be an identifier describing the scope of the
290 : : * contexts that will share it.
291 : : *
292 : : * If given, @id should be an identifier that is at least unique to @domain,
293 : : * even if @domain is %NULL.
294 : : *
295 : : * Returns: (transfer full): a new `ValentContext`.
296 : : *
297 : : * Since: 1.0
298 : : */
299 : : ValentContext *
300 : 261 : valent_context_new (ValentContext *parent,
301 : : const char *domain,
302 : : const char *id)
303 : : {
304 : 261 : return g_object_new (VALENT_TYPE_CONTEXT,
305 : : "domain", domain,
306 : : "id", id,
307 : : "parent", parent,
308 : : NULL);
309 : : }
310 : :
311 : : /**
312 : : * valent_context_get_domain: (get-property domain)
313 : : * @context: a `ValentContext`
314 : : *
315 : : * Get the context domain.
316 : : *
317 : : * Returns: (transfer none): the context domain
318 : : *
319 : : * Since: 1.0
320 : : */
321 : : const char *
322 : 63 : valent_context_get_domain (ValentContext *context)
323 : : {
324 : 63 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
325 : :
326 [ + - ]: 63 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
327 : :
328 : 63 : return priv->domain;
329 : : }
330 : :
331 : : /**
332 : : * valent_context_get_id: (get-property id)
333 : : * @context: a `ValentContext`
334 : : *
335 : : * Get the context ID.
336 : : *
337 : : * Returns: (transfer none): the context ID
338 : : *
339 : : * Since: 1.0
340 : : */
341 : : const char *
342 : 3 : valent_context_get_id (ValentContext *context)
343 : : {
344 : 3 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
345 : :
346 [ + - ]: 3 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
347 : :
348 : 3 : return priv->id;
349 : : }
350 : :
351 : : /**
352 : : * valent_context_get_parent: (get-property parent)
353 : : * @context: a `ValentContext`
354 : : *
355 : : * Get the parent context.
356 : : *
357 : : * Returns: (transfer none) (nullable): a `ValentContext`
358 : : */
359 : : ValentContext *
360 : 1 : valent_context_get_parent (ValentContext *context)
361 : : {
362 : 1 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
363 : :
364 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
365 : :
366 : 1 : return priv->parent;
367 : : }
368 : :
369 : : /**
370 : : * valent_context_get_path:
371 : : * @context: a `ValentContext`
372 : : *
373 : : * Get the virtual path.
374 : : *
375 : : * Returns: (transfer none): a relative path
376 : : *
377 : : * Since: 1.0
378 : : */
379 : : const char *
380 : 458 : valent_context_get_path (ValentContext *context)
381 : : {
382 : 458 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
383 : :
384 [ + - ]: 458 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
385 : :
386 : 458 : return priv->path;
387 : : }
388 : :
389 : : /**
390 : : * valent_context_clear_cache:
391 : : * @context: a `ValentContext`
392 : : *
393 : : * Clear cache data.
394 : : *
395 : : * The method will remove all files in the cache directory.
396 : : *
397 : : * Since: 1.0
398 : : */
399 : : void
400 : 4 : valent_context_clear_cache (ValentContext *context)
401 : : {
402 : 4 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
403 : 4 : g_autoptr (GError) error = NULL;
404 : :
405 [ + - - - ]: 4 : g_return_if_fail (VALENT_IS_CONTEXT (context));
406 : :
407 [ - + - - ]: 4 : if (!remove_directory (priv->cache, NULL, &error) &&
408 : 0 : !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
409 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
410 : : }
411 : :
412 : : /**
413 : : * valent_context_clear:
414 : : * @context: a `ValentContext`
415 : : *
416 : : * Clear cache and configuration data.
417 : : *
418 : : * The method will remove all files in the cache and configuration directories.
419 : : *
420 : : * Since: 1.0
421 : : */
422 : : void
423 : 7 : valent_context_clear (ValentContext *context)
424 : : {
425 : 7 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
426 : 7 : g_autoptr (GError) error = NULL;
427 : :
428 [ + - ]: 7 : g_return_if_fail (VALENT_IS_CONTEXT (context));
429 : :
430 : : /* FIXME: We have to be careful not to remove device config directories */
431 [ + - ]: 7 : if (priv->domain == NULL)
432 : : return;
433 : :
434 [ + + - + ]: 13 : if (!remove_directory (priv->cache, NULL, &error) &&
435 : 6 : !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
436 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
437 : 7 : g_clear_error (&error);
438 : :
439 [ + + - + ]: 13 : if (!remove_directory (priv->config, NULL, &error) &&
440 : 6 : !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
441 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
442 [ - + ]: 7 : g_clear_error (&error);
443 : : }
444 : :
445 : : /**
446 : : * valent_context_get_cache_file:
447 : : * @context: a `ValentContext`
448 : : * @filename: (type filename): a filename
449 : : *
450 : : * Create a new cache file.
451 : : *
452 : : * This method creates a new [iface@Gio.File] for @filename in the cache
453 : : * directory.
454 : : *
455 : : * Returns: (transfer full) (nullable): a new `GFile`
456 : : *
457 : : * Since: 1.0
458 : : */
459 : : GFile *
460 : 55 : valent_context_get_cache_file (ValentContext *context,
461 : : const char *filename)
462 : : {
463 : 55 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
464 : :
465 [ + - ]: 55 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
466 [ - + ]: 55 : g_return_val_if_fail (ensure_directory (priv->cache), NULL);
467 [ + - - + ]: 55 : g_return_val_if_fail (filename != NULL && *filename != '\0', NULL);
468 : :
469 : 55 : return g_file_get_child (priv->cache, filename);
470 : : }
471 : :
472 : : /**
473 : : * valent_context_get_config_file:
474 : : * @context: a `ValentContext`
475 : : * @filename: (type filename): a filename
476 : : *
477 : : * Create a new config file.
478 : : *
479 : : * This method creates a new [iface@Gio.File] for @filename in the config
480 : : * directory.
481 : : *
482 : : * Returns: (transfer full) (nullable): a new `GFile`
483 : : *
484 : : * Since: 1.0
485 : : */
486 : : GFile *
487 : 21 : valent_context_get_config_file (ValentContext *context,
488 : : const char *filename)
489 : : {
490 : 21 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
491 : :
492 [ + - ]: 21 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
493 [ - + ]: 21 : g_return_val_if_fail (ensure_directory (priv->config), NULL);
494 [ + - - + ]: 21 : g_return_val_if_fail (filename != NULL && *filename != '\0', NULL);
495 : :
496 : 21 : return g_file_get_child (priv->config, filename);
497 : : }
498 : :
499 : : /**
500 : : * valent_context_get_data_file:
501 : : * @context: a `ValentContext`
502 : : * @filename: (type filename): a filename
503 : : *
504 : : * Create a new data file.
505 : : *
506 : : * This method creates a new [iface@Gio.File] for @filename in the data
507 : : * directory.
508 : : *
509 : : * Returns: (transfer full) (nullable): a new `GFile`
510 : : *
511 : : * Since: 1.0
512 : : */
513 : : GFile *
514 : 1 : valent_context_get_data_file (ValentContext *context,
515 : : const char *filename)
516 : : {
517 : 1 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
518 : :
519 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
520 [ - + ]: 1 : g_return_val_if_fail (ensure_directory (priv->data), NULL);
521 [ + - - + ]: 1 : g_return_val_if_fail (filename != NULL && *filename != '\0', NULL);
522 : :
523 : 1 : return g_file_get_child (priv->data, filename);
524 : : }
525 : :
526 : : /**
527 : : * valent_context_get_plugin_context:
528 : : * @context: a `ValentContext`
529 : : * @plugin_info: a `PeasPluginInfo`
530 : : *
531 : : * Create a new `ValentContext` for a plugin.
532 : : *
533 : : * If given, @domain should be an identifier describing the scope of the
534 : : * contexts that will share it.
535 : : *
536 : : * If given, @id should be an identifier that is at least unique to @domain,
537 : : * even if @domain is %NULL.
538 : : *
539 : : * Returns: (transfer full): a new `ValentContext`.
540 : : *
541 : : * Since: 1.0
542 : : */
543 : : ValentContext *
544 : 425 : valent_context_get_plugin_context (ValentContext *context,
545 : : PeasPluginInfo *plugin_info)
546 : : {
547 [ + - ]: 425 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
548 [ - + ]: 425 : g_return_val_if_fail (plugin_info != NULL, NULL);
549 : :
550 : 425 : return g_object_new (VALENT_TYPE_CONTEXT,
551 : : "parent", context,
552 : : "domain", "plugin",
553 : : "id", peas_plugin_info_get_module_name (plugin_info),
554 : : NULL);
555 : : }
556 : :
557 : : /**
558 : : * valent_context_get_plugin_settings:
559 : : * @context: a `ValentContext`
560 : : * @plugin_info: a `PeasPluginInfo`
561 : : * @plugin_key: an external data key
562 : : *
563 : : * Create a [class@Gio.Settings] object for a plugin.
564 : : *
565 : : * If the plugin is not built-in, an attempt will be made to compile a
566 : : * [struct@Gio.SettingsSchema] for @schema_id, in the module directory of
567 : : * @plugin_info.
568 : : *
569 : : * Returns: (transfer full) (nullable): the new `GSettings` object
570 : : *
571 : : * Since: 1.0
572 : : */
573 : : GSettings *
574 : 123 : valent_context_get_plugin_settings (ValentContext *context,
575 : : PeasPluginInfo *plugin_info,
576 : : const char *plugin_key)
577 : : {
578 : 123 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
579 : 123 : GSettingsSchemaSource *default_source;
580 : 123 : const char *schema_id = NULL;
581 : 246 : g_autoptr (GSettingsSchema) schema = NULL;
582 [ + + ]: 123 : g_autofree char *path = NULL;
583 : :
584 [ + - ]: 123 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
585 [ - + ]: 123 : g_return_val_if_fail (plugin_info != NULL, NULL);
586 [ + - - + ]: 123 : g_return_val_if_fail (plugin_key != NULL && *plugin_key != '\0', NULL);
587 : :
588 : 123 : schema_id = peas_plugin_info_get_external_data (plugin_info, plugin_key);
589 : :
590 [ + + - + ]: 123 : if (schema_id == NULL || *schema_id == '\0')
591 : : return NULL;
592 : :
593 : : /* Check the default schema source first */
594 : 96 : default_source = g_settings_schema_source_get_default ();
595 : 96 : schema = g_settings_schema_source_lookup (default_source, schema_id, TRUE);
596 : :
597 : : /* Adapted from `peas-plugin-info.c` (LGPL-2.1-or-later) */
598 [ - + ]: 96 : if (schema == NULL)
599 : : {
600 : 0 : g_autoptr (GSettingsSchemaSource) source = NULL;
601 [ # # ]: 0 : g_autoptr (GFile) gschema_compiled = NULL;
602 : 0 : const char *module_dir = NULL;
603 : :
604 : 0 : module_dir = peas_plugin_info_get_module_dir (plugin_info);
605 : 0 : gschema_compiled = g_file_new_build_filename (module_dir,
606 : : "gschemas.compiled",
607 : : NULL);
608 : :
609 [ # # ]: 0 : if (!g_file_query_exists (gschema_compiled, NULL))
610 : : {
611 : 0 : const char *argv[] = {
612 : : "glib-compile-schemas",
613 : : "--targetdir", module_dir,
614 : : module_dir,
615 : : NULL
616 : : };
617 : :
618 : 0 : g_spawn_sync (NULL, (char **)argv, NULL, G_SPAWN_SEARCH_PATH,
619 : : NULL, NULL, NULL, NULL, NULL, NULL);
620 : : }
621 : :
622 : 0 : source = g_settings_schema_source_new_from_directory (module_dir,
623 : : default_source,
624 : : FALSE,
625 : : NULL);
626 : :
627 [ # # ]: 0 : if (source != NULL)
628 : 0 : schema = g_settings_schema_source_lookup (source, schema_id, TRUE);
629 : : }
630 : :
631 [ # # ]: 0 : if (schema == NULL)
632 : : {
633 : 0 : g_critical ("Settings schema '%s' not installed", schema_id);
634 : 0 : return NULL;
635 : : }
636 : :
637 : 96 : path = g_strdup_printf ("/ca/andyholmes/valent/%s/", priv->path);
638 : :
639 : 96 : return g_settings_new_full (schema, NULL, path);
640 : : }
641 : :
642 : : /**
643 : : * valent_context_get_root:
644 : : *
645 : : * Get the root context.
646 : : *
647 : : * Returns: (transfer none): a `ValentContext`
648 : : *
649 : : * Since: 1.0
650 : : */
651 : : ValentContext *
652 : 0 : valent_context_get_root (ValentContext *context)
653 : : {
654 : 0 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
655 : 0 : ValentContext *root = context;
656 : :
657 [ # # ]: 0 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
658 : :
659 [ # # ]: 0 : if (priv->parent != NULL)
660 : : root = valent_context_get_root (priv->parent);
661 : :
662 : : return root;
663 : : }
664 : :
665 : : /**
666 : : * valent_context_create_settings:
667 : : * @context: a `ValentContext`
668 : : * @schema_id: a `GSettings` schema ID
669 : : *
670 : : * Create a [class@Gio.Settings] object.
671 : : *
672 : : * This is a simple wrapper around [ctor@Gio.Settings.new_full] that creates a
673 : : * `GSettings` object for the path of @context. No attempt will be made to
674 : : * find or compile missing schemas.
675 : : *
676 : : * Returns: (transfer full) (nullable): the new `GSettings` object
677 : : *
678 : : * Since: 1.0
679 : : */
680 : : GSettings *
681 : 334 : valent_context_create_settings (ValentContext *context,
682 : : const char *schema_id)
683 : : {
684 : 334 : ValentContextPrivate *priv = valent_context_get_instance_private (context);
685 : 334 : GSettingsSchemaSource *default_source;
686 : 668 : g_autoptr (GSettingsSchema) schema = NULL;
687 [ + - ]: 334 : g_autofree char *path = NULL;
688 : :
689 [ + - ]: 334 : g_return_val_if_fail (VALENT_IS_CONTEXT (context), NULL);
690 [ + - - + ]: 334 : g_return_val_if_fail (schema_id != NULL && *schema_id != '\0', NULL);
691 : :
692 : 334 : default_source = g_settings_schema_source_get_default ();
693 : 334 : schema = g_settings_schema_source_lookup (default_source, schema_id, TRUE);
694 : :
695 [ - + ]: 334 : if (schema == NULL)
696 : : {
697 : 0 : g_critical ("Settings schema '%s' not installed", schema_id);
698 : 0 : return NULL;
699 : : }
700 : :
701 : 334 : path = g_strdup_printf ("/ca/andyholmes/valent/%s/", priv->path);
702 : :
703 : 334 : return g_settings_new_full (schema, NULL, path);
704 : : }
705 : :
|