Fix busy loop in X11 WaitEventsIterator

WaitEventsIterator implements waiting by first calling XPeekEvent which
will block until at least 1 event is queued, and then it delegates to
PollEventsIterator to actually handle the new event. PollEventsIterator
was previously picky about which events it would process. Events of
other types would get stuck at the head of the X event queue, and
PollEventsIterator would return None. This initiated a busy loop in the
WaitEventsIterator because it would XPeekEvent, see that something is
there, and then PollEventsIterator would return None, and the process
would repeat.

This is resolved by using XNextEvent in the PollEventsIterator instead
of XCheckTypedEvent. Any event in the queue will be popped. Even if
winit isn't interested in the event, this means XPeekEvent will block
again to wait for another event instead of the previous behavior.
This commit is contained in:
Joe Wilm 2017-02-15 08:29:12 -08:00
parent adf42909c8
commit 2ee658048a

View file

@ -158,18 +158,26 @@ impl<'a> Iterator for PollEventsIterator<'a> {
}
let mut xev = unsafe { mem::uninitialized() };
let res = unsafe { (xlib.XCheckMaskEvent)(self.window.x.display.display, -1, &mut xev) };
if res == 0 {
let res = unsafe { (xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::ClientMessage, &mut xev) };
if res == 0 {
let res = unsafe { (xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::GenericEvent, &mut xev) };
if res == 0 {
return None;
}
// Get the next X11 event. XNextEvent will block if there's no
// events available; checking the count first ensures an event will
// be returned without blocking.
//
// Functions like XCheckTypedEvent can prevent events from being
// popped if they are of the wrong type in which case winit would
// enter a busy loop. To avoid that, XNextEvent is used to pop
// events off the queue since it will accept any event type.
unsafe {
let count = (xlib.XPending)(self.window.x.display.display);
if count == 0 {
return None;
}
}
let res = (xlib.XNextEvent)(self.window.x.display.display, &mut xev);
// Can res ever be none zero if count is > 0?
assert!(res == 0);
};
match xev.get_type() {
ffi::MappingNotify => {