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 [ + + + - ]: 6630 : 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 : 200 : valent_extension_list_actions (GActionGroup *action_group)
130 : : {
131 : 200 : ValentExtension *self = VALENT_EXTENSION (action_group);
132 : 200 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
133 : 400 : g_auto (GStrv) actions = NULL;
134 : 200 : GHashTableIter iter;
135 : 200 : gpointer key;
136 : 200 : unsigned int i = 0;
137 : :
138 [ - + ]: 200 : actions = g_new0 (char *, g_hash_table_size (priv->actions) + 1);
139 : :
140 : 200 : g_hash_table_iter_init (&iter, priv->actions);
141 : :
142 [ + + ]: 536 : while (g_hash_table_iter_next (&iter, &key, NULL))
143 [ - + ]: 672 : actions[i++] = g_strdup (key);
144 : :
145 : 200 : 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 : 52 : g_action_group_iface_init (GActionGroupInterface *iface)
184 : : {
185 : 52 : iface->activate_action = valent_extension_activate_action;
186 : 52 : iface->change_action_state = valent_extension_change_action_state;
187 : 52 : iface->list_actions = valent_extension_list_actions;
188 : 52 : iface->query_action = valent_extension_query_action;
189 : 52 : }
190 : :
191 : : /*
192 : : * GActionMap
193 : : */
194 : : static void
195 : 607 : on_action_enabled_changed (GAction *action,
196 : : GParamSpec *pspec,
197 : : GActionGroup *action_group)
198 : : {
199 : 607 : g_action_group_action_enabled_changed (action_group,
200 : : g_action_get_name (action),
201 : : g_action_get_enabled (action));
202 : 607 : }
203 : :
204 : : static void
205 : 24 : on_action_state_changed (GAction *action,
206 : : GParamSpec *pspec,
207 : : GActionGroup *action_group)
208 : : {
209 : 48 : g_autoptr (GVariant) value = NULL;
210 : :
211 : 24 : value = g_action_get_state (action);
212 [ + - ]: 24 : g_action_group_action_state_changed (action_group,
213 : : g_action_get_name (action),
214 : : value);
215 : 24 : }
216 : :
217 : : static void
218 : 377 : valent_extension_disconnect_action (ValentExtension *self,
219 : : GAction *action)
220 : : {
221 : 377 : g_signal_handlers_disconnect_by_func (action, on_action_enabled_changed, self);
222 : 377 : g_signal_handlers_disconnect_by_func (action, on_action_state_changed, self);
223 : 377 : }
224 : :
225 : : static GAction *
226 : 393 : valent_extension_lookup_action (GActionMap *action_map,
227 : : const char *action_name)
228 : : {
229 : 393 : ValentExtension *self = VALENT_EXTENSION (action_map);
230 : 393 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
231 : :
232 : 393 : return g_hash_table_lookup (priv->actions, action_name);
233 : : }
234 : :
235 : : static void
236 : 404 : valent_extension_add_action (GActionMap *action_map,
237 : : GAction *action)
238 : : {
239 : 404 : ValentExtension *self = VALENT_EXTENSION (action_map);
240 : 404 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
241 : 404 : const char *action_name;
242 : 404 : GAction *replacing;
243 : :
244 : 404 : action_name = g_action_get_name (action);
245 : :
246 [ + - ]: 404 : if ((replacing = g_hash_table_lookup (priv->actions, action_name)) == action)
247 : : return;
248 : :
249 [ - + ]: 404 : 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 : 404 : g_signal_connect_object (action,
256 : : "notify::enabled",
257 : : G_CALLBACK (on_action_enabled_changed),
258 : : action_map, 0);
259 : :
260 [ + + ]: 404 : if (g_action_get_state_type (action) != NULL)
261 : 39 : g_signal_connect_object (action,
262 : : "notify::state",
263 : : G_CALLBACK (on_action_state_changed),
264 : : action_map, 0);
265 : :
266 [ - + ]: 404 : g_hash_table_replace (priv->actions,
267 : 404 : g_strdup (action_name),
268 : : g_object_ref (action));
269 : 404 : 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 : 52 : g_action_map_iface_init (GActionMapInterface *iface)
290 : : {
291 : 52 : iface->add_action = valent_extension_add_action;
292 : 52 : iface->lookup_action = valent_extension_lookup_action;
293 : 52 : iface->remove_action = valent_extension_remove_action;
294 : 52 : }
295 : :
296 : : /*
297 : : * ValentObject
298 : : */
299 : : static void
300 : 578 : valent_extension_destroy (ValentObject *object)
301 : : {
302 : 578 : ValentExtension *self = VALENT_EXTENSION (object);
303 : 578 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
304 : 578 : GHashTableIter iter;
305 : 578 : const char *action_name;
306 : 578 : GAction *action;
307 : :
308 : 578 : g_hash_table_iter_init (&iter, priv->actions);
309 [ + + ]: 954 : while (g_hash_table_iter_next (&iter, (void **)&action_name, (void **)&action))
310 : : {
311 : 376 : g_action_group_action_removed (G_ACTION_GROUP (self), action_name);
312 : 376 : valent_extension_disconnect_action (self, action);
313 : 376 : g_hash_table_iter_remove (&iter);
314 : : }
315 : :
316 : 578 : valent_extension_plugin_state_changed (self, VALENT_PLUGIN_STATE_INACTIVE, NULL);
317 : :
318 : 578 : VALENT_OBJECT_CLASS (valent_extension_parent_class)->destroy (object);
319 : 578 : }
320 : :
321 : : /*
322 : : * GObject
323 : : */
324 : : static void
325 : 321 : valent_extension_constructed (GObject *object)
326 : : {
327 : 321 : ValentExtension *self = VALENT_EXTENSION (object);
328 : 321 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
329 : :
330 : 321 : G_OBJECT_CLASS (valent_extension_parent_class)->constructed (object);
331 : :
332 : : /* If this is an extension backed by a plugin, try to create
333 : : * a settings object from the plugin info.
334 : : */
335 [ + + + - ]: 321 : if (priv->plugin_info != NULL && priv->context != NULL)
336 : : {
337 : 296 : GType type_base = g_type_parent (G_OBJECT_TYPE (self));
338 : 296 : const char *type_name = g_type_name (type_base);
339 : 296 : g_autofree char *key = NULL;
340 : :
341 [ - + + - : 296 : if (g_str_has_prefix (type_name, "Valent"))
+ - ]
342 : 296 : key = g_strdup_printf ("X-%sSettings", &type_name[strlen ("Valent")]);
343 : : else
344 : 0 : key = g_strdup_printf ("X-%sSettings", type_name);
345 : :
346 : 296 : priv->settings = valent_context_get_plugin_settings (priv->context,
347 : : priv->plugin_info,
348 : : key);
349 : : }
350 : :
351 : : /* If this is an extension with failable initialization, it is
352 : : * expected to update the state with the result.
353 : : */
354 [ + - + - : 321 : if (G_IS_INITABLE (object) || G_IS_ASYNC_INITABLE (object))
+ - + - +
- + - + -
+ + ]
355 : 12 : priv->plugin_state = VALENT_PLUGIN_STATE_INACTIVE;
356 : 321 : }
357 : : static void
358 : 303 : valent_extension_finalize (GObject *object)
359 : : {
360 : 303 : ValentExtension *self = VALENT_EXTENSION (object);
361 : 303 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
362 : :
363 : 303 : g_clear_error (&priv->plugin_error);
364 [ + - ]: 303 : g_clear_pointer (&priv->actions, g_hash_table_unref);
365 [ + + ]: 303 : g_clear_object (&priv->context);
366 [ + + ]: 303 : g_clear_object (&priv->plugin_info);
367 [ + + ]: 303 : g_clear_object (&priv->settings);
368 : :
369 : 303 : G_OBJECT_CLASS (valent_extension_parent_class)->finalize (object);
370 : 303 : }
371 : :
372 : : static void
373 : 0 : valent_extension_get_property (GObject *object,
374 : : guint prop_id,
375 : : GValue *value,
376 : : GParamSpec *pspec)
377 : : {
378 : 0 : ValentExtension *self = VALENT_EXTENSION (object);
379 : 0 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
380 : :
381 [ # # # # : 0 : switch ((ValentExtensionProperty)prop_id)
# ]
382 : : {
383 : 0 : case PROP_CONTEXT:
384 : 0 : g_value_set_object (value, valent_extension_get_context (self));
385 : 0 : break;
386 : :
387 : 0 : case PROP_PLUGIN_INFO:
388 : 0 : g_value_set_object (value, priv->plugin_info);
389 : 0 : break;
390 : :
391 : 0 : case PROP_PLUGIN_STATE:
392 : 0 : g_value_set_enum (value, priv->plugin_state);
393 : 0 : break;
394 : :
395 : 0 : case PROP_SETTINGS:
396 : 0 : g_value_set_object (value, priv->settings);
397 : 0 : break;
398 : :
399 : 0 : default:
400 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
401 : : }
402 : 0 : }
403 : :
404 : : static void
405 : 642 : valent_extension_set_property (GObject *object,
406 : : guint prop_id,
407 : : const GValue *value,
408 : : GParamSpec *pspec)
409 : : {
410 : 642 : ValentExtension *self = VALENT_EXTENSION (object);
411 : 642 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
412 : :
413 [ + + - ]: 642 : switch ((ValentExtensionProperty)prop_id)
414 : : {
415 : 321 : case PROP_CONTEXT:
416 : 321 : priv->context = g_value_dup_object (value);
417 : 321 : break;
418 : :
419 : 321 : case PROP_PLUGIN_INFO:
420 : 321 : priv->plugin_info = g_value_dup_object (value);
421 : 321 : break;
422 : :
423 : 0 : case PROP_PLUGIN_STATE:
424 : : case PROP_SETTINGS:
425 : : default:
426 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427 : : }
428 : 642 : }
429 : :
430 : : static void
431 : 52 : valent_extension_class_init (ValentExtensionClass *klass)
432 : : {
433 : 52 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
434 : 52 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
435 : :
436 : 52 : object_class->constructed = valent_extension_constructed;
437 : 52 : object_class->finalize = valent_extension_finalize;
438 : 52 : object_class->get_property = valent_extension_get_property;
439 : 52 : object_class->set_property = valent_extension_set_property;
440 : :
441 : 52 : vobject_class->destroy = valent_extension_destroy;
442 : :
443 : : /**
444 : : * ValentExtension:context: (getter get_context)
445 : : *
446 : : * The [class@Valent.Device] this plugin is bound to.
447 : : *
448 : : * Since: 1.0
449 : : */
450 : 104 : properties [PROP_CONTEXT] =
451 : 52 : g_param_spec_object ("context", NULL, NULL,
452 : : VALENT_TYPE_CONTEXT,
453 : : (G_PARAM_READWRITE |
454 : : G_PARAM_CONSTRUCT_ONLY |
455 : : G_PARAM_EXPLICIT_NOTIFY |
456 : : G_PARAM_STATIC_STRINGS));
457 : :
458 : : /**
459 : : * ValentExtension:plugin-info:
460 : : *
461 : : * The [class@Peas.PluginInfo] describing this plugin.
462 : : *
463 : : * Since: 1.0
464 : : */
465 : 104 : properties [PROP_PLUGIN_INFO] =
466 : 52 : g_param_spec_object ("plugin-info", NULL, NULL,
467 : : PEAS_TYPE_PLUGIN_INFO,
468 : : (G_PARAM_READWRITE |
469 : : G_PARAM_CONSTRUCT_ONLY |
470 : : G_PARAM_EXPLICIT_NOTIFY |
471 : : G_PARAM_STATIC_STRINGS));
472 : :
473 : : /**
474 : : * ValentExtension:plugin-state:
475 : : *
476 : : * The [enum@Valent.PluginState] describing the state of the extension.
477 : : *
478 : : * Since: 1.0
479 : : */
480 : 104 : properties [PROP_PLUGIN_STATE] =
481 : 52 : g_param_spec_enum ("plugin-state", NULL, NULL,
482 : : VALENT_TYPE_PLUGIN_STATE,
483 : : VALENT_PLUGIN_STATE_ACTIVE,
484 : : (G_PARAM_READABLE |
485 : : G_PARAM_EXPLICIT_NOTIFY |
486 : : G_PARAM_STATIC_STRINGS));
487 : :
488 : : /**
489 : : * ValentExtension:settings: (getter get_settings)
490 : : *
491 : : * The [class@Gio.Settings] for this plugin.
492 : : *
493 : : * Since: 1.0
494 : : */
495 : 104 : properties [PROP_SETTINGS] =
496 : 52 : g_param_spec_object ("settings", NULL, NULL,
497 : : G_TYPE_SETTINGS,
498 : : (G_PARAM_READABLE |
499 : : G_PARAM_EXPLICIT_NOTIFY |
500 : : G_PARAM_STATIC_STRINGS));
501 : :
502 : 52 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
503 : 52 : }
504 : :
505 : : static void
506 : 321 : valent_extension_init (ValentExtension *self)
507 : : {
508 : 321 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (self);
509 : :
510 : 321 : priv->actions = g_hash_table_new_full (g_str_hash,
511 : : g_str_equal,
512 : : g_free,
513 : : g_object_unref);
514 : 321 : }
515 : :
516 : : /**
517 : : * valent_extension_get_context: (get-property context)
518 : : * @extension: a `ValentExtension`
519 : : *
520 : : * Get the settings for this plugin.
521 : : *
522 : : * Returns: (transfer none) (nullable): a `ValentContext`
523 : : *
524 : : * Since: 1.0
525 : : */
526 : : ValentContext *
527 : 30 : valent_extension_get_context (ValentExtension *extension)
528 : : {
529 : 30 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
530 : :
531 [ + - ]: 30 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), NULL);
532 : :
533 : 30 : return priv->context;
534 : : }
535 : :
536 : : /**
537 : : * valent_extension_get_settings: (get-property settings)
538 : : * @extension: a `ValentExtension`
539 : : *
540 : : * Get the settings for this plugin.
541 : : *
542 : : * Returns: (transfer none) (nullable): a `GSettings`
543 : : *
544 : : * Since: 1.0
545 : : */
546 : : GSettings *
547 : 83 : valent_extension_get_settings (ValentExtension *extension)
548 : : {
549 : 83 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
550 : :
551 [ + - ]: 83 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), NULL);
552 : :
553 : 83 : return priv->settings;
554 : : }
555 : :
556 : : /**
557 : : * valent_extension_plugin_state_check:
558 : : * @extension: a `ValentExtension`
559 : : * @error: (nullable): a `GError`
560 : : *
561 : : * Get the extension state, while propagating any errors that describe it.
562 : : *
563 : : * Returns: a `ValentPluginState`
564 : : *
565 : : * Since: 1.0
566 : : */
567 : : ValentPluginState
568 : 117 : valent_extension_plugin_state_check (ValentExtension *extension,
569 : : GError **error)
570 : : {
571 : 117 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
572 : :
573 [ + - ]: 117 : g_return_val_if_fail (VALENT_IS_EXTENSION (extension), VALENT_PLUGIN_STATE_INACTIVE);
574 [ + + - + ]: 117 : g_return_val_if_fail (error == NULL || *error == NULL, VALENT_PLUGIN_STATE_INACTIVE);
575 : :
576 [ - + - - ]: 117 : if (priv->plugin_error != NULL && error != NULL)
577 : 0 : *error = g_error_copy (priv->plugin_error);
578 : :
579 : 117 : return priv->plugin_state;
580 : : }
581 : :
582 : : /**
583 : : * valent_extension_plugin_state_changed:
584 : : * @extension: a `ValentExtension`
585 : : * @state: a `ValentPluginState`
586 : : * @error: (nullable): a `GError`
587 : : *
588 : : * Emits [signal@GObject.Object::notify] for
589 : : * [property@Valent.Extension:plugin-state].
590 : : *
591 : : * Implementations should call this method to inform the managing object of
592 : : * changes to the state of the extension, especially unrecoverable errors.
593 : : *
594 : : * Since: 1.0
595 : : */
596 : : void
597 : 589 : valent_extension_plugin_state_changed (ValentExtension *extension,
598 : : ValentPluginState state,
599 : : const GError *error)
600 : : {
601 : 589 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
602 : :
603 [ + - ]: 589 : g_return_if_fail (VALENT_IS_EXTENSION (extension));
604 [ - + ]: 589 : g_return_if_fail (state != VALENT_PLUGIN_STATE_ERROR || error != NULL);
605 : :
606 : 589 : g_clear_error (&priv->plugin_error);
607 [ - + ]: 589 : if (state == VALENT_PLUGIN_STATE_ERROR && error != NULL)
608 : 0 : priv->plugin_error = g_error_copy (error);
609 : :
610 [ + + - + ]: 589 : if (priv->plugin_state != state || priv->plugin_error != NULL)
611 : : {
612 : 309 : priv->plugin_state = state;
613 : 309 : valent_object_notify_by_pspec (VALENT_OBJECT (extension),
614 : : properties [PROP_PLUGIN_STATE]);
615 : : }
616 : : }
617 : :
618 : : /**
619 : : * valent_extension_toggle_actions:
620 : : * @extension: a `ValentExtension`
621 : : * @enabled: boolean
622 : : *
623 : : * Enable or disable all actions.
624 : : *
625 : : * Set the [property@Gio.Action:enabled] property of the actions for @extension to
626 : : * @enabled.
627 : : *
628 : : * Since: 1.0
629 : : */
630 : : void
631 : 221 : valent_extension_toggle_actions (ValentExtension *extension,
632 : : gboolean enabled)
633 : : {
634 : 221 : ValentExtensionPrivate *priv = valent_extension_get_instance_private (extension);
635 : 221 : GHashTableIter iter;
636 : 221 : GSimpleAction *action;
637 : :
638 [ + - ]: 221 : g_return_if_fail (VALENT_IS_EXTENSION (extension));
639 : :
640 : 221 : g_hash_table_iter_init (&iter, priv->actions);
641 : :
642 [ + + ]: 845 : while (g_hash_table_iter_next (&iter, NULL, (void **)&action))
643 : 624 : g_simple_action_set_enabled (action, enabled);
644 : : }
645 : :
|