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