From 8c21b0bee5a551870bc22268273dd2b436260d56 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 28 May 2014 15:50:06 +0200 Subject: [PATCH] docs: Add some more information in the "input handling model" chapter Grabs/Touch/Gestures are now fairly well covered. Only keyboard handling is left. --- docs/reference/gtk/input-handling.xml | 167 ++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 9 deletions(-) diff --git a/docs/reference/gtk/input-handling.xml b/docs/reference/gtk/input-handling.xml index 4806b9e3c4..92017072fc 100644 --- a/docs/reference/gtk/input-handling.xml +++ b/docs/reference/gtk/input-handling.xml @@ -72,6 +72,14 @@ GdkEventTouch + + Additionally, GDK/GTK synthesizes other signals to let know whether + grabs (system-wide or in-app) are taking input away: + + GdkEventGrabBroken + GtkWidget::grab-notify + + When GTK+ is initialized, it sets up an event handler function with gdk_event_handler_set(), which receives all of these input events @@ -95,6 +103,13 @@ to react to the event. + + After the “capture” phase, the widget that was intended to be the + destination of the event will let run gestures attached to it with + GTK_PHASE_TARGET. This is known as the “target” phase, and does only + happen on that widget. + + Next, the appropriate event signal is emitted for the event in question, e.g. “motion-notify-event”. Handling these signals was the primary @@ -106,19 +121,85 @@ The default handlers for the event signals send the event - to gestures that are attached with GTK_PHASE_TARGET. Therefore, - gestures in the ”target” phase are only used if the widget does + to gestures that are attached with GTK_PHASE_BUBBLE. Therefore, + gestures in the “bubble” phase are only used if the widget does not have its own event handlers, or takes care to chain up to the - default handlers. + default GtkWidget handlers. - After calling the event handlers, in the so-called ”bubble” phase, - gestures that are attached with GTK_PHASE_BUBBLE get a chance - to react to the event. + Anytime during the propagation phase, a widget may indicate that a + received event was consumed and propagation should therefore be stopped. + In traditional event handlers, this is hinted by returning GDK_EVENT_STOP, + if gestures are used, this may happen when the widget tells the gesture + to claim the event touch sequence (or the pointer events) for its own. See the + "gesture states" section below to know more of the latter. + + + + + Touch events + + + 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. - + + On some windowing platforms, multitouch devices perform pointer emulation, this works + by granting a “pointer emulating” hint to one of the currently interacting touch + sequences, which will be reported on every GdkEventTouch event from that sequence. By + default, if a widget didn't request touch events by setting GDK_TOUCH_MASK on its + event mask and didn't override GtkWidget::touch-event, GTK+ will transform these + “pointer emulating” events into semantically similar GdkEventButton and GdkEventMotion + events. Depending on GDK_TOUCH_MASK being in the event mask or not, non-pointer-emulating + sequences could still trigger gestures or just get filtered out, regardless of the widget + not handling those directly. + + + + If the widget sets GDK_TOUCH_MASK on its event mask and doesn't chain up on + GtkWidget::touch-event, only touch events will be received, and no pointer emulation + will be performed. + + + + + Grabs + + + 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. + + + + 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. + + + + 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. + + + + On gestures, these signals are handled automatically, causing the gesture + to cancel all tracked pointer/touch events, and signal the end of recognition. + @@ -129,9 +210,77 @@ - Gestures + Event controllers and gestures - + + 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. + + + + Gestures are a set of specific controllers that are prepared to handle pointer + and/or touch events, each gestures 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. + + + + Being gestures “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: + + + + 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 gesture has finished. + + + Grouping a “drag” gesture with a “pan” gesture will only effectively allow + dragging in the panning orientation, as both gestures share state. + + + If “press” and “long press” are wanted simultaneously, those would need grouping. + + + + + + + Gesture states + + 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. + + + + 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. + + + + 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. + + + + 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. +