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

@ -19,7 +19,7 @@ use crate::platform::x11::XlibErrorHook;
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, KeyEvent},
event::KeyEvent,
event_loop::{
AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
EventLoopWindowTarget as RootELW,
@ -767,21 +767,21 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
self.run_ondemand(callback)
}
pub fn run_ondemand<F>(&mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_ondemand(callback))
}
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback))
}
@ -845,22 +845,29 @@ impl<T> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle())
}
}
fn sticky_exit_callback<T, F>(
evt: Event<T>,
target: &RootELW<T>,
control_flow: &mut ControlFlow,
callback: &mut F,
) where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
{
// make ControlFlow::ExitWithCode sticky by providing a dummy
// control flow reference if it is already ExitWithCode.
if let ControlFlow::ExitWithCode(code) = *control_flow {
callback(evt, target, &mut ControlFlow::ExitWithCode(code))
} else {
callback(evt, target, control_flow)
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
x11_or_wayland!(match self; Self(evlp) => evlp.set_control_flow(control_flow))
}
pub(crate) fn control_flow(&self) -> ControlFlow {
x11_or_wayland!(match self; Self(evlp) => evlp.control_flow())
}
pub(crate) fn exit(&self) {
x11_or_wayland!(match self; Self(evlp) => evlp.exit())
}
pub(crate) fn exiting(&self) -> bool {
x11_or_wayland!(match self; Self(evlp) => evlp.exiting())
}
fn set_exit_code(&self, code: i32) {
x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
}
fn exit_code(&self) -> Option<i32> {
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
}
}

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>,

View file

@ -4,6 +4,7 @@ use sctk::reexports::client::Proxy;
use sctk::output::OutputData;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::event_loop::ControlFlow;
use crate::platform_impl::platform::VideoMode as PlatformVideoMode;
use super::event_loop::EventLoopWindowTarget;
@ -23,6 +24,30 @@ impl<T> EventLoopWindowTarget<T> {
// There's no primary monitor on Wayland.
None
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(Some(0))
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get().is_some()
}
pub(crate) fn set_exit_code(&self, code: i32) {
self.exit.set(Some(code))
}
pub(crate) fn exit_code(&self) -> Option<i32> {
self.exit.get()
}
}
#[derive(Clone, Debug)]

View file

