diff options
author | Owen W. Taylor <otaylor@fishsoup.net> | 2012-09-26 10:28:06 -0400 |
---|---|---|
committer | Owen W. Taylor <otaylor@fishsoup.net> | 2013-02-14 17:19:49 -0500 |
commit | a69285da08a2a61d5fd817ee8ccb88a6b6deaef6 (patch) | |
tree | c4fdef3922ea6eca4d1e16ef320b3a6760cbe09b /gdk/gdkevents.c | |
parent | 05386b44e04bc23e6cd68b74dd9047b874a2020b (diff) | |
download | gtk+-a69285da08a2a61d5fd817ee8ccb88a6b6deaef6.tar.gz |
Compress motion synchronized with the paint cycle
When we have pending motion events, instead of delivering them
directly, request the new FLUSH_EVENTS phase of the frame clock.
This allows us to compress repeated motion events sent to the
same window.
In the FLUSH_EVENTS phase, which occur at priority GDK_PRIORITY_EVENTS + 1,
we deliver any pending motion events then turn off event delivery
until the end of the next frame. Turning off event delivery means
that we'll reliably paint the compressed motion events even if more
have arrived.
Add a motion-compression test case which demonstrates behavior when
an application takes too long handle motion events. It is unusable
without this patch but behaves fine with the patch.
https://bugzilla.gnome.org/show_bug.cgi?id=685460
Diffstat (limited to 'gdk/gdkevents.c')
-rw-r--r-- | gdk/gdkevents.c | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 204863c4bf..d068e13c2b 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -85,13 +85,27 @@ _gdk_event_emit (GdkEvent *event) GList* _gdk_event_queue_find_first (GdkDisplay *display) { - GList *tmp_list = display->queued_events; + GList *tmp_list; + GList *pending_motion = NULL; + + if (display->events_paused) + return NULL; + tmp_list = display->queued_events; while (tmp_list) { GdkEventPrivate *event = tmp_list->data; - if (!(event->flags & GDK_EVENT_PENDING)) - return tmp_list; + + if (event->flags & GDK_EVENT_PENDING) + continue; + + if (pending_motion) + return pending_motion; + + if (event->event.type == GDK_MOTION_NOTIFY && !display->flushing_events) + pending_motion = tmp_list; + else + return tmp_list; tmp_list = g_list_next (tmp_list); } @@ -248,6 +262,55 @@ _gdk_event_unqueue (GdkDisplay *display) return event; } +void +_gdk_event_queue_handle_motion_compression (GdkDisplay *display) +{ + GList *tmp_list; + GList *pending_motions = NULL; + GdkWindow *pending_motion_window = NULL; + + /* If the last N events in the event queue are motion notify + * events for the same window, drop all but the last */ + + tmp_list = display->queued_tail; + + while (tmp_list) + { + GdkEventPrivate *event = tmp_list->data; + + if (event->flags & GDK_EVENT_PENDING) + break; + + if (event->event.type != GDK_MOTION_NOTIFY) + break; + + if (pending_motion_window != NULL && + pending_motion_window != event->event.motion.window) + break; + + pending_motion_window = event->event.motion.window; + pending_motions = tmp_list; + + tmp_list = tmp_list->prev; + } + + while (pending_motions && pending_motions->next != NULL) + { + GList *next = pending_motions->next; + display->queued_events = g_list_delete_link (display->queued_events, + pending_motions); + pending_motions = next; + } + + if (pending_motions && + pending_motions == display->queued_events && + pending_motions == display->queued_tail) + { + GdkFrameClock *clock = gdk_window_get_frame_clock (pending_motion_window); + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS); + } +} + /** * gdk_event_handler_set: * @func: the function to call to handle events from GDK. |