1 #include <gtk/gtk.h>
2 
3 #define GTK_COMPILATION
4 #include "gdk/gdkeventsprivate.h"
5 
6 typedef struct {
7   GtkWidget *widget;
8   int x;
9   int y;
10   guint state;
11   guint pressed : 1;
12 } PointState;
13 
14 static PointState mouse_state;
15 static PointState touch_state[10]; /* touchpoint 0 gets pointer emulation,
16                                     * use it first in tests for consistency.
17                                     */
18 
19 #define EVENT_SEQUENCE(point) (GdkEventSequence*) ((point) - touch_state + 1)
20 
21 static void
inject_event(GdkEvent * event)22 inject_event (GdkEvent *event)
23 {
24   gboolean handled;
25 
26   g_signal_emit_by_name (event->surface, "event", event, &handled);
27 }
28 
29 static void
point_press(PointState * point,GtkWidget * widget,guint button)30 point_press (PointState *point,
31              GtkWidget  *widget,
32              guint       button)
33 {
34   GdkDisplay *display;
35   GdkDevice *device;
36   GdkSeat *seat;
37   GdkSurface *surface;
38   GdkEvent *ev;
39 
40   display = gtk_widget_get_display (widget);
41   seat = gdk_display_get_default_seat (display);
42   device = gdk_seat_get_pointer (seat);
43   surface = gtk_native_get_surface (gtk_widget_get_native (widget));
44 
45   if (point == &mouse_state)
46     {
47       ev = gdk_button_event_new (GDK_BUTTON_PRESS,
48                                  surface,
49                                  device,
50                                  device,
51                                  NULL,
52                                  GDK_CURRENT_TIME,
53                                  point->x,
54                                  point->y,
55                                  button,
56                                  point->state);
57 
58       point->state |= GDK_BUTTON1_MASK << (button - 1);
59     }
60   else
61     {
62       ev = gdk_touch_event_new (GDK_TOUCH_BEGIN,
63                                 EVENT_SEQUENCE (point),
64                                 surface,
65                                 device,
66                                 device,
67                                 GDK_CURRENT_TIME,
68                                 point->state,
69                                 point->x,
70                                 point->y,
71                                 point == &touch_state[0]);
72     }
73 
74   inject_event (ev);
75 
76   g_object_unref (ev);
77 
78   point->widget = widget;
79 }
80 
81 static void
point_update(PointState * point,GtkWidget * widget,double x,double y)82 point_update (PointState *point,
83               GtkWidget  *widget,
84               double      x,
85               double      y)
86 {
87   GdkDisplay *display;
88   GdkDevice *device;
89   GdkSeat *seat;
90   GdkSurface *surface;
91   GdkEvent *ev;
92 
93   display = gtk_widget_get_display (widget);
94   seat = gdk_display_get_default_seat (display);
95   device = gdk_seat_get_pointer (seat);
96   surface = gtk_native_get_surface (gtk_widget_get_native (widget));
97 
98   point->x = x;
99   point->y = y;
100 
101   if (point == &mouse_state)
102     {
103       ev = gdk_motion_event_new (surface,
104                                  device,
105                                  device,
106                                  NULL,
107                                  GDK_CURRENT_TIME,
108                                  point->state,
109                                  point->x,
110                                  point->y);
111     }
112   else
113     {
114       if (!point->widget || widget != point->widget)
115         return;
116 
117       ev = gdk_touch_event_new (GDK_TOUCH_UPDATE,
118                                 EVENT_SEQUENCE (point),
119                                 surface,
120                                 device,
121                                 device,
122                                 GDK_CURRENT_TIME,
123                                 point->state,
124                                 point->x,
125                                 point->y,
126                                 point == &touch_state[0]);
127     }
128 
129   inject_event (ev);
130 
131   g_object_unref (ev);
132 }
133 
134 static void
point_release(PointState * point,guint button)135 point_release (PointState *point,
136                guint       button)
137 {
138   GdkDisplay *display;
139   GdkDevice *device;
140   GdkSeat *seat;
141   GdkSurface *surface;
142   GdkEvent *ev;
143 
144   if (point->widget == NULL)
145     return;
146 
147   display = gtk_widget_get_display (point->widget);
148   seat = gdk_display_get_default_seat (display);
149   device = gdk_seat_get_pointer (seat);
150   surface = gtk_native_get_surface (gtk_widget_get_native (point->widget));
151 
152   if (!point->widget)
153     return;
154 
155   if (point == &mouse_state)
156     {
157       if ((point->state & (GDK_BUTTON1_MASK << (button - 1))) == 0)
158         return;
159 
160       ev = gdk_button_event_new (GDK_BUTTON_RELEASE,
161                                  surface,
162                                  device,
163                                  device,
164                                  NULL,
165                                  GDK_CURRENT_TIME,
166                                  point->x,
167                                  point->y,
168                                  button,
169                                  point->state);
170 
171       point->state &= ~(GDK_BUTTON1_MASK << (button - 1));
172     }
173   else
174     {
175       ev = gdk_touch_event_new (GDK_TOUCH_END,
176                                 EVENT_SEQUENCE (point),
177                                 surface,
178                                 device,
179                                 device,
180                                 GDK_CURRENT_TIME,
181                                 point->state,
182                                 point->x,
183                                 point->y,
184                                 point == &touch_state[0]);
185     }
186 
187   inject_event (ev);
188 
189   g_object_unref (ev);
190 }
191 
192 static const char *
phase_nick(GtkPropagationPhase phase)193 phase_nick (GtkPropagationPhase phase)
194 {
195  GTypeClass *class;
196  GEnumValue *value;
197 
198  class = g_type_class_ref (GTK_TYPE_PROPAGATION_PHASE);
199  value = g_enum_get_value ((GEnumClass*)class, phase);
200  g_type_class_unref (class);
201 
202  return value->value_nick;
203 }
204 
205 static const char *
state_nick(GtkEventSequenceState state)206 state_nick (GtkEventSequenceState state)
207 {
208  GTypeClass *class;
209  GEnumValue *value;
210 
211  class = g_type_class_ref (GTK_TYPE_EVENT_SEQUENCE_STATE);
212  value = g_enum_get_value ((GEnumClass*)class, state);
213  g_type_class_unref (class);
214 
215  return value->value_nick;
216 }
217 
218 typedef struct {
219   GtkEventController *controller;
220   GString *str;
221   gboolean exit;
222 } LegacyData;
223 
224 static gboolean
legacy_cb(GtkEventControllerLegacy * c,GdkEvent * button,gpointer data)225 legacy_cb (GtkEventControllerLegacy *c, GdkEvent *button, gpointer data)
226 {
227   if (gdk_event_get_event_type (button) == GDK_BUTTON_PRESS)
228     {
229       LegacyData *ld = data;
230       GtkWidget *w;
231 
232       w = gtk_event_controller_get_widget (ld->controller);
233 
234       if (ld->str->len > 0)
235         g_string_append (ld->str, ", ");
236       g_string_append_printf (ld->str, "legacy %s", gtk_widget_get_name (w));
237 
238       return ld->exit;
239     }
240 
241   return GDK_EVENT_PROPAGATE;
242 }
243 
244 typedef struct {
245   GString *str;
246   GtkEventSequenceState state;
247 } GestureData;
248 
249 static void
press_cb(GtkGesture * g,int n_press,double x,double y,gpointer data)250 press_cb (GtkGesture *g, int n_press, double x, double y, gpointer data)
251 {
252   GtkEventController *c = GTK_EVENT_CONTROLLER (g);
253   GdkEventSequence *sequence;
254   GtkPropagationPhase phase;
255   GestureData *gd = data;
256   const char *name;
257 
258   name = g_object_get_data (G_OBJECT (g), "name");
259   phase = gtk_event_controller_get_propagation_phase (c);
260 
261   if (gd->str->len > 0)
262     g_string_append (gd->str, ", ");
263   g_string_append_printf (gd->str, "%s %s", phase_nick (phase), name);
264 
265   sequence = gtk_gesture_get_last_updated_sequence (g);
266 
267   if (sequence)
268     g_string_append_printf (gd->str, " (%x)", GPOINTER_TO_UINT (sequence));
269 
270   if (gd->state != GTK_EVENT_SEQUENCE_NONE)
271     gtk_gesture_set_state (g, gd->state);
272 }
273 
274 static void
cancel_cb(GtkGesture * g,GdkEventSequence * sequence,gpointer data)275 cancel_cb (GtkGesture *g, GdkEventSequence *sequence, gpointer data)
276 {
277   GestureData *gd = data;
278   const char *name;
279 
280   name = g_object_get_data (G_OBJECT (g), "name");
281 
282   if (gd->str->len > 0)
283     g_string_append (gd->str, ", ");
284   g_string_append_printf (gd->str, "%s cancelled", name);
285 }
286 
287 static void
begin_cb(GtkGesture * g,GdkEventSequence * sequence,gpointer data)288 begin_cb (GtkGesture *g, GdkEventSequence *sequence, gpointer data)
289 {
290   GestureData *gd = data;
291   const char *name;
292 
293   name = g_object_get_data (G_OBJECT (g), "name");
294 
295   if (gd->str->len > 0)
296     g_string_append (gd->str, ", ");
297   g_string_append_printf (gd->str, "%s began", name);
298 
299   if (gd->state != GTK_EVENT_SEQUENCE_NONE)
300     gtk_gesture_set_state (g, gd->state);
301 }
302 
303 static void
end_cb(GtkGesture * g,GdkEventSequence * sequence,gpointer data)304 end_cb (GtkGesture *g, GdkEventSequence *sequence, gpointer data)
305 {
306   GestureData *gd = data;
307   const char *name;
308 
309   name = g_object_get_data (G_OBJECT (g), "name");
310 
311   if (gd->str->len > 0)
312     g_string_append (gd->str, ", ");
313   g_string_append_printf (gd->str, "%s ended", name);
314 }
315 
316 static void
update_cb(GtkGesture * g,GdkEventSequence * sequence,gpointer data)317 update_cb (GtkGesture *g, GdkEventSequence *sequence, gpointer data)
318 {
319   GestureData *gd = data;
320   const char *name;
321 
322   name = g_object_get_data (G_OBJECT (g), "name");
323 
324   if (gd->str->len > 0)
325     g_string_append (gd->str, ", ");
326   g_string_append_printf (gd->str, "%s updated", name);
327 }
328 
329 static void
state_changed_cb(GtkGesture * g,GdkEventSequence * sequence,GtkEventSequenceState state,gpointer data)330 state_changed_cb (GtkGesture *g, GdkEventSequence *sequence, GtkEventSequenceState state, gpointer data)
331 {
332   GestureData *gd = data;
333   const char *name;
334 
335   name = g_object_get_data (G_OBJECT (g), "name");
336 
337   if (gd->str->len > 0)
338     g_string_append (gd->str, ", ");
339   g_string_append_printf (gd->str, "%s state %s", name, state_nick (state));
340 
341   if (sequence != NULL)
342     g_string_append_printf (gd->str, " (%x)", GPOINTER_TO_UINT (sequence));
343 }
344 
345 
346 static GtkGesture *
add_gesture(GtkWidget * w,const char * name,GtkPropagationPhase phase,GString * str,GtkEventSequenceState state)347 add_gesture (GtkWidget *w, const char *name, GtkPropagationPhase phase, GString *str, GtkEventSequenceState state)
348 {
349   GtkGesture *g;
350   GestureData *data;
351 
352   data = g_new (GestureData, 1);
353   data->str = str;
354   data->state = state;
355 
356   g = gtk_gesture_click_new ();
357   gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (g), FALSE);
358   gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (g), 1);
359   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (g), phase);
360   gtk_widget_add_controller (w, GTK_EVENT_CONTROLLER (g));
361 
362   g_object_set_data (G_OBJECT (g), "name", (gpointer)name);
363 
364   g_signal_connect (g, "pressed", G_CALLBACK (press_cb), data);
365   g_signal_connect (g, "cancel", G_CALLBACK (cancel_cb), data);
366   g_signal_connect (g, "update", G_CALLBACK (update_cb), data);
367   g_signal_connect (g, "sequence-state-changed", G_CALLBACK (state_changed_cb), data);
368 
369   return g;
370 }
371 
372 static GtkGesture *
add_mt_gesture(GtkWidget * w,const char * name,GtkPropagationPhase phase,GString * str,GtkEventSequenceState state)373 add_mt_gesture (GtkWidget *w, const char *name, GtkPropagationPhase phase, GString *str, GtkEventSequenceState state)
374 {
375   GtkGesture *g;
376   GestureData *data;
377 
378   data = g_new (GestureData, 1);
379   data->str = str;
380   data->state = state;
381 
382   g = gtk_gesture_rotate_new ();
383   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (g), phase);
384   gtk_widget_add_controller (w, GTK_EVENT_CONTROLLER (g));
385 
386   g_object_set_data (G_OBJECT (g), "name", (gpointer)name);
387 
388   g_signal_connect (g, "begin", G_CALLBACK (begin_cb), data);
389   g_signal_connect (g, "update", G_CALLBACK (update_cb), data);
390   g_signal_connect (g, "end", G_CALLBACK (end_cb), data);
391   g_signal_connect (g, "sequence-state-changed", G_CALLBACK (state_changed_cb), data);
392 
393   return g;
394 }
395 
396 static void
add_legacy(GtkWidget * w,GString * str,gboolean exit)397 add_legacy (GtkWidget *w, GString *str, gboolean exit)
398 {
399   LegacyData *data;
400 
401   data = g_new (LegacyData, 1);
402   data->controller = gtk_event_controller_legacy_new ();
403   data->str = str;
404   data->exit = exit;
405 
406   gtk_event_controller_set_propagation_phase (data->controller, GTK_PHASE_BUBBLE);
407   gtk_widget_add_controller (w, data->controller);
408   g_signal_connect (data->controller, "event", G_CALLBACK (legacy_cb), data);
409 }
410 
411 static void
test_phases(void)412 test_phases (void)
413 {
414   GtkWidget *A, *B, *C;
415   GString *str;
416   GtkAllocation allocation;
417 
418   A = gtk_window_new ();
419   gtk_widget_set_name (A, "A");
420   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
421   gtk_widget_set_name (B, "B");
422   C = gtk_image_new ();
423   gtk_widget_set_hexpand (C, TRUE);
424   gtk_widget_set_vexpand (C, TRUE);
425   gtk_widget_set_name (C, "C");
426 
427   gtk_box_append (GTK_BOX (A), B);
428   gtk_box_append (GTK_BOX (B), C);
429 
430   gtk_widget_show (A);
431 
432   str = g_string_new ("");
433 
434   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
435   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
436   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
437   add_gesture (A, "a2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
438   add_gesture (B, "b2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
439   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
440   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
441   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
442   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
443 
444   gtk_widget_get_allocation (B, &allocation);
445 
446   point_update (&mouse_state, A, allocation.x, allocation.y);
447   point_press (&mouse_state, A, 1);
448 
449   g_assert_cmpstr (str->str, ==,
450                    "capture a1, "
451                    "capture b1, "
452                    "capture c1, "
453                    "target c2, "
454                    "bubble c3, "
455                    "bubble b3, "
456                    "bubble a3");
457 
458   g_string_free (str, TRUE);
459 
460   gtk_window_destroy (A);
461 }
462 
463 static void
test_mixed(void)464 test_mixed (void)
465 {
466   GtkWidget *A, *B, *C;
467   GString *str;
468   GtkAllocation allocation;
469 
470   A = gtk_window_new ();
471   gtk_widget_set_name (A, "A");
472   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
473   gtk_widget_set_name (B, "B");
474   C = gtk_image_new ();
475   gtk_widget_set_hexpand (C, TRUE);
476   gtk_widget_set_vexpand (C, TRUE);
477   gtk_widget_set_name (C, "C");
478 
479   gtk_box_append (GTK_BOX (A), B);
480   gtk_box_append (GTK_BOX (B), C);
481 
482   gtk_widget_show (A);
483 
484   str = g_string_new ("");
485 
486   add_legacy (A, str, GDK_EVENT_PROPAGATE);
487   add_legacy (B, str, GDK_EVENT_PROPAGATE);
488   add_legacy (C, str, GDK_EVENT_PROPAGATE);
489 
490   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
491   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
492   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
493   add_gesture (A, "a2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
494   add_gesture (B, "b2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
495   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
496   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
497   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
498   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
499 
500   gtk_widget_get_allocation (B, &allocation);
501 
502   point_update (&mouse_state, A, allocation.x, allocation.y);
503   point_press (&mouse_state, A, 1);
504 
505   g_assert_cmpstr (str->str, ==,
506                    "capture a1, "
507                    "capture b1, "
508                    "capture c1, "
509                    "target c2, "
510                    "bubble c3, "
511                    "legacy C, "
512                    "bubble b3, "
513                    "legacy B, "
514                    "bubble a3, "
515                    "legacy A");
516 
517   g_string_free (str, TRUE);
518 
519   gtk_window_destroy (A);
520 }
521 
522 static void
test_early_exit(void)523 test_early_exit (void)
524 {
525   GtkWidget *A, *B, *C;
526   GString *str;
527   GtkAllocation allocation;
528 
529   A = gtk_window_new ();
530   gtk_widget_set_name (A, "A");
531   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
532   gtk_widget_set_name (B, "B");
533   C = gtk_image_new ();
534   gtk_widget_set_hexpand (C, TRUE);
535   gtk_widget_set_vexpand (C, TRUE);
536   gtk_widget_set_name (C, "C");
537 
538   gtk_box_append (GTK_BOX (A), B);
539   gtk_box_append (GTK_BOX (B), C);
540 
541   gtk_widget_show (A);
542 
543   str = g_string_new ("");
544 
545   add_legacy (A, str, GDK_EVENT_PROPAGATE);
546   add_legacy (B, str, GDK_EVENT_STOP);
547   add_legacy (C, str, GDK_EVENT_PROPAGATE);
548 
549   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
550   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
551   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
552   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
553   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
554   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
555   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
556 
557   gtk_widget_get_allocation (B, &allocation);
558 
559   point_update (&mouse_state, A, allocation.x, allocation.y);
560   point_press (&mouse_state, A, 1);
561 
562   g_assert_cmpstr (str->str, ==,
563                    "capture a1, "
564                    "capture b1, "
565                    "capture c1, "
566                    "target c2, "
567                    "bubble c3, "
568                    "legacy C, "
569                    "bubble b3, "
570                    "legacy B");
571 
572   g_string_free (str, TRUE);
573 
574   gtk_window_destroy (A);
575 }
576 
577 static void
test_claim_capture(void)578 test_claim_capture (void)
579 {
580   GtkWidget *A, *B, *C;
581   GString *str;
582   GtkAllocation allocation;
583 
584   A = gtk_window_new ();
585   gtk_widget_set_name (A, "A");
586   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
587   gtk_widget_set_name (B, "B");
588   C = gtk_image_new ();
589   gtk_widget_set_hexpand (C, TRUE);
590   gtk_widget_set_vexpand (C, TRUE);
591   gtk_widget_set_name (C, "C");
592 
593   gtk_box_append (GTK_BOX (A), B);
594   gtk_box_append (GTK_BOX (B), C);
595 
596   gtk_widget_show (A);
597 
598   str = g_string_new ("");
599 
600   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
601   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
602   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_CLAIMED);
603   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
604   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
605   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
606   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
607 
608   gtk_widget_get_allocation (B, &allocation);
609 
610   point_update (&mouse_state, A, allocation.x, allocation.y);
611   point_press (&mouse_state, A, 1);
612 
613   g_assert_cmpstr (str->str, ==,
614                    "capture a1, "
615                    "capture b1, "
616                    "capture c1, "
617                    "c1 state claimed");
618 
619   g_string_free (str, TRUE);
620 
621   gtk_window_destroy (A);
622 }
623 
624 static void
test_claim_target(void)625 test_claim_target (void)
626 {
627   GtkWidget *A, *B, *C;
628   GString *str;
629   GtkAllocation allocation;
630 
631   A = gtk_window_new ();
632   gtk_widget_set_name (A, "A");
633   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
634   gtk_widget_set_name (B, "B");
635   C = gtk_image_new ();
636   gtk_widget_set_hexpand (C, TRUE);
637   gtk_widget_set_vexpand (C, TRUE);
638   gtk_widget_set_name (C, "C");
639 
640   gtk_box_append (GTK_BOX (A), B);
641   gtk_box_append (GTK_BOX (B), C);
642 
643   gtk_widget_show (A);
644 
645   str = g_string_new ("");
646 
647   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
648   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
649   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
650   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_CLAIMED);
651   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
652   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
653   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
654 
655   gtk_widget_get_allocation (B, &allocation);
656   point_update (&mouse_state, A, allocation.x, allocation.y);
657   point_press (&mouse_state, A, 1);
658 
659   g_assert_cmpstr (str->str, ==,
660                    "capture a1, "
661                    "capture b1, "
662                    "capture c1, "
663                    "target c2, "
664                    "c2 state claimed");
665 
666   g_string_free (str, TRUE);
667 
668   gtk_window_destroy (A);
669 }
670 
671 static void
test_claim_bubble(void)672 test_claim_bubble (void)
673 {
674   GtkWidget *A, *B, *C;
675   GString *str;
676   GtkAllocation allocation;
677 
678   A = gtk_window_new ();
679   gtk_widget_set_name (A, "A");
680   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
681   gtk_widget_set_name (B, "B");
682   C = gtk_image_new ();
683   gtk_widget_set_hexpand (C, TRUE);
684   gtk_widget_set_vexpand (C, TRUE);
685   gtk_widget_set_name (C, "C");
686 
687   gtk_box_append (GTK_BOX (A), B);
688   gtk_box_append (GTK_BOX (B), C);
689 
690   gtk_widget_show (A);
691 
692   str = g_string_new ("");
693 
694   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
695   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
696   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
697   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
698   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
699   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_CLAIMED);
700   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
701 
702   gtk_widget_get_allocation (B, &allocation);
703   point_update (&mouse_state, A, allocation.x, allocation.y);
704   point_press (&mouse_state, A, 1);
705 
706   g_assert_cmpstr (str->str, ==,
707                    "capture a1, "
708                    "capture b1, "
709                    "capture c1, "
710                    "target c2, "
711                    "bubble c3, "
712                    "bubble b3, "
713                    "c3 cancelled, "
714                    "c2 cancelled, "
715                    "c1 cancelled, "
716                    "b3 state claimed"
717                    );
718 
719   g_string_free (str, TRUE);
720 
721   gtk_window_destroy (A);
722 }
723 
724 static void
test_early_claim_capture(void)725 test_early_claim_capture (void)
726 {
727   GtkWidget *A, *B, *C;
728   GtkGesture *g;
729   GString *str;
730   GtkAllocation allocation;
731 
732   A = gtk_window_new ();
733   gtk_widget_set_name (A, "A");
734   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
735   gtk_widget_set_name (B, "B");
736   C = gtk_image_new ();
737   gtk_widget_set_hexpand (C, TRUE);
738   gtk_widget_set_vexpand (C, TRUE);
739   gtk_widget_set_name (C, "C");
740 
741   gtk_box_append (GTK_BOX (A), B);
742   gtk_box_append (GTK_BOX (B), C);
743 
744   gtk_widget_show (A);
745 
746   str = g_string_new ("");
747 
748   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
749   g = add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_CLAIMED);
750   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_CLAIMED);
751   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
752   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
753   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
754   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
755 
756   gtk_widget_get_allocation (B, &allocation);
757   point_update (&mouse_state, A, allocation.x, allocation.y);
758   point_press (&mouse_state, A, 1);
759 
760   g_assert_cmpstr (str->str, ==,
761                    "capture a1, "
762                    "capture b1, "
763                    "b1 state claimed");
764 
765   /* Reset the string */
766   g_string_erase (str, 0, str->len);
767 
768   gtk_gesture_set_state (g, GTK_EVENT_SEQUENCE_DENIED);
769 
770   g_assert_cmpstr (str->str, ==,
771                    "capture c1, "
772                    "c1 state claimed, "
773                    "b1 state denied");
774 
775   point_release (&mouse_state, 1);
776 
777   g_string_free (str, TRUE);
778   gtk_window_destroy (A);
779 }
780 
781 static void
test_late_claim_capture(void)782 test_late_claim_capture (void)
783 {
784   GtkWidget *A, *B, *C;
785   GtkGesture *g;
786   GString *str;
787   GtkAllocation allocation;
788 
789   A = gtk_window_new ();
790   gtk_widget_set_name (A, "A");
791   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
792   gtk_widget_set_name (B, "B");
793   C = gtk_image_new ();
794   gtk_widget_set_hexpand (C, TRUE);
795   gtk_widget_set_vexpand (C, TRUE);
796   gtk_widget_set_name (C, "C");
797 
798   gtk_box_append (GTK_BOX (A), B);
799   gtk_box_append (GTK_BOX (B), C);
800 
801   gtk_widget_show (A);
802 
803   str = g_string_new ("");
804 
805   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
806   g = add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
807   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
808   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_CLAIMED);
809   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
810   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
811   add_gesture (C, "c3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
812 
813   gtk_widget_get_allocation (B, &allocation);
814   point_update (&mouse_state, A, allocation.x, allocation.y);
815   point_press (&mouse_state, A, 1);
816 
817   g_assert_cmpstr (str->str, ==,
818                    "capture a1, "
819                    "capture b1, "
820                    "capture c1, "
821                    "target c2, "
822                    "c2 state claimed");
823 
824   /* Reset the string */
825   g_string_erase (str, 0, str->len);
826 
827   gtk_gesture_set_state (g, GTK_EVENT_SEQUENCE_CLAIMED);
828 
829   g_assert_cmpstr (str->str, ==,
830                    "c2 cancelled, "
831                    "c1 cancelled, "
832                    "b1 state claimed");
833 
834   point_release (&mouse_state, 1);
835 
836   g_string_free (str, TRUE);
837   gtk_window_destroy (A);
838 }
839 
840 static void
test_group(void)841 test_group (void)
842 {
843   GtkWidget *A, *B, *C;
844   GString *str;
845   GtkGesture *g1, *g2;
846   GtkAllocation allocation;
847 
848   A = gtk_window_new ();
849   gtk_widget_set_name (A, "A");
850   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
851   gtk_widget_set_name (B, "B");
852   C = gtk_image_new ();
853   gtk_widget_set_hexpand (C, TRUE);
854   gtk_widget_set_vexpand (C, TRUE);
855   gtk_widget_set_name (C, "C");
856 
857   gtk_box_append (GTK_BOX (A), B);
858   gtk_box_append (GTK_BOX (B), C);
859 
860   gtk_widget_show (A);
861 
862   str = g_string_new ("");
863 
864   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
865   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
866   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
867   g1 = add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_NONE);
868   g2 = add_gesture (C, "c3", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_CLAIMED);
869   gtk_gesture_group (g1, g2);
870   add_gesture (A, "a3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
871   add_gesture (B, "b3", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
872   add_gesture (C, "c4", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
873 
874   gtk_widget_get_allocation (B, &allocation);
875   point_update (&mouse_state, A, allocation.x, allocation.y);
876   point_press (&mouse_state, A, 1);
877 
878   g_assert_cmpstr (str->str, ==,
879                    "capture a1, "
880                    "capture b1, "
881                    "capture c1, "
882                    "target c3, "
883                    "c3 state claimed, "
884                    "c2 state claimed, "
885                    "target c2");
886 
887   g_string_free (str, TRUE);
888 
889   gtk_window_destroy (A);
890 }
891 
892 static void
test_gestures_outside_grab(void)893 test_gestures_outside_grab (void)
894 {
895   GtkWidget *A, *B, *C, *D;
896   GString *str;
897   GtkAllocation allocation;
898 
899   A = gtk_window_new ();
900   gtk_widget_set_name (A, "A");
901   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
902   gtk_widget_set_name (B, "B");
903   C = gtk_image_new ();
904   gtk_widget_set_hexpand (C, TRUE);
905   gtk_widget_set_vexpand (C, TRUE);
906   gtk_widget_set_name (C, "C");
907 
908   gtk_box_append (GTK_BOX (A), B);
909   gtk_box_append (GTK_BOX (B), C);
910 
911   gtk_widget_show (A);
912 
913   D = gtk_window_new ();
914   gtk_widget_show (D);
915 
916   str = g_string_new ("");
917 
918   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
919   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
920   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
921   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_CLAIMED);
922   add_gesture (B, "b2", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
923   add_gesture (A, "a2", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
924 
925   gtk_widget_get_allocation (B, &allocation);
926   point_update (&mouse_state, A, allocation.x, allocation.y);
927   point_press (&mouse_state, A, 1);
928 
929   g_assert_cmpstr (str->str, ==,
930                    "capture a1, "
931                    "capture b1, "
932                    "capture c1, "
933                    "target c2, "
934                    "c2 state claimed");
935 
936   /* Set a grab on another window */
937   g_string_erase (str, 0, str->len);
938   gtk_grab_add (D);
939 
940   g_assert_cmpstr (str->str, ==,
941                    "c1 cancelled, "
942                    "c2 cancelled, "
943                    "b1 cancelled, "
944                    "a1 cancelled");
945 
946   g_string_free (str, TRUE);
947 
948   gtk_window_destroy (A);
949   gtk_window_destroy (D);
950 }
951 
952 static void
test_gestures_inside_grab(void)953 test_gestures_inside_grab (void)
954 {
955   GtkWidget *A, *B, *C;
956   GString *str;
957   GtkAllocation allocation;
958 
959   A = gtk_window_new ();
960   gtk_widget_set_name (A, "A");
961   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
962   gtk_widget_set_name (B, "B");
963   C = gtk_image_new ();
964   gtk_widget_set_hexpand (C, TRUE);
965   gtk_widget_set_vexpand (C, TRUE);
966   gtk_widget_set_name (C, "C");
967 
968   gtk_box_append (GTK_BOX (A), B);
969   gtk_box_append (GTK_BOX (B), C);
970 
971   gtk_widget_show (A);
972 
973   str = g_string_new ("");
974 
975   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
976   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
977   add_gesture (C, "c1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
978   add_gesture (C, "c2", GTK_PHASE_TARGET, str, GTK_EVENT_SEQUENCE_CLAIMED);
979   add_gesture (B, "b2", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
980   add_gesture (A, "a2", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_NONE);
981 
982   gtk_widget_get_allocation (B, &allocation);
983   point_update (&mouse_state, A, allocation.x, allocation.y);
984   point_press (&mouse_state, A, 1);
985 
986   g_assert_cmpstr (str->str, ==,
987                    "capture a1, "
988                    "capture b1, "
989                    "capture c1, "
990                    "target c2, "
991                    "c2 state claimed");
992 
993   /* Set a grab on B */
994   g_string_erase (str, 0, str->len);
995   gtk_grab_add (B);
996   g_assert_cmpstr (str->str, ==,
997                    "a1 cancelled");
998 
999   /* Update with the grab under effect */
1000   g_string_erase (str, 0, str->len);
1001   point_update (&mouse_state, A, allocation.x, allocation.y);
1002   g_assert_cmpstr (str->str, ==,
1003                    "b1 updated, "
1004                    "c1 updated, "
1005                    "c2 updated");
1006 
1007   g_string_free (str, TRUE);
1008 
1009   gtk_window_destroy (A);
1010 }
1011 
1012 static void
test_multitouch_on_single(void)1013 test_multitouch_on_single (void)
1014 {
1015   GtkWidget *A, *B, *C;
1016   GString *str;
1017   GtkAllocation allocation;
1018 
1019   A = gtk_window_new ();
1020   gtk_widget_set_name (A, "A");
1021   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1022   gtk_widget_set_name (B, "B");
1023   C = gtk_image_new ();
1024   gtk_widget_set_hexpand (C, TRUE);
1025   gtk_widget_set_vexpand (C, TRUE);
1026   gtk_widget_set_name (C, "C");
1027 
1028   gtk_box_append (GTK_BOX (A), B);
1029   gtk_box_append (GTK_BOX (B), C);
1030 
1031   gtk_widget_show (A);
1032 
1033   str = g_string_new ("");
1034 
1035   add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_NONE);
1036   add_gesture (B, "b1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_CLAIMED);
1037 
1038   gtk_widget_get_allocation (B, &allocation);
1039 
1040   /* First touch down */
1041   point_update (&touch_state[0], A, allocation.x, allocation.y);
1042   point_press (&touch_state[0], A, 1);
1043 
1044   g_assert_cmpstr (str->str, ==,
1045                    "capture a1 (1), "
1046                    "capture b1 (1), "
1047                    "b1 state claimed (1)");
1048 
1049   /* Second touch down */
1050   g_string_erase (str, 0, str->len);
1051   point_update (&touch_state[1], A, allocation.x, allocation.y);
1052   point_press (&touch_state[1], A, 1);
1053 
1054   g_assert_cmpstr (str->str, ==,
1055                    "a1 state denied (2), "
1056                    "b1 state denied (2)");
1057 
1058   g_string_free (str, TRUE);
1059 
1060   gtk_window_destroy (A);
1061 }
1062 
1063 static void
test_multitouch_activation(void)1064 test_multitouch_activation (void)
1065 {
1066   GtkWidget *A, *B, *C;
1067   GString *str;
1068   GtkAllocation allocation;
1069 
1070   A = gtk_window_new ();
1071   gtk_widget_set_name (A, "A");
1072   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1073   gtk_widget_set_name (B, "B");
1074   C = gtk_image_new ();
1075   gtk_widget_set_hexpand (C, TRUE);
1076   gtk_widget_set_vexpand (C, TRUE);
1077   gtk_widget_set_name (C, "C");
1078 
1079   gtk_box_append (GTK_BOX (A), B);
1080   gtk_box_append (GTK_BOX (B), C);
1081 
1082   gtk_widget_show (A);
1083 
1084   str = g_string_new ("");
1085 
1086   add_mt_gesture (C, "c1", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_CLAIMED);
1087   gtk_widget_get_allocation (B, &allocation);
1088 
1089   /* First touch down */
1090   point_update (&touch_state[0], A, allocation.x, allocation.y);
1091   point_press (&touch_state[0], A, 1);
1092 
1093   g_assert_cmpstr (str->str, ==, "");
1094 
1095   /* Second touch down */
1096   point_update (&touch_state[1], A, allocation.x, allocation.y);
1097   point_press (&touch_state[1], A, 1);
1098 
1099   g_assert_cmpstr (str->str, ==,
1100                    "c1 began, "
1101                    "c1 state claimed (2), "
1102                    "c1 state claimed (1)");
1103 
1104   /* First touch up */
1105   g_string_erase (str, 0, str->len);
1106   point_release (&touch_state[0], 1);
1107 
1108   g_assert_cmpstr (str->str, ==,
1109                    "c1 ended");
1110 
1111   /* A third touch down triggering again action */
1112   g_string_erase (str, 0, str->len);
1113   point_update (&touch_state[2], A, allocation.x, allocation.y);
1114   point_press (&touch_state[2], A, 1);
1115 
1116   g_assert_cmpstr (str->str, ==,
1117                    "c1 began, "
1118                    "c1 state claimed (3)");
1119 
1120   /* One touch up, gesture is finished again */
1121   g_string_erase (str, 0, str->len);
1122   point_release (&touch_state[2], 1);
1123 
1124   g_assert_cmpstr (str->str, ==,
1125                    "c1 ended");
1126 
1127   /* Another touch up, gesture remains inactive */
1128   g_string_erase (str, 0, str->len);
1129   point_release (&touch_state[1], 1);
1130 
1131   g_assert_cmpstr (str->str, ==, "");
1132 
1133   g_string_free (str, TRUE);
1134 
1135   gtk_window_destroy (A);
1136 }
1137 
1138 static void
test_multitouch_interaction(void)1139 test_multitouch_interaction (void)
1140 {
1141   GtkWidget *A, *B, *C;
1142   GtkGesture *g;
1143   GString *str;
1144   GtkAllocation allocation;
1145 
1146   A = gtk_window_new ();
1147   gtk_widget_set_name (A, "A");
1148   B = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1149   gtk_widget_set_name (B, "B");
1150   C = gtk_image_new ();
1151   gtk_widget_set_hexpand (C, TRUE);
1152   gtk_widget_set_vexpand (C, TRUE);
1153   gtk_widget_set_name (C, "C");
1154 
1155   gtk_box_append (GTK_BOX (A), B);
1156   gtk_box_append (GTK_BOX (B), C);
1157 
1158   gtk_widget_show (A);
1159 
1160   str = g_string_new ("");
1161 
1162   g = add_gesture (A, "a1", GTK_PHASE_CAPTURE, str, GTK_EVENT_SEQUENCE_CLAIMED);
1163   add_mt_gesture (C, "c1", GTK_PHASE_BUBBLE, str, GTK_EVENT_SEQUENCE_CLAIMED);
1164   gtk_widget_get_allocation (B, &allocation);
1165 
1166   /* First touch down, a1 claims the sequence */
1167   point_update (&touch_state[0], A, allocation.x, allocation.y);
1168   point_press (&touch_state[0], A, 1);
1169 
1170   g_assert_cmpstr (str->str, ==,
1171                    "capture a1 (1), "
1172                    "a1 state claimed (1)");
1173 
1174   /* Second touch down, a1 denies and c1 takes over */
1175   g_string_erase (str, 0, str->len);
1176   point_update (&touch_state[1], A, allocation.x, allocation.y);
1177   point_press (&touch_state[1], A, 1);
1178 
1179   /* Denying sequences in touch-excess situation is a responsibility of the caller */
1180   gtk_gesture_set_state (g, GTK_EVENT_SEQUENCE_DENIED);
1181 
1182   g_assert_cmpstr (str->str, ==,
1183                    "a1 state denied (2), "
1184                    "c1 began, "
1185                    "c1 state claimed (1), "
1186                    "c1 state claimed (2), "
1187                    "a1 state denied (1)");
1188 
1189   /* Move first point, only c1 should update */
1190   g_string_erase (str, 0, str->len);
1191   point_update (&touch_state[0], A, allocation.x, allocation.y);
1192 
1193   g_assert_cmpstr (str->str, ==,
1194                    "c1 updated");
1195 
1196   /* First touch up */
1197   g_string_erase (str, 0, str->len);
1198   point_release (&touch_state[0], 1);
1199 
1200   g_assert_cmpstr (str->str, ==,
1201                    "c1 ended");
1202 
1203   /* A third touch down triggering again action on c1 */
1204   g_string_erase (str, 0, str->len);
1205   point_update (&touch_state[2], A, allocation.x, allocation.y);
1206   point_press (&touch_state[2], A, 1);
1207 
1208   g_assert_cmpstr (str->str, ==,
1209                    "a1 state denied (3), "
1210                    "c1 began, "
1211                    "c1 state claimed (3)");
1212 
1213   /* One touch up, gesture is finished again */
1214   g_string_erase (str, 0, str->len);
1215   point_release (&touch_state[2], 1);
1216 
1217   g_assert_cmpstr (str->str, ==,
1218                    "c1 ended");
1219 
1220   /* Another touch up, gesture remains inactive */
1221   g_string_erase (str, 0, str->len);
1222   point_release (&touch_state[1], 1);
1223 
1224   g_assert_cmpstr (str->str, ==, "");
1225 
1226   g_string_free (str, TRUE);
1227 
1228   gtk_window_destroy (A);
1229 }
1230 
1231 int
main(int argc,char * argv[])1232 main (int argc, char *argv[])
1233 {
1234   gtk_test_init (&argc, &argv);
1235 
1236   g_test_add_func ("/gestures/propagation/phases", test_phases);
1237   g_test_add_func ("/gestures/propagation/mixed", test_mixed);
1238   g_test_add_func ("/gestures/propagation/early-exit", test_early_exit);
1239   g_test_add_func ("/gestures/claim/capture", test_claim_capture);
1240   g_test_add_func ("/gestures/claim/target", test_claim_target);
1241   g_test_add_func ("/gestures/claim/bubble", test_claim_bubble);
1242   g_test_add_func ("/gestures/claim/early-capture", test_early_claim_capture);
1243   g_test_add_func ("/gestures/claim/late-capture", test_late_claim_capture);
1244   g_test_add_func ("/gestures/group", test_group);
1245   g_test_add_func ("/gestures/grabs/gestures-outside-grab", test_gestures_outside_grab);
1246   g_test_add_func ("/gestures/grabs/gestures-inside-grab", test_gestures_inside_grab);
1247   g_test_add_func ("/gestures/multitouch/gesture-single", test_multitouch_on_single);
1248   g_test_add_func ("/gestures/multitouch/multitouch-activation", test_multitouch_activation);
1249   g_test_add_func ("/gestures/multitouch/interaction", test_multitouch_interaction);
1250 
1251   return g_test_run ();
1252 }
1253