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
This commit is contained in:
Matthias Clasen 2020-06-08 18:07:40 -04:00
parent 8cb50ac6e9
commit 86eece78b1
3 changed files with 93 additions and 2 deletions

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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);
}
/**