9.8 KiB
Title: Overview of actions in GTK Slug: actions
This chapter describes in detail how GTK uses actions to connect
activatable UI elements to callbacks. GTK inherits the underlying
architecture of GAction
and GMenu
for describing abstract actions
and menus from the GIO library.
Basics about actions
A GAction
is essentially a way to tell the toolkit about a piece of
functionality in your program, and to give it a name.
Actions are purely functional. They do not contain any presentational information.
An action has four pieces of information associated with it:
- a name as an identifier (usually all-lowercase, untranslated English string)
- an enabled flag indicating if the action can be activated or not (like the "sensitive" property on widgets)
- an optional state value, for stateful actions (like a boolean for toggles)
- an optional parameter type, used when activating the action
An action supports two operations. You can activate it, which requires passing a parameter of the correct type And you can request to change the actions state (for stateful actions) to a new state value of the correct type.
Here are some rules about an action:
- the name is immutable (in the sense that it will never change) and it is never %NULL
- the enabled flag can change
- the parameter type is immutable
- the parameter type is optional: it can be %NULL
- if the parameter type is %NULL then action activation must be done without a parameter (ie: a %NULL GVariant pointer)
- if the parameter type is non-%NULL then the parameter must have this type
- the state can change, but it cannot change type
- if the action was stateful when it was created, it will always have a state and it will always have exactly the same type (such as boolean or string)
- if the action was stateless when it was created, it can never have a state
- you can only request state changes on stateful actions and it is only possible to request that the state change to a value of the same type as the existing state
An action does not have any sort of presentational information such as a label, an icon or a way of creating a widget from it.
Action state and parameters
Most actions in your application will be stateless actions with no parameters. These typically appear as menu items with no special decoration. An example is "quit".
Stateful actions are used to represent an action which has a closely-associated state of some kind. A good example is a "fullscreen" action. For this case, you would expect to see a checkmark next to the menu item when the fullscreen option is active. This is usually called a toggle action, and it has a boolean state. By convention, toggle actions have no parameter type for activation: activating the action always toggles the state.
Another common case is to have an action representing a enumeration of possible values of a given type (typically string). This is often called a radio action and is usually represented in the user interface with radio buttons or radio menu items, or sometimes a combobox. A good example is "text-justify" with possible values "left", "center", and "right". By convention, these types of actions have a parameter type equal to their state type, and activating them with a particular parameter value is equivalent to changing their state to that value.
This approach to handling radio buttons is different than many other
action systems such as GtkAction
. With GAction
, there is only one action
for "text-justify" and "left", "center" and "right" are possible states on
that action. There are not three separate "justify-left", "justify-center"
and "justify-right" actions.
The final common type of action is a stateless action with a parameter. This is typically used for actions like "open-bookmark" where the parameter to the action would be the identifier of the bookmark to open.
Because some types of actions cannot be invoked without a parameter, it is often important to specify a parameter when referring to the action from a place where it will be invoked (such as from a radio button that sets the state to a particular value or from a menu item that opens a specific bookmark). In these contexts, the value used for the action parameter is typically called the target of the action.
Even though toggle actions have a state, they do not have a parameter. Therefore, a target value is not needed when referring to them — they will always be toggled on activation.
Most APIs that allow using a GAction
(such as GMenuModel
and GtkActionable
)
allow use of detailed action names. This is a convenient way of specifying
an action name and an action target with a single string.
In the case that the action target is a string with no unusual characters (ie: only alphanumeric, plus '-' and '.') then you can use a detailed action name of the form "justify::left" to specify the justify action with a target of left.
In the case that the action target is not a string, or contains unusual characters, you can use the more general format "action-name(5)", where the "5" here is any valid text-format GVariant (ie: a string that can be parsed by g_variant_parse()). Another example is "open-bookmark('http://gnome.org/')".
You can convert between detailed action names and split-out action names and target values using g_action_parse_detailed_name() and g_action_print_detailed_name() but usually you will not need to. Most APIs will provide both ways of specifying actions with targets.
Action scopes
Actions are always scoped to a particular object on which they operate.
In GTK, actions are typically scoped to either an application or a window, but any widget can have actions associated with it.
Actions scoped to windows should be the actions that specifically impact that window. These are actions like "fullscreen" and "close", or in the case that a window contains a document, "save" and "print".
Actions that impact the application as a whole rather than one specific window are scoped to the application. These are actions like "about" and "preferences".
If a particular action is scoped to a window then it is scoped to a specific window. Another way of saying this: if your application has a "fullscreen" action that applies to windows and it has three windows, then it will have three fullscreen actions: one for each window.
Having a separate action per-window allows for each window to have a separate state for each instance of the action as well as being able to control the enabled state of the action on a per-window basis.
Actions are added to their relevant scope (application, window or widget)
either using the GActionMap
interface, or by using
gtk_widget_insert_action_group(). Actions that will be the same for all
instances of a widget class can be added globally using
gtk_widget_class_install_action().
Action groups and action maps
Actions rarely occurs in isolation. It is common to have groups
of related actions, which are represented by instances of the
GActionGroup
interface.
Action maps are a variant of action groups that allow to change the name of the action as it is looked up. In GTK, the convention is to add a prefix to the action name to indicate the scope of the actions, such as "app." for the actions with application scope or "win." for those with window scope.
When referring to actions on a GActionMap only the name of the
action itself is used (ie: "quit", not "app.quit"). The
"app.quit" form is only used when referring to actions from
places like a GMenu
or GtkActionable
widget where the scope
of the action is not already known.
GtkApplication
and GtkApplicationWindow
implement the GActionMap
interface, so you can just add actions directly to them. For
other widgets, use gtk_widget_insert_action_group() to add
actions to it.
If you want to insert several actions at the same time, it is
typically faster and easier to use GActionEntry
.
Connecting actions to widgets
Any widget that implements the GtkActionable
interface can
be connected to an action just by setting the ::action-name
property. If the action has a parameter, you will also need
to set the ::action-target property. Widgets that implement
GtkActionable
include GtkSwitch
, GtkButton
, and their
respective subclasses.
Another way of obtaining widgets that are connected to actions
is to create a menu using a GMenu
menu model. GMenu
provides an
abstract way to describe typical menus: nested groups of items
where each item can have a label, and icon, and an action.
A typical use of GMenu
inside GTK is to set up an application
menubar with gtk_application_set_menubar(). Another, maybe more
common use is to create a popover for a menubutton, using
gtk_menu_button_set_menu_model().
Unlike traditional menus, those created from menu models don't
have keyboard accelerators associated with menu items. Instead,
GtkApplication
offers the gtk_application_set_accels_for_action()
API to associate keyboard shortcuts with actions.
Activation
When a widget with a connected action is activated, GTK finds
the action to activate by walking up the widget hierarchy,
looking for a matching action, ending up at the GtkApplication
.
Built-in Actions
GTK uses actions for its own purposes in a number places. These built-in actions can sometimes be activated by applications, and you should avoid naming conflicts with them when creating your own actions.
- default.activate
- Activates the default widget in a context (typically a
GtkWindow
,GtkDialog
orGtkPopover
) - clipboard.cut, clipboard.copy, clipboard.paste
- Clipboard operations on entries, text view and labels, typically used in the context menu
- selection.delete, selection.select-all
- Selection operations on entries, text view and labels
- color.select, color.customize
- Operate on colors in a
GtkColorChooserWidget
. These actions are unusual in that they have the non-trivial parameter type (dddd).