Copyright | Will Thompson and Iñaki García Etxebarria |
---|---|
License | LGPL-2.1 |
Maintainer | Iñaki García Etxebarria |
Safe Haskell | None |
Language | Haskell2010 |
GtkGesture
is the base class for gesture recognition.
Although GtkGesture
is quite generalized to serve as a base for
multi-touch gestures, it is suitable to implement single-touch and
pointer-based gestures (using the special Nothing
GdkEventSequence
value for these).
The number of touches that a GtkGesture
need to be recognized is
controlled by the Gesture:nPoints property, if a
gesture is keeping track of less or more than that number of sequences,
it won't check whether the gesture is recognized.
As soon as the gesture has the expected number of touches, it will check
regularly if it is recognized, the criteria to consider a gesture as
"recognized" is left to GtkGesture
subclasses.
A recognized gesture will then emit the following signals:
- Gesture::begin when the gesture is recognized.
- Gesture::update, whenever an input event is processed.
- Gesture::end when the gesture is no longer recognized.
Event propagation
In order to receive events, a gesture needs to set a propagation phase
through eventControllerSetPropagationPhase
.
In the capture phase, events are propagated from the toplevel down to the target widget, and gestures that are attached to containers above the widget get a chance to interact with the event before it reaches the target.
In the bubble phase, events are propagated up from the target widget to the toplevel, and gestures that are attached to containers above the widget get a chance to interact with events that have not been handled yet.
States of a sequence
Whenever input interaction happens, a single event may trigger a cascade
of GtkGesture
s, both across the parents of the widget receiving the
event and in parallel within an individual widget. It is a responsibility
of the widgets using those gestures to set the state of touch sequences
accordingly in order to enable cooperation of gestures around the
GdkEventSequence
s triggering those.
Within a widget, gestures can be grouped through gestureGroup
.
Grouped gestures synchronize the state of sequences, so calling
gestureSetState
on one will effectively propagate
the state throughout the group.
By default, all sequences start out in the EventSequenceStateNone
state,
sequences in this state trigger the gesture event handler, but event
propagation will continue unstopped by gestures.
If a sequence enters into the EventSequenceStateDenied
state, the gesture
group will effectively ignore the sequence, letting events go unstopped
through the gesture, but the "slot" will still remain occupied while
the touch is active.
If a sequence enters in the EventSequenceStateClaimed
state, the gesture
group will grab all interaction on the sequence, by:
- Setting the same sequence to
EventSequenceStateDenied
on every other gesture group within the widget, and every gesture on parent widgets in the propagation chain. - Emitting Gesture::cancel on every gesture in widgets underneath in the propagation chain.
- Stopping event propagation after the gesture group handles the event.
Note: if a sequence is set early to EventSequenceStateClaimed
on
EventTypeTouchBegin
/EventTypeButtonPress
(so those events are captured before
reaching the event widget, this implies PropagationPhaseCapture
), one similar
event will be emulated if the sequence changes to EventSequenceStateDenied
.
This way event coherence is preserved before event propagation is unstopped
again.
Sequence states can't be changed freely.
See gestureSetState
to know about the possible
lifetimes of a GdkEventSequence
.
Touchpad gestures
On the platforms that support it, GtkGesture
will handle transparently
touchpad gesture events. The only precautions users of GtkGesture
should
do to enable this support are:
- If the gesture has
PropagationPhaseNone
, ensuring events of typeEventTypeTouchpadSwipe
andEventTypeTouchpadPinch
are handled by theGtkGesture
Synopsis
- newtype Gesture = Gesture (ManagedPtr Gesture)
- class (GObject o, IsDescendantOf Gesture o) => IsGesture o
- toGesture :: (MonadIO m, IsGesture o) => o -> m Gesture
- gestureGetBoundingBox :: (HasCallStack, MonadIO m, IsGesture a) => a -> m (Bool, Rectangle)
- gestureGetBoundingBoxCenter :: (HasCallStack, MonadIO m, IsGesture a) => a -> m (Bool, Double, Double)
- gestureGetDevice :: (HasCallStack, MonadIO m, IsGesture a) => a -> m (Maybe Device)
- gestureGetGroup :: (HasCallStack, MonadIO m, IsGesture a) => a -> m [Gesture]
- gestureGetLastEvent :: (HasCallStack, MonadIO m, IsGesture a) => a -> Maybe EventSequence -> m (Maybe Event)
- gestureGetLastUpdatedSequence :: (HasCallStack, MonadIO m, IsGesture a) => a -> m (Maybe EventSequence)
- gestureGetPoint :: (HasCallStack, MonadIO m, IsGesture a) => a -> Maybe EventSequence -> m (Bool, Double, Double)
- gestureGetSequenceState :: (HasCallStack, MonadIO m, IsGesture a) => a -> EventSequence -> m EventSequenceState
- gestureGetSequences :: (HasCallStack, MonadIO m, IsGesture a) => a -> m [EventSequence]
- gestureGroup :: (HasCallStack, MonadIO m, IsGesture a, IsGesture b) => a -> b -> m ()
- gestureHandlesSequence :: (HasCallStack, MonadIO m, IsGesture a) => a -> Maybe EventSequence -> m Bool
- gestureIsActive :: (HasCallStack, MonadIO m, IsGesture a) => a -> m Bool
- gestureIsGroupedWith :: (HasCallStack, MonadIO m, IsGesture a, IsGesture b) => a -> b -> m Bool
- gestureIsRecognized :: (HasCallStack, MonadIO m, IsGesture a) => a -> m Bool
- gestureSetSequenceState :: (HasCallStack, MonadIO m, IsGesture a) => a -> EventSequence -> EventSequenceState -> m Bool
- gestureSetState :: (HasCallStack, MonadIO m, IsGesture a) => a -> EventSequenceState -> m Bool
- gestureUngroup :: (HasCallStack, MonadIO m, IsGesture a) => a -> m ()
- constructGestureNPoints :: (IsGesture o, MonadIO m) => Word32 -> m (GValueConstruct o)
- getGestureNPoints :: (MonadIO m, IsGesture o) => o -> m Word32
- type GestureBeginCallback = Maybe EventSequence -> IO ()
- afterGestureBegin :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureBeginCallback) -> m SignalHandlerId
- onGestureBegin :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureBeginCallback) -> m SignalHandlerId
- type GestureCancelCallback = Maybe EventSequence -> IO ()
- afterGestureCancel :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureCancelCallback) -> m SignalHandlerId
- onGestureCancel :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureCancelCallback) -> m SignalHandlerId
- type GestureEndCallback = Maybe EventSequence -> IO ()
- afterGestureEnd :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureEndCallback) -> m SignalHandlerId
- onGestureEnd :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureEndCallback) -> m SignalHandlerId
- type GestureSequenceStateChangedCallback = Maybe EventSequence -> EventSequenceState -> IO ()
- afterGestureSequenceStateChanged :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureSequenceStateChangedCallback) -> m SignalHandlerId
- onGestureSequenceStateChanged :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureSequenceStateChangedCallback) -> m SignalHandlerId
- type GestureUpdateCallback = Maybe EventSequence -> IO ()
- afterGestureUpdate :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureUpdateCallback) -> m SignalHandlerId
- onGestureUpdate :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureUpdateCallback) -> m SignalHandlerId
Exported types
Memory-managed wrapper type.
Instances
Eq Gesture Source # | |
GObject Gesture Source # | |
Defined in GI.Gtk.Objects.Gesture | |
ManagedPtrNewtype Gesture Source # | |
Defined in GI.Gtk.Objects.Gesture toManagedPtr :: Gesture -> ManagedPtr Gesture # | |
TypedObject Gesture Source # | |
Defined in GI.Gtk.Objects.Gesture | |
HasParentTypes Gesture Source # | |
Defined in GI.Gtk.Objects.Gesture | |
IsGValue (Maybe Gesture) Source # | Convert |
Defined in GI.Gtk.Objects.Gesture | |
type ParentTypes Gesture Source # | |
Defined in GI.Gtk.Objects.Gesture |
class (GObject o, IsDescendantOf Gesture o) => IsGesture o Source #
Instances
(GObject o, IsDescendantOf Gesture o) => IsGesture o Source # | |
Defined in GI.Gtk.Objects.Gesture |
Methods
Click to display all available methods, including inherited ones
Methods
bindProperty, bindPropertyFull, forceFloating, freezeNotify, getv, group, handlesSequence, isActive, isFloating, isGroupedWith, isRecognized, notify, notifyByPspec, ref, refSink, reset, runDispose, stealData, stealQdata, thawNotify, ungroup, unref, watchClosure.
Getters
getBoundingBox, getBoundingBoxCenter, getCurrentEvent, getCurrentEventDevice, getCurrentEventState, getCurrentEventTime, getData, getDevice, getGroup, getLastEvent, getLastUpdatedSequence, getName, getPoint, getPropagationLimit, getPropagationPhase, getProperty, getQdata, getSequenceState, getSequences, getWidget.
Setters
setData, setDataFull, setName, setPropagationLimit, setPropagationPhase, setProperty, setSequenceState, setState, setStaticName.
getBoundingBox
gestureGetBoundingBox Source #
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m (Bool, Rectangle) |
If there are touch sequences being currently handled by gesture
,
returns True
and fills in rect
with the bounding box containing
all active touches.
Otherwise, False
will be returned.
Note: This function will yield unexpected results on touchpad
gestures. Since there is no correlation between physical and
pixel distances, these will look as if constrained in an
infinitely small area, rect
width and height will thus be 0
regardless of the number of touchpoints.
getBoundingBoxCenter
getDevice
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m (Maybe Device) | Returns: a |
Returns the logical GdkDevice
that is currently operating
on gesture
.
This returns Nothing
if the gesture is not being interacted.
getGroup
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m [Gesture] | Returns: The list
of |
Returns all gestures in the group of gesture
getLastEvent
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> Maybe EventSequence |
|
-> m (Maybe Event) | Returns: The last event from |
Returns the last event that was processed for sequence
.
Note that the returned pointer is only valid as long as the
sequence
is still interpreted by the gesture
. If in doubt,
you should make a copy of the event.
getLastUpdatedSequence
gestureGetLastUpdatedSequence Source #
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m (Maybe EventSequence) | Returns: The last updated sequence |
Returns the GdkEventSequence
that was last updated on gesture
.
getPoint
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> Maybe EventSequence |
|
-> m (Bool, Double, Double) | Returns: |
If sequence
is currently being interpreted by gesture
,
returns True
and fills in x
and y
with the last coordinates
stored for that event sequence.
The coordinates are always relative to the widget allocation.
getSequenceState
gestureGetSequenceState Source #
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> EventSequence |
|
-> m EventSequenceState | Returns: The sequence state in |
Returns the sequence
state, as seen by gesture
.
getSequences
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m [EventSequence] | Returns: A list
of |
Returns the list of GdkEventSequences
currently being interpreted
by gesture
.
group
:: (HasCallStack, MonadIO m, IsGesture a, IsGesture b) | |
=> a |
|
-> b |
|
-> m () |
Adds gesture
to the same group than groupGesture
.
Gestures are by default isolated in their own groups.
Both gestures must have been added to the same widget before they can be grouped.
When gestures are grouped, the state of GdkEventSequences
is kept in sync for all of those, so calling
gestureSetSequenceState
, on one will transfer
the same value to the others.
Groups also perform an "implicit grabbing" of sequences, if a
GdkEventSequence
state is set to EventSequenceStateClaimed
on one group, every other gesture group attached to the same
GtkWidget
will switch the state for that sequence to
EventSequenceStateDenied
.
handlesSequence
gestureHandlesSequence Source #
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> Maybe EventSequence |
|
-> m Bool | Returns: |
Returns True
if gesture
is currently handling events
corresponding to sequence
.
isActive
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m Bool | Returns: |
Returns True
if the gesture is currently active.
A gesture is active while there are touch sequences interacting with it.
isGroupedWith
:: (HasCallStack, MonadIO m, IsGesture a, IsGesture b) | |
=> a |
|
-> b |
|
-> m Bool | Returns: whether the gestures are grouped |
Returns True
if both gestures pertain to the same group.
isRecognized
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m Bool | Returns: |
Returns True
if the gesture is currently recognized.
A gesture is recognized if there are as many interacting
touch sequences as required by gesture
.
setSequenceState
gestureSetSequenceState Source #
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> EventSequence |
|
-> EventSequenceState |
|
-> m Bool | Returns: |
Deprecated: (Since version 4.10.)Use gestureSetState
Sets the state of sequence
in gesture
.
Sequences start in state EventSequenceStateNone
, and whenever
they change state, they can never go back to that state. Likewise,
sequences in state EventSequenceStateDenied
cannot turn back to
a not denied state. With these rules, the lifetime of an event
sequence is constrained to the next four:
- None
- None → Denied
- None → Claimed
- None → Claimed → Denied
Note: Due to event handling ordering, it may be unsafe to set the state on another gesture within a Gesture::begin signal handler, as the callback might be executed before the other gesture knows about the sequence. A safe way to perform this could be:
c code
static void first_gesture_begin_cb (GtkGesture *first_gesture, GdkEventSequence *sequence, gpointer user_data) { gtk_gesture_set_sequence_state (first_gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED); gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); } static void second_gesture_begin_cb (GtkGesture *second_gesture, GdkEventSequence *sequence, gpointer user_data) { if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED) gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); }
If both gestures are in the same group, just set the state on the gesture emitting the event, the sequence will be already be initialized to the group's global state when the second gesture processes the event.
setState
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> EventSequenceState |
|
-> m Bool | Returns: |
Sets the state of all sequences that gesture
is currently
interacting with.
Sequences start in state EventSequenceStateNone
, and whenever
they change state, they can never go back to that state. Likewise,
sequences in state EventSequenceStateDenied
cannot turn back to
a not denied state. With these rules, the lifetime of an event
sequence is constrained to the next four:
- None
- None → Denied
- None → Claimed
- None → Claimed → Denied
Note: Due to event handling ordering, it may be unsafe to set the state on another gesture within a Gesture::begin signal handler, as the callback might be executed before the other gesture knows about the sequence. A safe way to perform this could be:
c code
static void first_gesture_begin_cb (GtkGesture *first_gesture, GdkEventSequence *sequence, gpointer user_data) { gtk_gesture_set_state (first_gesture, GTK_EVENT_SEQUENCE_CLAIMED); gtk_gesture_set_state (second_gesture, GTK_EVENT_SEQUENCE_DENIED); } static void second_gesture_begin_cb (GtkGesture *second_gesture, GdkEventSequence *sequence, gpointer user_data) { if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED) gtk_gesture_set_state (second_gesture, GTK_EVENT_SEQUENCE_DENIED); }
If both gestures are in the same group, just set the state on the gesture emitting the event, the sequence will be already be initialized to the group's global state when the second gesture processes the event.
ungroup
:: (HasCallStack, MonadIO m, IsGesture a) | |
=> a |
|
-> m () |
Separates gesture
into an isolated group.
Properties
nPoints
The number of touch points that trigger recognition on this gesture.
constructGestureNPoints :: (IsGesture o, MonadIO m) => Word32 -> m (GValueConstruct o) Source #
Construct a GValueConstruct
with valid value for the “n-points
” property. This is rarely needed directly, but it is used by new
.
getGestureNPoints :: (MonadIO m, IsGesture o) => o -> m Word32 Source #
Get the value of the “n-points
” property.
When overloading is enabled, this is equivalent to
get
gesture #nPoints
Signals
begin
type GestureBeginCallback Source #
= Maybe EventSequence |
|
-> IO () |
Emitted when the gesture is recognized.
This means the number of touch sequences matches Gesture:nPoints.
Note: These conditions may also happen when an extra touch
(eg. a third touch on a 2-touches gesture) is lifted, in that
situation sequence
won't pertain to the current set of active
touches, so don't rely on this being true.
afterGestureBegin :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureBeginCallback) -> m SignalHandlerId Source #
Connect a signal handler for the begin signal, to be run after the default handler. When overloading is enabled, this is equivalent to
after
gesture #begin callback
By default the object invoking the signal is not passed to the callback.
If you need to access it, you can use the implit ?self
parameter.
Note that this requires activating the ImplicitParams
GHC extension.
onGestureBegin :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureBeginCallback) -> m SignalHandlerId Source #
Connect a signal handler for the begin signal, to be run before the default handler. When overloading is enabled, this is equivalent to
on
gesture #begin callback
cancel
type GestureCancelCallback Source #
= Maybe EventSequence |
|
-> IO () |
Emitted whenever a sequence is cancelled.
This usually happens on active touches when
eventControllerReset
is called on gesture
(manually, due to grabs...), or the individual sequence
was claimed by parent widgets' controllers (see
gestureSetSequenceState
).
gesture
must forget everything about sequence
as in
response to this signal.
afterGestureCancel :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureCancelCallback) -> m SignalHandlerId Source #
Connect a signal handler for the cancel signal, to be run after the default handler. When overloading is enabled, this is equivalent to
after
gesture #cancel callback
By default the object invoking the signal is not passed to the callback.
If you need to access it, you can use the implit ?self
parameter.
Note that this requires activating the ImplicitParams
GHC extension.
onGestureCancel :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureCancelCallback) -> m SignalHandlerId Source #
Connect a signal handler for the cancel signal, to be run before the default handler. When overloading is enabled, this is equivalent to
on
gesture #cancel callback
end
type GestureEndCallback Source #
= Maybe EventSequence |
|
-> IO () |
Emitted when gesture
either stopped recognizing the event
sequences as something to be handled, or the number of touch
sequences became higher or lower than Gesture:nPoints.
Note: sequence
might not pertain to the group of sequences that
were previously triggering recognition on gesture
(ie. a just
pressed touch sequence that exceeds Gesture:nPoints).
This situation may be detected by checking through
gestureHandlesSequence
.
afterGestureEnd :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureEndCallback) -> m SignalHandlerId Source #
Connect a signal handler for the end signal, to be run after the default handler. When overloading is enabled, this is equivalent to
after
gesture #end callback
By default the object invoking the signal is not passed to the callback.
If you need to access it, you can use the implit ?self
parameter.
Note that this requires activating the ImplicitParams
GHC extension.
onGestureEnd :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureEndCallback) -> m SignalHandlerId Source #
Connect a signal handler for the end signal, to be run before the default handler. When overloading is enabled, this is equivalent to
on
gesture #end callback
sequenceStateChanged
type GestureSequenceStateChangedCallback Source #
= Maybe EventSequence |
|
-> EventSequenceState |
|
-> IO () |
Emitted whenever a sequence state changes.
See gestureSetSequenceState
to know
more about the expectable sequence lifetimes.
afterGestureSequenceStateChanged :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureSequenceStateChangedCallback) -> m SignalHandlerId Source #
Connect a signal handler for the sequenceStateChanged signal, to be run after the default handler. When overloading is enabled, this is equivalent to
after
gesture #sequenceStateChanged callback
By default the object invoking the signal is not passed to the callback.
If you need to access it, you can use the implit ?self
parameter.
Note that this requires activating the ImplicitParams
GHC extension.
onGestureSequenceStateChanged :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureSequenceStateChangedCallback) -> m SignalHandlerId Source #
Connect a signal handler for the sequenceStateChanged signal, to be run before the default handler. When overloading is enabled, this is equivalent to
on
gesture #sequenceStateChanged callback
update
type GestureUpdateCallback Source #
= Maybe EventSequence |
|
-> IO () |
Emitted whenever an event is handled while the gesture is recognized.
sequence
is guaranteed to pertain to the set of active touches.
afterGestureUpdate :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureUpdateCallback) -> m SignalHandlerId Source #
Connect a signal handler for the update signal, to be run after the default handler. When overloading is enabled, this is equivalent to
after
gesture #update callback
By default the object invoking the signal is not passed to the callback.
If you need to access it, you can use the implit ?self
parameter.
Note that this requires activating the ImplicitParams
GHC extension.
onGestureUpdate :: (IsGesture a, MonadIO m) => a -> ((?self :: a) => GestureUpdateCallback) -> m SignalHandlerId Source #
Connect a signal handler for the update signal, to be run before the default handler. When overloading is enabled, this is equivalent to
on
gesture #update callback