From 86eece78b16e40dec6aca5a3b20d9e6eb648ad3c Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 8 Jun 2020 18:07:40 -0400 Subject: [PATCH] gdk: Compress scroll events Only return one accumulated scroll event per frame. Compress them by adding up the deltas. Still missing: a way to capture history, like we do for motion events. Fixes: #2800 --- gdk/gdkevents.c | 93 +++++++++++++++++++++++++++++++++++++++++++++- gdk/gdkinternals.h | 1 + gdk/gdksurface.c | 1 + 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index e1a58006cb..1b20a57dac 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -619,6 +619,96 @@ _gdk_event_unqueue (GdkDisplay *display) return event; } +/* + * If the last N events in the event queue are smooth scroll events + * for the same surface and device, combine them into one. + */ +void +gdk_event_queue_handle_scroll_compression (GdkDisplay *display) +{ + GList *l; + GdkSurface *surface = NULL; + GdkDevice *device = NULL; + GdkEvent *last_event = NULL; + GList *scrolls = NULL; + double delta_x, delta_y; + double dx, dy; + + delta_x = delta_y = 0; + + l = g_queue_peek_tail_link (&display->queued_events); + + while (l) + { + GdkEvent *event = l->data; + + if (event->flags & GDK_EVENT_PENDING) + break; + + if (event->event_type != GDK_SCROLL || + gdk_scroll_event_get_direction (event) != GDK_SCROLL_SMOOTH) + break; + + if (surface != NULL && + surface != event->surface) + break; + + if (device != NULL && + device != event->device) + break; + + if (!last_event) + last_event = event; + + surface = event->surface; + device = event->device; + scrolls = l; + + gdk_scroll_event_get_deltas (event, &dx, &dy); + delta_x += dx; + delta_y += dy; + + l = l->prev; + } + + while (scrolls && scrolls->next != NULL) + { + GList *next = scrolls->next; + + gdk_event_unref (scrolls->data); + g_queue_delete_link (&display->queued_events, scrolls); + scrolls = next; + } + + if (scrolls) + { + GdkEvent *old_event, *event; + + old_event = scrolls->data; + + event = gdk_scroll_event_new (surface, + device, + gdk_event_get_source_device (old_event), + gdk_event_get_device_tool (old_event), + gdk_event_get_time (old_event), + gdk_event_get_modifier_state (old_event), + delta_x, + delta_y, + gdk_scroll_event_is_stop (old_event)); + + g_queue_delete_link (&display->queued_events, scrolls); + g_queue_push_tail (&display->queued_events, event); + } + + if (g_queue_get_length (&display->queued_events) == 1 && + g_queue_peek_head_link (&display->queued_events) == scrolls) + { + GdkFrameClock *clock = gdk_surface_get_frame_clock (surface); + if (clock) /* might be NULL if surface was destroyed */ + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS); + } +} + static void gdk_motion_event_push_history (GdkEvent *event, GdkEvent *history_event) @@ -641,7 +731,6 @@ gdk_motion_event_push_history (GdkEvent *event, self->history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord)); g_array_append_val (self->history, hist); - } void @@ -710,7 +799,7 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display) { GdkFrameClock *clock = gdk_surface_get_frame_clock (pending_motion_surface); if (clock) /* might be NULL if surface was destroyed */ - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS); + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS); } } diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index e30872edc6..b26aac73eb 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -123,6 +123,7 @@ GList* _gdk_event_queue_append (GdkDisplay *display, GdkEvent *event); void _gdk_event_queue_handle_motion_compression (GdkDisplay *display); +void gdk_event_queue_handle_scroll_compression (GdkDisplay *display); void _gdk_event_queue_flush (GdkDisplay *display); gboolean _gdk_cairo_surface_extents (cairo_surface_t *surface, diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 1c5aeb180a..9e5946794d 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -2366,6 +2366,7 @@ _gdk_windowing_got_event (GdkDisplay *display, * candidate it queues up flushing the event queue. */ _gdk_event_queue_handle_motion_compression (display); + gdk_event_queue_handle_scroll_compression (display); } /**