From 0b5cac6433882011a67e190b758a5766d23f97a3 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlos@lanedo.com>
Date: Fri, 2 Nov 2012 17:45:24 +0100
Subject: [PATCH] scrolledwindow: Stop scrolling when a second touch point is
detected
If the scrolled window is receiving touch events, it is likely
that the contained child wants to handle multiple touches, so
if a second touch arrives when scrolling didn't start yet, release
the captured event and give up on the scroll attempt.
---
gtk/gtkscrolledwindow.c | 74 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 62 insertions(+), 12 deletions(-)
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 7929863..050d31d 100644
a
|
b
|
struct _GtkScrolledWindowPrivate |
153 | 153 | |
154 | 154 | /* Kinetic scrolling */ |
155 | 155 | GdkEvent *button_press_event; |
| 156 | GdkEventSequence *sequence; |
156 | 157 | GdkWindow *overshoot_window; |
157 | 158 | GdkDevice *drag_device; |
158 | 159 | guint kinetic_scrolling : 1; |
… |
… |
static void gtk_scrolled_window_size_allocate (GtkWidget *widge |
228 | 229 | GtkAllocation *allocation); |
229 | 230 | static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widget, |
230 | 231 | GdkEventScroll *event); |
| 232 | static gboolean gtk_scrolled_window_check_stop_event_capture (GtkWidget *widget, |
| 233 | GdkEvent *event); |
231 | 234 | static gboolean gtk_scrolled_window_captured_event (GtkWidget *widget, |
232 | 235 | GdkEvent *event); |
233 | 236 | static gboolean gtk_scrolled_window_focus (GtkWidget *widget, |
… |
… |
gtk_scrolled_window_captured_motion_notify (GtkWidget *widget, |
2740 | 2743 | gtk_widget_get_window (widget), |
2741 | 2744 | GDK_OWNERSHIP_WINDOW, |
2742 | 2745 | TRUE, |
2743 | | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK, |
| 2746 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_TOUCH_MASK, |
2744 | 2747 | NULL, |
2745 | 2748 | gdk_event_get_time (event)); |
2746 | 2749 | |
2747 | 2750 | priv->last_button_event_valid = FALSE; |
2748 | 2751 | |
2749 | | if (priv->button_press_event) |
2750 | | { |
2751 | | gdk_event_free (priv->button_press_event); |
2752 | | priv->button_press_event = NULL; |
2753 | | } |
2754 | | |
2755 | 2752 | _gtk_scrolled_window_get_overshoot (scrolled_window, |
2756 | 2753 | &old_overshoot_x, &old_overshoot_y); |
2757 | 2754 | |
… |
… |
gtk_scrolled_window_captured_button_press (GtkWidget *widget, |
2879 | 2876 | return FALSE; |
2880 | 2877 | } |
2881 | 2878 | |
| 2879 | |
| 2880 | static gboolean |
| 2881 | gtk_scrolled_window_check_stop_event_capture (GtkWidget *widget, |
| 2882 | GdkEvent *event) |
| 2883 | { |
| 2884 | GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget); |
| 2885 | GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW (widget)->priv; |
| 2886 | |
| 2887 | if (priv->in_drag) |
| 2888 | return FALSE; |
| 2889 | |
| 2890 | if (priv->drag_device) |
| 2891 | { |
| 2892 | gtk_device_grab_remove (widget, priv->drag_device); |
| 2893 | gdk_device_ungrab (priv->drag_device, |
| 2894 | gtk_get_current_event_time ()); |
| 2895 | priv->drag_device = NULL; |
| 2896 | |
| 2897 | gtk_scrolled_window_release_captured_event (scrolled_window); |
| 2898 | } |
| 2899 | |
| 2900 | priv->in_drag = FALSE; |
| 2901 | priv->sequence = NULL; |
| 2902 | |
| 2903 | return TRUE; |
| 2904 | } |
| 2905 | |
| 2906 | |
2882 | 2907 | static gboolean |
2883 | 2908 | gtk_scrolled_window_captured_event (GtkWidget *widget, |
2884 | 2909 | GdkEvent *event) |
2885 | 2910 | { |
2886 | 2911 | gboolean retval = FALSE; |
2887 | 2912 | GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW (widget)->priv; |
| 2913 | GdkEventSequence *sequence; |
2888 | 2914 | |
2889 | 2915 | if (gdk_window_get_window_type (event->any.window) == GDK_WINDOW_TEMP) |
2890 | 2916 | return FALSE; |
2891 | 2917 | |
| 2918 | sequence = gdk_event_get_event_sequence (event); |
| 2919 | |
2892 | 2920 | switch (event->type) |
2893 | 2921 | { |
2894 | 2922 | case GDK_TOUCH_BEGIN: |
2895 | 2923 | case GDK_BUTTON_PRESS: |
2896 | | retval = gtk_scrolled_window_captured_button_press (widget, event); |
| 2924 | /* Let children handle multiple touches. If scrolling didn't start yet, |
| 2925 | * and a second touch arrives, give up on scrolling and release the event. |
| 2926 | */ |
| 2927 | if (event->type == GDK_TOUCH_BEGIN && priv->sequence != sequence && |
| 2928 | gtk_scrolled_window_check_stop_event_capture (widget, event)) |
| 2929 | retval = TRUE; |
| 2930 | else if (priv->sequence == sequence) |
| 2931 | { |
| 2932 | retval = gtk_scrolled_window_captured_button_press (widget, event); |
| 2933 | |
| 2934 | if (!priv->sequence) |
| 2935 | priv->sequence = sequence; |
| 2936 | } |
2897 | 2937 | break; |
2898 | 2938 | case GDK_TOUCH_END: |
2899 | 2939 | case GDK_BUTTON_RELEASE: |
2900 | | if (priv->drag_device) |
2901 | | retval = gtk_scrolled_window_captured_button_release (widget, event); |
| 2940 | if (priv->drag_device && priv->sequence == sequence) |
| 2941 | { |
| 2942 | retval = gtk_scrolled_window_captured_button_release (widget, event); |
| 2943 | priv->sequence = NULL; |
| 2944 | } |
2902 | 2945 | else |
2903 | | priv->last_button_event_valid = FALSE; |
| 2946 | { |
| 2947 | priv->last_button_event_valid = FALSE; |
| 2948 | |
| 2949 | if (priv->drag_device) |
| 2950 | retval = TRUE; |
| 2951 | } |
2904 | 2952 | break; |
2905 | 2953 | case GDK_TOUCH_UPDATE: |
2906 | 2954 | case GDK_MOTION_NOTIFY: |
2907 | | if (priv->drag_device) |
| 2955 | if (priv->drag_device && priv->sequence == sequence) |
2908 | 2956 | retval = gtk_scrolled_window_captured_motion_notify (widget, event); |
| 2957 | else |
| 2958 | retval = TRUE; |
2909 | 2959 | break; |
2910 | 2960 | case GDK_LEAVE_NOTIFY: |
2911 | 2961 | case GDK_ENTER_NOTIFY: |