mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-02-02 23:06:32 +11:00
Add exit code to ControlFlow::Exit
(#2100)
* Add exit code to control flow and impl on linux * Fix examples to have an exit code * Fix doc examples to use an exit code * Improve documentation wording on the exit code * Add exit code example * Add exit code on windows * Change i32 as exit code to u8 This avoids nasty surprises with negative numbers on some unix-alikes due to two's complement. * Fix android usages of ControlFlow::Exit * Fix ios usages of ControlFlow::Exit * Fix web usages of ControlFlow::Exit * Add macos exit code * Add changelog note * Document exit code on display server disconnection * Revert "Change i32 as exit code to u8" This reverts commit f88fba0253b45de6a2ac0c3cbcf01f50503c9396. * Change Exit to ExitWithCode and make an Exit const * Revert "Add exit code example" This reverts commit fbd3d03de9c2d7516c7a63da489c99f498b710df. * Revert "Fix doc examples to use an exit code" This reverts commit daabcdf9ef9e16acad715c094ae442529e39fcbc. * Revert "Fix examples to have an exit code" This reverts commit 0df486896b8d106acf65ba83c45cc88d60d228e1. * Fix unix-alike to use ExitWithCode instead of Exit * Fix windows to use ExitWithCode rather than Exit * Silence warning about non-uppercase Exit const * Refactor exit code handling * Fix macos Exit usage and recover original semantic * Fix ios to use ExitWithCode instead of Exit * Update documentation to reflect ExitWithCode * Fix web to use ExitWithCode when needed, not Exit * Fix android to use ExitWithCode, not Exit * Apply documenation nits * Apply even more documentation nits * Move change in CHANGELOG.md under "Unreleased" * Try to use OS error code as exit code on wayland
This commit is contained in:
parent
2a2abc4843
commit
a52f755ce8
14 changed files with 140 additions and 92 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
# Unreleased
|
||||||
|
|
||||||
|
- **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs.
|
||||||
|
|
||||||
# 0.26.1 (2022-01-05)
|
# 0.26.1 (2022-01-05)
|
||||||
|
|
||||||
- Fix linking to the `ColorSync` framework on macOS 10.7, and in newer Rust versions.
|
- Fix linking to the `ColorSync` framework on macOS 10.7, and in newer Rust versions.
|
||||||
|
|
|
@ -64,9 +64,9 @@ impl<T> fmt::Debug for EventLoopWindowTarget<T> {
|
||||||
///
|
///
|
||||||
/// ## Persistency
|
/// ## Persistency
|
||||||
/// Almost every change is persistent between multiple calls to the event loop closure within a
|
/// Almost every change is persistent between multiple calls to the event loop closure within a
|
||||||
/// given run loop. The only exception to this is `Exit` which, once set, cannot be unset. Changes
|
/// given run loop. The only exception to this is `ExitWithCode` which, once set, cannot be unset.
|
||||||
/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset
|
/// Changes are **not** persistent between multiple calls to `run_return` - issuing a new call will
|
||||||
/// the control flow to `Poll`.
|
/// reset the control flow to `Poll`.
|
||||||
///
|
///
|
||||||
/// [events_cleared]: crate::event::Event::RedrawEventsCleared
|
/// [events_cleared]: crate::event::Event::RedrawEventsCleared
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -86,9 +86,29 @@ pub enum ControlFlow {
|
||||||
/// arrives or the given time is reached.
|
/// arrives or the given time is reached.
|
||||||
WaitUntil(Instant),
|
WaitUntil(Instant),
|
||||||
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
||||||
/// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
|
/// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will
|
||||||
/// in the `control_flow` parameter being reset to `Exit`.
|
/// result in the `control_flow` parameter being reset to `ExitWithCode`.
|
||||||
Exit,
|
///
|
||||||
|
/// The contained number will be used as exit code. The [`Exit`] constant is a shortcut for this
|
||||||
|
/// with exit code 0.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **Android / iOS / WASM**: The supplied exit code is unused.
|
||||||
|
/// - **Unix**: On most Unix-like platforms, only the 8 least significant bits will be used,
|
||||||
|
/// which can cause surprises with negative exit values (`-42` would end up as `214`). See
|
||||||
|
/// [`std::process::exit`].
|
||||||
|
///
|
||||||
|
/// [`Exit`]: ControlFlow::Exit
|
||||||
|
ExitWithCode(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlFlow {
|
||||||
|
/// Alias for [`ExitWithCode`]`(0)`.
|
||||||
|
///
|
||||||
|
/// [`ExitWithCode`]: ControlFlow::ExitWithCode
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const Exit: Self = Self::ExitWithCode(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControlFlow {
|
impl Default for ControlFlow {
|
||||||
|
@ -145,6 +165,11 @@ impl<T> EventLoop<T> {
|
||||||
///
|
///
|
||||||
/// Any values not passed to this function will *not* be dropped.
|
/// Any values not passed to this function will *not* be dropped.
|
||||||
///
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **X11 / Wayland**: The program terminates with exit code 1 if the display server
|
||||||
|
/// disconnects.
|
||||||
|
///
|
||||||
/// [`ControlFlow`]: crate::event_loop::ControlFlow
|
/// [`ControlFlow`]: crate::event_loop::ControlFlow
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run<F>(self, event_handler: F) -> !
|
pub fn run<F>(self, event_handler: F) -> !
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
//! You can retrieve events by calling [`EventLoop::run`][event_loop_run]. This function will
|
//! You can retrieve events by calling [`EventLoop::run`][event_loop_run]. This function will
|
||||||
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
||||||
//! will run until the `control_flow` argument given to the closure is set to
|
//! will run until the `control_flow` argument given to the closure is set to
|
||||||
//! [`ControlFlow`]`::`[`Exit`], at which point [`Event`]`::`[`LoopDestroyed`] is emitted and the
|
//! [`ControlFlow`]`::`[`ExitWithCode`] (which [`ControlFlow`]`::`[`Exit`] aliases to), at which
|
||||||
//! entire program terminates.
|
//! point [`Event`]`::`[`LoopDestroyed`] is emitted and the entire program terminates.
|
||||||
//!
|
//!
|
||||||
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
||||||
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on
|
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on
|
||||||
|
@ -114,6 +114,7 @@
|
||||||
//! [event_loop_run]: event_loop::EventLoop::run
|
//! [event_loop_run]: event_loop::EventLoop::run
|
||||||
//! [`ControlFlow`]: event_loop::ControlFlow
|
//! [`ControlFlow`]: event_loop::ControlFlow
|
||||||
//! [`Exit`]: event_loop::ControlFlow::Exit
|
//! [`Exit`]: event_loop::ControlFlow::Exit
|
||||||
|
//! [`ExitWithCode`]: event_loop::ControlFlow::ExitWithCode
|
||||||
//! [`Window`]: window::Window
|
//! [`Window`]: window::Window
|
||||||
//! [`WindowId`]: window::WindowId
|
//! [`WindowId`]: window::WindowId
|
||||||
//! [`WindowBuilder`]: window::WindowBuilder
|
//! [`WindowBuilder`]: window::WindowBuilder
|
||||||
|
|
|
@ -33,7 +33,12 @@ pub trait EventLoopExtRunReturn {
|
||||||
/// underlying OS APIs, which cannot be hidden by `winit` without severe stability repercussions.
|
/// underlying OS APIs, which cannot be hidden by `winit` without severe stability repercussions.
|
||||||
///
|
///
|
||||||
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
|
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
|
||||||
fn run_return<F>(&mut self, event_handler: F)
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **Unix-alikes** (**X11** or **Wayland**): This function returns `1` upon disconnection from
|
||||||
|
/// the display server.
|
||||||
|
fn run_return<F>(&mut self, event_handler: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(
|
F: FnMut(
|
||||||
Event<'_, Self::UserEvent>,
|
Event<'_, Self::UserEvent>,
|
||||||
|
@ -45,7 +50,7 @@ pub trait EventLoopExtRunReturn {
|
||||||
impl<T> EventLoopExtRunReturn for EventLoop<T> {
|
impl<T> EventLoopExtRunReturn for EventLoop<T> {
|
||||||
type UserEvent = T;
|
type UserEvent = T;
|
||||||
|
|
||||||
fn run_return<F>(&mut self, event_handler: F)
|
fn run_return<F>(&mut self, event_handler: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(
|
F: FnMut(
|
||||||
Event<'_, Self::UserEvent>,
|
Event<'_, Self::UserEvent>,
|
||||||
|
|
|
@ -73,10 +73,10 @@ pub struct EventLoop<T: 'static> {
|
||||||
|
|
||||||
macro_rules! call_event_handler {
|
macro_rules! call_event_handler {
|
||||||
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
|
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
|
||||||
if $cf != ControlFlow::Exit {
|
if let ControlFlow::ExitWithCode(code) = $cf {
|
||||||
$event_handler($event, $window_target, &mut $cf);
|
$event_handler($event, $window_target, &mut ControlFlow::ExitWithCode(code));
|
||||||
} else {
|
} else {
|
||||||
$event_handler($event, $window_target, &mut ControlFlow::Exit);
|
$event_handler($event, $window_target, &mut $cf);
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
F: 'static
|
F: 'static
|
||||||
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(event_handler);
|
let exit_code = self.run_return(event_handler);
|
||||||
::std::process::exit(0);
|
::std::process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut event_handler: F)
|
pub fn run_return<F>(&mut self, mut event_handler: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -339,7 +339,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => {
|
ControlFlow::ExitWithCode(code) => {
|
||||||
self.first_event = poll(
|
self.first_event = poll(
|
||||||
self.looper
|
self.looper
|
||||||
.poll_once_timeout(Duration::from_millis(0))
|
.poll_once_timeout(Duration::from_millis(0))
|
||||||
|
@ -349,7 +349,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
requested_resume: None,
|
requested_resume: None,
|
||||||
};
|
};
|
||||||
break 'event_loop;
|
break 'event_loop code;
|
||||||
}
|
}
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
self.first_event = poll(
|
self.first_event = poll(
|
||||||
|
|
|
@ -296,7 +296,7 @@ impl AppState {
|
||||||
};
|
};
|
||||||
(waiting_event_handler, event)
|
(waiting_event_handler, event)
|
||||||
}
|
}
|
||||||
(ControlFlow::Exit, _) => bug!("unexpected `ControlFlow` `Exit`"),
|
(ControlFlow::ExitWithCode(_), _) => bug!("unexpected `ControlFlow` `Exit`"),
|
||||||
s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
|
s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ impl AppState {
|
||||||
});
|
});
|
||||||
self.waker.start()
|
self.waker.start()
|
||||||
}
|
}
|
||||||
(_, ControlFlow::Exit) => {
|
(_, ControlFlow::ExitWithCode(_)) => {
|
||||||
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
|
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
|
||||||
// it is not possible to quit an iOS app gracefully and programatically
|
// it is not possible to quit an iOS app gracefully and programatically
|
||||||
warn!("`ControlFlow::Exit` ignored on iOS");
|
warn!("`ControlFlow::Exit` ignored on iOS");
|
||||||
|
|
|
@ -655,7 +655,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, callback: F)
|
pub fn run_return<F>(&mut self, callback: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -741,16 +741,13 @@ fn sticky_exit_callback<T, F>(
|
||||||
) where
|
) where
|
||||||
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
// make ControlFlow::Exit sticky by providing a dummy
|
// make ControlFlow::ExitWithCode sticky by providing a dummy
|
||||||
// control flow reference if it is already Exit.
|
// control flow reference if it is already ExitWithCode.
|
||||||
let mut dummy = ControlFlow::Exit;
|
if let ControlFlow::ExitWithCode(code) = *control_flow {
|
||||||
let cf = if *control_flow == ControlFlow::Exit {
|
callback(evt, target, &mut ControlFlow::ExitWithCode(code))
|
||||||
&mut dummy
|
|
||||||
} else {
|
} else {
|
||||||
control_flow
|
callback(evt, target, control_flow)
|
||||||
};
|
}
|
||||||
// user callback
|
|
||||||
callback(evt, target, cf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_is_main_thread(suggested_method: &str) {
|
fn assert_is_main_thread(suggested_method: &str) {
|
||||||
|
|
|
@ -206,11 +206,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
where
|
where
|
||||||
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static,
|
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static,
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
let exit_code = self.run_return(callback);
|
||||||
process::exit(0)
|
process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -235,7 +235,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
// really an option. Instead we inform that the event loop got destroyed. We may
|
// really an option. Instead we inform that the event loop got destroyed. We may
|
||||||
// communicate an error that something was terminated, but winit doesn't provide us
|
// communicate an error that something was terminated, but winit doesn't provide us
|
||||||
// with an API to do that via some event.
|
// with an API to do that via some event.
|
||||||
loop {
|
// Still, we set the exit code to the error's OS error code, or to 1 if not possible.
|
||||||
|
let exit_code = loop {
|
||||||
// Handle pending user events. We don't need back buffer, since we can't dispatch
|
// Handle pending user events. We don't need back buffer, since we can't dispatch
|
||||||
// user events indirectly via callback to the user.
|
// user events indirectly via callback to the user.
|
||||||
for user_event in pending_user_events.borrow_mut().drain(..) {
|
for user_event in pending_user_events.borrow_mut().drain(..) {
|
||||||
|
@ -431,20 +432,19 @@ impl<T: 'static> EventLoop<T> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(dispatched) = queue.dispatch_pending(state, |_, _, _| unimplemented!()) {
|
match queue.dispatch_pending(state, |_, _, _| unimplemented!()) {
|
||||||
dispatched > 0
|
Ok(dispatched) => dispatched > 0,
|
||||||
} else {
|
Err(error) => break error.raw_os_error().unwrap_or(1),
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::ExitWithCode(code) => break code,
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
// Non-blocking dispatch.
|
// Non-blocking dispatch.
|
||||||
let timeout = Duration::from_millis(0);
|
let timeout = Duration::from_millis(0);
|
||||||
if self.loop_dispatch(Some(timeout)).is_err() {
|
if let Err(error) = self.loop_dispatch(Some(timeout)) {
|
||||||
break;
|
break error.raw_os_error().unwrap_or(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
|
@ -460,8 +460,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.loop_dispatch(timeout).is_err() {
|
if let Err(error) = self.loop_dispatch(timeout) {
|
||||||
break;
|
break error.raw_os_error().unwrap_or(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
|
@ -483,8 +483,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
Duration::from_millis(0)
|
Duration::from_millis(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.loop_dispatch(Some(duration)).is_err() {
|
if let Err(error) = self.loop_dispatch(Some(duration)) {
|
||||||
break;
|
break error.raw_os_error().unwrap_or(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
@ -510,9 +510,10 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
callback(Event::LoopDestroyed, &self.window_target, &mut control_flow);
|
callback(Event::LoopDestroyed, &self.window_target, &mut control_flow);
|
||||||
|
exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -258,7 +258,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&self.target
|
&self.target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -266,7 +266,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let mut events = Events::with_capacity(8);
|
let mut events = Events::with_capacity(8);
|
||||||
let mut cause = StartCause::Init;
|
let mut cause = StartCause::Init;
|
||||||
|
|
||||||
loop {
|
let exit_code = loop {
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
crate::event::Event::NewEvents(cause),
|
crate::event::Event::NewEvents(cause),
|
||||||
&self.target,
|
&self.target,
|
||||||
|
@ -329,7 +329,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let (deadline, timeout);
|
let (deadline, timeout);
|
||||||
|
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::ExitWithCode(code) => break code,
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
cause = StartCause::Poll;
|
cause = StartCause::Poll;
|
||||||
deadline = None;
|
deadline = None;
|
||||||
|
@ -376,21 +376,22 @@ impl<T: 'static> EventLoop<T> {
|
||||||
requested_resume: deadline,
|
requested_resume: deadline,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::LoopDestroyed,
|
crate::event::Event::LoopDestroyed,
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
|
exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(mut self, callback: F) -> !
|
pub fn run<F>(mut self, callback: F) -> !
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
let exit_code = self.run_return(callback);
|
||||||
::std::process::exit(0);
|
::std::process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
|
fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
|
||||||
|
|
|
@ -62,7 +62,6 @@ pub trait EventHandler: Debug {
|
||||||
|
|
||||||
struct EventLoopHandler<T: 'static> {
|
struct EventLoopHandler<T: 'static> {
|
||||||
callback: Weak<RefCell<dyn FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
|
callback: Weak<RefCell<dyn FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
|
||||||
will_exit: bool,
|
|
||||||
window_target: Rc<RootWindowTarget<T>>,
|
window_target: Rc<RootWindowTarget<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,25 +97,25 @@ impl<T> Debug for EventLoopHandler<T> {
|
||||||
impl<T> EventHandler for EventLoopHandler<T> {
|
impl<T> EventHandler for EventLoopHandler<T> {
|
||||||
fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) {
|
fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) {
|
||||||
self.with_callback(|this, mut callback| {
|
self.with_callback(|this, mut callback| {
|
||||||
(callback)(event.userify(), &this.window_target, control_flow);
|
if let ControlFlow::ExitWithCode(code) = *control_flow {
|
||||||
this.will_exit |= *control_flow == ControlFlow::Exit;
|
let dummy = &mut ControlFlow::ExitWithCode(code);
|
||||||
if this.will_exit {
|
(callback)(event.userify(), &this.window_target, dummy);
|
||||||
*control_flow = ControlFlow::Exit;
|
} else {
|
||||||
|
(callback)(event.userify(), &this.window_target, control_flow);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
|
||||||
self.with_callback(|this, mut callback| {
|
self.with_callback(|this, mut callback| {
|
||||||
let mut will_exit = this.will_exit;
|
|
||||||
for event in this.window_target.p.receiver.try_iter() {
|
for event in this.window_target.p.receiver.try_iter() {
|
||||||
(callback)(Event::UserEvent(event), &this.window_target, control_flow);
|
if let ControlFlow::ExitWithCode(code) = *control_flow {
|
||||||
will_exit |= *control_flow == ControlFlow::Exit;
|
let dummy = &mut ControlFlow::ExitWithCode(code);
|
||||||
if will_exit {
|
(callback)(Event::UserEvent(event), &this.window_target, dummy);
|
||||||
*control_flow = ControlFlow::Exit;
|
} else {
|
||||||
|
(callback)(Event::UserEvent(event), &this.window_target, control_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.will_exit = will_exit;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +159,10 @@ impl Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_exit(&self) -> bool {
|
fn should_exit(&self) -> bool {
|
||||||
*self.control_flow.lock().unwrap() == ControlFlow::Exit
|
matches!(
|
||||||
|
*self.control_flow.lock().unwrap(),
|
||||||
|
ControlFlow::ExitWithCode(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_control_flow_and_update_prev(&self) -> ControlFlow {
|
fn get_control_flow_and_update_prev(&self) -> ControlFlow {
|
||||||
|
@ -268,16 +270,20 @@ impl AppState {
|
||||||
) {
|
) {
|
||||||
*HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler {
|
*HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler {
|
||||||
callback,
|
callback,
|
||||||
will_exit: false,
|
|
||||||
window_target,
|
window_target,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit() {
|
pub fn exit() -> i32 {
|
||||||
HANDLER.set_in_callback(true);
|
HANDLER.set_in_callback(true);
|
||||||
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::LoopDestroyed));
|
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::LoopDestroyed));
|
||||||
HANDLER.set_in_callback(false);
|
HANDLER.set_in_callback(false);
|
||||||
HANDLER.callback.lock().unwrap().take();
|
HANDLER.callback.lock().unwrap().take();
|
||||||
|
if let ControlFlow::ExitWithCode(code) = HANDLER.get_old_and_new_control_flow().1 {
|
||||||
|
code
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launched(app_delegate: &Object) {
|
pub fn launched(app_delegate: &Object) {
|
||||||
|
@ -332,7 +338,7 @@ impl AppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlFlow::Exit => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
|
ControlFlow::ExitWithCode(_) => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
|
||||||
};
|
};
|
||||||
HANDLER.set_in_callback(true);
|
HANDLER.set_in_callback(true);
|
||||||
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::NewEvents(cause)));
|
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::NewEvents(cause)));
|
||||||
|
@ -435,7 +441,7 @@ impl AppState {
|
||||||
}
|
}
|
||||||
HANDLER.update_start_time();
|
HANDLER.update_start_time();
|
||||||
match HANDLER.get_old_and_new_control_flow() {
|
match HANDLER.get_old_and_new_control_flow() {
|
||||||
(ControlFlow::Exit, _) | (_, ControlFlow::Exit) => (),
|
(ControlFlow::ExitWithCode(_), _) | (_, ControlFlow::ExitWithCode(_)) => (),
|
||||||
(old, new) if old == new => (),
|
(old, new) if old == new => (),
|
||||||
(_, ControlFlow::Wait) => HANDLER.waker().stop(),
|
(_, ControlFlow::Wait) => HANDLER.waker().stop(),
|
||||||
(_, ControlFlow::WaitUntil(instant)) => HANDLER.waker().start_at(instant),
|
(_, ControlFlow::WaitUntil(instant)) => HANDLER.waker().start_at(instant),
|
||||||
|
|
|
@ -155,11 +155,11 @@ impl<T> EventLoop<T> {
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
F: 'static + FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
let exit_code = self.run_return(callback);
|
||||||
process::exit(0);
|
process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, callback: F)
|
pub fn run_return<F>(&mut self, callback: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ impl<T> EventLoop<T> {
|
||||||
|
|
||||||
self._callback = Some(Rc::clone(&callback));
|
self._callback = Some(Rc::clone(&callback));
|
||||||
|
|
||||||
autoreleasepool(|| unsafe {
|
let exit_code = autoreleasepool(|| unsafe {
|
||||||
let app = NSApp();
|
let app = NSApp();
|
||||||
assert_ne!(app, nil);
|
assert_ne!(app, nil);
|
||||||
|
|
||||||
|
@ -192,9 +192,11 @@ impl<T> EventLoop<T> {
|
||||||
drop(self._callback.take());
|
drop(self._callback.take());
|
||||||
resume_unwind(panic);
|
resume_unwind(panic);
|
||||||
}
|
}
|
||||||
AppState::exit();
|
AppState::exit()
|
||||||
});
|
});
|
||||||
drop(self._callback.take());
|
drop(self._callback.take());
|
||||||
|
|
||||||
|
exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> Proxy<T> {
|
pub fn create_proxy(&self) -> Proxy<T> {
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl<T: 'static> Runner<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_single_event(&mut self, event: Event<'_, T>, control: &mut root::ControlFlow) {
|
fn handle_single_event(&mut self, event: Event<'_, T>, control: &mut root::ControlFlow) {
|
||||||
let is_closed = *control == root::ControlFlow::Exit;
|
let is_closed = matches!(*control, root::ControlFlow::ExitWithCode(_));
|
||||||
|
|
||||||
(self.event_handler)(event, control);
|
(self.event_handler)(event, control);
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ impl<T: 'static> Shared<T> {
|
||||||
RunnerEnum::Destroyed => return,
|
RunnerEnum::Destroyed => return,
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_closed = *control == root::ControlFlow::Exit;
|
let is_closed = matches!(*control, root::ControlFlow::ExitWithCode(_));
|
||||||
|
|
||||||
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
|
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
|
||||||
// If the runner doesn't exist and this method recurses, it will recurse infinitely
|
// If the runner doesn't exist and this method recurses, it will recurse infinitely
|
||||||
|
@ -456,7 +456,7 @@ impl<T: 'static> Shared<T> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root::ControlFlow::Exit => State::Exit,
|
root::ControlFlow::ExitWithCode(_) => State::Exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
match *self.0.runner.borrow_mut() {
|
match *self.0.runner.borrow_mut() {
|
||||||
|
|
|
@ -188,11 +188,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(event_handler);
|
let exit_code = self.run_return(event_handler);
|
||||||
::std::process::exit(0);
|
::std::process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut event_handler: F)
|
pub fn run_return<F>(&mut self, mut event_handler: F) -> i32
|
||||||
where
|
where
|
||||||
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
|
@ -209,13 +209,13 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
let runner = &self.window_target.p.runner_shared;
|
let runner = &self.window_target.p.runner_shared;
|
||||||
|
|
||||||
unsafe {
|
let exit_code = unsafe {
|
||||||
let mut msg = mem::zeroed();
|
let mut msg = mem::zeroed();
|
||||||
|
|
||||||
runner.poll();
|
runner.poll();
|
||||||
'main: loop {
|
'main: loop {
|
||||||
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
|
||||||
break 'main;
|
break 'main 0;
|
||||||
}
|
}
|
||||||
winuser::TranslateMessage(&msg);
|
winuser::TranslateMessage(&msg);
|
||||||
winuser::DispatchMessageW(&msg);
|
winuser::DispatchMessageW(&msg);
|
||||||
|
@ -225,16 +225,20 @@ impl<T: 'static> EventLoop<T> {
|
||||||
panic::resume_unwind(payload);
|
panic::resume_unwind(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if runner.control_flow() == ControlFlow::Exit && !runner.handling_events() {
|
if let ControlFlow::ExitWithCode(code) = runner.control_flow() {
|
||||||
break 'main;
|
if !runner.handling_events() {
|
||||||
|
break 'main code;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
runner.loop_destroyed();
|
runner.loop_destroyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
runner.reset_runner();
|
runner.reset_runner();
|
||||||
|
exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||||
|
@ -763,7 +767,7 @@ unsafe fn process_control_flow<T: 'static>(runner: &EventLoopRunner<T>) {
|
||||||
Box::into_raw(WaitUntilInstantBox::new(until)) as LPARAM,
|
Box::into_raw(WaitUntilInstantBox::new(until)) as LPARAM,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ControlFlow::Exit => (),
|
ControlFlow::ExitWithCode(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,10 +241,10 @@ impl<T> EventLoopRunner<T> {
|
||||||
let mut event_handler = self.event_handler.take()
|
let mut event_handler = self.event_handler.take()
|
||||||
.expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
|
.expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
|
||||||
|
|
||||||
if control_flow != ControlFlow::Exit {
|
if let ControlFlow::ExitWithCode(code) = control_flow {
|
||||||
event_handler(event, &mut control_flow);
|
event_handler(event, &mut ControlFlow::ExitWithCode(code));
|
||||||
} else {
|
} else {
|
||||||
event_handler(event, &mut ControlFlow::Exit);
|
event_handler(event, &mut control_flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(self.event_handler.replace(Some(event_handler)).is_none());
|
assert!(self.event_handler.replace(Some(event_handler)).is_none());
|
||||||
|
@ -372,10 +372,12 @@ impl<T> EventLoopRunner<T> {
|
||||||
let start_cause = match (init, self.control_flow()) {
|
let start_cause = match (init, self.control_flow()) {
|
||||||
(true, _) => StartCause::Init,
|
(true, _) => StartCause::Init,
|
||||||
(false, ControlFlow::Poll) => StartCause::Poll,
|
(false, ControlFlow::Poll) => StartCause::Poll,
|
||||||
(false, ControlFlow::Exit) | (false, ControlFlow::Wait) => StartCause::WaitCancelled {
|
(false, ControlFlow::ExitWithCode(_)) | (false, ControlFlow::Wait) => {
|
||||||
requested_resume: None,
|
StartCause::WaitCancelled {
|
||||||
start: self.last_events_cleared.get(),
|
requested_resume: None,
|
||||||
},
|
start: self.last_events_cleared.get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
(false, ControlFlow::WaitUntil(requested_resume)) => {
|
(false, ControlFlow::WaitUntil(requested_resume)) => {
|
||||||
if Instant::now() < requested_resume {
|
if Instant::now() < requested_resume {
|
||||||
StartCause::WaitCancelled {
|
StartCause::WaitCancelled {
|
||||||
|
|
Loading…
Add table
Reference in a new issue