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