parent
8fdd81ecef
commit
e648169861
60 changed files with 800 additions and 860 deletions
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue