From 2ee658048aa7ace8bbd2e736387510aad02406b1 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Wed, 15 Feb 2017 08:29:12 -0800 Subject: [PATCH] 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. --- src/api/x11/window.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index f3640183..45ffd4d5 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -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 => {