@ -66,14 +66,14 @@ use self::{
event_processor::EventProcessor,
ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender},
};
use super::{common::xkb_state::KbdState, OsError};
use super::{common::xkb_state::KbdState, ControlFlow, OsError};
use crate::{
error::{EventLoopError, OsError as RootOsError},
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
event_loop::{DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
platform::pump_events::PumpStatus,
platform_impl::{
platform::{min_timeout, sticky_exit_callback, WindowId},
platform::{min_timeout, WindowId},
PlatformSpecificWindowBuilderAttributes,
},
window::WindowAttributes,
@ -148,6 +148,8 @@ pub struct EventLoopWindowTarget<T> {
wm_delete_window: xproto::Atom,
net_wm_ping: xproto::Atom,
ime_sender: ImeSender,
control_flow: Cell<ControlFlow>,
exit: Cell<Option<i32>>,
root: xproto::Window,
ime: RefCell<Ime>,
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
@ -159,7 +161,6 @@ pub struct EventLoopWindowTarget<T> {
pub struct EventLoop<T: 'static> {
loop_running: bool,
control_flow: ControlFlow,
event_loop: Loop<'static, EventLoopState>,
waker: calloop::ping::Ping,
event_processor: EventProcessor<T>,
@ -303,6 +304,8 @@ impl<T: 'static> EventLoop<T> {
let window_target = EventLoopWindowTarget {
ime,
root,
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(None),
windows: Default::default(),
_marker: ::std::marker::PhantomData,
ime_sender,
@ -368,7 +371,6 @@ impl<T: 'static> EventLoop<T> {
EventLoop {
loop_running: false,
control_flow: ControlFlow::default(),
event_loop,
waker,
event_processor,
@ -398,7 +400,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
@ -432,7 +434,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>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
if !self.loop_running {
self.loop_running = true;
@ -440,7 +442,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);
@ -448,19 +450,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 {
@ -476,7 +472,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>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let start = Instant::now();
@ -486,17 +482,12 @@ impl<T: 'static> EventLoop<T> {
// If we already have work to do then we don't want to block on the next poll.
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)
@ -510,7 +501,7 @@ impl<T: 'static> EventLoop<T> {
{
log::error!("Failed to poll for events: {error:?}");
let exit_code = error.raw_os_error().unwrap_or(1);
self.control_flow = ControlFlow::ExitWithCode(exit_code);
self.set_exit_code(exit_code);
return;
}
@ -528,7 +519,7 @@ impl<T: 'static> EventLoop<T> {
// 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,
@ -547,11 +538,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!(),
};
self.single_iteration(&mut callback, cause);
@ -559,30 +545,18 @@ impl<T: 'static> EventLoop<T> {
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let mut control_flow = self.control_flow;
sticky_exit_callback(
crate::event::Event::NewEvents(cause),
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::NewEvents(cause), &self.target);
// NB: For consistency all platforms must emit a 'resumed' event even though X11
// applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init {
sticky_exit_callback(
crate::event::Event::Resumed,
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::Resumed, &self.target);
}
// Process all pending events
self.drain_events(callback, &mut control_flow);
self.drain_events(callback);
// Empty activation tokens.
while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
@ -593,7 +567,7 @@ impl<T: 'static> EventLoop<T> {
});
match token {
Some(Ok(token)) => sticky_exit_callback(
Some(Ok(token)) => callback(
crate::event::Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: crate::event::WindowEvent::ActivationTokenDone {
@ -602,8 +576,6 @@ impl<T: 'static> EventLoop<T> {
},
},
&self.target,
&mut control_flow,
callback,
),
Some(Err(e)) => {
log::error!("Failed to get activation token: {}", e);
@ -615,12 +587,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer
{
while let Ok(event) = self.user_receiver.try_recv() {
sticky_exit_callback(
crate::event::Event::UserEvent(event),
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::UserEvent(event), &self.target);
}
}
@ -634,34 +601,25 @@ impl<T: 'static> EventLoop<T> {
for window_id in windows {
let window_id = crate::window::WindowId(window_id);
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
},
&self.target,
&mut control_flow,
callback,
);
}
}
// This is always the last event we dispatch before poll again
{
sticky_exit_callback(
crate::event::Event::AboutToWait,
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::AboutToWait, &self.target);
}
self.control_flow = control_flow;
}
fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
fn drain_events<F>(&mut self, callback: &mut F)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let target = &self.target;
let mut xev = MaybeUninit::uninit();
@ -670,25 +628,38 @@ impl<T: 'static> EventLoop<T> {
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() };
self.event_processor.process_event(&mut xev, |event| {
sticky_exit_callback(
event,
target,
control_flow,
&mut |event, window_target, control_flow| {
if let Event::WindowEvent {
window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested,
} = event
{
wt.redraw_sender.send(wid).unwrap();
} else {
callback(event, window_target, control_flow);
}
},
);
if let Event::WindowEvent {
window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested,
} = event
{
wt.redraw_sender.send(wid).unwrap();
} else {
callback(event, target);
}
});
}
}
fn set_control_flow(&self, control_flow: ControlFlow) {
self.target.p.set_control_flow(control_flow)
}
fn control_flow(&self) -> ControlFlow {
self.target.p.control_flow()
}
fn exiting(&self) -> bool {
self.target.p.exiting()
}
fn set_exit_code(&self, code: i32) {
self.target.p.set_exit_code(code)
}
fn exit_code(&self) -> Option<i32> {
self.target.p.exit_code()
}
}
pub(crate) fn get_xtarget<T>(target: &RootELW<T>) -> &EventLoopWindowTarget<T> {
@ -743,6 +714,30 @@ impl<T> EventLoopWindowTarget<T> {
display_handle.screen = self.xconn.default_screen_index() as c_int;
RawDisplayHandle::Xlib(display_handle)
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(Some(0))
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get().is_some()
}
pub(crate) fn set_exit_code(&self, code: i32) {
self.exit.set(Some(code))
}
pub(crate) fn exit_code(&self) -> Option<i32> {
self.exit.get()
}
}
impl<T: 'static> EventLoopProxy<T> {