Commit a69285da authored by Owen W. Taylor's avatar Owen W. Taylor

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
parent 05386b44
...@@ -308,7 +308,11 @@ gdk_display_get_event (GdkDisplay *display) ...@@ -308,7 +308,11 @@ gdk_display_get_event (GdkDisplay *display)
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
GDK_DISPLAY_GET_CLASS (display)->queue_events (display); GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
return _gdk_event_unqueue (display);
if (display->events_paused)
return NULL;
else
return _gdk_event_unqueue (display);
} }
/** /**
...@@ -2003,6 +2007,31 @@ gdk_display_notify_startup_complete (GdkDisplay *display, ...@@ -2003,6 +2007,31 @@ gdk_display_notify_startup_complete (GdkDisplay *display,
GDK_DISPLAY_GET_CLASS (display)->notify_startup_complete (display, startup_id); GDK_DISPLAY_GET_CLASS (display)->notify_startup_complete (display, startup_id);
} }
void
_gdk_display_set_events_paused (GdkDisplay *display,
gboolean events_paused)
{
display->events_paused = !!events_paused;
}
void
_gdk_display_flush_events (GdkDisplay *display)
{
display->flushing_events = TRUE;
while (TRUE)
{
GdkEvent *event = _gdk_event_unqueue (display);
if (event == NULL)
break;
_gdk_event_emit (event);
gdk_event_free (event);
}
display->flushing_events = FALSE;
}
void void
_gdk_display_event_data_copy (GdkDisplay *display, _gdk_display_event_data_copy (GdkDisplay *display,
const GdkEvent *event, const GdkEvent *event,
......
...@@ -114,6 +114,8 @@ struct _GdkDisplay ...@@ -114,6 +114,8 @@ struct _GdkDisplay
GdkDevice *core_pointer; /* Core pointer device */ GdkDevice *core_pointer; /* Core pointer device */
guint closed : 1; /* Whether this display has been closed */ guint closed : 1; /* Whether this display has been closed */
guint events_paused : 1; /* Whether events are blocked */
guint flushing_events : 1; /* Inside gdk_display_flush_events */
GArray *touch_implicit_grabs; GArray *touch_implicit_grabs;
GHashTable *device_grabs; GHashTable *device_grabs;
...@@ -296,6 +298,9 @@ void _gdk_display_pointer_info_foreach (GdkDisplay *display ...@@ -296,6 +298,9 @@ void _gdk_display_pointer_info_foreach (GdkDisplay *display
GdkDisplayPointerInfoForeach func, GdkDisplayPointerInfoForeach func,
gpointer user_data); gpointer user_data);
gulong _gdk_display_get_next_serial (GdkDisplay *display); gulong _gdk_display_get_next_serial (GdkDisplay *display);
void _gdk_display_set_events_paused (GdkDisplay *display,
gboolean events_paused);
void _gdk_display_flush_events (GdkDisplay *display);
void _gdk_display_event_data_copy (GdkDisplay *display, void _gdk_display_event_data_copy (GdkDisplay *display,
const GdkEvent *event, const GdkEvent *event,
GdkEvent *new_event); GdkEvent *new_event);
......
...@@ -85,13 +85,27 @@ _gdk_event_emit (GdkEvent *event) ...@@ -85,13 +85,27 @@ _gdk_event_emit (GdkEvent *event)
GList* GList*
_gdk_event_queue_find_first (GdkDisplay *display) _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) while (tmp_list)
{ {
GdkEventPrivate *event = tmp_list->data; 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); tmp_list = g_list_next (tmp_list);
} }
...@@ -248,6 +262,55 @@ _gdk_event_unqueue (GdkDisplay *display) ...@@ -248,6 +262,55 @@ _gdk_event_unqueue (GdkDisplay *display)
return event; 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: * gdk_event_handler_set:
* @func: the function to call to handle events from GDK. * @func: the function to call to handle events from GDK.
......
...@@ -91,11 +91,13 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT) ...@@ -91,11 +91,13 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
enum { enum {
FRAME_REQUESTED, FRAME_REQUESTED,
FLUSH_EVENTS,
BEFORE_PAINT, BEFORE_PAINT,
UPDATE, UPDATE,
LAYOUT, LAYOUT,
PAINT, PAINT,
AFTER_PAINT, AFTER_PAINT,
RESUME_EVENTS,
LAST_SIGNAL LAST_SIGNAL
}; };
...@@ -120,6 +122,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface) ...@@ -120,6 +122,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
/**
* GdkFrameClock::flush-events:
* @clock: the frame clock emitting the signal
*
* FIXME.
*/
signals[FLUSH_EVENTS] =
g_signal_new (g_intern_static_string ("flush-events"),
GDK_TYPE_FRAME_CLOCK,
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/** /**
* GdkFrameClock::before-paint: * GdkFrameClock::before-paint:
* @clock: the frame clock emitting the signal * @clock: the frame clock emitting the signal
...@@ -202,6 +219,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface) ...@@ -202,6 +219,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
NULL, NULL, NULL, NULL,
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
/**
* GdkFrameClock::resume-events:
* @clock: the frame clock emitting the signal
*
* FIXME.
*/
signals[RESUME_EVENTS] =
g_signal_new (g_intern_static_string ("resume-events"),
GDK_TYPE_FRAME_CLOCK,
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
} }
/** /**
......
...@@ -64,12 +64,14 @@ void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target, ...@@ -64,12 +64,14 @@ void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target,
#define GDK_FRAME_CLOCK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK, GdkFrameClockInterface)) #define GDK_FRAME_CLOCK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK, GdkFrameClockInterface))
typedef enum { typedef enum {
GDK_FRAME_CLOCK_PHASE_NONE = 0, GDK_FRAME_CLOCK_PHASE_NONE = 0,
GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 0, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS = 1 << 0,
GDK_FRAME_CLOCK_PHASE_UPDATE = 1 << 1, GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 1,
GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 2, GDK_FRAME_CLOCK_PHASE_UPDATE = 1 << 2,
GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 3, GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 3,
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 4 GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 4,
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 5,
GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS = 1 << 6
} GdkFrameClockPhase; } GdkFrameClockPhase;
struct _GdkFrameClockInterface struct _GdkFrameClockInterface
...@@ -87,11 +89,13 @@ struct _GdkFrameClockInterface ...@@ -87,11 +89,13 @@ struct _GdkFrameClockInterface
/* signals */ /* signals */
/* void (* frame_requested) (GdkFrameClock *clock); */ /* void (* frame_requested) (GdkFrameClock *clock); */
/* void (* flush_events) (GdkFrameClock *clock); */
/* void (* before_paint) (GdkFrameClock *clock); */ /* void (* before_paint) (GdkFrameClock *clock); */
/* void (* update) (GdkFrameClock *clock); */ /* void (* update) (GdkFrameClock *clock); */
/* void (* layout) (GdkFrameClock *clock); */ /* void (* layout) (GdkFrameClock *clock); */
/* void (* paint) (GdkFrameClock *clock); */ /* void (* paint) (GdkFrameClock *clock); */
/* void (* after_paint) (GdkFrameClock *clock); */ /* void (* after_paint) (GdkFrameClock *clock); */
/* void (* resume_events) (GdkFrameClock *clock); */
}; };
GType gdk_frame_clock_get_type (void) G_GNUC_CONST; GType gdk_frame_clock_get_type (void) G_GNUC_CONST;
......
...@@ -39,13 +39,15 @@ struct _GdkFrameClockIdlePrivate ...@@ -39,13 +39,15 @@ struct _GdkFrameClockIdlePrivate
guint64 frame_time; guint64 frame_time;
guint64 min_next_frame_time; guint64 min_next_frame_time;
guint idle_id; guint flush_idle_id;
guint paint_idle_id;
guint freeze_count; guint freeze_count;
GdkFrameClockPhase requested; GdkFrameClockPhase requested;
GdkFrameClockPhase phase; GdkFrameClockPhase phase;
}; };
static gboolean gdk_frame_clock_flush_idle (void *data);
static gboolean gdk_frame_clock_paint_idle (void *data); static gboolean gdk_frame_clock_paint_idle (void *data);
static void gdk_frame_clock_idle_finalize (GObject *object); static void gdk_frame_clock_idle_finalize (GObject *object);
...@@ -144,7 +146,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) ...@@ -144,7 +146,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
{ {
GdkFrameClockIdlePrivate *priv = clock_idle->priv; GdkFrameClockIdlePrivate *priv = clock_idle->priv;
if (priv->idle_id == 0 && priv->freeze_count == 0 && priv->requested != 0) if (priv->freeze_count == 0)
{ {
guint min_interval = 0; guint min_interval = 0;
...@@ -155,41 +157,89 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) ...@@ -155,41 +157,89 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
min_interval = (min_interval_us + 500) / 1000; min_interval = (min_interval_us + 500) / 1000;
} }
priv->idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_REDRAW, if (priv->flush_idle_id == 0 &&
min_interval, (priv->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0)
gdk_frame_clock_paint_idle, {
g_object_ref (clock_idle), priv->flush_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS + 1,
(GDestroyNotify) g_object_unref); min_interval,
gdk_frame_clock_flush_idle,
g_object_ref (clock_idle),
(GDestroyNotify) g_object_unref);
}
if (priv->paint_idle_id == 0 &&
(priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0)
{
priv->paint_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_REDRAW,
min_interval,
gdk_frame_clock_paint_idle,
g_object_ref (clock_idle),
(GDestroyNotify) g_object_unref);
gdk_frame_clock_frame_requested (GDK_FRAME_CLOCK (clock_idle)); gdk_frame_clock_frame_requested (GDK_FRAME_CLOCK (clock_idle));
}
} }
} }
static gboolean
gdk_frame_clock_flush_idle (void *data)
{
GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
priv->flush_idle_id = 0;
if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE)
return FALSE;
priv->phase = GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS;
g_signal_emit_by_name (G_OBJECT (clock), "flush-events");
if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0)
priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
else
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
return FALSE;
}
static gboolean static gboolean
gdk_frame_clock_paint_idle (void *data) gdk_frame_clock_paint_idle (void *data)
{ {
GdkFrameClock *clock = GDK_FRAME_CLOCK (data); GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
GdkFrameClockIdlePrivate *priv = clock_idle->priv; GdkFrameClockIdlePrivate *priv = clock_idle->priv;
gboolean skip_to_resume_events;
priv->idle_id = 0; priv->paint_idle_id = 0;
skip_to_resume_events =
(priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0;
switch (priv->phase) switch (priv->phase)
{ {
case GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS:
break;
case GDK_FRAME_CLOCK_PHASE_NONE: case GDK_FRAME_CLOCK_PHASE_NONE:
case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT: case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
if (priv->freeze_count == 0) if (priv->freeze_count == 0)
{ {
priv->frame_time = compute_frame_time (clock_idle); priv->frame_time = compute_frame_time (clock_idle);
priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; /* We always emit ::before-paint and ::after-paint if
/* We always emit ::before-paint and ::after-paint even if * any of the intermediate phases are requested and
* not explicitly requested, and unlike other phases,
* they don't get repeated if you freeze/thaw while * they don't get repeated if you freeze/thaw while
* in them. */ * in them. */
g_signal_emit_by_name (G_OBJECT (clock), "before-paint"); if (!skip_to_resume_events)
priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE; {
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
}
priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE;
} }
case GDK_FRAME_CLOCK_PHASE_UPDATE: case GDK_FRAME_CLOCK_PHASE_UPDATE:
if (priv->freeze_count == 0) if (priv->freeze_count == 0)
...@@ -224,9 +274,24 @@ gdk_frame_clock_paint_idle (void *data) ...@@ -224,9 +274,24 @@ gdk_frame_clock_paint_idle (void *data)
if (priv->freeze_count == 0) if (priv->freeze_count == 0)
{ {
priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT; priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT; if (!skip_to_resume_events)
g_signal_emit_by_name (G_OBJECT (clock), "after-paint"); {
/* the ::after-paint phase doesn't get repeated on freeze/thaw */ priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
}
/* the ::after-paint phase doesn't get repeated on freeze/thaw,
*/
priv->phase = GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS;
}
case GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS:
if (priv->freeze_count == 0)
{
if (priv->requested & GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)
{
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS;
g_signal_emit_by_name (G_OBJECT (clock), "resume-events");
}
/* the ::resume-event phase doesn't get repeated on freeze/thaw */
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
} }
} }
...@@ -276,10 +341,15 @@ gdk_frame_clock_idle_freeze (GdkFrameClock *clock) ...@@ -276,10 +341,15 @@ gdk_frame_clock_idle_freeze (GdkFrameClock *clock)
if (priv->freeze_count == 1) if (priv->freeze_count == 1)
{ {
if (priv->idle_id) if (priv->flush_idle_id)
{ {
g_source_remove (priv->idle_id); g_source_remove (priv->flush_idle_id);
priv->idle_id = 0; priv->flush_idle_id = 0;
}
if (priv->paint_idle_id)
{
g_source_remove (priv->paint_idle_id);
priv->paint_idle_id = 0;
} }
} }
} }
...@@ -294,7 +364,14 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock) ...@@ -294,7 +364,14 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
priv->freeze_count--; priv->freeze_count--;
if (priv->freeze_count == 0) if (priv->freeze_count == 0)
maybe_start_idle (clock_idle); {
maybe_start_idle (clock_idle);
/* If nothing is requested so we didn't start an idle, we need
* to skip to the end of the state chain, since the idle won't
* run and do it for us. */
if (priv->paint_idle_id == 0)
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
}
} }
static void static void
......
...@@ -300,6 +300,9 @@ GList* _gdk_event_queue_insert_after (GdkDisplay *display, ...@@ -300,6 +300,9 @@ GList* _gdk_event_queue_insert_after (GdkDisplay *display,
GList* _gdk_event_queue_insert_before(GdkDisplay *display, GList* _gdk_event_queue_insert_before(GdkDisplay *display,
GdkEvent *after_event, GdkEvent *after_event,
GdkEvent *event); GdkEvent *event);
void _gdk_event_queue_handle_motion_compression (GdkDisplay *display);
void _gdk_event_button_generate (GdkDisplay *display, void _gdk_event_button_generate (GdkDisplay *display,
GdkEvent *event); GdkEvent *event);
......
...@@ -10038,7 +10038,7 @@ _gdk_windowing_got_event (GdkDisplay *display, ...@@ -10038,7 +10038,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
{ {
GdkWindow *event_window; GdkWindow *event_window;
gdouble x, y; gdouble x, y;
gboolean unlink_event; gboolean unlink_event = FALSE;
GdkDeviceGrabInfo *button_release_grab; GdkDeviceGrabInfo *button_release_grab;
GdkPointerWindowInfo *pointer_info = NULL; GdkPointerWindowInfo *pointer_info = NULL;
GdkDevice *device, *source_device; GdkDevice *device, *source_device;
...@@ -10081,7 +10081,7 @@ _gdk_windowing_got_event (GdkDisplay *display, ...@@ -10081,7 +10081,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
event_window = event->any.window; event_window = event->any.window;
if (!event_window) if (!event_window)
return; goto out;
#ifdef DEBUG_WINDOW_PRINTING #ifdef DEBUG_WINDOW_PRINTING
if (event->type == GDK_KEY_PRESS && if (event->type == GDK_KEY_PRESS &&
...@@ -10096,13 +10096,13 @@ _gdk_windowing_got_event (GdkDisplay *display, ...@@ -10096,13 +10096,13 @@ _gdk_windowing_got_event (GdkDisplay *display,
{ {
event_window->native_visibility = event->visibility.state; event_window->native_visibility = event->visibility.state;
gdk_window_update_visibility_recursively (event_window, event_window); gdk_window_update_visibility_recursively (event_window, event_window);
return; goto out;
} }
if (!(is_button_type (event->type) || if (!(is_button_type (event->type) ||
is_motion_type (event->type)) || is_motion_type (event->type)) ||
event_window->window_type == GDK_WINDOW_ROOT) event_window->window_type == GDK_WINDOW_ROOT)
return; goto out;
is_toplevel = gdk_window_is_toplevel (event_window); is_toplevel = gdk_window_is_toplevel (event_window);
...@@ -10195,7 +10195,6 @@ _gdk_windowing_got_event (GdkDisplay *display, ...@@ -10195,7 +10195,6 @@ _gdk_windowing_got_event (GdkDisplay *display,
_gdk_display_enable_motion_hints (display, device); _gdk_display_enable_motion_hints (display, device);
} }
unlink_event = FALSE;
if (is_motion_type (event->type)) if (is_motion_type (event->type))
unlink_event = proxy_pointer_event (display, event, serial); unlink_event = proxy_pointer_event (display, event, serial);
else if (is_button_type (event->type)) else if (is_button_type (event->type))
...@@ -10237,6 +10236,13 @@ _gdk_windowing_got_event (GdkDisplay *display, ...@@ -10237,6 +10236,13 @@ _gdk_windowing_got_event (GdkDisplay *display,
g_list_free_1 (event_link); g_list_free_1 (event_link);
gdk_event_free (event); gdk_event_free (event);
} }
/* This does two things - first it sees if there are motions at the
* end of the queue that can be compressed. Second, if there is just
* a single motion that won't be dispatched because it is a compression
* candidate it queues up flushing the event queue.
*/
_gdk_event_queue_handle_motion_compression (display);
} }
/** /**
...@@ -11603,6 +11609,22 @@ gdk_property_delete (GdkWindow *window, ...@@ -11603,6 +11609,22 @@ gdk_property_delete (GdkWindow *window,
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property); GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property);
} }
static void
gdk_window_flush_events (GdkFrameClock *clock,
void *data)
{
GdkWindow *window;
GdkDisplay *display;
window = GDK_WINDOW (data);
display = gdk_window_get_display (window);
_gdk_display_flush_events (display);
_gdk_display_set_events_paused (display, TRUE);
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
}
static void static void
gdk_window_paint_on_clock (GdkFrameClock *clock, gdk_window_paint_on_clock (GdkFrameClock *clock,
void *data) void *data)
...@@ -11616,6 +11638,19 @@ gdk_window_paint_on_clock (GdkFrameClock *clock, ...@@ -11616,6 +11638,19 @@ gdk_window_paint_on_clock (GdkFrameClock *clock,
gdk_window_process_updates_with_mode (window, PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN); gdk_window_process_updates_with_mode (window, PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN);
} }
static void
gdk_window_resume_events (GdkFrameClock *clock,
void *data)
{
GdkWindow *window;
GdkDisplay *display;
window = GDK_WINDOW (data);
display = gdk_window_get_display (window);
_gdk_display_set_events_paused (display, FALSE);
}
/** /**
* gdk_window_set_frame_clock: * gdk_window_set_frame_clock:
* @window: window to set frame clock on * @window: window to set frame clock on
...@@ -11651,17 +11686,31 @@ gdk_window_set_frame_clock (GdkWindow *window, ...@@ -11651,17 +11686,31 @@ gdk_window_set_frame_clock (GdkWindow *window,
if (clock) if (clock)
{ {
g_object_ref (clock); g_object_ref (clock);
g_signal_connect (G_OBJECT (clock),
"flush-events",
G_CALLBACK (gdk_window_flush_events),
window);
g_signal_connect (G_OBJECT (clock), g_signal_connect (G_OBJECT (clock),
"paint", "paint",
G_CALLBACK (gdk_window_paint_on_clock), G_CALLBACK (gdk_window_paint_on_clock),
window); window);
g_signal_connect (G_OBJECT (clock),
"resume-events",
G_CALLBACK (gdk_window_resume_events),
window);
} }
if (window->frame_clock) if (window->frame_clock)
{ {
g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
G_CALLBACK (gdk_window_flush_events),
window);
g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock), g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
G_CALLBACK (gdk_window_paint_on_clock), G_CALLBACK (gdk_window_paint_on_clock),
window); window);
g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
G_CALLBACK (gdk_window_resume_events),
window);
g_object_unref (window->frame_clock); g_object_unref (window->frame_clock);
} }
......
...@@ -26,6 +26,7 @@ endif ...@@ -26,6 +26,7 @@ endif
noinst_PROGRAMS = $(TEST_PROGS) \ noinst_PROGRAMS = $(TEST_PROGS) \
animated-resizing \ animated-resizing \
motion-compression \
simple \ simple \
flicker \ flicker \
print-editor \ print-editor \
...@@ -152,6 +153,7 @@ endif ...@@ -152,6 +153,7 @@ endif
animated_resizing_DEPENDENCIES = $(TEST_DEPS) animated_resizing_DEPENDENCIES = $(TEST_DEPS)
flicker_DEPENDENCIES = $(TEST_DEPS) flicker_DEPENDENCIES = $(TEST_DEPS)