Move ControlFlow to EventLoopWindowTarget

Fixes #3042.
This commit is contained in:
daxpedda 2023-09-07 08:25:04 +02:00 committed by GitHub
parent 8fdd81ecef
commit e648169861
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 800 additions and 860 deletions

View file

@ -1,6 +1,6 @@
//! The event-loop routines.
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::io::Result as IOResult;
use std::marker::PhantomData;
use std::mem;
@ -24,7 +24,6 @@ use crate::event_loop::{
};
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::min_timeout;
use crate::platform_impl::platform::sticky_exit_callback;
use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError};
mod proxy;
@ -44,9 +43,6 @@ pub struct EventLoop<T: 'static> {
/// Has `run` or `run_ondemand` been called or a call to `pump_events` that starts the loop
loop_running: bool,
/// The application's latest control_flow state
control_flow: ControlFlow,
buffer_sink: EventSink,
compositor_updates: Vec<WindowCompositorUpdate>,
window_ids: Vec<WindowId>,
@ -168,13 +164,14 @@ impl<T: 'static> EventLoop<T> {
wayland_dispatcher: wayland_dispatcher.clone(),
event_loop_awakener,
queue_handle,
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(None),
state: RefCell::new(winit_state),
_marker: PhantomData,
};
let event_loop = Self {
loop_running: false,
control_flow: ControlFlow::default(),
compositor_updates: Vec::new(),
buffer_sink: EventSink::default(),
window_ids: Vec::new(),
@ -194,7 +191,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
@ -225,7 +222,7 @@ impl<T: 'static> EventLoop<T> {
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
if !self.loop_running {
self.loop_running = true;
@ -233,7 +230,7 @@ impl<T: 'static> EventLoop<T> {
// Reset the internal state for the loop as we start running to
// ensure consistent behaviour in case the loop runs and exits more
// than once.
self.control_flow = ControlFlow::Poll;
self.set_control_flow(ControlFlow::Poll);
// Run the initial loop iteration.
self.single_iteration(&mut callback, StartCause::Init);
@ -241,19 +238,13 @@ impl<T: 'static> EventLoop<T> {
// Consider the possibility that the `StartCause::Init` iteration could
// request to Exit.
if !matches!(self.control_flow, ControlFlow::ExitWithCode(_)) {
if !self.exiting() {
self.poll_events_with_timeout(timeout, &mut callback);
}
if let ControlFlow::ExitWithCode(code) = self.control_flow {
if let Some(code) = self.exit_code() {
self.loop_running = false;
let mut dummy = self.control_flow;
sticky_exit_callback(
Event::LoopExiting,
self.window_target(),
&mut dummy,
&mut callback,
);
callback(Event::LoopExiting, self.window_target());
PumpStatus::Exit(code)
} else {
@ -263,7 +254,7 @@ impl<T: 'static> EventLoop<T> {
pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
let cause = loop {
let start = Instant::now();
@ -299,7 +290,7 @@ impl<T: 'static> EventLoop<T> {
}
Err(error) => {
error!("Error dispatching wayland queue: {}", error);
self.control_flow = ControlFlow::ExitWithCode(1);
self.set_exit_code(1);
return;
}
}
@ -308,17 +299,12 @@ impl<T: 'static> EventLoop<T> {
timeout = if instant_wakeup {
Some(Duration::ZERO)
} else {
let control_flow_timeout = match self.control_flow {
let control_flow_timeout = match self.control_flow() {
ControlFlow::Wait => None,
ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start))
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
min_timeout(control_flow_timeout, timeout)
};
@ -336,13 +322,13 @@ impl<T: 'static> EventLoop<T> {
// with an API to do that via some event.
// Still, we set the exit code to the error's OS error code, or to 1 if not possible.
let exit_code = error.raw_os_error().unwrap_or(1);
self.control_flow = ControlFlow::ExitWithCode(exit_code);
self.set_exit_code(exit_code);
return;
}
// NB: `StartCause::Init` is handled as a special case and doesn't need
// to be considered here
let cause = match self.control_flow {
let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled {
start,
@ -361,11 +347,6 @@ impl<T: 'static> EventLoop<T> {
}
}
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
// Reduce spurious wake-ups.
@ -380,14 +361,12 @@ impl<T: 'static> EventLoop<T> {
self.single_iteration(&mut callback, cause);
}
fn single_iteration<F>(&mut self, mut callback: &mut F, cause: StartCause)
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
// NOTE currently just indented to simplify the diff
let mut control_flow = self.control_flow;
// We retain these grow-only scratch buffers as part of the EventLoop
// for the sake of avoiding lots of reallocs. We take them here to avoid
// trying to mutably borrow `self` more than once and we swap them back
@ -396,33 +375,18 @@ impl<T: 'static> EventLoop<T> {
let mut buffer_sink = std::mem::take(&mut self.buffer_sink);
let mut window_ids = std::mem::take(&mut self.window_ids);
sticky_exit_callback(
Event::NewEvents(cause),
&self.window_target,
&mut control_flow,
callback,
);
callback(Event::NewEvents(cause), &self.window_target);
// NB: For consistency all platforms must emit a 'resumed' event even though Wayland
// applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init {
sticky_exit_callback(
Event::Resumed,
&self.window_target,
&mut control_flow,
callback,
);
callback(Event::Resumed, &self.window_target);
}
// Handle pending user events. We don't need back buffer, since we can't dispatch
// user events indirectly via callback to the user.
for user_event in self.pending_user_events.borrow_mut().drain(..) {
sticky_exit_callback(
Event::UserEvent(user_event),
&self.window_target,
&mut control_flow,
&mut callback,
);
callback(Event::UserEvent(user_event), &self.window_target);
}
// Drain the pending compositor updates.
@ -445,7 +409,7 @@ impl<T: 'static> EventLoop<T> {
let old_physical_size = physical_size;
let new_inner_size = Arc::new(Mutex::new(physical_size));
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::ScaleFactorChanged {
@ -456,8 +420,6 @@ impl<T: 'static> EventLoop<T> {
},
},
&self.window_target,
&mut control_flow,
&mut callback,
);
let physical_size = *new_inner_size.lock().unwrap();
@ -499,26 +461,22 @@ impl<T: 'static> EventLoop<T> {
physical_size
});
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::Resized(physical_size),
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
if compositor_update.close_window {
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::CloseRequested,
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
}
@ -529,7 +487,7 @@ impl<T: 'static> EventLoop<T> {
});
for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap();
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
callback(event, &self.window_target);
}
// Handle non-synthetic events.
@ -538,7 +496,7 @@ impl<T: 'static> EventLoop<T> {
});
for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap();
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
callback(event, &self.window_target);
}
// Collect the window ids
@ -581,14 +539,12 @@ impl<T: 'static> EventLoop<T> {
});
if request_redraw {
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::RedrawRequested,
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
}
@ -599,14 +555,8 @@ impl<T: 'static> EventLoop<T> {
});
// This is always the last event we dispatch before poll again
sticky_exit_callback(
Event::AboutToWait,
&self.window_target,
&mut control_flow,
&mut callback,
);
callback(Event::AboutToWait, &self.window_target);
self.control_flow = control_flow;
std::mem::swap(&mut self.compositor_updates, &mut compositor_updates);
std::mem::swap(&mut self.buffer_sink, &mut buffer_sink);
std::mem::swap(&mut self.window_ids, &mut window_ids);
@ -660,6 +610,26 @@ impl<T: 'static> EventLoop<T> {
))))
})
}
fn set_control_flow(&self, control_flow: ControlFlow) {
self.window_target.p.set_control_flow(control_flow)
}
fn control_flow(&self) -> ControlFlow {
self.window_target.p.control_flow()
}
fn exiting(&self) -> bool {
self.window_target.p.exiting()
}
fn set_exit_code(&self, code: i32) {
self.window_target.p.set_exit_code(code)
}
fn exit_code(&self) -> Option<i32> {
self.window_target.p.exit_code()
}
}
pub struct EventLoopWindowTarget<T> {
@ -669,6 +639,12 @@ pub struct EventLoopWindowTarget<T> {
/// The main queue used by the event loop.
pub queue_handle: QueueHandle<WinitState>,
/// The application's latest control_flow state
pub(crate) control_flow: Cell<ControlFlow>,
/// The application's exit state.
pub(crate) exit: Cell<Option<i32>>,
// TODO remove that RefCell once we can pass `&mut` in `Window::new`.
/// Winit state.
pub state: RefCell<WinitState>,