forked from AuroraMiddleware/gtk
bceca277ea
Remove references to no longer existing apis, and reword some things. Say surface instead of window. Start filling out the keyboard section.
340 lines
13 KiB
XML
340 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:
|
||
<simplelist>
|
||
<member>#GdkEventButton</member>
|
||
<member>#GdkEventMotion</member>
|
||
<member>#GdkEventCrossing</member>
|
||
<member>#GdkEventKey</member>
|
||
<member>#GdkEventFocus</member>
|
||
<member>#GdkEventTouch</member>
|
||
</simplelist>
|
||
</para>
|
||
<para>
|
||
Additionally, GDK/GTK synthesizes other signals to let know whether
|
||
grabs (system-wide or in-app) are taking input away:
|
||
<simplelist>
|
||
<member>#GdkEventGrabBroken</member>
|
||
<member>#GtkWidget::grab-notify</member>
|
||
</simplelist>
|
||
</para>
|
||
<para>
|
||
When GTK creates a GdkSurface, it connects to the ::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 gtk_main_do_event(). See its documentation
|
||
for details of what it does: compression of enter/leave events,
|
||
identification of the widget receiving the event, pushing the event onto a
|
||
stack for gtk_get_current_event(), and propagating the event to the
|
||
widget.
|
||
</para>
|
||
|
||
<para>
|
||
When a GDK backend produces an input event, it is tied to a #GdkDevice and
|
||
a #GdkSurface, which in turn represents a windowing system surface in the
|
||
backend. If a widget has grabbed the current input device, or all input
|
||
devices, the event is propagated to that #GtkWidget. Otherwise, it is
|
||
propagated to the the #GtkWidget which called gtk_widget_register_surface()
|
||
on the #GdkSurface receiving the event.
|
||
</para>
|
||
|
||
<para>
|
||
Grabs are implemented for each input device, and globally. A grab for a
|
||
specific input device (gtk_device_grab_add()), is sent events in
|
||
preference to a global grab (gtk_grab_add()). Input grabs only have effect
|
||
within the #GtkWindowGroup containing the #GtkWidget which registered the
|
||
event’s #GdkSurface. If this #GtkWidget is a child of the grab widget, the
|
||
event is propagated to the child — this is the basis for propagating
|
||
events within modal dialogs.
|
||
</para>
|
||
|
||
<para>
|
||
An event is propagated to a widget using gtk_propagate_event().
|
||
Propagation goes down and up the widget hierarchy in three phases
|
||
(see #GtkPropagationPhase) towards a target widget.
|
||
</para>
|
||
|
||
<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>Touch events</title>
|
||
|
||
<para>
|
||
Touch events are emitted as events of type %GDK_TOUCH_BEGIN,
|
||
%GDK_TOUCH_UPDATE or %GDK_TOUCH_END, those events contain an
|
||
“event sequence” that univocally identifies the physical touch
|
||
until it is lifted from the device.
|
||
</para>
|
||
</refsect2>
|
||
|
||
<refsect2>
|
||
<title>Grabs</title>
|
||
|
||
<para>
|
||
Grabs are a method to claim all input events from a device,
|
||
they happen either implicitly on pointer and touch devices,
|
||
or explicitly. Implicit grabs happen on user interaction, when
|
||
a #GdkEventButtonPress happens, all events from then on, until
|
||
after the corresponding #GdkEventButtonRelease, will be reported
|
||
to the widget that got the first event. Likewise, on touch events,
|
||
every #GdkEventSequence will deliver only events to the widget
|
||
that received its %GDK_TOUCH_BEGIN event.
|
||
</para>
|
||
|
||
<para>
|
||
Explicit grabs happen programatically (both activation and
|
||
deactivation), and can be either system-wide (GDK grabs) or
|
||
application-wide (GTK grabs). On the windowing platforms that
|
||
support it, GDK grabs will prevent any interaction with any other
|
||
application/window/widget than the grabbing one, whereas GTK grabs
|
||
will be effective only within the application (across all its
|
||
windows), still allowing for interaction with other applications.
|
||
</para>
|
||
|
||
<para>
|
||
But one important aspect of grabs is that they may potentially
|
||
happen at any point somewhere else, even while the pointer/touch
|
||
device is already grabbed. This makes it necessary for widgets to
|
||
handle the cancellation of any ongoing interaction. Depending on
|
||
whether a GTK or GDK grab is causing this, the widget will
|
||
respectively receive a #GtkWidget::grab-notify signal, or a
|
||
#GdkEventGrabBroken event.
|
||
</para>
|
||
|
||
<para>
|
||
On gestures, these signals are handled automatically, causing the
|
||
gesture to cancel all tracked pointer/touch events, and signal
|
||
the end of recognition.
|
||
</para>
|
||
</refsect2>
|
||
|
||
<refsect2>
|
||
<title>Keyboard input</title>
|
||
|
||
<para>
|
||
Every #GtkWindow maintains a single focus location (in
|
||
the ::focus-widget property). The focus widget is the
|
||
target widget for key events sent to the window. Only
|
||
widgets which have ::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>
|
||
|
||
<!-- mnemonics, accelerators, bindings -->
|
||
</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>
|
||
</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>
|