2 * Copyright © 2010 Codethink Limited
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Authors: Ryan Lortie <desrt@desrt.ca>
23 #include "gactiongroup.h"
26 #include "gmarshal-internal.h"
31 * `GActionGroup` represents a group of actions.
33 * Actions can be used to expose functionality in a structured way, either
34 * from one part of a program to another, or to the outside world. Action
35 * groups are often used together with a `GMenuModel` that provides additional
36 * representation data for displaying the actions to the user, e.g. in a menu.
38 * The main way to interact with the actions in a `GActionGroup` is to
39 * activate them with [method@Gio.ActionGroup.activate_action]. Activating an
40 * action may require a `GVariant` parameter. The required type of the
41 * parameter can be inquired with [method@Gio.ActionGroup.get_action_parameter_type].
42 * Actions may be disabled, see [method@Gio.ActionGroup.get_action_enabled].
43 * Activating a disabled action has no effect.
45 * Actions may optionally have a state in the form of a #GVariant. The current
46 * state of an action can be inquired with [method@Gio.ActionGroup.get_action_state].
47 * Activating a stateful action may change its state, but it is also possible to
48 * set the state by calling [method@Gio.ActionGroup.change_action_state].
50 * As typical example, consider a text editing application which has an
51 * option to change the current font to 'bold'. A good way to represent
52 * this would be a stateful action, with a boolean state. Activating the
53 * action would toggle the state.
55 * Each action in the group has a unique name (which is a string). All
56 * method calls, except [method@Gio.ActionGroup.list_actions] take the name of
57 * an action as an argument.
59 * The `GActionGroup` API is meant to be the 'public' API to the action
60 * group. The calls here are exactly the interaction that 'external
61 * forces' (eg: UI, incoming D-Bus messages, etc.) are supposed to have
62 * with actions. 'Internal' APIs (ie: ones meant only to be accessed by
63 * the action group implementation) are found on subclasses. This is
64 * why you will find - for example - [method@Gio.ActionGroup.get_action_enabled]
65 * but not an equivalent set() call.
67 * Signals are emitted on the action group in response to state changes
68 * on individual actions.
70 * Implementations of `GActionGroup` should provide implementations for
71 * the virtual functions [method@Gio.ActionGroup.list_actions] and
72 * [method@Gio.ActionGroup.query_action]. The other virtual functions should
73 * not be implemented - their "wrappers" are actually implemented with
74 * calls to [method@Gio.ActionGroup.query_action].
78 * GActionGroupInterface:
79 * @has_action: the virtual function pointer for g_action_group_has_action()
80 * @list_actions: the virtual function pointer for g_action_group_list_actions()
81 * @get_action_parameter_type: the virtual function pointer for g_action_group_get_action_parameter_type()
82 * @get_action_state_type: the virtual function pointer for g_action_group_get_action_state_type()
83 * @get_action_state_hint: the virtual function pointer for g_action_group_get_action_state_hint()
84 * @get_action_enabled: the virtual function pointer for g_action_group_get_action_enabled()
85 * @get_action_state: the virtual function pointer for g_action_group_get_action_state()
86 * @change_action_state: the virtual function pointer for g_action_group_change_action_state()
87 * @activate_action: the virtual function pointer for g_action_group_activate_action()
88 * @action_added: the class closure for the #GActionGroup::action-added signal
89 * @action_removed: the class closure for the #GActionGroup::action-removed signal
90 * @action_enabled_changed: the class closure for the #GActionGroup::action-enabled-changed signal
91 * @action_state_changed: the class closure for the #GActionGroup::action-enabled-changed signal
92 * @query_action: the virtual function pointer for g_action_group_query_action()
94 * The virtual function table for #GActionGroup.
99 G_DEFINE_INTERFACE (GActionGroup, g_action_group, G_TYPE_OBJECT)
104 SIGNAL_ACTION_REMOVED,
105 SIGNAL_ACTION_ENABLED_CHANGED,
106 SIGNAL_ACTION_STATE_CHANGED,
110 static guint g_action_group_signals[NR_SIGNALS];
113 g_action_group_real_has_action (GActionGroup *action_group,
114 const gchar *action_name)
116 return g_action_group_query_action (action_group, action_name, NULL, NULL, NULL, NULL, NULL);
120 g_action_group_real_get_action_enabled (GActionGroup *action_group,
121 const gchar *action_name)
125 if (!g_action_group_query_action (action_group, action_name, &enabled, NULL, NULL, NULL, NULL))
131 static const GVariantType *
132 g_action_group_real_get_action_parameter_type (GActionGroup *action_group,
133 const gchar *action_name)
135 const GVariantType *type;
137 if (!g_action_group_query_action (action_group, action_name, NULL, &type, NULL, NULL, NULL))
143 static const GVariantType *
144 g_action_group_real_get_action_state_type (GActionGroup *action_group,
145 const gchar *action_name)
147 const GVariantType *type;
149 if (!g_action_group_query_action (action_group, action_name, NULL, NULL, &type, NULL, NULL))
156 g_action_group_real_get_action_state_hint (GActionGroup *action_group,
157 const gchar *action_name)
161 if (!g_action_group_query_action (action_group, action_name, NULL, NULL, NULL, &hint, NULL))
168 g_action_group_real_get_action_state (GActionGroup *action_group,
169 const gchar *action_name)
173 if (!g_action_group_query_action (action_group, action_name, NULL, NULL, NULL, NULL, &state))
180 g_action_group_real_query_action (GActionGroup *action_group,
181 const gchar *action_name,
183 const GVariantType **parameter_type,
184 const GVariantType **state_type,
185 GVariant **state_hint,
188 GActionGroupInterface *iface = G_ACTION_GROUP_GET_IFACE (action_group);
190 /* we expect implementations to override this method, but we also
191 * allow for implementations that existed before this method was
192 * introduced to override the individual accessors instead.
194 * detect the case that neither has happened and report it.
196 if G_UNLIKELY (iface->has_action == g_action_group_real_has_action ||
197 iface->get_action_enabled == g_action_group_real_get_action_enabled ||
198 iface->get_action_parameter_type == g_action_group_real_get_action_parameter_type ||
199 iface->get_action_state_type == g_action_group_real_get_action_state_type ||
200 iface->get_action_state_hint == g_action_group_real_get_action_state_hint ||
201 iface->get_action_state == g_action_group_real_get_action_state)
203 g_critical ("Class '%s' implements GActionGroup interface without overriding "
204 "query_action() method -- bailing out to avoid infinite recursion.",
205 G_OBJECT_TYPE_NAME (action_group));
209 if (!(* iface->has_action) (action_group, action_name))
213 *enabled = (* iface->get_action_enabled) (action_group, action_name);
215 if (parameter_type != NULL)
216 *parameter_type = (* iface->get_action_parameter_type) (action_group, action_name);
218 if (state_type != NULL)
219 *state_type = (* iface->get_action_state_type) (action_group, action_name);
221 if (state_hint != NULL)
222 *state_hint = (* iface->get_action_state_hint) (action_group, action_name);
225 *state = (* iface->get_action_state) (action_group, action_name);
231 g_action_group_default_init (GActionGroupInterface *iface)
233 iface->has_action = g_action_group_real_has_action;
234 iface->get_action_enabled = g_action_group_real_get_action_enabled;
235 iface->get_action_parameter_type = g_action_group_real_get_action_parameter_type;
236 iface->get_action_state_type = g_action_group_real_get_action_state_type;
237 iface->get_action_state_hint = g_action_group_real_get_action_state_hint;
238 iface->get_action_state = g_action_group_real_get_action_state;
239 iface->query_action = g_action_group_real_query_action;
242 * GActionGroup::action-added:
243 * @action_group: the #GActionGroup that changed
244 * @action_name: the name of the action in @action_group
246 * Signals that a new action was just added to the group.
247 * This signal is emitted after the action has been added
248 * and is now visible.
252 g_action_group_signals[SIGNAL_ACTION_ADDED] =
253 g_signal_new (I_("action-added"),
255 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
256 G_STRUCT_OFFSET (GActionGroupInterface, action_added),
263 * GActionGroup::action-removed:
264 * @action_group: the #GActionGroup that changed
265 * @action_name: the name of the action in @action_group
267 * Signals that an action is just about to be removed from the group.
268 * This signal is emitted before the action is removed, so the action
269 * is still visible and can be queried from the signal handler.
273 g_action_group_signals[SIGNAL_ACTION_REMOVED] =
274 g_signal_new (I_("action-removed"),
276 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
277 G_STRUCT_OFFSET (GActionGroupInterface, action_removed),
285 * GActionGroup::action-enabled-changed:
286 * @action_group: the #GActionGroup that changed
287 * @action_name: the name of the action in @action_group
288 * @enabled: whether the action is enabled or not
290 * Signals that the enabled status of the named action has changed.
294 g_action_group_signals[SIGNAL_ACTION_ENABLED_CHANGED] =
295 g_signal_new (I_("action-enabled-changed"),
297 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
298 G_STRUCT_OFFSET (GActionGroupInterface,
299 action_enabled_changed),
301 _g_cclosure_marshal_VOID__STRING_BOOLEAN,
305 g_signal_set_va_marshaller (g_action_group_signals[SIGNAL_ACTION_ENABLED_CHANGED],
306 G_TYPE_FROM_INTERFACE (iface),
307 _g_cclosure_marshal_VOID__STRING_BOOLEANv);
310 * GActionGroup::action-state-changed:
311 * @action_group: the #GActionGroup that changed
312 * @action_name: the name of the action in @action_group
313 * @value: the new value of the state
315 * Signals that the state of the named action has changed.
319 g_action_group_signals[SIGNAL_ACTION_STATE_CHANGED] =
320 g_signal_new (I_("action-state-changed"),
324 G_SIGNAL_MUST_COLLECT,
325 G_STRUCT_OFFSET (GActionGroupInterface,
326 action_state_changed),
328 _g_cclosure_marshal_VOID__STRING_VARIANT,
332 g_signal_set_va_marshaller (g_action_group_signals[SIGNAL_ACTION_STATE_CHANGED],
333 G_TYPE_FROM_INTERFACE (iface),
334 _g_cclosure_marshal_VOID__STRING_VARIANTv);
338 * g_action_group_list_actions:
339 * @action_group: a #GActionGroup
341 * Lists the actions contained within @action_group.
343 * The caller is responsible for freeing the list with g_strfreev() when
344 * it is no longer required.
346 * Returns: (transfer full): a %NULL-terminated array of the names of the
347 * actions in the group
352 g_action_group_list_actions (GActionGroup *action_group)
354 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), NULL);
356 return G_ACTION_GROUP_GET_IFACE (action_group)
357 ->list_actions (action_group);
361 * g_action_group_has_action:
362 * @action_group: a #GActionGroup
363 * @action_name: the name of the action to check for
365 * Checks if the named action exists within @action_group.
367 * Returns: whether the named action exists
372 g_action_group_has_action (GActionGroup *action_group,
373 const gchar *action_name)
375 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), FALSE);
377 return G_ACTION_GROUP_GET_IFACE (action_group)
378 ->has_action (action_group, action_name);
382 * g_action_group_get_action_parameter_type:
383 * @action_group: a #GActionGroup
384 * @action_name: the name of the action to query
386 * Queries the type of the parameter that must be given when activating
387 * the named action within @action_group.
389 * When activating the action using g_action_group_activate_action(),
390 * the #GVariant given to that function must be of the type returned
393 * In the case that this function returns %NULL, you must not give any
394 * #GVariant, but %NULL instead.
396 * The parameter type of a particular action will never change but it is
397 * possible for an action to be removed and for a new action to be added
398 * with the same name but a different parameter type.
400 * Returns: (nullable): the parameter type
405 g_action_group_get_action_parameter_type (GActionGroup *action_group,
406 const gchar *action_name)
408 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), NULL);
410 return G_ACTION_GROUP_GET_IFACE (action_group)
411 ->get_action_parameter_type (action_group, action_name);
415 * g_action_group_get_action_state_type:
416 * @action_group: a #GActionGroup
417 * @action_name: the name of the action to query
419 * Queries the type of the state of the named action within
422 * If the action is stateful then this function returns the
423 * #GVariantType of the state. All calls to
424 * g_action_group_change_action_state() must give a #GVariant of this
425 * type and g_action_group_get_action_state() will return a #GVariant
428 * If the action is not stateful then this function will return %NULL.
429 * In that case, g_action_group_get_action_state() will return %NULL
430 * and you must not call g_action_group_change_action_state().
432 * The state type of a particular action will never change but it is
433 * possible for an action to be removed and for a new action to be added
434 * with the same name but a different state type.
436 * Returns: (nullable): the state type, if the action is stateful
441 g_action_group_get_action_state_type (GActionGroup *action_group,
442 const gchar *action_name)
444 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), NULL);
446 return G_ACTION_GROUP_GET_IFACE (action_group)
447 ->get_action_state_type (action_group, action_name);
451 * g_action_group_get_action_state_hint:
452 * @action_group: a #GActionGroup
453 * @action_name: the name of the action to query
455 * Requests a hint about the valid range of values for the state of the
456 * named action within @action_group.
458 * If %NULL is returned it either means that the action is not stateful
459 * or that there is no hint about the valid range of values for the
460 * state of the action.
462 * If a #GVariant array is returned then each item in the array is a
463 * possible value for the state. If a #GVariant pair (ie: two-tuple) is
464 * returned then the tuple specifies the inclusive lower and upper bound
465 * of valid values for the state.
467 * In any case, the information is merely a hint. It may be possible to
468 * have a state value outside of the hinted range and setting a value
469 * within the range may fail.
471 * The return value (if non-%NULL) should be freed with
472 * g_variant_unref() when it is no longer required.
474 * Returns: (nullable) (transfer full): the state range hint
479 g_action_group_get_action_state_hint (GActionGroup *action_group,
480 const gchar *action_name)
482 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), NULL);
484 return G_ACTION_GROUP_GET_IFACE (action_group)
485 ->get_action_state_hint (action_group, action_name);
489 * g_action_group_get_action_enabled:
490 * @action_group: a #GActionGroup
491 * @action_name: the name of the action to query
493 * Checks if the named action within @action_group is currently enabled.
495 * An action must be enabled in order to be activated or in order to
496 * have its state changed from outside callers.
498 * Returns: whether or not the action is currently enabled
503 g_action_group_get_action_enabled (GActionGroup *action_group,
504 const gchar *action_name)
506 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), FALSE);
508 return G_ACTION_GROUP_GET_IFACE (action_group)
509 ->get_action_enabled (action_group, action_name);
513 * g_action_group_get_action_state:
514 * @action_group: a #GActionGroup
515 * @action_name: the name of the action to query
517 * Queries the current state of the named action within @action_group.
519 * If the action is not stateful then %NULL will be returned. If the
520 * action is stateful then the type of the return value is the type
521 * given by g_action_group_get_action_state_type().
523 * The return value (if non-%NULL) should be freed with
524 * g_variant_unref() when it is no longer required.
526 * Returns: (nullable) (transfer full): the current state of the action
531 g_action_group_get_action_state (GActionGroup *action_group,
532 const gchar *action_name)
534 g_return_val_if_fail (G_IS_ACTION_GROUP (action_group), NULL);
536 return G_ACTION_GROUP_GET_IFACE (action_group)
537 ->get_action_state (action_group, action_name);
541 * g_action_group_change_action_state:
542 * @action_group: a #GActionGroup
543 * @action_name: the name of the action to request the change on
544 * @value: the new state
546 * Request for the state of the named action within @action_group to be
549 * The action must be stateful and @value must be of the correct type.
550 * See g_action_group_get_action_state_type().
552 * This call merely requests a change. The action may refuse to change
553 * its state or may change its state to something other than @value.
554 * See g_action_group_get_action_state_hint().
556 * If the @value GVariant is floating, it is consumed.
561 g_action_group_change_action_state (GActionGroup *action_group,
562 const gchar *action_name,
565 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
566 g_return_if_fail (action_name != NULL);
567 g_return_if_fail (value != NULL);
569 G_ACTION_GROUP_GET_IFACE (action_group)
570 ->change_action_state (action_group, action_name, value);
574 * g_action_group_activate_action:
575 * @action_group: a #GActionGroup
576 * @action_name: the name of the action to activate
577 * @parameter: (nullable): parameters to the activation
579 * Activate the named action within @action_group.
581 * If the action is expecting a parameter, then the correct type of
582 * parameter must be given as @parameter. If the action is expecting no
583 * parameters then @parameter must be %NULL. See
584 * g_action_group_get_action_parameter_type().
586 * If the #GActionGroup implementation supports asynchronous remote
587 * activation over D-Bus, this call may return before the relevant
588 * D-Bus traffic has been sent, or any replies have been received. In
589 * order to block on such asynchronous activation calls,
590 * g_dbus_connection_flush() should be called prior to the code, which
591 * depends on the result of the action activation. Without flushing
592 * the D-Bus connection, there is no guarantee that the action would
593 * have been activated.
595 * The following code which runs in a remote app instance, shows an
596 * example of a "quit" action being activated on the primary app
597 * instance over D-Bus. Here g_dbus_connection_flush() is called
598 * before `exit()`. Without g_dbus_connection_flush(), the "quit" action
599 * may fail to be activated on the primary instance.
601 * |[<!-- language="C" -->
602 * // call "quit" action on primary instance
603 * g_action_group_activate_action (G_ACTION_GROUP (app), "quit", NULL);
605 * // make sure the action is activated now
606 * g_dbus_connection_flush (...);
608 * g_debug ("application has been terminated. exiting.");
616 g_action_group_activate_action (GActionGroup *action_group,
617 const gchar *action_name,
620 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
621 g_return_if_fail (action_name != NULL);
623 G_ACTION_GROUP_GET_IFACE (action_group)
624 ->activate_action (action_group, action_name, parameter);
628 * g_action_group_action_added:
629 * @action_group: a #GActionGroup
630 * @action_name: the name of an action in the group
632 * Emits the #GActionGroup::action-added signal on @action_group.
634 * This function should only be called by #GActionGroup implementations.
639 g_action_group_action_added (GActionGroup *action_group,
640 const gchar *action_name)
642 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
643 g_return_if_fail (action_name != NULL);
645 g_signal_emit (action_group,
646 g_action_group_signals[SIGNAL_ACTION_ADDED],
647 g_quark_try_string (action_name),
652 * g_action_group_action_removed:
653 * @action_group: a #GActionGroup
654 * @action_name: the name of an action in the group
656 * Emits the #GActionGroup::action-removed signal on @action_group.
658 * This function should only be called by #GActionGroup implementations.
663 g_action_group_action_removed (GActionGroup *action_group,
664 const gchar *action_name)
666 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
667 g_return_if_fail (action_name != NULL);
669 g_signal_emit (action_group,
670 g_action_group_signals[SIGNAL_ACTION_REMOVED],
671 g_quark_try_string (action_name),
676 * g_action_group_action_enabled_changed:
677 * @action_group: a #GActionGroup
678 * @action_name: the name of an action in the group
679 * @enabled: whether or not the action is now enabled
681 * Emits the #GActionGroup::action-enabled-changed signal on @action_group.
683 * This function should only be called by #GActionGroup implementations.
688 g_action_group_action_enabled_changed (GActionGroup *action_group,
689 const gchar *action_name,
692 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
693 g_return_if_fail (action_name != NULL);
697 g_signal_emit (action_group,
698 g_action_group_signals[SIGNAL_ACTION_ENABLED_CHANGED],
699 g_quark_try_string (action_name),
705 * g_action_group_action_state_changed:
706 * @action_group: a #GActionGroup
707 * @action_name: the name of an action in the group
708 * @state: the new state of the named action
710 * Emits the #GActionGroup::action-state-changed signal on @action_group.
712 * This function should only be called by #GActionGroup implementations.
717 g_action_group_action_state_changed (GActionGroup *action_group,
718 const gchar *action_name,
721 g_return_if_fail (G_IS_ACTION_GROUP (action_group));
722 g_return_if_fail (action_name != NULL);
724 g_signal_emit (action_group,
725 g_action_group_signals[SIGNAL_ACTION_STATE_CHANGED],
726 g_quark_try_string (action_name),
732 * g_action_group_query_action:
733 * @action_group: a #GActionGroup
734 * @action_name: the name of an action in the group
735 * @enabled: (out): if the action is presently enabled
736 * @parameter_type: (out) (transfer none) (optional): the parameter type, or %NULL if none needed
737 * @state_type: (out) (transfer none) (optional): the state type, or %NULL if stateless
738 * @state_hint: (out) (optional): the state hint, or %NULL if none
739 * @state: (out) (optional): the current state, or %NULL if stateless
741 * Queries all aspects of the named action within an @action_group.
743 * This function acquires the information available from
744 * g_action_group_has_action(), g_action_group_get_action_enabled(),
745 * g_action_group_get_action_parameter_type(),
746 * g_action_group_get_action_state_type(),
747 * g_action_group_get_action_state_hint() and
748 * g_action_group_get_action_state() with a single function call.
750 * This provides two main benefits.
752 * The first is the improvement in efficiency that comes with not having
753 * to perform repeated lookups of the action in order to discover
754 * different things about it. The second is that implementing
755 * #GActionGroup can now be done by only overriding this one virtual
758 * The interface provides a default implementation of this function that
759 * calls the individual functions, as required, to fetch the
760 * information. The interface also provides default implementations of
761 * those functions that call this function. All implementations,
762 * therefore, must override either this function or all of the others.
764 * If the action exists, %TRUE is returned and any of the requested
765 * fields (as indicated by having a non-%NULL reference passed in) are
766 * filled. If the action doesn't exist, %FALSE is returned and the
767 * fields may or may not have been modified.
769 * Returns: %TRUE if the action exists, else %FALSE
774 g_action_group_query_action (GActionGroup *action_group,
775 const gchar *action_name,
777 const GVariantType **parameter_type,
778 const GVariantType **state_type,
779 GVariant **state_hint,
782 return G_ACTION_GROUP_GET_IFACE (action_group)
783 ->query_action (action_group, action_name, enabled, parameter_type, state_type, state_hint, state);