From 48aa1bb08f89a1f3f8f290da771f183cdd5061d8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 21 Oct 2015 10:14:40 +1000 Subject: [PATCH] wayland: add gdk_event_is_scroll_stop_event() And use it to handle kinetic scrolling in the GtkScrolledWindow. However, dropping the delta check causes the X11-based kinetic scroll to break since we don't have the stop event here. Correct handling of xf86-input-libinput-based scroll events is still being discussed. https://bugzilla.gnome.org/show_bug.cgi?id=756729 --- docs/reference/gdk/gdk3-sections.txt | 1 + gdk/gdkevents.c | 23 +++++++++++++++++++++++ gdk/gdkevents.h | 4 ++++ gdk/gdkwindow.c | 1 + gdk/wayland/gdkdevice-wayland.c | 21 +++++++++++++++++++-- gtk/gtkscrolledwindow.c | 2 +- 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt index 7b1b9f7419..cfcce263ec 100644 --- a/docs/reference/gdk/gdk3-sections.txt +++ b/docs/reference/gdk/gdk3-sections.txt @@ -859,6 +859,7 @@ gdk_event_get_keyval gdk_event_get_root_coords gdk_event_get_scroll_direction gdk_event_get_scroll_deltas +gdk_event_is_scroll_stop_event gdk_event_get_state gdk_event_get_time gdk_event_get_window diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 9ed43176aa..83f8ab11f2 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -562,6 +562,7 @@ gdk_event_new (GdkEventType type) new_event->scroll.y_root = 0.; new_event->scroll.delta_x = 0.; new_event->scroll.delta_y = 0.; + new_event->scroll.is_stop = FALSE; break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: @@ -1418,6 +1419,28 @@ gdk_event_get_scroll_deltas (const GdkEvent *event, return fetched; } +/** + * gdk_event_is_scroll_stop_event + * @event: a #GdkEvent + * + * Check whether a scroll event is a stop scroll event. Scroll sequences + * with smooth scroll information may provide a stop scroll event once the + * interaction with the device finishes, e.g. by lifting a finger. This + * stop scroll event is the signal that a widget may trigger kinetic + * scrolling based on the current velocity. + * + * Stop scroll events always have a a delta of 0/0. + * + * Returns: %TRUE if the event is a scroll stop event + * + * Since: 3.20 + */ +gboolean +gdk_event_is_scroll_stop_event (const GdkEvent *event) +{ + return event->scroll.is_stop; +} + /** * gdk_event_get_axis: * @event: a #GdkEvent diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index ca019b7b9d..a502b2743f 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -824,6 +824,7 @@ struct _GdkEventScroll gdouble x_root, y_root; gdouble delta_x; gdouble delta_y; + guint is_stop : 1; }; /** @@ -1377,6 +1378,9 @@ gboolean gdk_event_get_scroll_deltas (const GdkEvent *event, gdouble *delta_x, gdouble *delta_y); +GDK_AVAILABLE_IN_3_20 +gboolean gdk_event_is_scroll_stop_event (const GdkEvent *event); + GDK_AVAILABLE_IN_ALL gboolean gdk_event_get_axis (const GdkEvent *event, GdkAxisUse axis_use, diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 57ffa641e1..6995db9eef 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -9328,6 +9328,7 @@ proxy_button_event (GdkEvent *source_event, event->scroll.device = source_event->scroll.device; event->scroll.delta_x = source_event->scroll.delta_x; event->scroll.delta_y = source_event->scroll.delta_y; + event->scroll.is_stop = source_event->scroll.is_stop; gdk_event_set_source_device (event, source_device); return TRUE; diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 50d07bd7f4..1afb9b001d 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -62,6 +62,7 @@ struct _GdkWaylandPointerFrameData /* Specific to the scroll event */ gdouble delta_x, delta_y; int32_t discrete_x, discrete_y; + gint8 is_scroll_stop; }; struct _GdkWaylandSeat @@ -972,7 +973,8 @@ flush_discrete_scroll_event (GdkWaylandSeat *seat, static void flush_smooth_scroll_event (GdkWaylandSeat *seat, gdouble delta_x, - gdouble delta_y) + gdouble delta_y, + gboolean is_stop) { GdkEvent *event; @@ -980,6 +982,7 @@ flush_smooth_scroll_event (GdkWaylandSeat *seat, event->scroll.direction = GDK_SCROLL_SMOOTH; event->scroll.delta_x = delta_x; event->scroll.delta_y = delta_y; + event->scroll.is_stop = is_stop; _gdk_wayland_display_deliver_event (seat->display, event); } @@ -988,6 +991,8 @@ static void flush_scroll_event (GdkWaylandSeat *seat, GdkWaylandPointerFrameData *pointer_frame) { + gboolean is_stop = FALSE; + if (pointer_frame->discrete_x || pointer_frame->discrete_y) { GdkScrollDirection direction; @@ -1004,14 +1009,24 @@ flush_scroll_event (GdkWaylandSeat *seat, flush_discrete_scroll_event (seat, direction); } + /* Axes can stop independently, if we stop on one axis but have a + * delta on the other, we don't count it as a stop event. + */ + if (pointer_frame->is_scroll_stop && + pointer_frame->delta_x == 0 && + pointer_frame->delta_y == 0) + is_stop = TRUE; + flush_smooth_scroll_event (seat, pointer_frame->delta_x, - pointer_frame->delta_y); + pointer_frame->delta_y, + is_stop); pointer_frame->delta_x = 0; pointer_frame->delta_y = 0; pointer_frame->discrete_x = 0; pointer_frame->discrete_y = 0; + pointer_frame->is_scroll_stop = FALSE; } static void @@ -1369,6 +1384,8 @@ pointer_handle_axis_stop (void *data, g_return_if_reached (); } + pointer_frame->is_scroll_stop = TRUE; + GDK_NOTE (EVENTS, g_message ("axis stop, seat %p", seat)); } diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index b27028cc44..0df1a62134 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -3321,7 +3321,7 @@ gtk_scrolled_window_scroll_event (GtkWidget *widget, * after scrolling finished, start kinetic scrolling when this * happens. */ - if (delta_y == 0 && delta_x == 0) + if (gdk_event_is_scroll_stop_event ((GdkEvent *) event)) { handled = TRUE; start_deceleration = TRUE;