1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2012, One Laptop Per Child.
3  * Copyright (C) 2014, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author(s): Carlos Garnacho <carlosg@gnome.org>
19  */
20 
21 /**
22  * SECTION:gtkgesture
23  * @Short_description: Base class for gestures
24  * @Title: GtkGesture
25  * @See_also: #GtkEventController, #GtkGestureSingle
26  *
27  * #GtkGesture is the base object for gesture recognition, although this
28  * object is quite generalized to serve as a base for multi-touch gestures,
29  * it is suitable to implement single-touch and pointer-based gestures (using
30  * the special %NULL #GdkEventSequence value for these).
31  *
32  * The number of touches that a #GtkGesture need to be recognized is controlled
33  * by the #GtkGesture:n-points property, if a gesture is keeping track of less
34  * or more than that number of sequences, it won't check wether the gesture
35  * is recognized.
36  *
37  * As soon as the gesture has the expected number of touches, the gesture will
38  * run the #GtkGesture::check signal regularly on input events until the gesture
39  * is recognized, the criteria to consider a gesture as "recognized" is left to
40  * #GtkGesture subclasses.
41  *
42  * A recognized gesture will then emit the following signals:
43  * - #GtkGesture::begin when the gesture is recognized.
44  * - A number of #GtkGesture::update, whenever an input event is processed.
45  * - #GtkGesture::end when the gesture is no longer recognized.
46  *
47  * ## Event propagation
48  *
49  * In order to receive events, a gesture needs to either set a propagation phase
50  * through gtk_event_controller_set_propagation_phase(), or feed those manually
51  * through gtk_event_controller_handle_event().
52  *
53  * In the capture phase, events are propagated from the toplevel down to the
54  * target widget, and gestures that are attached to containers above the widget
55  * get a chance to interact with the event before it reaches the target.
56  *
57  * After the capture phase, GTK+ emits the traditional #GtkWidget::button-press-event,
58  * #GtkWidget::button-release-event, #GtkWidget::touch-event, etc signals. Gestures
59  * with the %GTK_PHASE_TARGET phase are fed events from the default #GtkWidget::event
60  * handlers.
61  *
62  * In the bubble phase, events are propagated up from the target widget to the
63  * toplevel, and gestures that are attached to containers above the widget get
64  * a chance to interact with events that have not been handled yet.
65  *
66  * ## States of a sequence # {#touch-sequence-states}
67  *
68  * Whenever input interaction happens, a single event may trigger a cascade of
69  * #GtkGestures, both across the parents of the widget receiving the event and
70  * in parallel within an individual widget. It is a responsibility of the
71  * widgets using those gestures to set the state of touch sequences accordingly
72  * in order to enable cooperation of gestures around the #GdkEventSequences
73  * triggering those.
74  *
75  * Within a widget, gestures can be grouped through gtk_gesture_group(),
76  * grouped gestures synchronize the state of sequences, so calling
77  * gtk_gesture_set_sequence_state() on one will effectively propagate
78  * the state throughout the group.
79  *
80  * By default, all sequences start out in the #GTK_EVENT_SEQUENCE_NONE state,
81  * sequences in this state trigger the gesture event handler, but event
82  * propagation will continue unstopped by gestures.
83  *
84  * If a sequence enters into the #GTK_EVENT_SEQUENCE_DENIED state, the gesture
85  * group will effectively ignore the sequence, letting events go unstopped
86  * through the gesture, but the "slot" will still remain occupied while
87  * the touch is active.
88  *
89  * If a sequence enters in the #GTK_EVENT_SEQUENCE_CLAIMED state, the gesture
90  * group will grab all interaction on the sequence, by:
91  * - Setting the same sequence to #GTK_EVENT_SEQUENCE_DENIED on every other gesture
92  *   group within the widget, and every gesture on parent widgets in the propagation
93  *   chain.
94  * - calling #GtkGesture::cancel on every gesture in widgets underneath in the
95  *   propagation chain.
96  * - Stopping event propagation after the gesture group handles the event.
97  *
98  * Note: if a sequence is set early to #GTK_EVENT_SEQUENCE_CLAIMED on
99  * #GDK_TOUCH_BEGIN/#GDK_BUTTON_PRESS (so those events are captured before
100  * reaching the event widget, this implies #GTK_PHASE_CAPTURE), one similar
101  * event will emulated if the sequence changes to #GTK_EVENT_SEQUENCE_DENIED.
102  * This way event coherence is preserved before event propagation is unstopped
103  * again.
104  *
105  * Sequence states can't be changed freely, see gtk_gesture_set_sequence_state()
106  * to know about the possible lifetimes of a #GdkEventSequence.
107  *
108  * ## Touchpad gestures
109  *
110  * On the platforms that support it, #GtkGesture will handle transparently
111  * touchpad gesture events. The only precautions users of #GtkGesture should do
112  * to enable this support are:
113  * - Enabling %GDK_TOUCHPAD_GESTURE_MASK on their #GdkWindows
114  * - If the gesture has %GTK_PHASE_NONE, ensuring events of type
115  *   %GDK_TOUCHPAD_SWIPE and %GDK_TOUCHPAD_PINCH are handled by the #GtkGesture
116  */
117 
118 #include "config.h"
119 #include "gtkgesture.h"
120 #include "gtkwidgetprivate.h"
121 #include "gtkeventcontrollerprivate.h"
122 #include "gtkgestureprivate.h"
123 #include "gtktypebuiltins.h"
124 #include "gtkprivate.h"
125 #include "gtkmain.h"
126 #include "gtkintl.h"
127 #include "gtkmarshalers.h"
128 
129 typedef struct _GtkGesturePrivate GtkGesturePrivate;
130 typedef struct _PointData PointData;
131 
132 enum {
133   PROP_N_POINTS = 1,
134   PROP_WINDOW
135 };
136 
137 enum {
138   BEGIN,
139   END,
140   UPDATE,
141   CANCEL,
142   SEQUENCE_STATE_CHANGED,
143   N_SIGNALS
144 };
145 
146 struct _PointData
147 {
148   GdkEvent *event;
149   gdouble widget_x;
150   gdouble widget_y;
151 
152   /* Acummulators for touchpad events */
153   gdouble accum_dx;
154   gdouble accum_dy;
155 
156   guint press_handled : 1;
157   guint state : 2;
158 };
159 
160 struct _GtkGesturePrivate
161 {
162   GHashTable *points;
163   GdkEventSequence *last_sequence;
164   GdkWindow *user_window;
165   GdkWindow *window;
166   GdkDevice *device;
167   GList *group_link;
168   guint n_points;
169   guint recognized : 1;
170   guint touchpad : 1;
171 };
172 
173 static guint signals[N_SIGNALS] = { 0 };
174 
175 #define BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)
176 
177 #define EVENT_IS_TOUCHPAD_GESTURE(e) ((e)->type == GDK_TOUCHPAD_SWIPE || \
178                                       (e)->type == GDK_TOUCHPAD_PINCH)
179 
180 GList * _gtk_gesture_get_group_link (GtkGesture *gesture);
181 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(GtkGesture,gtk_gesture,GTK_TYPE_EVENT_CONTROLLER)182 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkGesture, gtk_gesture, GTK_TYPE_EVENT_CONTROLLER)
183 
184 static void
185 gtk_gesture_get_property (GObject    *object,
186                           guint       prop_id,
187                           GValue     *value,
188                           GParamSpec *pspec)
189 {
190   GtkGesturePrivate *priv = gtk_gesture_get_instance_private (GTK_GESTURE (object));
191 
192   switch (prop_id)
193     {
194     case PROP_N_POINTS:
195       g_value_set_uint (value, priv->n_points);
196       break;
197     case PROP_WINDOW:
198       g_value_set_object (value, priv->user_window);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202     }
203 }
204 
205 static void
gtk_gesture_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)206 gtk_gesture_set_property (GObject      *object,
207                           guint         prop_id,
208                           const GValue *value,
209                           GParamSpec   *pspec)
210 {
211   GtkGesturePrivate *priv = gtk_gesture_get_instance_private (GTK_GESTURE (object));
212 
213   switch (prop_id)
214     {
215     case PROP_N_POINTS:
216       priv->n_points = g_value_get_uint (value);
217       break;
218     case PROP_WINDOW:
219       gtk_gesture_set_window (GTK_GESTURE (object),
220                               g_value_get_object (value));
221       break;
222     default:
223       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224     }
225 }
226 
227 static void
gtk_gesture_finalize(GObject * object)228 gtk_gesture_finalize (GObject *object)
229 {
230   GtkGesture *gesture = GTK_GESTURE (object);
231   GtkGesturePrivate *priv = gtk_gesture_get_instance_private (gesture);
232 
233   gtk_gesture_ungroup (gesture);
234   g_list_free (priv->group_link);
235 
236   g_hash_table_destroy (priv->points);
237 
238   G_OBJECT_CLASS (gtk_gesture_parent_class)->finalize (object);
239 }
240 
241 static guint
_gtk_gesture_get_n_touchpad_points(GtkGesture * gesture,gboolean only_active)242 _gtk_gesture_get_n_touchpad_points (GtkGesture *gesture,
243                                     gboolean    only_active)
244 {
245   GtkGesturePrivate *priv;
246   PointData *data;
247 
248   priv = gtk_gesture_get_instance_private (gesture);
249 
250   if (!priv->touchpad)
251     return 0;
252 
253   data = g_hash_table_lookup (priv->points, NULL);
254 
255   if (!data)
256     return 0;
257 
258   if (only_active &&
259       (data->state == GTK_EVENT_SEQUENCE_DENIED ||
260        (data->event->type == GDK_TOUCHPAD_SWIPE &&
261         data->event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_END) ||
262        (data->event->type == GDK_TOUCHPAD_PINCH &&
263         data->event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_END)))
264     return 0;
265 
266   switch (data->event->type)
267     {
268     case GDK_TOUCHPAD_SWIPE:
269       return data->event->touchpad_swipe.n_fingers;
270     case GDK_TOUCHPAD_PINCH:
271       return data->event->touchpad_pinch.n_fingers;
272     default:
273       return 0;
274     }
275 }
276 
277 static guint
_gtk_gesture_get_n_touch_points(GtkGesture * gesture,gboolean only_active)278 _gtk_gesture_get_n_touch_points (GtkGesture *gesture,
279                                  gboolean    only_active)
280 {
281   GtkGesturePrivate *priv;
282   GHashTableIter iter;
283   guint n_points = 0;
284   PointData *data;
285 
286   priv = gtk_gesture_get_instance_private (gesture);
287   g_hash_table_iter_init (&iter, priv->points);
288 
289   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
290     {
291       if (only_active &&
292           (data->state == GTK_EVENT_SEQUENCE_DENIED ||
293            data->event->type == GDK_TOUCH_END ||
294            data->event->type == GDK_BUTTON_RELEASE))
295         continue;
296 
297       n_points++;
298     }
299 
300   return n_points;
301 }
302 
303 static guint
_gtk_gesture_get_n_physical_points(GtkGesture * gesture,gboolean only_active)304 _gtk_gesture_get_n_physical_points (GtkGesture *gesture,
305                                     gboolean    only_active)
306 {
307   GtkGesturePrivate *priv;
308 
309   priv = gtk_gesture_get_instance_private (gesture);
310 
311   if (priv->touchpad)
312     return _gtk_gesture_get_n_touchpad_points (gesture, only_active);
313   else
314     return _gtk_gesture_get_n_touch_points (gesture, only_active);
315 }
316 
317 static gboolean
gtk_gesture_check_impl(GtkGesture * gesture)318 gtk_gesture_check_impl (GtkGesture *gesture)
319 {
320   GtkGesturePrivate *priv;
321   guint n_points;
322 
323   priv = gtk_gesture_get_instance_private (gesture);
324   n_points = _gtk_gesture_get_n_physical_points (gesture, TRUE);
325 
326   return n_points == priv->n_points;
327 }
328 
329 static void
_gtk_gesture_set_recognized(GtkGesture * gesture,gboolean recognized,GdkEventSequence * sequence)330 _gtk_gesture_set_recognized (GtkGesture       *gesture,
331                              gboolean          recognized,
332                              GdkEventSequence *sequence)
333 {
334   GtkGesturePrivate *priv;
335 
336   priv = gtk_gesture_get_instance_private (gesture);
337 
338   if (priv->recognized == recognized)
339     return;
340 
341   priv->recognized = recognized;
342 
343   if (recognized)
344     g_signal_emit (gesture, signals[BEGIN], 0, sequence);
345   else
346     g_signal_emit (gesture, signals[END], 0, sequence);
347 }
348 
349 static gboolean
_gtk_gesture_do_check(GtkGesture * gesture)350 _gtk_gesture_do_check (GtkGesture *gesture)
351 {
352   GtkGestureClass *gesture_class;
353   gboolean retval = FALSE;
354 
355   gesture_class = GTK_GESTURE_GET_CLASS (gesture);
356 
357   if (!gesture_class->check)
358     return retval;
359 
360   retval = gesture_class->check (gesture);
361   return retval;
362 }
363 
364 static gboolean
_gtk_gesture_has_matching_touchpoints(GtkGesture * gesture)365 _gtk_gesture_has_matching_touchpoints (GtkGesture *gesture)
366 {
367   GtkGesturePrivate *priv = gtk_gesture_get_instance_private (gesture);
368   guint active_n_points, current_n_points;
369 
370   current_n_points = _gtk_gesture_get_n_physical_points (gesture, FALSE);
371   active_n_points = _gtk_gesture_get_n_physical_points (gesture, TRUE);
372 
373   return (active_n_points == priv->n_points &&
374           current_n_points == priv->n_points);
375 }
376 
377 static gboolean
_gtk_gesture_check_recognized(GtkGesture * gesture,GdkEventSequence * sequence)378 _gtk_gesture_check_recognized (GtkGesture       *gesture,
379                                GdkEventSequence *sequence)
380 {
381   GtkGesturePrivate *priv = gtk_gesture_get_instance_private (gesture);
382   gboolean has_matching_touchpoints;
383 
384   has_matching_touchpoints = _gtk_gesture_has_matching_touchpoints (gesture);
385 
386   if (priv->recognized && !has_matching_touchpoints)
387     _gtk_gesture_set_recognized (gesture, FALSE, sequence);
388   else if (!priv->recognized && has_matching_touchpoints &&
389            _gtk_gesture_do_check (gesture))
390     _gtk_gesture_set_recognized (gesture, TRUE, sequence);
391 
392   return priv->recognized;
393 }
394 
395 /* Finds the first window pertaining to the controller's widget */
396 static GdkWindow *
_find_widget_window(GtkGesture * gesture,GdkWindow * window)397 _find_widget_window (GtkGesture *gesture,
398                      GdkWindow  *window)
399 {
400   GtkWidget *widget, *window_widget;
401 
402   widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
403 
404   while (window && !gdk_window_is_destroyed (window))
405     {
406       gdk_window_get_user_data (window, (gpointer*) &window_widget);
407 
408       if (window_widget == widget ||
409           gtk_widget_get_window (widget) == window)
410         return window;
411 
412       window = gdk_window_get_effective_parent (window);
413     }
414 
415   return NULL;
416 }
417 
418 static void
_update_touchpad_deltas(PointData * data)419 _update_touchpad_deltas (PointData *data)
420 {
421   GdkEvent *event = data->event;
422 
423   if (!event)
424     return;
425 
426   if (event->type == GDK_TOUCHPAD_SWIPE)
427     {
428       if (event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
429         data->accum_dx = data->accum_dy = 0;
430       else if (event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE)
431         {
432           data->accum_dx += event->touchpad_swipe.dx;
433           data->accum_dy += event->touchpad_swipe.dy;
434         }
435     }
436   else if (event->type == GDK_TOUCHPAD_PINCH)
437     {
438       if (event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
439         data->accum_dx = data->accum_dy = 0;
440       else if (event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE)
441         {
442           data->accum_dx += event->touchpad_pinch.dx;
443           data->accum_dy += event->touchpad_pinch.dy;
444         }
445     }
446 }
447 
448 static void
_get_event_coordinates(PointData * data,gdouble * x,gdouble * y)449 _get_event_coordinates (PointData *data,
450                         gdouble   *x,
451                         gdouble   *y)
452 {
453   gdouble event_x, event_y;
454 
455   g_assert (data->event != NULL);
456 
457   gdk_event_get_coords (data->event, &event_x, &event_y);
458   event_x += data->accum_dx;
459   event_y += data->accum_dy;
460 
461   if (x)
462     *x = event_x;
463   if (y)
464     *y = event_y;
465 }
466 
467 static void
_update_widget_coordinates(GtkGesture * gesture,PointData * data)468 _update_widget_coordinates (GtkGesture *gesture,
469                             PointData  *data)
470 {
471   GdkWindow *window, *event_widget_window;
472   GtkWidget *event_widget, *widget;
473   GtkAllocation allocation;
474   gdouble event_x, event_y;
475   gint wx, wy, x, y;
476 
477   event_widget = gtk_get_event_widget (data->event);
478 
479   if (!event_widget)
480     return;
481 
482   widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
483   event_widget_window = gtk_widget_get_window (event_widget);
484   _get_event_coordinates (data, &event_x, &event_y);
485   window = data->event->any.window;
486 
487   while (window && window != event_widget_window)
488     {
489       gdk_window_get_position (window, &wx, &wy);
490       event_x += wx;
491       event_y += wy;
492       window = gdk_window_get_effective_parent (window);
493     }
494 
495   if (!window)
496     return;
497 
498   if (!gtk_widget_get_has_window (event_widget))
499     {
500       gtk_widget_get_allocation (event_widget, &allocation);
501       event_x -= allocation.x;
502       event_y -= allocation.y;
503     }
504 
505   gtk_widget_translate_coordinates (event_widget, widget,
506                                     event_x, event_y, &x, &y);
507   data->widget_x = x;
508   data->widget_y = y;
509 }
510 
511 static GtkEventSequenceState
gtk_gesture_get_group_state(GtkGesture * gesture,GdkEventSequence * sequence)512 gtk_gesture_get_group_state (GtkGesture       *gesture,
513                              GdkEventSequence *sequence)
514 {
515   GtkEventSequenceState state = GTK_EVENT_SEQUENCE_NONE;
516   GList *group_elem;
517 
518   group_elem = g_list_first (_gtk_gesture_get_group_link (gesture));
519 
520   for (; group_elem; group_elem = group_elem->next)
521     {
522       if (group_elem->data == gesture)
523         continue;
524       if (!gtk_gesture_handles_sequence (group_elem->data, sequence))
525         continue;
526 
527       state = gtk_gesture_get_sequence_state (group_elem->data, sequence);
528       break;
529     }
530 
531   return state;
532 }
533 
534 static gboolean
_gtk_gesture_update_point(GtkGesture * gesture,const GdkEvent * event,gboolean add)535 _gtk_gesture_update_point (GtkGesture     *gesture,
536                            const GdkEvent *event,
537                            gboolean        add)
538 {
539   GdkEventSequence *sequence;
540   GdkWindow *widget_window;
541   GtkGesturePrivate *priv;
542   GdkDevice *device;
543   gboolean existed, touchpad;
544   PointData *data;
545 
546   if (!gdk_event_get_coords (event, NULL, NULL))
547     return FALSE;
548 
549   device = gdk_event_get_device (event);
550 
551   if (!device)
552     return FALSE;
553 
554   priv = gtk_gesture_get_instance_private (gesture);
555   widget_window = _find_widget_window (gesture, event->any.window);
556 
557   if (!widget_window)
558     widget_window = event->any.window;
559 
560   touchpad = EVENT_IS_TOUCHPAD_GESTURE (event);
561 
562   if (add)
563     {
564       /* If the event happens with the wrong device, or
565        * on the wrong window, ignore.
566        */
567       if (priv->device && priv->device != device)
568         return FALSE;
569       if (priv->window && priv->window != widget_window)
570         return FALSE;
571       if (priv->user_window && priv->user_window != widget_window)
572         return FALSE;
573 
574       /* Make touchpad and touchscreen gestures mutually exclusive */
575       if (touchpad && g_hash_table_size (priv->points) > 0)
576         return FALSE;
577       else if (!touchpad && priv->touchpad)
578         return FALSE;
579     }
580   else if (!priv->device || !priv->window)
581     return FALSE;
582 
583   sequence = gdk_event_get_event_sequence (event);
584   existed = g_hash_table_lookup_extended (priv->points, sequence,
585                                           NULL, (gpointer *) &data);
586   if (!existed)
587     {
588       if (!add)
589         return FALSE;
590 
591       if (g_hash_table_size (priv->points) == 0)
592         {
593           priv->window = widget_window;
594           priv->device = device;
595           priv->touchpad = touchpad;
596         }
597 
598       data = g_new0 (PointData, 1);
599       g_hash_table_insert (priv->points, sequence, data);
600     }
601 
602   if (data->event)
603     gdk_event_free (data->event);
604 
605   data->event = gdk_event_copy (event);
606   _update_touchpad_deltas (data);
607   _update_widget_coordinates (gesture, data);
608 
609   if (!existed)
610     {
611       GtkEventSequenceState state;
612 
613       /* Deny the sequence right away if the expected
614        * number of points is exceeded, so this sequence
615        * can be tracked with gtk_gesture_handles_sequence().
616        *
617        * Otherwise, make the sequence inherit the same state
618        * from other gestures in the same group.
619        */
620       if (_gtk_gesture_get_n_physical_points (gesture, FALSE) > priv->n_points)
621         state = GTK_EVENT_SEQUENCE_DENIED;
622       else
623         state = gtk_gesture_get_group_state (gesture, sequence);
624 
625       gtk_gesture_set_sequence_state (gesture, sequence, state);
626     }
627 
628   return TRUE;
629 }
630 
631 static void
_gtk_gesture_check_empty(GtkGesture * gesture)632 _gtk_gesture_check_empty (GtkGesture *gesture)
633 {
634   GtkGesturePrivate *priv;
635 
636   priv = gtk_gesture_get_instance_private (gesture);
637 
638   if (g_hash_table_size (priv->points) == 0)
639     {
640       priv->window = NULL;
641       priv->device = NULL;
642       priv->touchpad = FALSE;
643     }
644 }
645 
646 static void
_gtk_gesture_remove_point(GtkGesture * gesture,const GdkEvent * event)647 _gtk_gesture_remove_point (GtkGesture     *gesture,
648                            const GdkEvent *event)
649 {
650   GdkEventSequence *sequence;
651   GtkGesturePrivate *priv;
652   GdkDevice *device;
653 
654   sequence = gdk_event_get_event_sequence (event);
655   device = gdk_event_get_device (event);
656   priv = gtk_gesture_get_instance_private (gesture);
657 
658   if (priv->device != device)
659     return;
660 
661   g_hash_table_remove (priv->points, sequence);
662   _gtk_gesture_check_empty (gesture);
663 }
664 
665 static void
_gtk_gesture_cancel_all(GtkGesture * gesture)666 _gtk_gesture_cancel_all (GtkGesture *gesture)
667 {
668   GdkEventSequence *sequence;
669   GtkGesturePrivate *priv;
670   GHashTableIter iter;
671 
672   priv = gtk_gesture_get_instance_private (gesture);
673   g_hash_table_iter_init (&iter, priv->points);
674 
675   while (g_hash_table_iter_next (&iter, (gpointer*) &sequence, NULL))
676     {
677       g_signal_emit (gesture, signals[CANCEL], 0, sequence);
678       g_hash_table_iter_remove (&iter);
679       _gtk_gesture_check_recognized (gesture, sequence);
680     }
681 
682   _gtk_gesture_check_empty (gesture);
683 }
684 
685 static gboolean
gesture_within_window(GtkGesture * gesture,GdkWindow * parent)686 gesture_within_window (GtkGesture *gesture,
687                        GdkWindow  *parent)
688 {
689   GdkWindow *window;
690   GtkWidget *widget;
691 
692   widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
693   window = gtk_widget_get_window (widget);
694 
695   while (window)
696     {
697       if (window == parent)
698         return TRUE;
699 
700       window = gdk_window_get_effective_parent (window);
701     }
702 
703   return FALSE;
704 }
705 
706 static gboolean
gtk_gesture_filter_event(GtkEventController * controller,const GdkEvent * event)707 gtk_gesture_filter_event (GtkEventController *controller,
708                           const GdkEvent     *event)
709 {
710   /* Even though GtkGesture handles these events, we want
711    * touchpad gestures disabled by default, it will be
712    * subclasses which punch the holes in for the events
713    * they can possibly handle.
714    */
715   return EVENT_IS_TOUCHPAD_GESTURE (event);
716 }
717 
718 static gboolean
gtk_gesture_handle_event(GtkEventController * controller,const GdkEvent * event)719 gtk_gesture_handle_event (GtkEventController *controller,
720                           const GdkEvent     *event)
721 {
722   GtkGesture *gesture = GTK_GESTURE (controller);
723   GdkEventSequence *sequence;
724   GtkGesturePrivate *priv;
725   GdkDevice *source_device;
726   gboolean was_recognized;
727 
728   source_device = gdk_event_get_source_device (event);
729 
730   if (!source_device)
731     return FALSE;
732 
733   priv = gtk_gesture_get_instance_private (gesture);
734   sequence = gdk_event_get_event_sequence (event);
735   was_recognized = gtk_gesture_is_recognized (gesture);
736 
737   if (gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_DENIED)
738     priv->last_sequence = sequence;
739 
740   if (event->type == GDK_BUTTON_PRESS ||
741       event->type == GDK_TOUCH_BEGIN ||
742       (event->type == GDK_TOUCHPAD_SWIPE &&
743        event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) ||
744       (event->type == GDK_TOUCHPAD_PINCH &&
745        event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN))
746     {
747       if (_gtk_gesture_update_point (gesture, event, TRUE))
748         {
749           gboolean triggered_recognition;
750 
751           triggered_recognition =
752             !was_recognized && _gtk_gesture_has_matching_touchpoints (gesture);
753 
754           if (_gtk_gesture_check_recognized (gesture, sequence))
755             {
756               PointData *data;
757 
758               data = g_hash_table_lookup (priv->points, sequence);
759 
760               /* If the sequence was claimed early, the press event will be consumed */
761               if (gtk_gesture_get_sequence_state (gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED)
762                 data->press_handled = TRUE;
763             }
764           else if (triggered_recognition && g_hash_table_size (priv->points) == 0)
765             {
766               /* Recognition was triggered, but the gesture reset during
767                * ::begin emission. Still, recognition was strictly triggered,
768                * so the event should be consumed.
769                */
770               return TRUE;
771             }
772         }
773     }
774   else if (event->type == GDK_BUTTON_RELEASE ||
775            event->type == GDK_TOUCH_END ||
776            (event->type == GDK_TOUCHPAD_SWIPE &&
777             event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_END) ||
778            (event->type == GDK_TOUCHPAD_PINCH &&
779             event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_END))
780     {
781       if (_gtk_gesture_update_point (gesture, event, FALSE))
782         {
783           if (was_recognized &&
784               _gtk_gesture_check_recognized (gesture, sequence))
785             g_signal_emit (gesture, signals[UPDATE], 0, sequence);
786 
787           _gtk_gesture_remove_point (gesture, event);
788         }
789     }
790   else if (event->type == GDK_MOTION_NOTIFY ||
791            event->type == GDK_TOUCH_UPDATE ||
792            (event->type == GDK_TOUCHPAD_SWIPE &&
793             event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE) ||
794            (event->type == GDK_TOUCHPAD_PINCH &&
795             event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE))
796     {
797       if (event->type == GDK_MOTION_NOTIFY)
798         {
799           if ((event->motion.state & BUTTONS_MASK) == 0)
800             return FALSE;
801 
802           if (event->motion.is_hint)
803             gdk_event_request_motions (&event->motion);
804         }
805 
806       if (_gtk_gesture_update_point (gesture, event, FALSE) &&
807           _gtk_gesture_check_recognized (gesture, sequence))
808         g_signal_emit (gesture, signals[UPDATE], 0, sequence);
809     }
810   else if (event->type == GDK_TOUCH_CANCEL)
811     {
812       if (!priv->touchpad)
813         _gtk_gesture_cancel_sequence (gesture, sequence);
814     }
815   else if ((event->type == GDK_TOUCHPAD_SWIPE &&
816             event->touchpad_swipe.phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL) ||
817            (event->type == GDK_TOUCHPAD_PINCH &&
818             event->touchpad_pinch.phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL))
819     {
820       if (priv->touchpad)
821         _gtk_gesture_cancel_sequence (gesture, sequence);
822     }
823   else if (event->type == GDK_GRAB_BROKEN)
824     {
825       if (!event->grab_broken.grab_window ||
826           !gesture_within_window (gesture, event->grab_broken.grab_window))
827         _gtk_gesture_cancel_all (gesture);
828 
829       return FALSE;
830     }
831   else
832     {
833       /* Unhandled event */
834       return FALSE;
835     }
836 
837   if (gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_CLAIMED)
838     return FALSE;
839 
840   return priv->recognized;
841 }
842 
843 static void
gtk_gesture_reset(GtkEventController * controller)844 gtk_gesture_reset (GtkEventController *controller)
845 {
846   _gtk_gesture_cancel_all (GTK_GESTURE (controller));
847 }
848 
849 static void
gtk_gesture_class_init(GtkGestureClass * klass)850 gtk_gesture_class_init (GtkGestureClass *klass)
851 {
852   GObjectClass *object_class = G_OBJECT_CLASS (klass);
853   GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
854 
855   object_class->get_property = gtk_gesture_get_property;
856   object_class->set_property = gtk_gesture_set_property;
857   object_class->finalize = gtk_gesture_finalize;
858 
859   controller_class->filter_event = gtk_gesture_filter_event;
860   controller_class->handle_event = gtk_gesture_handle_event;
861   controller_class->reset = gtk_gesture_reset;
862 
863   klass->check = gtk_gesture_check_impl;
864 
865   /**
866    * GtkGesture:n-points:
867    *
868    * The number of touch points that trigger recognition on this gesture,
869    *
870    *
871    * Since: 3.14
872    */
873   g_object_class_install_property (object_class,
874                                    PROP_N_POINTS,
875                                    g_param_spec_uint ("n-points",
876                                                       P_("Number of points"),
877                                                       P_("Number of points needed "
878                                                          "to trigger the gesture"),
879                                                       1, G_MAXUINT, 1,
880                                                       GTK_PARAM_READWRITE |
881 						      G_PARAM_CONSTRUCT_ONLY));
882   /**
883    * GtkGesture:window:
884    *
885    * If non-%NULL, the gesture will only listen for events that happen on
886    * this #GdkWindow, or a child of it.
887    *
888    * Since: 3.14
889    */
890   g_object_class_install_property (object_class,
891                                    PROP_WINDOW,
892                                    g_param_spec_object ("window",
893                                                         P_("GdkWindow to receive events about"),
894                                                         P_("GdkWindow to receive events about"),
895                                                         GDK_TYPE_WINDOW,
896                                                         GTK_PARAM_READWRITE));
897   /**
898    * GtkGesture::begin:
899    * @gesture: the object which received the signal
900    * @sequence: (nullable): the #GdkEventSequence that made the gesture to be recognized
901    *
902    * This signal is emitted when the gesture is recognized. This means the
903    * number of touch sequences matches #GtkGesture:n-points, and the #GtkGesture::check
904    * handler(s) returned #TRUE.
905    *
906    * Note: These conditions may also happen when an extra touch (eg. a third touch
907    * on a 2-touches gesture) is lifted, in that situation @sequence won't pertain
908    * to the current set of active touches, so don't rely on this being true.
909    *
910    * Since: 3.14
911    */
912   signals[BEGIN] =
913     g_signal_new (I_("begin"),
914                   G_TYPE_FROM_CLASS (klass),
915                   G_SIGNAL_RUN_LAST,
916                   G_STRUCT_OFFSET (GtkGestureClass, begin),
917                   NULL, NULL, NULL,
918                   G_TYPE_NONE, 1, GDK_TYPE_EVENT_SEQUENCE);
919   /**
920    * GtkGesture::end:
921    * @gesture: the object which received the signal
922    * @sequence: (nullable): the #GdkEventSequence that made gesture recognition to finish
923    *
924    * This signal is emitted when @gesture either stopped recognizing the event
925    * sequences as something to be handled (the #GtkGesture::check handler returned
926    * %FALSE), or the number of touch sequences became higher or lower than
927    * #GtkGesture:n-points.
928    *
929    * Note: @sequence might not pertain to the group of sequences that were
930    * previously triggering recognition on @gesture (ie. a just pressed touch
931    * sequence that exceeds #GtkGesture:n-points). This situation may be detected
932    * by checking through gtk_gesture_handles_sequence().
933    *
934    * Since: 3.14
935    */
936   signals[END] =
937     g_signal_new (I_("end"),
938                   G_TYPE_FROM_CLASS (klass),
939                   G_SIGNAL_RUN_LAST,
940                   G_STRUCT_OFFSET (GtkGestureClass, end),
941                   NULL, NULL, NULL,
942                   G_TYPE_NONE, 1, GDK_TYPE_EVENT_SEQUENCE);
943   /**
944    * GtkGesture::update:
945    * @gesture: the object which received the signal
946    * @sequence: (nullable): the #GdkEventSequence that was updated
947    *
948    * This signal is emitted whenever an event is handled while the gesture is
949    * recognized. @sequence is guaranteed to pertain to the set of active touches.
950    *
951    * Since: 3.14
952    */
953   signals[UPDATE] =
954     g_signal_new (I_("update"),
955                   G_TYPE_FROM_CLASS (klass),
956                   G_SIGNAL_RUN_LAST,
957                   G_STRUCT_OFFSET (GtkGestureClass, update),
958                   NULL, NULL, NULL,
959                   G_TYPE_NONE, 1, GDK_TYPE_EVENT_SEQUENCE);
960   /**
961    * GtkGesture::cancel:
962    * @gesture: the object which received the signal
963    * @sequence: (nullable): the #GdkEventSequence that was cancelled
964    *
965    * This signal is emitted whenever a sequence is cancelled. This usually
966    * happens on active touches when gtk_event_controller_reset() is called
967    * on @gesture (manually, due to grabs...), or the individual @sequence
968    * was claimed by parent widgets' controllers (see gtk_gesture_set_sequence_state()).
969    *
970    * @gesture must forget everything about @sequence as a reaction to this signal.
971    *
972    * Since: 3.14
973    */
974   signals[CANCEL] =
975     g_signal_new (I_("cancel"),
976                   G_TYPE_FROM_CLASS (klass),
977                   G_SIGNAL_RUN_LAST,
978                   G_STRUCT_OFFSET (GtkGestureClass, cancel),
979                   NULL, NULL, NULL,
980                   G_TYPE_NONE, 1, GDK_TYPE_EVENT_SEQUENCE);
981   /**
982    * GtkGesture::sequence-state-changed:
983    * @gesture: the object which received the signal
984    * @sequence: (nullable): the #GdkEventSequence that was cancelled
985    * @state: the new sequence state
986    *
987    * This signal is emitted whenever a sequence state changes. See
988    * gtk_gesture_set_sequence_state() to know more about the expectable
989    * sequence lifetimes.
990    *
991    * Since: 3.14
992    */
993   signals[SEQUENCE_STATE_CHANGED] =
994     g_signal_new (I_("sequence-state-changed"),
995                   G_TYPE_FROM_CLASS (klass),
996                   G_SIGNAL_RUN_LAST,
997                   G_STRUCT_OFFSET (GtkGestureClass, sequence_state_changed),
998                   NULL, NULL,
999                   _gtk_marshal_VOID__BOXED_ENUM,
1000                   G_TYPE_NONE, 2, GDK_TYPE_EVENT_SEQUENCE,
1001                   GTK_TYPE_EVENT_SEQUENCE_STATE);
1002   g_signal_set_va_marshaller (signals[SEQUENCE_STATE_CHANGED],
1003                               G_TYPE_FROM_CLASS (klass),
1004                               _gtk_marshal_VOID__BOXED_ENUMv);
1005 }
1006 
1007 static void
free_point_data(gpointer data)1008 free_point_data (gpointer data)
1009 {
1010   PointData *point = data;
1011 
1012   if (point->event)
1013     gdk_event_free (point->event);
1014 
1015   g_free (point);
1016 }
1017 
1018 static void
gtk_gesture_init(GtkGesture * gesture)1019 gtk_gesture_init (GtkGesture *gesture)
1020 {
1021   GtkGesturePrivate *priv;
1022 
1023   priv = gtk_gesture_get_instance_private (gesture);
1024   priv->points = g_hash_table_new_full (NULL, NULL, NULL,
1025                                         (GDestroyNotify) free_point_data);
1026   gtk_event_controller_set_event_mask (GTK_EVENT_CONTROLLER (gesture),
1027                                        GDK_TOUCH_MASK |
1028                                        GDK_TOUCHPAD_GESTURE_MASK);
1029 
1030   priv->group_link = g_list_prepend (NULL, gesture);
1031 }
1032 
1033 /**
1034  * gtk_gesture_get_device:
1035  * @gesture: a #GtkGesture
1036  *
1037  * Returns the master #GdkDevice that is currently operating
1038  * on @gesture, or %NULL if the gesture is not being interacted.
1039  *
1040  * Returns: (nullable) (transfer none): a #GdkDevice, or %NULL
1041  *
1042  * Since: 3.14
1043  **/
1044 GdkDevice *
gtk_gesture_get_device(GtkGesture * gesture)1045 gtk_gesture_get_device (GtkGesture *gesture)
1046 {
1047   GtkGesturePrivate *priv;
1048 
1049   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1050 
1051   priv = gtk_gesture_get_instance_private (gesture);
1052 
1053   return priv->device;
1054 }
1055 
1056 /**
1057  * gtk_gesture_get_sequence_state:
1058  * @gesture: a #GtkGesture
1059  * @sequence: a #GdkEventSequence
1060  *
1061  * Returns the @sequence state, as seen by @gesture.
1062  *
1063  * Returns: The sequence state in @gesture
1064  *
1065  * Since: 3.14
1066  **/
1067 GtkEventSequenceState
gtk_gesture_get_sequence_state(GtkGesture * gesture,GdkEventSequence * sequence)1068 gtk_gesture_get_sequence_state (GtkGesture       *gesture,
1069                                 GdkEventSequence *sequence)
1070 {
1071   GtkGesturePrivate *priv;
1072   PointData *data;
1073 
1074   g_return_val_if_fail (GTK_IS_GESTURE (gesture),
1075                         GTK_EVENT_SEQUENCE_NONE);
1076 
1077   priv = gtk_gesture_get_instance_private (gesture);
1078   data = g_hash_table_lookup (priv->points, sequence);
1079 
1080   if (!data)
1081     return GTK_EVENT_SEQUENCE_NONE;
1082 
1083   return data->state;
1084 }
1085 
1086 /**
1087  * gtk_gesture_set_sequence_state:
1088  * @gesture: a #GtkGesture
1089  * @sequence: a #GdkEventSequence
1090  * @state: the sequence state
1091  *
1092  * Sets the state of @sequence in @gesture. Sequences start
1093  * in state #GTK_EVENT_SEQUENCE_NONE, and whenever they change
1094  * state, they can never go back to that state. Likewise,
1095  * sequences in state #GTK_EVENT_SEQUENCE_DENIED cannot turn
1096  * back to a not denied state. With these rules, the lifetime
1097  * of an event sequence is constrained to the next four:
1098  *
1099  * * None
1100  * * None → Denied
1101  * * None → Claimed
1102  * * None → Claimed → Denied
1103  *
1104  * Note: Due to event handling ordering, it may be unsafe to
1105  * set the state on another gesture within a #GtkGesture::begin
1106  * signal handler, as the callback might be executed before
1107  * the other gesture knows about the sequence. A safe way to
1108  * perform this could be:
1109  *
1110  * |[
1111  * static void
1112  * first_gesture_begin_cb (GtkGesture       *first_gesture,
1113  *                         GdkEventSequence *sequence,
1114  *                         gpointer          user_data)
1115  * {
1116  *   gtk_gesture_set_sequence_state (first_gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
1117  *   gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED);
1118  * }
1119  *
1120  * static void
1121  * second_gesture_begin_cb (GtkGesture       *second_gesture,
1122  *                          GdkEventSequence *sequence,
1123  *                          gpointer          user_data)
1124  * {
1125  *   if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED)
1126  *     gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED);
1127  * }
1128  * ]|
1129  *
1130  * If both gestures are in the same group, just set the state on
1131  * the gesture emitting the event, the sequence will be already
1132  * be initialized to the group's global state when the second
1133  * gesture processes the event.
1134  *
1135  * Returns: %TRUE if @sequence is handled by @gesture,
1136  *          and the state is changed successfully
1137  *
1138  * Since: 3.14
1139  **/
1140 gboolean
gtk_gesture_set_sequence_state(GtkGesture * gesture,GdkEventSequence * sequence,GtkEventSequenceState state)1141 gtk_gesture_set_sequence_state (GtkGesture            *gesture,
1142                                 GdkEventSequence      *sequence,
1143                                 GtkEventSequenceState  state)
1144 {
1145   GtkGesturePrivate *priv;
1146   PointData *data;
1147 
1148   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1149   g_return_val_if_fail (state >= GTK_EVENT_SEQUENCE_NONE &&
1150                         state <= GTK_EVENT_SEQUENCE_DENIED, FALSE);
1151 
1152   priv = gtk_gesture_get_instance_private (gesture);
1153   data = g_hash_table_lookup (priv->points, sequence);
1154 
1155   if (!data)
1156     return FALSE;
1157 
1158   if (data->state == state)
1159     return FALSE;
1160 
1161   /* denied sequences remain denied */
1162   if (data->state == GTK_EVENT_SEQUENCE_DENIED)
1163     return FALSE;
1164 
1165   /* Sequences can't go from claimed/denied to none */
1166   if (state == GTK_EVENT_SEQUENCE_NONE &&
1167       data->state != GTK_EVENT_SEQUENCE_NONE)
1168     return FALSE;
1169 
1170   data->state = state;
1171   g_signal_emit (gesture, signals[SEQUENCE_STATE_CHANGED], 0,
1172                  sequence, state);
1173 
1174   if (state == GTK_EVENT_SEQUENCE_DENIED)
1175     _gtk_gesture_check_recognized (gesture, sequence);
1176 
1177   return TRUE;
1178 }
1179 
1180 /**
1181  * gtk_gesture_set_state:
1182  * @gesture: a #GtkGesture
1183  * @state: the sequence state
1184  *
1185  * Sets the state of all sequences that @gesture is currently
1186  * interacting with. See gtk_gesture_set_sequence_state()
1187  * for more details on sequence states.
1188  *
1189  * Returns: %TRUE if the state of at least one sequence
1190  *     was changed successfully
1191  *
1192  * Since: 3.14
1193  */
1194 gboolean
gtk_gesture_set_state(GtkGesture * gesture,GtkEventSequenceState state)1195 gtk_gesture_set_state (GtkGesture            *gesture,
1196                        GtkEventSequenceState  state)
1197 {
1198   gboolean handled = FALSE;
1199   GtkGesturePrivate *priv;
1200   GList *sequences, *l;
1201 
1202   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1203   g_return_val_if_fail (state >= GTK_EVENT_SEQUENCE_NONE &&
1204                         state <= GTK_EVENT_SEQUENCE_DENIED, FALSE);
1205 
1206   priv = gtk_gesture_get_instance_private (gesture);
1207   sequences = g_hash_table_get_keys (priv->points);
1208 
1209   for (l = sequences; l; l = l->next)
1210     handled |= gtk_gesture_set_sequence_state (gesture, l->data, state);
1211 
1212   g_list_free (sequences);
1213 
1214   return handled;
1215 }
1216 
1217 /**
1218  * gtk_gesture_get_sequences:
1219  * @gesture: a #GtkGesture
1220  *
1221  * Returns the list of #GdkEventSequences currently being interpreted
1222  * by @gesture.
1223  *
1224  * Returns: (transfer container) (element-type GdkEventSequence): A list
1225  *          of #GdkEventSequences, the list elements are owned by GTK+
1226  *          and must not be freed or modified, the list itself must be deleted
1227  *          through g_list_free()
1228  *
1229  * Since: 3.14
1230  **/
1231 GList *
gtk_gesture_get_sequences(GtkGesture * gesture)1232 gtk_gesture_get_sequences (GtkGesture *gesture)
1233 {
1234   GdkEventSequence *sequence;
1235   GtkGesturePrivate *priv;
1236   GList *sequences = NULL;
1237   GHashTableIter iter;
1238   PointData *data;
1239 
1240   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1241 
1242   priv = gtk_gesture_get_instance_private (gesture);
1243   g_hash_table_iter_init (&iter, priv->points);
1244 
1245   while (g_hash_table_iter_next (&iter, (gpointer *) &sequence, (gpointer *) &data))
1246     {
1247       if (data->state == GTK_EVENT_SEQUENCE_DENIED)
1248         continue;
1249       if (data->event->type == GDK_TOUCH_END ||
1250           data->event->type == GDK_BUTTON_RELEASE)
1251         continue;
1252 
1253       sequences = g_list_prepend (sequences, sequence);
1254     }
1255 
1256   return sequences;
1257 }
1258 
1259 /**
1260  * gtk_gesture_get_last_updated_sequence:
1261  * @gesture: a #GtkGesture
1262  *
1263  * Returns the #GdkEventSequence that was last updated on @gesture.
1264  *
1265  * Returns: (transfer none) (nullable): The last updated sequence
1266  *
1267  * Since: 3.14
1268  **/
1269 GdkEventSequence *
gtk_gesture_get_last_updated_sequence(GtkGesture * gesture)1270 gtk_gesture_get_last_updated_sequence (GtkGesture *gesture)
1271 {
1272   GtkGesturePrivate *priv;
1273 
1274   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1275 
1276   priv = gtk_gesture_get_instance_private (gesture);
1277 
1278   return priv->last_sequence;
1279 }
1280 
1281 /**
1282  * gtk_gesture_get_last_event:
1283  * @gesture: a #GtkGesture
1284  * @sequence: (nullable): a #GdkEventSequence
1285  *
1286  * Returns the last event that was processed for @sequence.
1287  *
1288  * Note that the returned pointer is only valid as long as the @sequence
1289  * is still interpreted by the @gesture. If in doubt, you should make
1290  * a copy of the event.
1291  *
1292  * Returns: (transfer none) (nullable): The last event from @sequence
1293  **/
1294 const GdkEvent *
gtk_gesture_get_last_event(GtkGesture * gesture,GdkEventSequence * sequence)1295 gtk_gesture_get_last_event (GtkGesture       *gesture,
1296                             GdkEventSequence *sequence)
1297 {
1298   GtkGesturePrivate *priv;
1299   PointData *data;
1300 
1301   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1302 
1303   priv = gtk_gesture_get_instance_private (gesture);
1304   data = g_hash_table_lookup (priv->points, sequence);
1305 
1306   if (!data)
1307     return NULL;
1308 
1309   return data->event;
1310 }
1311 
1312 /**
1313  * gtk_gesture_get_point:
1314  * @gesture: a #GtkGesture
1315  * @sequence: (allow-none): a #GdkEventSequence, or %NULL for pointer events
1316  * @x: (out) (allow-none): return location for X axis of the sequence coordinates
1317  * @y: (out) (allow-none): return location for Y axis of the sequence coordinates
1318  *
1319  * If @sequence is currently being interpreted by @gesture, this
1320  * function returns %TRUE and fills in @x and @y with the last coordinates
1321  * stored for that event sequence. The coordinates are always relative to the
1322  * widget allocation.
1323  *
1324  * Returns: %TRUE if @sequence is currently interpreted
1325  *
1326  * Since: 3.14
1327  **/
1328 gboolean
gtk_gesture_get_point(GtkGesture * gesture,GdkEventSequence * sequence,gdouble * x,gdouble * y)1329 gtk_gesture_get_point (GtkGesture       *gesture,
1330                        GdkEventSequence *sequence,
1331                        gdouble          *x,
1332                        gdouble          *y)
1333 {
1334   GtkGesturePrivate *priv;
1335   PointData *data;
1336 
1337   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1338 
1339   priv = gtk_gesture_get_instance_private (gesture);
1340 
1341   if (!g_hash_table_lookup_extended (priv->points, sequence,
1342                                      NULL, (gpointer *) &data))
1343     return FALSE;
1344 
1345   if (x)
1346     *x = data->widget_x;
1347   if (y)
1348     *y = data->widget_y;
1349 
1350   return TRUE;
1351 }
1352 
1353 gboolean
_gtk_gesture_get_last_update_time(GtkGesture * gesture,GdkEventSequence * sequence,guint32 * evtime)1354 _gtk_gesture_get_last_update_time (GtkGesture       *gesture,
1355                                    GdkEventSequence *sequence,
1356                                    guint32          *evtime)
1357 {
1358   GtkGesturePrivate *priv;
1359   PointData *data;
1360 
1361   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1362 
1363   priv = gtk_gesture_get_instance_private (gesture);
1364 
1365   if (!g_hash_table_lookup_extended (priv->points, sequence,
1366                                      NULL, (gpointer *) &data))
1367     return FALSE;
1368 
1369   if (evtime)
1370     *evtime = gdk_event_get_time (data->event);
1371 
1372   return TRUE;
1373 };
1374 
1375 /**
1376  * gtk_gesture_get_bounding_box:
1377  * @gesture: a #GtkGesture
1378  * @rect: (out): bounding box containing all active touches.
1379  *
1380  * If there are touch sequences being currently handled by @gesture,
1381  * this function returns %TRUE and fills in @rect with the bounding
1382  * box containing all active touches. Otherwise, %FALSE will be
1383  * returned.
1384  *
1385  * Note: This function will yield unexpected results on touchpad
1386  * gestures. Since there is no correlation between physical and
1387  * pixel distances, these will look as if constrained in an
1388  * infinitely small area, @rect width and height will thus be 0
1389  * regardless of the number of touchpoints.
1390  *
1391  * Returns: %TRUE if there are active touches, %FALSE otherwise
1392  *
1393  * Since: 3.14
1394  **/
1395 gboolean
gtk_gesture_get_bounding_box(GtkGesture * gesture,GdkRectangle * rect)1396 gtk_gesture_get_bounding_box (GtkGesture   *gesture,
1397                               GdkRectangle *rect)
1398 {
1399   GtkGesturePrivate *priv;
1400   gdouble x1, y1, x2, y2;
1401   GHashTableIter iter;
1402   guint n_points = 0;
1403   PointData *data;
1404 
1405   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1406   g_return_val_if_fail (rect != NULL, FALSE);
1407 
1408   priv = gtk_gesture_get_instance_private (gesture);
1409   x1 = y1 = G_MAXDOUBLE;
1410   x2 = y2 = -G_MAXDOUBLE;
1411 
1412   g_hash_table_iter_init (&iter, priv->points);
1413 
1414   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
1415     {
1416       gdouble x, y;
1417 
1418       if (data->state == GTK_EVENT_SEQUENCE_DENIED)
1419         continue;
1420       if (data->event->type == GDK_TOUCH_END ||
1421           data->event->type == GDK_BUTTON_RELEASE)
1422         continue;
1423 
1424       gdk_event_get_coords (data->event, &x, &y);
1425       n_points++;
1426       x1 = MIN (x1, x);
1427       y1 = MIN (y1, y);
1428       x2 = MAX (x2, x);
1429       y2 = MAX (y2, y);
1430     }
1431 
1432   if (n_points == 0)
1433     return FALSE;
1434 
1435   rect->x = x1;
1436   rect->y = y1;
1437   rect->width = x2 - x1;
1438   rect->height = y2 - y1;
1439 
1440   return TRUE;
1441 }
1442 
1443 
1444 /**
1445  * gtk_gesture_get_bounding_box_center:
1446  * @gesture: a #GtkGesture
1447  * @x: (out): X coordinate for the bounding box center
1448  * @y: (out): Y coordinate for the bounding box center
1449  *
1450  * If there are touch sequences being currently handled by @gesture,
1451  * this function returns %TRUE and fills in @x and @y with the center
1452  * of the bounding box containing all active touches. Otherwise, %FALSE
1453  * will be returned.
1454  *
1455  * Returns: %FALSE if no active touches are present, %TRUE otherwise
1456  *
1457  * Since: 3.14
1458  **/
1459 gboolean
gtk_gesture_get_bounding_box_center(GtkGesture * gesture,gdouble * x,gdouble * y)1460 gtk_gesture_get_bounding_box_center (GtkGesture *gesture,
1461                                      gdouble    *x,
1462                                      gdouble    *y)
1463 {
1464   const GdkEvent *last_event;
1465   GdkRectangle rect;
1466   GdkEventSequence *sequence;
1467 
1468   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1469   g_return_val_if_fail (x != NULL && y != NULL, FALSE);
1470 
1471   sequence = gtk_gesture_get_last_updated_sequence (gesture);
1472   last_event = gtk_gesture_get_last_event (gesture, sequence);
1473 
1474   if (EVENT_IS_TOUCHPAD_GESTURE (last_event))
1475     return gtk_gesture_get_point (gesture, sequence, x, y);
1476   else if (!gtk_gesture_get_bounding_box (gesture, &rect))
1477     return FALSE;
1478 
1479   *x = rect.x + rect.width / 2;
1480   *y = rect.y + rect.height / 2;
1481   return TRUE;
1482 }
1483 
1484 /**
1485  * gtk_gesture_is_active:
1486  * @gesture: a #GtkGesture
1487  *
1488  * Returns %TRUE if the gesture is currently active.
1489  * A gesture is active meanwhile there are touch sequences
1490  * interacting with it.
1491  *
1492  * Returns: %TRUE if gesture is active
1493  *
1494  * Since: 3.14
1495  **/
1496 gboolean
gtk_gesture_is_active(GtkGesture * gesture)1497 gtk_gesture_is_active (GtkGesture *gesture)
1498 {
1499   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1500 
1501   return _gtk_gesture_get_n_physical_points (gesture, TRUE) != 0;
1502 }
1503 
1504 /**
1505  * gtk_gesture_is_recognized:
1506  * @gesture: a #GtkGesture
1507  *
1508  * Returns %TRUE if the gesture is currently recognized.
1509  * A gesture is recognized if there are as many interacting
1510  * touch sequences as required by @gesture, and #GtkGesture::check
1511  * returned %TRUE for the sequences being currently interpreted.
1512  *
1513  * Returns: %TRUE if gesture is recognized
1514  *
1515  * Since: 3.14
1516  **/
1517 gboolean
gtk_gesture_is_recognized(GtkGesture * gesture)1518 gtk_gesture_is_recognized (GtkGesture *gesture)
1519 {
1520   GtkGesturePrivate *priv;
1521 
1522   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1523 
1524   priv = gtk_gesture_get_instance_private (gesture);
1525 
1526   return priv->recognized;
1527 }
1528 
1529 gboolean
_gtk_gesture_check(GtkGesture * gesture)1530 _gtk_gesture_check (GtkGesture *gesture)
1531 {
1532   GtkGesturePrivate *priv;
1533 
1534   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1535 
1536   priv = gtk_gesture_get_instance_private (gesture);
1537 
1538   return _gtk_gesture_check_recognized (gesture, priv->last_sequence);
1539 }
1540 
1541 /**
1542  * gtk_gesture_handles_sequence:
1543  * @gesture: a #GtkGesture
1544  * @sequence: (nullable): a #GdkEventSequence or %NULL
1545  *
1546  * Returns %TRUE if @gesture is currently handling events corresponding to
1547  * @sequence.
1548  *
1549  * Returns: %TRUE if @gesture is handling @sequence, %FALSE otherwise
1550  *
1551  * Since: 3.14
1552  **/
1553 gboolean
gtk_gesture_handles_sequence(GtkGesture * gesture,GdkEventSequence * sequence)1554 gtk_gesture_handles_sequence (GtkGesture       *gesture,
1555                               GdkEventSequence *sequence)
1556 {
1557   GtkGesturePrivate *priv;
1558   PointData *data;
1559 
1560   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1561 
1562   priv = gtk_gesture_get_instance_private (gesture);
1563   data = g_hash_table_lookup (priv->points, sequence);
1564 
1565   if (!data)
1566     return FALSE;
1567 
1568   if (data->state == GTK_EVENT_SEQUENCE_DENIED)
1569     return FALSE;
1570 
1571   return TRUE;
1572 }
1573 
1574 gboolean
_gtk_gesture_cancel_sequence(GtkGesture * gesture,GdkEventSequence * sequence)1575 _gtk_gesture_cancel_sequence (GtkGesture       *gesture,
1576                               GdkEventSequence *sequence)
1577 {
1578   GtkGesturePrivate *priv;
1579   PointData *data;
1580 
1581   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1582 
1583   priv = gtk_gesture_get_instance_private (gesture);
1584   data = g_hash_table_lookup (priv->points, sequence);
1585 
1586   if (!data)
1587     return FALSE;
1588 
1589   g_signal_emit (gesture, signals[CANCEL], 0, sequence);
1590   _gtk_gesture_remove_point (gesture, data->event);
1591   _gtk_gesture_check_recognized (gesture, sequence);
1592 
1593   return TRUE;
1594 }
1595 
1596 /**
1597  * gtk_gesture_get_window:
1598  * @gesture: a #GtkGesture
1599  *
1600  * Returns the user-defined window that receives the events
1601  * handled by @gesture. See gtk_gesture_set_window() for more
1602  * information.
1603  *
1604  * Returns: (nullable) (transfer none): the user defined window, or %NULL if none
1605  *
1606  * Since: 3.14
1607  **/
1608 GdkWindow *
gtk_gesture_get_window(GtkGesture * gesture)1609 gtk_gesture_get_window (GtkGesture *gesture)
1610 {
1611   GtkGesturePrivate *priv;
1612 
1613   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1614 
1615   priv = gtk_gesture_get_instance_private (gesture);
1616 
1617   return priv->user_window;
1618 }
1619 
1620 /**
1621  * gtk_gesture_set_window:
1622  * @gesture: a #GtkGesture
1623  * @window: (allow-none): a #GdkWindow, or %NULL
1624  *
1625  * Sets a specific window to receive events about, so @gesture
1626  * will effectively handle only events targeting @window, or
1627  * a child of it. @window must pertain to gtk_event_controller_get_widget().
1628  *
1629  * Since: 3.14
1630  **/
1631 void
gtk_gesture_set_window(GtkGesture * gesture,GdkWindow * window)1632 gtk_gesture_set_window (GtkGesture *gesture,
1633                         GdkWindow  *window)
1634 {
1635   GtkGesturePrivate *priv;
1636 
1637   g_return_if_fail (GTK_IS_GESTURE (gesture));
1638   g_return_if_fail (!window || GDK_IS_WINDOW (window));
1639 
1640   priv = gtk_gesture_get_instance_private (gesture);
1641 
1642   if (window)
1643     {
1644       GtkWidget *window_widget;
1645 
1646       gdk_window_get_user_data (window, (gpointer*) &window_widget);
1647       g_return_if_fail (window_widget ==
1648                         gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
1649     }
1650 
1651   if (priv->user_window == window)
1652     return;
1653 
1654   priv->user_window = window;
1655   g_object_notify (G_OBJECT (gesture), "window");
1656 }
1657 
1658 GList *
_gtk_gesture_get_group_link(GtkGesture * gesture)1659 _gtk_gesture_get_group_link (GtkGesture *gesture)
1660 {
1661   GtkGesturePrivate *priv;
1662 
1663   priv = gtk_gesture_get_instance_private (gesture);
1664 
1665   return priv->group_link;
1666 }
1667 
1668 /**
1669  * gtk_gesture_group:
1670  * @gesture: a #GtkGesture
1671  * @group_gesture: #GtkGesture to group @gesture with
1672  *
1673  * Adds @gesture to the same group than @group_gesture. Gestures
1674  * are by default isolated in their own groups.
1675  *
1676  * When gestures are grouped, the state of #GdkEventSequences
1677  * is kept in sync for all of those, so calling gtk_gesture_set_sequence_state(),
1678  * on one will transfer the same value to the others.
1679  *
1680  * Groups also perform an "implicit grabbing" of sequences, if a
1681  * #GdkEventSequence state is set to #GTK_EVENT_SEQUENCE_CLAIMED on one group,
1682  * every other gesture group attached to the same #GtkWidget will switch the
1683  * state for that sequence to #GTK_EVENT_SEQUENCE_DENIED.
1684  *
1685  * Since: 3.14
1686  **/
1687 void
gtk_gesture_group(GtkGesture * gesture,GtkGesture * group_gesture)1688 gtk_gesture_group (GtkGesture *gesture,
1689                    GtkGesture *group_gesture)
1690 {
1691   GList *link, *group_link, *next;
1692 
1693   g_return_if_fail (GTK_IS_GESTURE (gesture));
1694   g_return_if_fail (GTK_IS_GESTURE (group_gesture));
1695   g_return_if_fail (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (group_gesture)) ==
1696                     gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
1697 
1698   link = _gtk_gesture_get_group_link (gesture);
1699 
1700   if (link->prev || link->next)
1701     {
1702       if (gtk_gesture_is_grouped_with (gesture, group_gesture))
1703         return;
1704       gtk_gesture_ungroup (gesture);
1705     }
1706 
1707   group_link = _gtk_gesture_get_group_link (group_gesture);
1708   next = group_link->next;
1709 
1710   /* Rewire link so it's inserted after the group_gesture elem */
1711   link->prev = group_link;
1712   link->next = next;
1713   group_link->next = link;
1714   if (next)
1715     next->prev = link;
1716 }
1717 
1718 /**
1719  * gtk_gesture_ungroup:
1720  * @gesture: a #GtkGesture
1721  *
1722  * Separates @gesture into an isolated group.
1723  *
1724  * Since: 3.14
1725  **/
1726 void
gtk_gesture_ungroup(GtkGesture * gesture)1727 gtk_gesture_ungroup (GtkGesture *gesture)
1728 {
1729   GList *link, *prev, *next;
1730 
1731   g_return_if_fail (GTK_IS_GESTURE (gesture));
1732 
1733   link = _gtk_gesture_get_group_link (gesture);
1734   prev = link->prev;
1735   next = link->next;
1736 
1737   /* Detach link from the group chain */
1738   if (prev)
1739     prev->next = next;
1740   if (next)
1741     next->prev = prev;
1742 
1743   link->next = link->prev = NULL;
1744 }
1745 
1746 /**
1747  * gtk_gesture_get_group:
1748  * @gesture: a #GtkGesture
1749  *
1750  * Returns all gestures in the group of @gesture
1751  *
1752  * Returns: (element-type GtkGesture) (transfer container): The list
1753  *   of #GtkGestures, free with g_list_free()
1754  *
1755  * Since: 3.14
1756  **/
1757 GList *
gtk_gesture_get_group(GtkGesture * gesture)1758 gtk_gesture_get_group (GtkGesture *gesture)
1759 {
1760   GList *link;
1761 
1762   g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
1763 
1764   link = _gtk_gesture_get_group_link (gesture);
1765 
1766   return g_list_copy (g_list_first (link));
1767 }
1768 
1769 /**
1770  * gtk_gesture_is_grouped_with:
1771  * @gesture: a #GtkGesture
1772  * @other: another #GtkGesture
1773  *
1774  * Returns %TRUE if both gestures pertain to the same group.
1775  *
1776  * Returns: whether the gestures are grouped
1777  *
1778  * Since: 3.14
1779  **/
1780 gboolean
gtk_gesture_is_grouped_with(GtkGesture * gesture,GtkGesture * other)1781 gtk_gesture_is_grouped_with (GtkGesture *gesture,
1782                              GtkGesture *other)
1783 {
1784   GList *link;
1785 
1786   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1787   g_return_val_if_fail (GTK_IS_GESTURE (other), FALSE);
1788 
1789   link = _gtk_gesture_get_group_link (gesture);
1790   link = g_list_first (link);
1791 
1792   return g_list_find (link, other) != NULL;
1793 }
1794 
1795 gboolean
_gtk_gesture_handled_sequence_press(GtkGesture * gesture,GdkEventSequence * sequence)1796 _gtk_gesture_handled_sequence_press (GtkGesture       *gesture,
1797                                      GdkEventSequence *sequence)
1798 {
1799   GtkGesturePrivate *priv;
1800   PointData *data;
1801 
1802   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1803 
1804   priv = gtk_gesture_get_instance_private (gesture);
1805   data = g_hash_table_lookup (priv->points, sequence);
1806 
1807   if (!data)
1808     return FALSE;
1809 
1810   return data->press_handled;
1811 }
1812 
1813 gboolean
_gtk_gesture_get_pointer_emulating_sequence(GtkGesture * gesture,GdkEventSequence ** sequence)1814 _gtk_gesture_get_pointer_emulating_sequence (GtkGesture        *gesture,
1815                                              GdkEventSequence **sequence)
1816 {
1817   GtkGesturePrivate *priv;
1818   GdkEventSequence *seq;
1819   GHashTableIter iter;
1820   PointData *data;
1821 
1822   g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
1823 
1824   priv = gtk_gesture_get_instance_private (gesture);
1825   g_hash_table_iter_init (&iter, priv->points);
1826 
1827   while (g_hash_table_iter_next (&iter, (gpointer*) &seq, (gpointer*) &data))
1828     {
1829       switch (data->event->type)
1830         {
1831         case GDK_TOUCH_BEGIN:
1832         case GDK_TOUCH_UPDATE:
1833         case GDK_TOUCH_END:
1834           if (!data->event->touch.emulating_pointer)
1835             continue;
1836           /* Fall through */
1837         case GDK_BUTTON_PRESS:
1838         case GDK_BUTTON_RELEASE:
1839         case GDK_MOTION_NOTIFY:
1840           *sequence = seq;
1841           return TRUE;
1842         default:
1843           break;
1844         }
1845     }
1846 
1847   return FALSE;
1848 }
1849