forked from AuroraMiddleware/gtk
74dcbae1f3
Remove some less than accurate details, and add an illustration.
333 lines
13 KiB
XML
333 lines
13 KiB
XML
<?xml version="1.0"?>
|
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
|
]>
|
|
<refentry id="chap-input-handling">
|
|
<refmeta>
|
|
<refentrytitle>The GTK Input Model</refentrytitle>
|
|
<manvolnum>3</manvolnum>
|
|
<refmiscinfo>GTK Library</refmiscinfo>
|
|
</refmeta>
|
|
|
|
<refnamediv>
|
|
<refname>The GTK Input Model</refname>
|
|
<refpurpose>
|
|
input and event handling in detail
|
|
</refpurpose>
|
|
</refnamediv>
|
|
|
|
|
|
<refsect1 id="input-overview">
|
|
<title>Overview of GTK input and event handling</title>
|
|
|
|
<para>
|
|
This chapter describes in detail how GTK handles input. If you are interested
|
|
in what happens to translate a key press or mouse motion of the users into a
|
|
change of a GTK widget, you should read this chapter. This knowledge will also
|
|
be useful if you decide to implement your own widgets.
|
|
</para>
|
|
|
|
<refsect2>
|
|
<title>Devices and events</title>
|
|
|
|
<!-- input devices: master/slave, keyboard/pointer/touch -->
|
|
<para>
|
|
The most basic input devices that every computer user has interacted with are
|
|
keyboards and mice; beyond these, GTK supports touchpads, touchscreens and
|
|
more exotic input devices such as graphics tablets. Inside GTK, every such
|
|
input device is represented by a #GdkDevice object.
|
|
</para>
|
|
|
|
<para>
|
|
To simplify dealing with the variability between these input devices, GTK
|
|
has a concept of master and slave devices. The concrete physical devices that
|
|
have many different characteristics (mice may have 2 or 3 or 8 buttons,
|
|
keyboards have different layouts and may or may not have a separate number
|
|
block, etc) are represented as slave devices. Each slave device is
|
|
associated with a virtual master device. Master devices always come in
|
|
pointer/keyboard pairs - you can think of such a pair as a 'seat'.
|
|
</para>
|
|
<para>
|
|
GTK widgets generally deal with the master devices, and thus can be used
|
|
with any pointing device or keyboard.
|
|
</para>
|
|
|
|
<para>
|
|
When a user interacts with an input device (e.g. moves a mouse or presses
|
|
a key on the keyboard), GTK receives events from the windowing system.
|
|
These are typically directed at a specific surface - for pointer events,
|
|
the surface under the pointer (grabs complicate this), for keyboard events,
|
|
the surface with the keyboard focus.
|
|
</para>
|
|
<para>
|
|
GDK translates these raw windowing system events into #GdkEvents.
|
|
Typical input events are button clicks, pointer motion, key presses
|
|
or touch events. These are all represented as #GdkEvents, but you can
|
|
differentiate between different events by looking at their type, using
|
|
gdk_event_get_event_type().
|
|
</para>
|
|
<para>
|
|
Some events, such as touch events or button press-release pairs,
|
|
are connected in to each other in an “event sequence” that
|
|
univocally identifies events that are related to the same
|
|
interaction.
|
|
</para>
|
|
<para>
|
|
When GTK creates a GdkSurface, it connects to the #GdkSurface::event
|
|
signal on it, which receives all of these input events. Surfaces have
|
|
have signals and properties, e.g. to deal with window management
|
|
related events.
|
|
</para>
|
|
</refsect2>
|
|
|
|
<refsect2 id="event-propagation">
|
|
<title>Event propagation</title>
|
|
|
|
<para>
|
|
The function which initially receives input events on the GTK
|
|
side is responsible for a number of tasks.
|
|
</para>
|
|
<orderedlist>
|
|
<listitem><para>
|
|
Find the widget which got the event.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Generate crossing (i.e. enter and leave) events when the focus or hover
|
|
location change from one widget to another.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
The event is sent to widgets.
|
|
</para></listitem>
|
|
</orderedlist>
|
|
|
|
<para>
|
|
An event is propagated down and up the widget hierarchy in three phases
|
|
(see #GtkPropagationPhase) towards a target widget.
|
|
</para>
|
|
|
|
<informalfigure>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata fileref="capture-bubble.png" format="PNG"/>
|
|
</imageobject>
|
|
</mediaobject>
|
|
</informalfigure>
|
|
|
|
<para>
|
|
For key events, the top-level window gets a first shot at activating
|
|
mnemonics and accelerators. If that does not consume the events,
|
|
the target widget for event propagation is window's current focus
|
|
widget (see gtk_window_get_focus()).
|
|
</para>
|
|
|
|
<para>
|
|
For pointer events, the target widget is determined by picking
|
|
the widget at the events coordinates (see gtk_window_pick()).
|
|
</para>
|
|
|
|
<para>In the first phase (the “capture” phase) the event is
|
|
delivered to each widget from the top-most (the top-level
|
|
#GtkWindow or grab widget) down to the target #GtkWidget.
|
|
<link linkend="event-controllers-and-gestures">Event
|
|
controllers</link> that are attached with %GTK_PHASE_CAPTURE
|
|
get a chance to react to the event.
|
|
</para>
|
|
|
|
<para>
|
|
After the “capture” phase, the widget that was intended to be the
|
|
destination of the event will run event controllers attached to
|
|
it with %GTK_PHASE_TARGET. This is known as the “target” phase,
|
|
and only happens on that widget.
|
|
</para>
|
|
|
|
<para>
|
|
In the last phase (the “bubble” phase), the event is delivered
|
|
to each widget from the target to the top-most, and event
|
|
controllers attached with %GTK_PHASE_BUBBLE are run.
|
|
</para>
|
|
|
|
<para>
|
|
Events are not delivered to a widget which is insensitive or
|
|
unmapped.
|
|
</para>
|
|
|
|
<para>
|
|
Any time during the propagation phase, a controller may indicate
|
|
that a received event was consumed and propagation should
|
|
therefore be stopped. If gestures are used, this may happen
|
|
when the gesture claims the event touch sequence (or the
|
|
pointer events) for its own. See the “gesture states” section
|
|
below to learn more about gestures and sequences.
|
|
</para>
|
|
</refsect2>
|
|
|
|
<refsect2>
|
|
<title>Keyboard input</title>
|
|
|
|
<para>
|
|
Every #GtkWindow maintains a single focus location (in the
|
|
#GtkWindow:focus-widget property). The focus widget is the target
|
|
widget for key events sent to the window. Only widgets which have
|
|
#GtkWidget:can-focus set to %TRUE can become the focus. Typically
|
|
these are input controls such as entries or text fields, but e.g.
|
|
buttons can take the focus too.
|
|
</para>
|
|
|
|
<para>
|
|
Input widgets can be given the focus by clicking on them, but focus
|
|
can also be moved around with certain key events (this is known as
|
|
“keyboard navigation”). GTK reserves the Tab key to move the focus
|
|
to the next location, and Shift-Tab to move it back to the previous
|
|
one. In addition many containers allow “directional navigation” with
|
|
the arrow keys.
|
|
</para>
|
|
|
|
<para>
|
|
Many widgets can be “activated” to trigger and action. E.g., you can
|
|
activate a button or switch by clicking on them, but you can also
|
|
activate them with the keyboard, by using the Enter or Space keys.
|
|
</para>
|
|
|
|
<para>
|
|
Apart from keyboard navigation, activation and directly typing into
|
|
entries or text views, GTK widgets can use key events for activating
|
|
“shortcuts”. Shortcuts generally act as a quick way to move the focus
|
|
around or to activate a widget that does not currently have the focus.
|
|
</para>
|
|
|
|
<para>
|
|
GTK has traditionally supported different kinds of shortcuts:
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>Accelerators</term>
|
|
<listitem><para>
|
|
Accelerators are any other shortcuts that can be activated regardless
|
|
of where the focus is, and typically trigger global actions, such as
|
|
Ctrl-Q to quit an application.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Mnmemonics</term>
|
|
<listitem><para>
|
|
Mnemonics are usually triggered using Alt as a modifier for a letter.
|
|
They are used in places where a label is associated with a control,
|
|
and are indicated by underlining the letter in the label. As a special
|
|
case, inside menus (i.e. inside #GtkPopoverMenu), mnemonics can be
|
|
trigered without the modifier.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>Key bindings</term>
|
|
<listitem><para>
|
|
Key bindings are specific to individual widgets, such as Ctrl-C or
|
|
Ctrl-V in an entry copy to or paste from the clipboard. They are only
|
|
triggered when the widget has focus.
|
|
</para></listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
<para>
|
|
GTK traditionally handles accelerators and mnemonics in a global scope,
|
|
during the capture phase, and key bindings locally, during the target phase.
|
|
</para>
|
|
<para>
|
|
Under the hood, all shortcuts are represented as instances of #GtkShortcut,
|
|
and they are managed by #GtkShortcutController.
|
|
</para>
|
|
</refsect2>
|
|
|
|
<refsect2 id="event-controllers-and-gestures">
|
|
<title>Event controllers and gestures</title>
|
|
|
|
<para>
|
|
Event controllers are standalone objects that can perform
|
|
specific actions upon received #GdkEvents. These are tied
|
|
to a #GtkWidget, and can be told of the event propagation
|
|
phase at which they will manage the events.
|
|
</para>
|
|
|
|
<para>
|
|
Gestures are a set of specific controllers that are prepared
|
|
to handle pointer and/or touch events, each gesture
|
|
implementation attempts to recognize specific actions out the
|
|
received events, notifying of the state/progress accordingly to
|
|
let the widget react to those. On multi-touch gestures, every
|
|
interacting touch sequence will be tracked independently.
|
|
</para>
|
|
|
|
<para>
|
|
Since gestures are “simple” units, it is not uncommon to tie
|
|
several together to perform higher level actions, grouped
|
|
gestures handle the same event sequences simultaneously, and
|
|
those sequences share a same state across all grouped
|
|
gestures. Some examples of grouping may be:
|
|
|
|
<simplelist>
|
|
<member>
|
|
A “drag” and a “swipe” gestures may want grouping.
|
|
The former will report events as the dragging happens,
|
|
the latter will tell the swipe X/Y velocities only after
|
|
recognition has finished.
|
|
</member>
|
|
<member>
|
|
Grouping a “drag” gesture with a “pan” gesture will only
|
|
effectively allow dragging in the panning orientation, as
|
|
both gestures share state.
|
|
</member>
|
|
<member>
|
|
If “press” and “long press” are wanted simultaneously,
|
|
those would need grouping.
|
|
</member>
|
|
</simplelist>
|
|
</para>
|
|
|
|
<para>
|
|
Shortcuts are handled by #GtkShortcutController, which is
|
|
a complex event handler that can either activate shortcuts
|
|
itself, or propagate them to another controller, depending
|
|
on its #GtkShortcutController:scope.
|
|
</para>
|
|
</refsect2>
|
|
|
|
<refsect2>
|
|
<title>Gesture states</title>
|
|
<para>
|
|
Gestures have a notion of “state” for each individual touch
|
|
sequence. When events from a touch sequence are first received,
|
|
the touch sequence will have “none” state, this means the touch
|
|
sequence is being handled by the gesture to possibly trigger
|
|
actions, but the event propagation will not be stopped.
|
|
</para>
|
|
|
|
<para>
|
|
When the gesture enters recognition, or at a later point in time,
|
|
the widget may choose to claim the touch sequences (individually
|
|
or as a group), hence stopping event propagation after the event
|
|
is run through every gesture in that widget and propagation phase.
|
|
Anytime this happens, the touch sequences are cancelled downwards
|
|
the propagation chain, to let these know that no further events
|
|
will be sent.
|
|
</para>
|
|
|
|
<para>
|
|
Alternatively, or at a later point in time, the widget may choose
|
|
to deny the touch sequences, thus letting those go through again
|
|
in event propagation. When this happens in the capture phase, and
|
|
if there are no other claiming gestures in the widget,
|
|
a %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS event will be emulated and
|
|
propagated downwards, in order to preserve consistency.
|
|
</para>
|
|
|
|
<para>
|
|
Grouped gestures always share the same state for a given touch
|
|
sequence, so setting the state on one does transfer the state to
|
|
the others. They also are mutually exclusive, within a widget
|
|
there may be only one gesture group claiming a given sequence.
|
|
If another gesture group claims later that same sequence, the
|
|
first group will deny the sequence.
|
|
</para>
|
|
</refsect2>
|
|
|
|
</refsect1>
|
|
</refentry>
|