mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 02:40:11 +00:00
Handle recursion from motion event handlers
If a motion event handler (or other handler running from the flush-events phase of the frame clock) recursed the main loop then flushing wouldn't complete until after the recursed main loop returned, and various aspects of the state would get out of sync. To fix this, change flushing of the event queue to simply mark events as ready to flush, and let normal event delivery handle the rest. https://bugzilla.gnome.org/show_bug.cgi?id=705176
This commit is contained in:
parent
0db8aeaad9
commit
f50a3af1b7
@ -62,10 +62,7 @@ gdk_event_source_prepare (GSource *source,
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
if (display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
else
|
||||
retval = (_gdk_event_queue_find_first (display) != NULL);
|
||||
retval = (_gdk_event_queue_find_first (display) != NULL);
|
||||
|
||||
gdk_threads_leave ();
|
||||
|
||||
@ -80,9 +77,8 @@ gdk_event_source_check (GSource *source)
|
||||
|
||||
gdk_threads_enter ();
|
||||
|
||||
if (event_source->display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
else if (event_source->event_poll_fd.revents & G_IO_IN)
|
||||
if (event_source->display->event_pause_count > 0 ||
|
||||
event_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = (_gdk_event_queue_find_first (event_source->display) != NULL);
|
||||
else
|
||||
retval = FALSE;
|
||||
|
@ -321,10 +321,8 @@ gdk_display_get_event (GdkDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
|
||||
|
||||
if (display->event_pause_count > 0)
|
||||
return NULL;
|
||||
|
||||
GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
|
||||
if (display->event_pause_count == 0)
|
||||
GDK_DISPLAY_GET_CLASS (display)->queue_events (display);
|
||||
|
||||
return _gdk_event_unqueue (display);
|
||||
}
|
||||
@ -2032,24 +2030,6 @@ _gdk_display_unpause_events (GdkDisplay *display)
|
||||
display->event_pause_count--;
|
||||
}
|
||||
|
||||
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
|
||||
_gdk_display_event_data_copy (GdkDisplay *display,
|
||||
const GdkEvent *event,
|
||||
|
@ -116,7 +116,6 @@ struct _GdkDisplay
|
||||
guint event_pause_count; /* How many times events are blocked */
|
||||
|
||||
guint closed : 1; /* Whether this display has been closed */
|
||||
guint flushing_events : 1; /* Inside gdk_display_flush_events */
|
||||
|
||||
GArray *touch_implicit_grabs;
|
||||
GHashTable *device_grabs;
|
||||
@ -300,7 +299,6 @@ void _gdk_display_pointer_info_foreach (GdkDisplay *display
|
||||
gulong _gdk_display_get_next_serial (GdkDisplay *display);
|
||||
void _gdk_display_pause_events (GdkDisplay *display);
|
||||
void _gdk_display_unpause_events (GdkDisplay *display);
|
||||
void _gdk_display_flush_events (GdkDisplay *display);
|
||||
void _gdk_display_event_data_copy (GdkDisplay *display,
|
||||
const GdkEvent *event,
|
||||
GdkEvent *new_event);
|
||||
|
@ -88,20 +88,20 @@ _gdk_event_queue_find_first (GdkDisplay *display)
|
||||
GList *tmp_list;
|
||||
GList *pending_motion = NULL;
|
||||
|
||||
if (display->event_pause_count > 0)
|
||||
return NULL;
|
||||
gboolean paused = display->event_pause_count > 0;
|
||||
|
||||
tmp_list = display->queued_events;
|
||||
while (tmp_list)
|
||||
{
|
||||
GdkEventPrivate *event = tmp_list->data;
|
||||
|
||||
if (!(event->flags & GDK_EVENT_PENDING))
|
||||
if ((event->flags & GDK_EVENT_PENDING) == 0 &&
|
||||
(!paused || (event->flags & GDK_EVENT_FLUSHED) != 0))
|
||||
{
|
||||
if (pending_motion)
|
||||
return pending_motion;
|
||||
|
||||
if (event->event.type == GDK_MOTION_NOTIFY && !display->flushing_events)
|
||||
if (event->event.type == GDK_MOTION_NOTIFY && (event->flags & GDK_EVENT_FLUSHED) == 0)
|
||||
pending_motion = tmp_list;
|
||||
else
|
||||
return tmp_list;
|
||||
@ -321,6 +321,18 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_event_queue_flush (GdkDisplay *display)
|
||||
{
|
||||
GList *tmp_list;
|
||||
|
||||
for (tmp_list = display->queued_events; tmp_list; tmp_list = tmp_list->next)
|
||||
{
|
||||
GdkEventPrivate *event = tmp_list->data;
|
||||
event->flags |= GDK_EVENT_FLUSHED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_handler_set:
|
||||
* @func: the function to call to handle events from GDK.
|
||||
|
@ -156,7 +156,13 @@ typedef enum
|
||||
* 1) touch events emulating pointer events
|
||||
* 2) pointer events being emulated by a touch sequence.
|
||||
*/
|
||||
GDK_EVENT_POINTER_EMULATED = 1 << 1
|
||||
GDK_EVENT_POINTER_EMULATED = 1 << 1,
|
||||
|
||||
/* When we are ready to draw a frame, we pause event delivery,
|
||||
* mark all events in the queue with this flag, and deliver
|
||||
* only those events until we finish the frame.
|
||||
*/
|
||||
GDK_EVENT_FLUSHED = 1 << 2
|
||||
} GdkEventFlags;
|
||||
|
||||
struct _GdkEventPrivate
|
||||
@ -305,6 +311,7 @@ GList* _gdk_event_queue_insert_before(GdkDisplay *display,
|
||||
GdkEvent *event);
|
||||
|
||||
void _gdk_event_queue_handle_motion_compression (GdkDisplay *display);
|
||||
void _gdk_event_queue_flush (GdkDisplay *display);
|
||||
|
||||
void _gdk_event_button_generate (GdkDisplay *display,
|
||||
GdkEvent *event);
|
||||
|
@ -10696,7 +10696,7 @@ gdk_window_flush_events (GdkFrameClock *clock,
|
||||
window = GDK_WINDOW (data);
|
||||
|
||||
display = gdk_window_get_display (window);
|
||||
_gdk_display_flush_events (display);
|
||||
_gdk_event_queue_flush (display);
|
||||
_gdk_display_pause_events (display);
|
||||
|
||||
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
|
||||
|
@ -647,7 +647,7 @@ gdk_event_prepare (GSource *source,
|
||||
*timeout = -1;
|
||||
|
||||
if (_gdk_display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
|
||||
else
|
||||
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
|
||||
_gdk_quartz_event_loop_check_pending ());
|
||||
@ -665,7 +665,7 @@ gdk_event_check (GSource *source)
|
||||
gdk_threads_enter ();
|
||||
|
||||
if (_gdk_display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
|
||||
else
|
||||
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
|
||||
_gdk_quartz_event_loop_check_pending ());
|
||||
|
@ -40,7 +40,7 @@ gdk_event_source_prepare(GSource *base, gint *timeout)
|
||||
*timeout = -1;
|
||||
|
||||
if (source->display->event_pause_count > 0)
|
||||
return FALSE;
|
||||
return _gdk_event_queue_find_first (source->display) != NULL;
|
||||
|
||||
/* We have to add/remove the GPollFD if we want to update our
|
||||
* poll event mask dynamically. Instead, let's just flush all
|
||||
@ -64,7 +64,7 @@ gdk_event_source_check(GSource *base)
|
||||
GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
|
||||
|
||||
if (source->display->event_pause_count > 0)
|
||||
return FALSE;
|
||||
return _gdk_event_queue_find_first (source->display) != NULL;
|
||||
|
||||
return _gdk_event_queue_find_first (source->display) != NULL ||
|
||||
source->pfd.revents;
|
||||
|
@ -3328,7 +3328,7 @@ gdk_event_prepare (GSource *source,
|
||||
*timeout = -1;
|
||||
|
||||
if (_gdk_display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval =_gdk_event_queue_find_first (_gdk_display) != NULL;
|
||||
else
|
||||
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
|
||||
(modal_win32_dialog == NULL &&
|
||||
@ -3347,7 +3347,7 @@ gdk_event_check (GSource *source)
|
||||
gdk_threads_enter ();
|
||||
|
||||
if (_gdk_display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval = gdk_event_queue_find_first (_gdk_display) != NULL;
|
||||
else if (event_poll_fd.revents & G_IO_IN)
|
||||
retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
|
||||
(modal_win32_dialog == NULL &&
|
||||
|
@ -278,7 +278,7 @@ gdk_event_source_prepare (GSource *source,
|
||||
*timeout = -1;
|
||||
|
||||
if (display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval = _gdk_event_queue_find_first (display) != NULL;
|
||||
else
|
||||
retval = (_gdk_event_queue_find_first (display) != NULL ||
|
||||
gdk_check_xpending (display));
|
||||
@ -297,7 +297,7 @@ gdk_event_source_check (GSource *source)
|
||||
gdk_threads_enter ();
|
||||
|
||||
if (event_source->display->event_pause_count > 0)
|
||||
retval = FALSE;
|
||||
retval = _gdk_event_queue_find_first (event_source->display) != NULL;
|
||||
else if (event_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
|
||||
gdk_check_xpending (event_source->display));
|
||||
|
Loading…
Reference in New Issue
Block a user