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