From a52f755ce8dfffe53329163364908937c780057d Mon Sep 17 00:00:00 2001 From: multisn8 Date: Tue, 11 Jan 2022 01:23:20 +0100 Subject: [PATCH] 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 --- CHANGELOG.md | 4 ++ src/event_loop.rs | 37 +++++++++++++++--- src/lib.rs | 5 ++- src/platform/run_return.rs | 9 ++++- src/platform_impl/android/mod.rs | 16 ++++---- src/platform_impl/ios/app_state.rs | 4 +- src/platform_impl/linux/mod.rs | 17 ++++----- .../linux/wayland/event_loop/mod.rs | 33 ++++++++-------- src/platform_impl/linux/x11/mod.rs | 13 ++++--- src/platform_impl/macos/app_state.rs | 38 +++++++++++-------- src/platform_impl/macos/event_loop.rs | 12 +++--- src/platform_impl/web/event_loop/runner.rs | 6 +-- src/platform_impl/windows/event_loop.rs | 22 ++++++----- .../windows/event_loop/runner.rs | 16 ++++---- 14 files changed, 140 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c55c07a..d7ccaba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) - Fix linking to the `ColorSync` framework on macOS 10.7, and in newer Rust versions. diff --git a/src/event_loop.rs b/src/event_loop.rs index edc5670a..17c01f5f 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -64,9 +64,9 @@ impl fmt::Debug for EventLoopWindowTarget { /// /// ## Persistency /// 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 -/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset -/// the control flow to `Poll`. +/// given run loop. The only exception to this is `ExitWithCode` which, once set, cannot be unset. +/// Changes are **not** persistent between multiple calls to `run_return` - issuing a new call will +/// reset the control flow to `Poll`. /// /// [events_cleared]: crate::event::Event::RedrawEventsCleared #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -86,9 +86,29 @@ pub enum ControlFlow { /// arrives or the given time is reached. WaitUntil(Instant), /// 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 - /// in the `control_flow` parameter being reset to `Exit`. - Exit, + /// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will + /// result in the `control_flow` parameter being reset to `ExitWithCode`. + /// + /// 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 { @@ -145,6 +165,11 @@ impl EventLoop { /// /// 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 #[inline] pub fn run(self, event_handler: F) -> ! diff --git a/src/lib.rs b/src/lib.rs index 9b549302..13b3c9ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,8 @@ //! 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 //! 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 -//! entire program terminates. +//! [`ControlFlow`]`::`[`ExitWithCode`] (which [`ControlFlow`]`::`[`Exit`] aliases to), at which +//! point [`Event`]`::`[`LoopDestroyed`] is emitted and the entire program terminates. //! //! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator`-based event loop //! 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 //! [`ControlFlow`]: event_loop::ControlFlow //! [`Exit`]: event_loop::ControlFlow::Exit +//! [`ExitWithCode`]: event_loop::ControlFlow::ExitWithCode //! [`Window`]: window::Window //! [`WindowId`]: window::WindowId //! [`WindowBuilder`]: window::WindowBuilder diff --git a/src/platform/run_return.rs b/src/platform/run_return.rs index 932d9e38..1c2fa623 100644 --- a/src/platform/run_return.rs +++ b/src/platform/run_return.rs @@ -33,7 +33,12 @@ pub trait EventLoopExtRunReturn { /// 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. - fn run_return(&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(&mut self, event_handler: F) -> i32 where F: FnMut( Event<'_, Self::UserEvent>, @@ -45,7 +50,7 @@ pub trait EventLoopExtRunReturn { impl EventLoopExtRunReturn for EventLoop { type UserEvent = T; - fn run_return(&mut self, event_handler: F) + fn run_return(&mut self, event_handler: F) -> i32 where F: FnMut( Event<'_, Self::UserEvent>, diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 0691bcc1..dae27493 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -73,10 +73,10 @@ pub struct EventLoop { macro_rules! call_event_handler { ( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{ - if $cf != ControlFlow::Exit { - $event_handler($event, $window_target, &mut $cf); + if let ControlFlow::ExitWithCode(code) = $cf { + $event_handler($event, $window_target, &mut ControlFlow::ExitWithCode(code)); } else { - $event_handler($event, $window_target, &mut ControlFlow::Exit); + $event_handler($event, $window_target, &mut $cf); } }}; } @@ -103,11 +103,11 @@ impl EventLoop { F: 'static + FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget, &mut ControlFlow), { - self.run_return(event_handler); - ::std::process::exit(0); + let exit_code = self.run_return(event_handler); + ::std::process::exit(exit_code); } - pub fn run_return(&mut self, mut event_handler: F) + pub fn run_return(&mut self, mut event_handler: F) -> i32 where F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget, &mut ControlFlow), { @@ -339,7 +339,7 @@ impl EventLoop { ); match control_flow { - ControlFlow::Exit => { + ControlFlow::ExitWithCode(code) => { self.first_event = poll( self.looper .poll_once_timeout(Duration::from_millis(0)) @@ -349,7 +349,7 @@ impl EventLoop { start: Instant::now(), requested_resume: None, }; - break 'event_loop; + break 'event_loop code; } ControlFlow::Poll => { self.first_event = poll( diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index 0d388c50..43330b0b 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -296,7 +296,7 @@ impl AppState { }; (waiting_event_handler, event) } - (ControlFlow::Exit, _) => bug!("unexpected `ControlFlow` `Exit`"), + (ControlFlow::ExitWithCode(_), _) => bug!("unexpected `ControlFlow` `Exit`"), s => bug!("`EventHandler` unexpectedly woke up {:?}", s), }; @@ -451,7 +451,7 @@ impl AppState { }); self.waker.start() } - (_, ControlFlow::Exit) => { + (_, ControlFlow::ExitWithCode(_)) => { // https://developer.apple.com/library/archive/qa/qa1561/_index.html // it is not possible to quit an iOS app gracefully and programatically warn!("`ControlFlow::Exit` ignored on iOS"); diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 953fca1d..b8e23365 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -655,7 +655,7 @@ impl EventLoop { x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy) } - pub fn run_return(&mut self, callback: F) + pub fn run_return(&mut self, callback: F) -> i32 where F: FnMut(crate::event::Event<'_, T>, &RootELW, &mut ControlFlow), { @@ -741,16 +741,13 @@ fn sticky_exit_callback( ) where F: FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { - // make ControlFlow::Exit sticky by providing a dummy - // control flow reference if it is already Exit. - let mut dummy = ControlFlow::Exit; - let cf = if *control_flow == ControlFlow::Exit { - &mut dummy + // 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 { - control_flow - }; - // user callback - callback(evt, target, cf) + callback(evt, target, control_flow) + } } fn assert_is_main_thread(suggested_method: &str) { diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 9e644103..7228fc5e 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -206,11 +206,11 @@ impl EventLoop { where F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget, &mut ControlFlow) + 'static, { - self.run_return(callback); - process::exit(0) + let exit_code = self.run_return(callback); + process::exit(exit_code); } - pub fn run_return(&mut self, mut callback: F) + pub fn run_return(&mut self, mut callback: F) -> i32 where F: FnMut(Event<'_, T>, &RootEventLoopWindowTarget, &mut ControlFlow), { @@ -235,7 +235,8 @@ impl EventLoop { // 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 // 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 // user events indirectly via callback to the user. for user_event in pending_user_events.borrow_mut().drain(..) { @@ -431,20 +432,19 @@ impl EventLoop { _ => unreachable!(), }; - if let Ok(dispatched) = queue.dispatch_pending(state, |_, _, _| unimplemented!()) { - dispatched > 0 - } else { - break; + match queue.dispatch_pending(state, |_, _, _| unimplemented!()) { + Ok(dispatched) => dispatched > 0, + Err(error) => break error.raw_os_error().unwrap_or(1), } }; match control_flow { - ControlFlow::Exit => break, + ControlFlow::ExitWithCode(code) => break code, ControlFlow::Poll => { // Non-blocking dispatch. let timeout = Duration::from_millis(0); - if self.loop_dispatch(Some(timeout)).is_err() { - break; + if let Err(error) = self.loop_dispatch(Some(timeout)) { + break error.raw_os_error().unwrap_or(1); } callback( @@ -460,8 +460,8 @@ impl EventLoop { None }; - if self.loop_dispatch(timeout).is_err() { - break; + if let Err(error) = self.loop_dispatch(timeout) { + break error.raw_os_error().unwrap_or(1); } callback( @@ -483,8 +483,8 @@ impl EventLoop { Duration::from_millis(0) }; - if self.loop_dispatch(Some(duration)).is_err() { - break; + if let Err(error) = self.loop_dispatch(Some(duration)) { + break error.raw_os_error().unwrap_or(1); } let now = Instant::now(); @@ -510,9 +510,10 @@ impl EventLoop { } } } - } + }; callback(Event::LoopDestroyed, &self.window_target, &mut control_flow); + exit_code } #[inline] diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 27c92c46..38180862 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -258,7 +258,7 @@ impl EventLoop { &self.target } - pub fn run_return(&mut self, mut callback: F) + pub fn run_return(&mut self, mut callback: F) -> i32 where F: FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { @@ -266,7 +266,7 @@ impl EventLoop { let mut events = Events::with_capacity(8); let mut cause = StartCause::Init; - loop { + let exit_code = loop { sticky_exit_callback( crate::event::Event::NewEvents(cause), &self.target, @@ -329,7 +329,7 @@ impl EventLoop { let (deadline, timeout); match control_flow { - ControlFlow::Exit => break, + ControlFlow::ExitWithCode(code) => break code, ControlFlow::Poll => { cause = StartCause::Poll; deadline = None; @@ -376,21 +376,22 @@ impl EventLoop { requested_resume: deadline, }; } - } + }; callback( crate::event::Event::LoopDestroyed, &self.target, &mut control_flow, ); + exit_code } pub fn run(mut self, callback: F) -> ! where F: 'static + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { - self.run_return(callback); - ::std::process::exit(0); + let exit_code = self.run_return(callback); + ::std::process::exit(exit_code); } fn drain_events(&mut self, callback: &mut F, control_flow: &mut ControlFlow) diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs index 3c8c0535..d421f1a2 100644 --- a/src/platform_impl/macos/app_state.rs +++ b/src/platform_impl/macos/app_state.rs @@ -62,7 +62,6 @@ pub trait EventHandler: Debug { struct EventLoopHandler { callback: Weak, &RootWindowTarget, &mut ControlFlow)>>, - will_exit: bool, window_target: Rc>, } @@ -98,25 +97,25 @@ impl Debug for EventLoopHandler { impl EventHandler for EventLoopHandler { fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) { self.with_callback(|this, mut callback| { - (callback)(event.userify(), &this.window_target, control_flow); - this.will_exit |= *control_flow == ControlFlow::Exit; - if this.will_exit { - *control_flow = ControlFlow::Exit; + if let ControlFlow::ExitWithCode(code) = *control_flow { + let dummy = &mut ControlFlow::ExitWithCode(code); + (callback)(event.userify(), &this.window_target, dummy); + } else { + (callback)(event.userify(), &this.window_target, control_flow); } }); } fn handle_user_events(&mut self, control_flow: &mut ControlFlow) { self.with_callback(|this, mut callback| { - let mut will_exit = this.will_exit; for event in this.window_target.p.receiver.try_iter() { - (callback)(Event::UserEvent(event), &this.window_target, control_flow); - will_exit |= *control_flow == ControlFlow::Exit; - if will_exit { - *control_flow = ControlFlow::Exit; + if let ControlFlow::ExitWithCode(code) = *control_flow { + let dummy = &mut ControlFlow::ExitWithCode(code); + (callback)(Event::UserEvent(event), &this.window_target, dummy); + } 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 { - *self.control_flow.lock().unwrap() == ControlFlow::Exit + matches!( + *self.control_flow.lock().unwrap(), + ControlFlow::ExitWithCode(_) + ) } fn get_control_flow_and_update_prev(&self) -> ControlFlow { @@ -268,16 +270,20 @@ impl AppState { ) { *HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler { callback, - will_exit: false, window_target, })); } - pub fn exit() { + pub fn exit() -> i32 { HANDLER.set_in_callback(true); HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::LoopDestroyed)); HANDLER.set_in_callback(false); 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) { @@ -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.handle_nonuser_event(EventWrapper::StaticEvent(Event::NewEvents(cause))); @@ -435,7 +441,7 @@ impl AppState { } HANDLER.update_start_time(); match HANDLER.get_old_and_new_control_flow() { - (ControlFlow::Exit, _) | (_, ControlFlow::Exit) => (), + (ControlFlow::ExitWithCode(_), _) | (_, ControlFlow::ExitWithCode(_)) => (), (old, new) if old == new => (), (_, ControlFlow::Wait) => HANDLER.waker().stop(), (_, ControlFlow::WaitUntil(instant)) => HANDLER.waker().start_at(instant), diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 25976213..4b3d641a 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -155,11 +155,11 @@ impl EventLoop { where F: 'static + FnMut(Event<'_, T>, &RootWindowTarget, &mut ControlFlow), { - self.run_return(callback); - process::exit(0); + let exit_code = self.run_return(callback); + process::exit(exit_code); } - pub fn run_return(&mut self, callback: F) + pub fn run_return(&mut self, callback: F) -> i32 where F: FnMut(Event<'_, T>, &RootWindowTarget, &mut ControlFlow), { @@ -176,7 +176,7 @@ impl EventLoop { self._callback = Some(Rc::clone(&callback)); - autoreleasepool(|| unsafe { + let exit_code = autoreleasepool(|| unsafe { let app = NSApp(); assert_ne!(app, nil); @@ -192,9 +192,11 @@ impl EventLoop { drop(self._callback.take()); resume_unwind(panic); } - AppState::exit(); + AppState::exit() }); drop(self._callback.take()); + + exit_code } pub fn create_proxy(&self) -> Proxy { diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index 4c51a8a3..f0591240 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -84,7 +84,7 @@ impl Runner { } 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); @@ -409,7 +409,7 @@ impl Shared { 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 // If the runner doesn't exist and this method recurses, it will recurse infinitely @@ -456,7 +456,7 @@ impl Shared { ), } } - root::ControlFlow::Exit => State::Exit, + root::ControlFlow::ExitWithCode(_) => State::Exit, }; match *self.0.runner.borrow_mut() { diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index b7bc1cd4..24183154 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -188,11 +188,11 @@ impl EventLoop { where F: 'static + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { - self.run_return(event_handler); - ::std::process::exit(0); + let exit_code = self.run_return(event_handler); + ::std::process::exit(exit_code); } - pub fn run_return(&mut self, mut event_handler: F) + pub fn run_return(&mut self, mut event_handler: F) -> i32 where F: FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { @@ -209,13 +209,13 @@ impl EventLoop { let runner = &self.window_target.p.runner_shared; - unsafe { + let exit_code = unsafe { let mut msg = mem::zeroed(); runner.poll(); 'main: loop { if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { - break 'main; + break 'main 0; } winuser::TranslateMessage(&msg); winuser::DispatchMessageW(&msg); @@ -225,16 +225,20 @@ impl EventLoop { panic::resume_unwind(payload); } - if runner.control_flow() == ControlFlow::Exit && !runner.handling_events() { - break 'main; + if let ControlFlow::ExitWithCode(code) = runner.control_flow() { + if !runner.handling_events() { + break 'main code; + } } } - } + }; unsafe { runner.loop_destroyed(); } + runner.reset_runner(); + exit_code } pub fn create_proxy(&self) -> EventLoopProxy { @@ -763,7 +767,7 @@ unsafe fn process_control_flow(runner: &EventLoopRunner) { Box::into_raw(WaitUntilInstantBox::new(until)) as LPARAM, ); } - ControlFlow::Exit => (), + ControlFlow::ExitWithCode(_) => (), } } diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index cf327674..a82c57a6 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -241,10 +241,10 @@ impl EventLoopRunner { let mut event_handler = self.event_handler.take() .expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)"); - if control_flow != ControlFlow::Exit { - event_handler(event, &mut control_flow); + if let ControlFlow::ExitWithCode(code) = control_flow { + event_handler(event, &mut ControlFlow::ExitWithCode(code)); } else { - event_handler(event, &mut ControlFlow::Exit); + event_handler(event, &mut control_flow); } assert!(self.event_handler.replace(Some(event_handler)).is_none()); @@ -372,10 +372,12 @@ impl EventLoopRunner { let start_cause = match (init, self.control_flow()) { (true, _) => StartCause::Init, (false, ControlFlow::Poll) => StartCause::Poll, - (false, ControlFlow::Exit) | (false, ControlFlow::Wait) => StartCause::WaitCancelled { - requested_resume: None, - start: self.last_events_cleared.get(), - }, + (false, ControlFlow::ExitWithCode(_)) | (false, ControlFlow::Wait) => { + StartCause::WaitCancelled { + requested_resume: None, + start: self.last_events_cleared.get(), + } + } (false, ControlFlow::WaitUntil(requested_resume)) => { if Instant::now() < requested_resume { StartCause::WaitCancelled {