On X11, Fix for repeated event loop iteration when ControlFlow was Wait (#2155)

* On X11, Fix for repeated event loop iteration
when `ControlFlow` was `Wait`

* ControlFlow::Poll now runs continously as should
This commit is contained in:
Artúr Kovács 2022-02-04 12:13:04 +01:00 committed by GitHub
parent bc1dc1fd63
commit 0e52672f4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 44 deletions

View file

@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre
# Unreleased # Unreleased
- On X11, fix for repeated event loop iteration when `ControlFlow` was `Wait`
- On Wayland, report unaccelerated mouse deltas in `DeviceEvent::MouseMotion`. - On Wayland, report unaccelerated mouse deltas in `DeviceEvent::MouseMotion`.
- **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`. - **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`.
- Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable. - Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable.

View file

@ -32,7 +32,7 @@ use std::{
ptr, ptr,
rc::Rc, rc::Rc,
slice, slice,
sync::mpsc::{Receiver, Sender}, sync::mpsc::{Receiver, Sender, TryRecvError},
sync::{mpsc, Arc, Weak}, sync::{mpsc, Arc, Weak},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -63,6 +63,39 @@ struct WakeSender<T> {
waker: Arc<Waker>, waker: Arc<Waker>,
} }
struct PeekableReceiver<T> {
recv: Receiver<T>,
first: Option<T>,
}
impl<T> PeekableReceiver<T> {
pub fn from_recv(recv: Receiver<T>) -> Self {
Self { recv, first: None }
}
pub fn has_incoming(&mut self) -> bool {
if self.first.is_some() {
return true;
}
match self.recv.try_recv() {
Ok(v) => {
self.first = Some(v);
return true;
}
Err(TryRecvError::Empty) => return false,
Err(TryRecvError::Disconnected) => {
warn!("Channel was disconnected when checking incoming");
return false;
}
}
}
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
if let Some(first) = self.first.take() {
return Ok(first);
}
self.recv.try_recv()
}
}
pub struct EventLoopWindowTarget<T> { pub struct EventLoopWindowTarget<T> {
xconn: Arc<XConnection>, xconn: Arc<XConnection>,
wm_delete_window: ffi::Atom, wm_delete_window: ffi::Atom,
@ -79,8 +112,8 @@ pub struct EventLoop<T: 'static> {
poll: Poll, poll: Poll,
waker: Arc<Waker>, waker: Arc<Waker>,
event_processor: EventProcessor<T>, event_processor: EventProcessor<T>,
redraw_channel: Receiver<WindowId>, redraw_receiver: PeekableReceiver<WindowId>,
user_channel: Receiver<T>, //waker.wake needs to be called whenever something gets sent user_receiver: PeekableReceiver<T>, //waker.wake needs to be called whenever something gets sent
user_sender: Sender<T>, user_sender: Sender<T>,
target: Rc<RootELW<T>>, target: Rc<RootELW<T>>,
} }
@ -240,8 +273,8 @@ impl<T: 'static> EventLoop<T> {
poll, poll,
waker, waker,
event_processor, event_processor,
redraw_channel, redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
user_channel, user_receiver: PeekableReceiver::from_recv(user_channel),
user_sender, user_sender,
target, target,
} }
@ -262,29 +295,38 @@ impl<T: 'static> EventLoop<T> {
where where
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow), F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{ {
let mut control_flow = ControlFlow::default(); struct IterationResult {
let mut events = Events::with_capacity(8); deadline: Option<Instant>,
let mut cause = StartCause::Init; timeout: Option<Duration>,
wait_start: Instant,
let exit_code = loop { }
fn single_iteration<T, F>(
this: &mut EventLoop<T>,
control_flow: &mut ControlFlow,
cause: &mut StartCause,
callback: &mut F,
) -> IterationResult
where
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{
sticky_exit_callback( sticky_exit_callback(
crate::event::Event::NewEvents(cause), crate::event::Event::NewEvents(*cause),
&self.target, &this.target,
&mut control_flow, control_flow,
&mut callback, callback,
); );
// Process all pending events // Process all pending events
self.drain_events(&mut callback, &mut control_flow); this.drain_events(callback, control_flow);
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_channel.try_recv() { while let Ok(event) = this.user_receiver.try_recv() {
sticky_exit_callback( sticky_exit_callback(
crate::event::Event::UserEvent(event), crate::event::Event::UserEvent(event),
&self.target, &this.target,
&mut control_flow, control_flow,
&mut callback, callback,
); );
} }
} }
@ -292,16 +334,16 @@ impl<T: 'static> EventLoop<T> {
{ {
sticky_exit_callback( sticky_exit_callback(
crate::event::Event::MainEventsCleared, crate::event::Event::MainEventsCleared,
&self.target, &this.target,
&mut control_flow, control_flow,
&mut callback, callback,
); );
} }
// Empty the redraw requests // Empty the redraw requests
{ {
let mut windows = HashSet::new(); let mut windows = HashSet::new();
while let Ok(window_id) = self.redraw_channel.try_recv() { while let Ok(window_id) = this.redraw_receiver.try_recv() {
windows.insert(window_id); windows.insert(window_id);
} }
@ -309,9 +351,9 @@ impl<T: 'static> EventLoop<T> {
let window_id = crate::window::WindowId(super::WindowId::X(window_id)); let window_id = crate::window::WindowId(super::WindowId::X(window_id));
sticky_exit_callback( sticky_exit_callback(
Event::RedrawRequested(window_id), Event::RedrawRequested(window_id),
&self.target, &this.target,
&mut control_flow, control_flow,
&mut callback, callback,
); );
} }
} }
@ -319,9 +361,9 @@ impl<T: 'static> EventLoop<T> {
{ {
sticky_exit_callback( sticky_exit_callback(
crate::event::Event::RedrawEventsCleared, crate::event::Event::RedrawEventsCleared,
&self.target, &this.target,
&mut control_flow, control_flow,
&mut callback, callback,
); );
} }
@ -329,14 +371,20 @@ impl<T: 'static> EventLoop<T> {
let (deadline, timeout); let (deadline, timeout);
match control_flow { match control_flow {
ControlFlow::ExitWithCode(code) => break code, ControlFlow::ExitWithCode(_) => {
return IterationResult {
wait_start: start,
deadline: None,
timeout: None,
};
}
ControlFlow::Poll => { ControlFlow::Poll => {
cause = StartCause::Poll; *cause = StartCause::Poll;
deadline = None; deadline = None;
timeout = Some(Duration::from_millis(0)); timeout = Some(Duration::from_millis(0));
} }
ControlFlow::Wait => { ControlFlow::Wait => {
cause = StartCause::WaitCancelled { *cause = StartCause::WaitCancelled {
start, start,
requested_resume: None, requested_resume: None,
}; };
@ -344,38 +392,71 @@ impl<T: 'static> EventLoop<T> {
timeout = None; timeout = None;
} }
ControlFlow::WaitUntil(wait_deadline) => { ControlFlow::WaitUntil(wait_deadline) => {
cause = StartCause::ResumeTimeReached { *cause = StartCause::ResumeTimeReached {
start, start,
requested_resume: wait_deadline, requested_resume: *wait_deadline,
}; };
timeout = if wait_deadline > start { timeout = if *wait_deadline > start {
Some(wait_deadline - start) Some(*wait_deadline - start)
} else { } else {
Some(Duration::from_millis(0)) Some(Duration::from_millis(0))
}; };
deadline = Some(wait_deadline); deadline = Some(*wait_deadline);
} }
} }
return IterationResult {
wait_start: start,
deadline,
timeout,
};
}
// If the XConnection already contains buffered events, we don't let mut control_flow = ControlFlow::default();
// need to wait for data on the socket. let mut events = Events::with_capacity(8);
if !self.event_processor.poll() { let mut cause = StartCause::Init;
if let Err(e) = self.poll.poll(&mut events, timeout) {
// run the initial loop iteration
let mut iter_result = single_iteration(self, &mut control_flow, &mut cause, &mut callback);
let exit_code = loop {
if let ControlFlow::ExitWithCode(code) = control_flow {
break code;
}
let has_pending = self.event_processor.poll()
|| self.user_receiver.has_incoming()
|| self.redraw_receiver.has_incoming();
if !has_pending {
// Wait until
if let Err(e) = self.poll.poll(&mut events, iter_result.timeout) {
if e.raw_os_error() != Some(libc::EINTR) { if e.raw_os_error() != Some(libc::EINTR) {
panic!("epoll returned an error: {:?}", e); panic!("epoll returned an error: {:?}", e);
} }
} }
events.clear(); events.clear();
if control_flow == ControlFlow::Wait {
// We don't go straight into executing the event loop iteration, we instead go
// to the start of this loop and check again if there's any pending event. We
// must do this because during the execution of the iteration we sometimes wake
// the mio waker, and if the waker is already awaken before we call poll(),
// then poll doesn't block, but it returns immediately. This caused the event
// loop to run continously even if the control_flow was `Wait`
continue;
}
} }
let wait_cancelled = deadline.map_or(false, |deadline| Instant::now() < deadline); let wait_cancelled = iter_result
.deadline
.map_or(false, |deadline| Instant::now() < deadline);
if wait_cancelled { if wait_cancelled {
cause = StartCause::WaitCancelled { cause = StartCause::WaitCancelled {
start, start: iter_result.wait_start,
requested_resume: deadline, requested_resume: iter_result.deadline,
}; };
} }
iter_result = single_iteration(self, &mut control_flow, &mut cause, &mut callback);
}; };
callback( callback(