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-extension"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libpeas.h>
10 : :
11 : : #include "valent-context.h"
12 : : #include "valent-core-enums.h"
13 : : #include "valent-object.h"
14 : : #include "valent-resource.h"
15 : :
16 : : #include "valent-extension.h"
17 : :
18 : :
19 : : /**
20 : : * ValentExtension:
21 : : *
22 : : * An abstract base class for extensions.
23 : : *
24 : : * `ValentExtension` is a base class for extensions with conveniences for
25 : : * [iface@Gio.Action], [class@Gio.Settings] backed by [class@Valent.Context].
26 : : *
27 : : * ## Implementation Notes
28 : : *
29 : : * Implementations that also implement [iface@Gio.Initable] or
30 : : * [iface@Gio.AsyncInitable] are marked as `VALENT_PLUGIN_STATE_INACTIVE` during
31 : : * construction and must call [method@Valent.Extension.plugin_state_changed] to
32 : : * reflect the result of initialization.
33 : : *
34 : : * ## Plugin Actions
35 : : *
36 : : * `ValentExtension` implements the [iface@Gio.ActionGroup] and
37 : : * [iface@Gio.ActionMap] interfaces, providing a simple way for plugins to
38 : : * expose functions and states. Each [iface@Gio.Action] added to the action map
39 : : * will be included in the object action group with the plugin's module name as
40 : : * a prefix (eg. `share.uri`).
41 : : *
42 : : * ## `.plugin` File
43 : : *
44 : : * Implementations may define the extra fields in the `.plugin` file, to take
45 : : * advantage of core features in the base class.
46 : : *
47 : : * The field names are inferred from the GType name of the implementation, with
48 : : * `Valent` being stripped if present. For example `ValentDevicePlugin` becomes
49 : : * `X-DevicePluginSettings`, while `NameDevicePlugin` would become
50 : : * `X-NameDevicePluginSettings`.
51 : : *
52 : : * - Extension Category Field
53 : : *
54 : : * A list of categories separated by semi-colons, serving as a hint for
55 : : * organizational purposes. This should be in the form `Main;Additional;`,
56 : : * with values from the freedesktop.org Desktop Menu Specification.
57 : : *
58 : : * Field pattern: `X-<type name>Category`
59 : : *
60 : : * - [class@Gio.Settings] Schema Field
61 : : *
62 : : * A [class@Gio.Settings] schema ID for the extensions's settings. See
63 : : * [method@Valent.Context.get_plugin_settings] for more information.
64 : : *
65 : : * Field pattern: `X-<type name>Settings`
66 : : *
67 : : * Since: 1.0
68 : : */
69 : :
70 : : typedef struct
71 : : {
72 : : PeasPluginInfo *plugin_info;
73 : : ValentPluginState plugin_state;
74 : : GError *plugin_error;
75 : :
76 : : GHashTable *actions;
77 : : ValentContext *context;
78 : : GSettings *settings;
79 : : } ValentExtensionPrivate;
80 : :
81 : : static void g_action_group_iface_init (GActionGroupInterface *iface);
82 : : static void g_action_map_iface_init (GActionMapInterface *iface);
83 : :
84 [ + + + - ]: 6599 : G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ValentExtension, valent_extension, VALENT_TYPE_RESOURCE,
85 : : G_ADD_PRIVATE (ValentExtension)
86 : : G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_group_iface_init)
87 : : G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP, g_action_map_iface_init))
88 : :
89 : : typedef enum {
90 : : PROP_CONTEXT = 1,
91 : : PROP_PLUGIN_INFO,
92 : : PROP_PLUGIN_STATE,
93 : : PROP_SETTINGS,
94 : : } ValentExtensionProperty;
95 : :
96 : : static GParamSpec *properties[PROP_SETTINGS + 1] = { NULL, };
97 : :
98 : :
99 : : /*
100 : : * GActionGroup
101 : : */
102 : : static void
103 : 9 : valent_extension_activate_action (GActionGroup *action_group,
104 : : const char *action_name,
105 : : GVariant *parameter)
106 : : {
107 : 9 : ValentExtension *self = VALENT_EXTENSION (action_group);
108 : 9 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
109 : 9 : GAction *action;
110 : :
111 [ + - ]: 9 : if ((action = g_hash_table_lookup (priv->actions, action_name)) != NULL)
112 : 9 : g_action_activate (action, parameter);
113 : 9 : }
114 : :
115 : : static void
116 : 1 : valent_extension_change_action_state (GActionGroup *action_group,
117 : : const char *action_name,
118 : : GVariant *value)
119 : : {
120 : 1 : ValentExtension *self = VALENT_EXTENSION (action_group);
121 : 1 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
122 : 1 : GAction *action;
123 : :
124 [ + - ]: 1 : if ((action = g_hash_table_lookup (priv->actions, action_name)) != NULL)
125 : 1 : g_action_change_state (action, value);
126 : 1 : }
127 : :
128 : : static char **
129 : 212 : valent_extension_list_actions (GActionGroup *action_group)
130 : : {
131 : 212 : ValentExtension *self = VALENT_EXTENSION (action_group);
132 : 212 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
133 : 424 : g_auto (GStrv) actions = NULL;
134 : 212 : GHashTableIter iter;
135 : 212 : gpointer key;
136 : 212 : unsigned int i = 0;
137 : :
138 [ - + ]: 212 : actions = g_new0 (char *, g_hash_table_size (priv->actions) + 1);
139 : :
140 : 212 : g_hash_table_iter_init (&iter, priv->actions);
141 : :
142 [ + + ]: 563 : while (g_hash_table_iter_next (&iter, &key, NULL))
143 [ - + ]: 702 : actions[i++] = g_strdup (key);
144 : :
145 : 212 : return g_steal_pointer (&actions);
146 : : }
147 : :
148 : : static gboolean
149 : 2 : valent_extension_query_action (GActionGroup *action_group,
150 : : const char *action_name,
151 : : gboolean *enabled,
152 : : const GVariantType **parameter_type,
153 : : const GVariantType **state_type,
154 : : GVariant **state_hint,
155 : : GVariant **state)
156 : : {
157 : 2 : ValentExtension *self = VALENT_EXTENSION (action_group);
158 : 2 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
159 : 2 : GAction *action;
160 : :
161 [ + - ]: 2 : if ((action = g_hash_table_lookup (priv->actions, action_name)) == NULL)
162 : : return FALSE;
163 : :
164 [ + + ]: 2 : if (enabled)
165 : 1 : *enabled = g_action_get_enabled (action);
166 : :
167 [ + + ]: 2 : if (parameter_type)
168 : 1 : *parameter_type = g_action_get_parameter_type (action);
169 : :
170 [ + + ]: 2 : if (state_type)
171 : 1 : *state_type = g_action_get_state_type (action);
172 : :
173 [ + + ]: 2 : if (state_hint)
174 : 1 : *state_hint = g_action_get_state_hint (action);
175 : :
176 [ + - ]: 2 : if (state)
177 : 2 : *state = g_action_get_state (action);
178 : :
179 : : return TRUE;
180 : : }
181 : :
182 : : static void
183 : 58 : g_action_group_iface_init (GActionGroupInterface *iface)
184 : : {
185 : 58 : iface->activate_action = valent_extension_activate_action;
186 : 58 : iface->change_action_state = valent_extension_change_action_state;
187 : 58 : iface->list_actions = valent_extension_list_actions;
188 : 58 : iface->query_action = valent_extension_query_action;
189 : 58 : }
190 : :
191 : : /*
192 : : * GActionMap
193 : : */
194 : : static void
195 : 605 : on_action_enabled_changed (GAction *action,
196 : : GParamSpec *pspec,
197 : : GActionGroup *action_group)
198 : : {
199 : 605 : g_action_group_action_enabled_changed (action_group,
200 : : g_action_get_name (action),
201 : : g_action_get_enabled (action));
202 : 605 : }
203 : :
204 : : static void
205 : 25 : on_action_state_changed (GAction *action,
206 : : GParamSpec *pspec,
207 : : GActionGroup *action_group)
208 : : {
209 : 50 : g_autoptr (GVariant) value = NULL;
210 : :
211 : 25 : value = g_action_get_state (action);
212 [ + - ]: 25 : g_action_group_action_state_changed (action_group,
213 : : g_action_get_name (action),
214 : : value);
215 : 25 : }
216 : :
217 : : static void
218 : 379 : valent_extension_disconnect_action (ValentExtension *self,
219 : : GAction *action)
220 : : {
221 : 379 : g_signal_handlers_disconnect_by_func (action, on_action_enabled_changed, self);
222 : 379 : g_signal_handlers_disconnect_by_func (action, on_action_state_changed, self);
223 : 379 : }
224 : :
225 : : static GAction *
226 : 411 : valent_extension_lookup_action (GActionMap *action_map,
227 : : const char *action_name)
228 : : {
229 : 411 : ValentExtension *self = VALENT_EXTENSION (action_map);
230 : 411 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
231 : :
232 : 411 : return g_hash_table_lookup (priv->actions, action_name);
233 : : }
234 : :
235 : : static void
236 : 409 : valent_extension_add_action (GActionMap *action_map,
237 : : GAction *action)
238 : : {
239 : 409 : ValentExtension *self = VALENT_EXTENSION (action_map);
240 : 409 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
241 : 409 : const char *action_name;
242 : 409 : GAction *replacing;
243 : :
244 : 409 : action_name = g_action_get_name (action);
245 : :
246 [ + - ]: 409 : if ((replacing = g_hash_table_lookup (priv->actions, action_name)) == action)
247 : : return;
248 : :
249 [ - + ]: 409 : if (replacing != NULL)
250 : : {
251 : 0 : g_action_group_action_removed (G_ACTION_GROUP (action_map), action_name);
252 : 0 : valent_extension_disconnect_action (self, replacing);
253 : : }
254 : :
255 : 409 : g_signal_connect_object (action,
256 : : "notify::enabled",
257 : : G_CALLBACK (on_action_enabled_changed),
258 : : action_map, 0);
259 : :
260 [ + + ]: 409 : if (g_action_get_state_type (action) != NULL)
261 : 36 : g_signal_connect_object (action,
262 : : "notify::state",
263 : : G_CALLBACK (on_action_state_changed),
264 : : action_map, 0);
265 : :
266 [ - + ]: 409 : g_hash_table_replace (priv->actions,
267 : 409 : g_strdup (action_name),
268 : : g_object_ref (action));
269 : 409 : g_action_group_action_added (G_ACTION_GROUP (action_map), action_name);
270 : : }
271 : :
272 : : static void
273 : 1 : valent_extension_remove_action (GActionMap *action_map,
274 : : const char *action_name)
275 : : {
276 : 1 : ValentExtension *self = VALENT_EXTENSION (action_map);
277 : 1 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
278 : 1 : GAction *action;
279 : :
280 [ + - ]: 1 : if ((action = g_hash_table_lookup (priv->actions, action_name)) != NULL)
281 : : {
282 : 1 : g_action_group_action_removed (G_ACTION_GROUP (action_map), action_name);
283 : 1 : valent_extension_disconnect_action (self, action);
284 : 1 : g_hash_table_remove (priv->actions, action_name);
285 : : }
286 : 1 : }
287 : :
288 : : static void
289 : 58 : g_action_map_iface_init (GActionMapInterface *iface)
290 : : {
291 : 58 : iface->add_action = valent_extension_add_action;
292 : 58 : iface->lookup_action = valent_extension_lookup_action;
293 : 58 : iface->remove_action = valent_extension_remove_action;
294 : 58 : }
295 : :
296 : : /*
297 : : * ValentObject
298 : : */
299 : : static void
300 : 591 : valent_extension_destroy (ValentObject *object)
301 : : {
302 : 591 : ValentExtension *self = VALENT_EXTENSION (object);
303 : 591 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
304 : 591 : GHashTableIter iter;
305 : 591 : const char *action_name;
306 : 591 : GAction *action;
307 : :
308 : 591 : g_hash_table_iter_init (&iter, priv->actions);
309 [ + + ]: 969 : while (g_hash_table_iter_next (&iter, (void **)&action_name, (void **)&action))
310 : : {
311 : 378 : g_action_group_action_removed (G_ACTION_GROUP (self), action_name);
312 : 378 : valent_extension_disconnect_action (self, action);
313 : 378 : g_hash_table_iter_remove (&iter);
314 : : }
315 : :
316 : 591 : valent_extension_plugin_state_changed (self, VALENT_PLUGIN_STATE_INACTIVE, NULL);
317 : :
318 : 591 : VALENT_OBJECT_CLASS (valent_extension_parent_class)->destroy (object);
319 : 591 : }
320 : :
321 : : /*
322 : : * GObject
323 : : */
324 : : static void
325 : 332 : valent_extension_constructed (GObject *object)
326 : : {
327 : 332 : ValentExtension *self = VALENT_EXTENSION (object);
328 : 332 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
329 : :
330 : 332 : G_OBJECT_CLASS (valent_extension_parent_class)->constructed (object);
331 : :
332 : : /* If this is an extension with failable initialization, it is
333 : : * expected to update the state with the result.
334 : : */
335 [ + - + - : 332 : if (G_IS_INITABLE (object) || G_IS_ASYNC_INITABLE (object))
+ - + - +
- + - + -
+ + ]
336 : 12 : priv->plugin_state = VALENT_PLUGIN_STATE_INACTIVE;
337 : 332 : }
338 : : static void
339 : 309 : valent_extension_finalize (GObject *object)
340 : : {
341 : 309 : ValentExtension *self = VALENT_EXTENSION (object);
342 : 309 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
343 : :
344 : 309 : g_clear_error (&priv->plugin_error);
345 [ + - ]: 309 : g_clear_pointer (&priv->actions, g_hash_table_unref);
346 [ + + ]: 309 : g_clear_object (&priv->context);
347 [ + + ]: 309 : g_clear_object (&priv->plugin_info);
348 [ + + ]: 309 : g_clear_object (&priv->settings);
349 : :
350 : 309 : G_OBJECT_CLASS (valent_extension_parent_class)->finalize (object);
351 : 309 : }
352 : :
353 : : static void
354 : 1 : valent_extension_get_property (GObject *object,
355 : : guint prop_id,
356 : : GValue *value,
357 : : GParamSpec *pspec)
358 : : {
359 : 1 : ValentExtension *self = VALENT_EXTENSION (object);
360 : 1 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
361 : :
362 [ + - - - : 1 : switch ((ValentExtensionProperty)prop_id)
- ]
363 : : {
364 : 1 : case PROP_CONTEXT:
365 : 1 : g_value_set_object (value, valent_extension_get_context (self));
366 : 1 : break;
367 : :
368 : 0 : case PROP_PLUGIN_INFO:
369 : 0 : g_value_set_object (value, priv->plugin_info);
370 : 0 : break;
371 : :
372 : 0 : case PROP_PLUGIN_STATE:
373 : 0 : g_value_set_enum (value, priv->plugin_state);
374 : 0 : break;
375 : :
376 : 0 : case PROP_SETTINGS:
377 : 0 : g_value_set_object (value, valent_extension_get_settings (self));
378 : 0 : break;
379 : :
380 : 0 : default:
381 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
382 : : }
383 : 1 : }
384 : :
385 : : static void
386 : 664 : valent_extension_set_property (GObject *object,
387 : : guint prop_id,
388 : : const GValue *value,
389 : : GParamSpec *pspec)
390 : : {
391 : 664 : ValentExtension *self = VALENT_EXTENSION (object);
392 : 664 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
393 : :
394 [ + + - ]: 664 : switch ((ValentExtensionProperty)prop_id)
395 : : {
396 : 332 : case PROP_CONTEXT:
397 : 332 : priv->context = g_value_dup_object (value);
398 : 332 : break;
399 : :
400 : 332 : case PROP_PLUGIN_INFO:
401 : 332 : priv->plugin_info = g_value_dup_object (value);
402 : 332 : break;
403 : :
404 : 0 : case PROP_PLUGIN_STATE:
405 : : case PROP_SETTINGS:
406 : : default:
407 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
408 : : }
409 : 664 : }
410 : :
411 : : static void
412 : 58 : valent_extension_class_init (ValentExtensionClass *klass)
413 : : {
414 : 58 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
415 : 58 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
416 : :
417 : 58 : object_class->constructed = valent_extension_constructed;
418 : 58 : object_class->finalize = valent_extension_finalize;
419 : 58 : object_class->get_property = valent_extension_get_property;
420 : 58 : object_class->set_property = valent_extension_set_property;
421 : :
422 : 58 : vobject_class->destroy = valent_extension_destroy;
423 : :
424 : : /**
425 : : * ValentExtension:context: (getter get_context)
426 : : *
427 : : * The [class@Valent.Device] this plugin is bound to.
428 : : *
429 : : * Since: 1.0
430 : : */
431 : 116 : properties [PROP_CONTEXT] =
432 : 58 : g_param_spec_object ("context", NULL, NULL,
433 : : VALENT_TYPE_CONTEXT,
434 : : (G_PARAM_READWRITE |
435 : : G_PARAM_CONSTRUCT_ONLY |
436 : : G_PARAM_EXPLICIT_NOTIFY |
437 : : G_PARAM_STATIC_STRINGS));
438 : :
439 : : /**
440 : : * ValentExtension:plugin-info:
441 : : *
442 : : * The [class@Peas.PluginInfo] describing this plugin.
443 : : *
444 : : * Since: 1.0
445 : : */
446 : 116 : properties [PROP_PLUGIN_INFO] =
447 : 58 : g_param_spec_object ("plugin-info", NULL, NULL,
448 : : PEAS_TYPE_PLUGIN_INFO,
449 : : (G_PARAM_READWRITE |
450 : : G_PARAM_CONSTRUCT_ONLY |
451 : : G_PARAM_EXPLICIT_NOTIFY |
452 : : G_PARAM_STATIC_STRINGS));
453 : :
454 : : /**
455 : : * ValentExtension:plugin-state:
456 : : *
457 : : * The [enum@Valent.PluginState] describing the state of the extension.
458 : : *
459 : : * Since: 1.0
460 : : */
461 : 116 : properties [PROP_PLUGIN_STATE] =
462 : 58 : g_param_spec_enum ("plugin-state", NULL, NULL,
463 : : VALENT_TYPE_PLUGIN_STATE,
464 : : VALENT_PLUGIN_STATE_ACTIVE,
465 : : (G_PARAM_READABLE |
466 : : G_PARAM_EXPLICIT_NOTIFY |
467 : : G_PARAM_STATIC_STRINGS));
468 : :
469 : : /**
470 : : * ValentExtension:settings: (getter get_settings)
471 : : *
472 : : * The [class@Gio.Settings] for this plugin.
473 : : *
474 : : * Since: 1.0
475 : : */
476 : 116 : properties [PROP_SETTINGS] =
477 : 58 : g_param_spec_object ("settings", NULL, NULL,
478 : : G_TYPE_SETTINGS,
479 : : (G_PARAM_READABLE |
480 : : G_PARAM_EXPLICIT_NOTIFY |
481 : : G_PARAM_STATIC_STRINGS));
482 : :
483 : 58 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
484 : 58 : }
485 : :
486 : : static void
487 : 332 : valent_extension_init (ValentExtension *self)
488 : : {
489 : 332 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
490 : :
491 : 332 : priv->actions = g_hash_table_new_full (g_str_hash,
492 : : g_str_equal,
493 : : g_free,
494 : : g_object_unref);
495 : 332 : }
496 : :
497 : : /**
498 : : * valent_extension_get_context: (get-property context)
499 : : * @extension: a `ValentExtension`
500 : : *
501 : : * Get the settings for this plugin.
502 : : *
503 : : * Returns: (transfer none) (nullable): a `ValentContext`
504 : : *
505 : : * Since: 1.0
506 : : */
507 : : ValentContext *
508 : 36 : valent_extension_get_context (ValentExtension *extension)
509 : : {
510 : 36 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
511 : :
512 [ + - ]: 36 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), NULL);
513 : :
514 [ + + ]: 36 : if (priv->context == NULL)
515 : : {
516 : 16 : ValentContext *context = NULL;
517 : 16 : const char *module_name = NULL;
518 : :
519 : : /* FIXME: context = valent_object_get_context (priv->object); */
520 : 16 : module_name = peas_plugin_info_get_module_name (priv->plugin_info);
521 : 16 : priv->context = valent_context_new (context, "plugin", module_name);
522 : : }
523 : :
524 : 36 : return priv->context;
525 : : }
526 : :
527 : : /**
528 : : * valent_extension_get_settings: (get-property settings)
529 : : * @extension: a `ValentExtension`
530 : : *
531 : : * Get the settings for this plugin.
532 : : *
533 : : * Returns: (transfer none) (nullable): a `GSettings`
534 : : *
535 : : * Since: 1.0
536 : : */
537 : : GSettings *
538 : 89 : valent_extension_get_settings (ValentExtension *extension)
539 : : {
540 : 89 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
541 : :
542 [ + - ]: 89 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), NULL);
543 : :
544 [ + + ]: 89 : if (priv->settings == NULL)
545 : : {
546 : 32 : GType type_base = g_type_parent (G_OBJECT_TYPE (extension));
547 : 32 : const char *type_name = g_type_name (type_base);
548 : 32 : g_autofree char *key = NULL;
549 : :
550 [ + - + - : 32 : if (g_str_has_prefix (type_name, "Valent"))
+ - ]
551 : 32 : key = g_strdup_printf ("X-%sSettings", &type_name[strlen ("Valent")]);
552 : : else
553 : 0 : key = g_strdup_printf ("X-%sSettings", type_name);
554 : :
555 : 32 : priv->settings = valent_context_get_plugin_settings (priv->context,
556 : : priv->plugin_info,
557 : : key);
558 : : }
559 : :
560 : 89 : return priv->settings;
561 : : }
562 : :
563 : : /**
564 : : * valent_extension_plugin_state_check:
565 : : * @extension: a `ValentExtension`
566 : : * @error: (nullable): a `GError`
567 : : *
568 : : * Get the extension state, while propagating any errors that describe it.
569 : : *
570 : : * Returns: a `ValentPluginState`
571 : : *
572 : : * Since: 1.0
573 : : */
574 : : ValentPluginState
575 : 116 : valent_extension_plugin_state_check (ValentExtension *extension,
576 : : GError **error)
577 : : {
578 : 116 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
579 : :
580 [ + - ]: 116 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), VALENT_PLUGIN_STATE_INACTIVE);
581 [ + + - + ]: 116 : g_return_val_if_fail (error == NULL || *error == NULL, VALENT_PLUGIN_STATE_INACTIVE);
582 : :
583 [ - + - - ]: 116 : if (priv->plugin_error != NULL && error != NULL)
584 : 0 : *error = g_error_copy (priv->plugin_error);
585 : :
586 : 116 : return priv->plugin_state;
587 : : }
588 : :
589 : : /**
590 : : * valent_extension_plugin_state_changed:
591 : : * @extension: a `ValentExtension`
592 : : * @state: a `ValentPluginState`
593 : : * @error: (nullable): a `GError`
594 : : *
595 : : * Emits [signal@GObject.Object::notify] for
596 : : * [property@Valent.Extension:plugin-state].
597 : : *
598 : : * Implementations should call this method to inform the managing object of
599 : : * changes to the state of the extension, especially unrecoverable errors.
600 : : *
601 : : * Since: 1.0
602 : : */
603 : : void
604 : 603 : valent_extension_plugin_state_changed (ValentExtension *extension,
605 : : ValentPluginState state,
606 : : const GError *error)
607 : : {
608 : 603 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
609 : :
610 [ + - ]: 603 : g_return_if_fail (VALENT_IS_EXTENSION (extension));
611 [ - + ]: 603 : g_return_if_fail (state != VALENT_PLUGIN_STATE_ERROR || error != NULL);
612 : :
613 : 603 : g_clear_error (&priv->plugin_error);
614 [ - + ]: 603 : if (state == VALENT_PLUGIN_STATE_ERROR && error != NULL)
615 : 0 : priv->plugin_error = g_error_copy (error);
616 : :
617 [ + + - + ]: 603 : if (priv->plugin_state != state || priv->plugin_error != NULL)
618 : : {
619 : 316 : priv->plugin_state = state;
620 : 316 : valent_object_notify_by_pspec (VALENT_OBJECT (extension),
621 : : properties [PROP_PLUGIN_STATE]);
622 : : }
623 : : }
624 : :
625 : : /**
626 : : * valent_extension_toggle_actions:
627 : : * @extension: a `ValentExtension`
628 : : * @enabled: boolean
629 : : *
630 : : * Enable or disable all actions.
631 : : *
632 : : * Set the [property@Gio.Action:enabled] property of the actions for @extension to
633 : : * @enabled.
634 : : *
635 : : * Since: 1.0
636 : : */
637 : : void
638 : 241 : valent_extension_toggle_actions (ValentExtension *extension,
639 : : gboolean enabled)
640 : : {
641 : 241 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
642 : 241 : GHashTableIter iter;
643 : 241 : GSimpleAction *action;
644 : :
645 [ + - ]: 241 : g_return_if_fail (VALENT_IS_EXTENSION (extension));
646 : :
647 : 241 : g_hash_table_iter_init (&iter, priv->actions);
648 : :
649 [ + + ]: 904 : while (g_hash_table_iter_next (&iter, NULL, (void **)&action))
650 : 663 : g_simple_action_set_enabled (action, enabled);
651 : : }
652 : :
|