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