mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
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:
parent
bc1dc1fd63
commit
0e52672f4a
|
@ -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.
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue