diff --git a/examples/application.rs b/examples/application.rs index 8b63a089f9..1adf25ecff 100644 --- a/examples/application.rs +++ b/examples/application.rs @@ -592,18 +592,18 @@ impl ApplicationHandler for Application { } } - #[cfg(not(android_platform))] - fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) { - // We must drop the context here. - self.context = None; - } - #[cfg(target_os = "macos")] fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> { Some(self) } } +impl Drop for Application { + fn drop(&mut self) { + info!("Application exited"); + } +} + #[cfg(target_os = "macos")] impl ApplicationHandlerExtMacOS for Application { fn standard_key_binding( diff --git a/examples/window.rs b/examples/window.rs index c0db0bcf77..b6077270b1 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -11,6 +11,8 @@ use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; +#[path = "util/tracing.rs"] +mod tracing; #[derive(Default, Debug)] struct App { @@ -70,9 +72,12 @@ fn main() -> Result<(), Box> { #[cfg(web_platform)] console_error_panic_hook::set_once(); + tracing::init(); + let event_loop = EventLoop::new()?; - let mut app = App::default(); // For alternative loop run options see `pump_events` and `run_on_demand` examples. - event_loop.run_app(&mut app).map_err(Into::into) + event_loop.run_app(App::default())?; + + Ok(()) } diff --git a/src/application.rs b/src/application.rs index 91013fb20e..0020ca9929 100644 --- a/src/application.rs +++ b/src/application.rs @@ -6,7 +6,17 @@ use crate::event_loop::ActiveEventLoop; use crate::platform::macos::ApplicationHandlerExtMacOS; use crate::window::WindowId; -/// The handler of the application events. +/// The handler of application-level events. +/// +/// See [the top-level docs] for example usage, and [`EventLoop::run_app`] for an overview of when +/// events are delivered. +/// +/// This is [dropped] when the event loop is shut down. Note that this only works if you're passing +/// the entire state to [`EventLoop::run_app`] (passing `&mut app` won't work). +/// +/// [the top-level docs]: crate +/// [`EventLoop::run_app`]: crate::event_loop::EventLoop::run_app +/// [dropped]: std::ops::Drop pub trait ApplicationHandler { /// Emitted when new events arrive from the OS to be processed. /// @@ -57,7 +67,6 @@ pub trait ApplicationHandler { /// /// [`resumed()`]: Self::resumed() /// [`suspended()`]: Self::suspended() - /// [`exiting()`]: Self::exiting() fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } @@ -162,8 +171,6 @@ pub trait ApplicationHandler { /// /// let (sender, receiver) = mpsc::channel(); /// - /// let mut app = MyApp { receiver }; - /// /// // Send an event in a loop /// let proxy = event_loop.create_proxy(); /// let background_thread = thread::spawn(move || { @@ -171,7 +178,7 @@ pub trait ApplicationHandler { /// loop { /// println!("sending: {i}"); /// if sender.send(i).is_err() { - /// // Stop sending once `MyApp` is dropped + /// // Stop sending once the receiver is dropped /// break; /// } /// // Trigger the wake-up _after_ we placed the event in the channel. @@ -182,9 +189,8 @@ pub trait ApplicationHandler { /// } /// }); /// - /// event_loop.run_app(&mut app)?; + /// event_loop.run_app(MyApp { receiver })?; /// - /// drop(app); /// background_thread.join().unwrap(); /// /// Ok(()) @@ -203,6 +209,10 @@ pub trait ApplicationHandler { ); /// Emitted when the OS sends an event to a device. + /// + /// For this to be called, it must be enabled with [`EventLoop::listen_device_events`]. + /// + /// [`EventLoop::listen_device_events`]: crate::event_loop::EventLoop::listen_device_events fn device_event( &mut self, event_loop: &dyn ActiveEventLoop, @@ -258,7 +268,7 @@ pub trait ApplicationHandler { /// to the user. This is a good place to stop refreshing UI, running animations and other visual /// things. It is driven by Android's [`onStop()`] method. /// - /// After this event the application either receives [`resumed()`] again, or [`exiting()`]. + /// After this event the application either receives [`resumed()`] again, or will exit. /// /// [`onStop()`]: https://developer.android.com/reference/android/app/Activity#onStop() /// @@ -268,7 +278,6 @@ pub trait ApplicationHandler { /// /// [`resumed()`]: Self::resumed() /// [`suspended()`]: Self::suspended() - /// [`exiting()`]: Self::exiting() fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } @@ -310,14 +319,6 @@ pub trait ApplicationHandler { let _ = event_loop; } - /// Emitted when the event loop is being shut down. - /// - /// This is irreversible - if this method is called, it is guaranteed that the event loop - /// will exit right after. - fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { - let _ = event_loop; - } - /// Emitted when the application has received a memory warning. /// /// ## Platform-specific @@ -413,11 +414,6 @@ impl ApplicationHandler for &mut A { (**self).destroy_surfaces(event_loop); } - #[inline] - fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { - (**self).exiting(event_loop); - } - #[inline] fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).memory_warning(event_loop); @@ -487,11 +483,6 @@ impl ApplicationHandler for Box { (**self).destroy_surfaces(event_loop); } - #[inline] - fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) { - (**self).exiting(event_loop); - } - #[inline] fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { (**self).memory_warning(event_loop); diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 15f1ec35d9..af998577cc 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -228,6 +228,8 @@ changelog entry. - Remove `Window::inner_position`, use the new `Window::surface_position` instead. - Remove `CustomCursorExtWeb`, use the `CustomCursorSource`. - Remove `CustomCursor::from_rgba`, use `CustomCursorSource` instead. +- Removed `ApplicationHandler::exited`, the event loop being shut down can now be listened to in + the `Drop` impl on the application handler. ### Fixed diff --git a/src/event.rs b/src/event.rs index b32522d6ff..2873a19375 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,39 +1,4 @@ //! The event enums and assorted supporting types. -//! -//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get -//! processed and used to modify the program state. For more details, see the root-level -//! documentation. -//! -//! Some of these events represent different "parts" of a traditional event-handling loop. You could -//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this: -//! -//! ```rust,ignore -//! let mut start_cause = StartCause::Init; -//! -//! while !elwt.exiting() { -//! app.new_events(event_loop, start_cause); -//! -//! for event in (window events, user events, device events) { -//! // This will pick the right method on the application based on the event. -//! app.handle_event(event_loop, event); -//! } -//! -//! for window_id in (redraw windows) { -//! app.window_event(event_loop, window_id, RedrawRequested); -//! } -//! -//! app.about_to_wait(event_loop); -//! start_cause = wait_if_necessary(); -//! } -//! -//! app.exiting(event_loop); -//! ``` -//! -//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully -//! describes what happens in what order. -//! -//! [`EventLoop::run_app(...)`]: crate::event_loop::EventLoop::run_app -//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil use std::path::PathBuf; use std::sync::{Mutex, Weak}; #[cfg(not(web_platform))] @@ -641,10 +606,12 @@ impl FingerId { /// /// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera /// or first-person game controls. Many physical actions, such as mouse movement, can produce both -/// device and window events. Because window events typically arise from virtual devices +/// device and [window events]. Because window events typically arise from virtual devices /// (corresponding to GUI pointers and keyboard focus) the device IDs may not match. /// /// Note that these events are delivered regardless of input focus. +/// +/// [window events]: WindowEvent #[derive(Clone, Copy, Debug, PartialEq)] pub enum DeviceEvent { /// Change in physical position of a pointing device. diff --git a/src/event_loop.rs b/src/event_loop.rs index 796489ad33..715d123de4 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -186,7 +186,56 @@ impl EventLoop { impl EventLoop { /// Run the application with the event loop on the calling thread. /// - /// See the [`set_control_flow()`] docs on how to change the event loop's behavior. + /// ## Event loop flow + /// + /// This function internally handles the different parts of a traditional event-handling loop. + /// You can imagine this method as being implemented like this: + /// + /// ```rust,ignore + /// let mut start_cause = StartCause::Init; + /// + /// // Run the event loop. + /// while !event_loop.exiting() { + /// // Wake up. + /// app.new_events(event_loop, start_cause); + /// + /// // Indicate that surfaces can now safely be created. + /// if start_cause == StartCause::Init { + /// app.can_create_surfaces(event_loop); + /// } + /// + /// // Handle proxy wake-up event. + /// if event_loop.proxy_wake_up_set() { + /// event_loop.proxy_wake_up_clear(); + /// app.proxy_wake_up(event_loop); + /// } + /// + /// // Handle actions done by the user / system such as moving the cursor, resizing the + /// // window, changing the window theme, etc. + /// for event in event_loop.events() { + /// match event { + /// window event => app.window_event(event_loop, window_id, event), + /// device event => app.device_event(event_loop, device_id, event), + /// } + /// } + /// + /// // Handle redraws. + /// for window_id in event_loop.pending_redraws() { + /// app.window_event(event_loop, window_id, WindowEvent::RedrawRequested); + /// } + /// + /// // Done handling events, wait until we're woken up again. + /// app.about_to_wait(event_loop); + /// start_cause = event_loop.wait_if_necessary(); + /// } + /// + /// // Finished running, drop application state. + /// drop(app); + /// ``` + /// + /// This is of course a very coarse-grained overview, and leaves out timing details like + /// [`ControlFlow::WaitUntil`] and life-cycle methods like [`ApplicationHandler::resumed`], but + /// it should give you an idea of how things fit together. /// /// ## Platform-specific /// @@ -381,14 +430,21 @@ pub trait ActiveEventLoop: AsAny + fmt::Debug { /// Gets the current [`ControlFlow`]. fn control_flow(&self) -> ControlFlow; - /// This exits the event loop. + /// Stop the event loop. /// - /// See [`exiting`][crate::application::ApplicationHandler::exiting]. + /// ## Platform-specific + /// + /// ### iOS + /// + /// It is not possible to programmatically exit/quit an application on iOS, so this function is + /// a no-op there. See also [this technical Q&A][qa1561]. + /// + /// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html fn exit(&self); - /// Returns if the [`EventLoop`] is about to stop. + /// Returns whether the [`EventLoop`] is about to stop. /// - /// See [`exit()`][Self::exit]. + /// Set by [`exit()`][Self::exit]. fn exiting(&self) -> bool; /// Gets a persistent reference to the underlying platform display. diff --git a/src/lib.rs b/src/lib.rs index 68ce042e5e..b5a308762a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,9 +26,8 @@ //! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a //! [`DeviceEvent`]. //! -//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will -//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and -//! will run until [`exit()`] is used, at which point [`exiting()`] is called. +//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will dispatch events +//! for every [`Window`] that was created with that particular [`EventLoop`]. //! //! 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 @@ -58,10 +57,19 @@ //! //! impl ApplicationHandler for App { //! fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { +//! // The event loop has launched, and we can initialize our UI state. +//! +//! // Create a simple window with default attributes. //! self.window = Some(event_loop.create_window(WindowAttributes::default()).unwrap()); //! } //! -//! fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, id: WindowId, event: WindowEvent) { +//! fn window_event( +//! &mut self, +//! event_loop: &dyn ActiveEventLoop, +//! id: WindowId, +//! event: WindowEvent, +//! ) { +//! // Called by `EventLoop::run_app` when a new event happens on the window. //! match event { //! WindowEvent::CloseRequested => { //! println!("The close button was pressed; stopping"); @@ -82,15 +90,18 @@ //! // applications which do not always need to. Applications that redraw continuously //! // can render here instead. //! self.window.as_ref().unwrap().request_redraw(); -//! } +//! }, //! _ => (), //! } //! } //! } //! //! # // Intentionally use `fn main` for clarity -//! fn main() { -//! let event_loop = EventLoop::new().unwrap(); +//! fn main() -> Result<(), Box> { +//! // Create a new event loop. +//! let event_loop = EventLoop::new()?; +//! +//! // Configure settings before launching. //! //! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't //! // dispatched any events. This is ideal for games and similar applications. @@ -101,8 +112,10 @@ //! // input, and uses significantly less power/CPU time than ControlFlow::Poll. //! event_loop.set_control_flow(ControlFlow::Wait); //! -//! let mut app = App::default(); -//! event_loop.run_app(&mut app); +//! // Launch and begin running the event loop. +//! event_loop.run_app(App::default())?; +//! +//! Ok(()) //! } //! ``` //! @@ -261,7 +274,6 @@ //! [`Window::id()`]: window::Window::id //! [`WindowEvent`]: event::WindowEvent //! [`DeviceEvent`]: event::DeviceEvent -//! [`exiting()`]: crate::application::ApplicationHandler::exiting //! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle //! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle //! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland. diff --git a/src/platform/ios.rs b/src/platform/ios.rs index d9438d35a4..5cbf85898b 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -85,12 +85,9 @@ //! //! - applicationDidBecomeActive is Resumed //! - applicationWillResignActive is Suspended -//! - applicationWillTerminate is LoopExiting +//! - applicationWillTerminate corresponds to `Drop`ping the application handler. //! -//! Keep in mind that after LoopExiting event is received every attempt to draw with -//! opengl will result in segfault. -//! -//! Also note that app may not receive the LoopExiting event if suspended; it might be SIGKILL'ed. +//! Note that an app may not receive the `Drop` event if suspended; it might be SIGKILL'ed. //! //! ## Custom `UIApplicationDelegate` //! diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 49b99e6779..7c751bcdc0 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -546,8 +546,6 @@ impl EventLoop { if self.exiting() { self.loop_running = false; - app.exiting(&self.window_target); - PumpStatus::Exit(0) } else { PumpStatus::Continue diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index 5a2f33fb2f..e260ef49d6 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -157,6 +157,7 @@ impl AppState { pub fn will_terminate(self: &Rc, _notification: &NSNotification) { trace_scope!("NSApplicationWillTerminateNotification"); // TODO: Notify every window that it will be destroyed, like done in iOS? + self.event_handler.terminate(); self.internal_exit(); } @@ -164,10 +165,10 @@ impl AppState { /// of the given closure. pub fn set_event_handler( &self, - handler: &mut dyn ApplicationHandler, + handler: impl ApplicationHandler, closure: impl FnOnce() -> R, ) -> R { - self.event_handler.set(handler, closure) + self.event_handler.set(Box::new(handler), closure) } pub fn event_loop_proxy(&self) -> &Arc { @@ -202,10 +203,6 @@ impl AppState { /// NOTE: that if the `NSApplication` has been launched then that state is preserved, /// and we won't need to re-launch the app if subsequent EventLoops are run. pub fn internal_exit(self: &Rc) { - self.with_handler(|app, event_loop| { - app.exiting(event_loop); - }); - self.set_is_running(false); self.set_stop_on_redraw(false); self.set_stop_before_wait(false); diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 3b0a03eac3..5baecb7e4c 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -285,10 +285,10 @@ impl EventLoop { // redundant wake ups. pub fn run_app_on_demand( &mut self, - mut app: A, + app: A, ) -> Result<(), EventLoopError> { self.app_state.clear_exit(); - self.app_state.set_event_handler(&mut app, || { + self.app_state.set_event_handler(app, || { autoreleasepool(|_| { // clear / normalize pump_events state self.app_state.set_wait_timeout(None); @@ -324,9 +324,9 @@ impl EventLoop { pub fn pump_app_events( &mut self, timeout: Option, - mut app: A, + app: A, ) -> PumpStatus { - self.app_state.set_event_handler(&mut app, || { + self.app_state.set_event_handler(app, || { autoreleasepool(|_| { // As a special case, if the application hasn't been launched yet then we at least // run the loop until it has fully launched. diff --git a/src/platform_impl/apple/event_handler.rs b/src/platform_impl/apple/event_handler.rs index a68d4bb8e6..81345f5129 100644 --- a/src/platform_impl/apple/event_handler.rs +++ b/src/platform_impl/apple/event_handler.rs @@ -8,10 +8,10 @@ use crate::application::ApplicationHandler; #[derive(Default)] pub(crate) struct EventHandler { /// This can be in the following states: - /// - Not registered by the event loop (None). + /// - Not registered by the event loop, or terminated (None). /// - Present (Some(handler)). /// - Currently executing the handler / in use (RefCell borrowed). - inner: RefCell>, + inner: RefCell>>, } impl fmt::Debug for EventHandler { @@ -37,7 +37,7 @@ impl EventHandler { /// from within the closure. pub(crate) fn set<'handler, R>( &self, - app: &'handler mut dyn ApplicationHandler, + app: Box, closure: impl FnOnce() -> R, ) -> R { // SAFETY: We extend the lifetime of the handler here so that we can @@ -48,8 +48,8 @@ impl EventHandler { // extended beyond `'handler`. let handler = unsafe { mem::transmute::< - &'handler mut dyn ApplicationHandler, - &'static mut dyn ApplicationHandler, + Box, + Box, >(app) }; @@ -71,10 +71,13 @@ impl EventHandler { fn drop(&mut self) { match self.0.inner.try_borrow_mut().as_deref_mut() { Ok(data @ Some(_)) => { - *data = None; + let handler = data.take(); + // Explicitly `Drop` the application handler. + drop(handler); }, Ok(None) => { - tracing::error!("tried to clear handler, but no handler was set"); + // Allowed, happens if the handler was cleared manually + // elsewhere (such as in `applicationWillTerminate:`). }, Err(_) => { // Note: This is not expected to ever happen, this @@ -110,16 +113,16 @@ impl EventHandler { matches!(self.inner.try_borrow().as_deref(), Ok(Some(_))) } - pub(crate) fn handle(&self, callback: impl FnOnce(&mut dyn ApplicationHandler)) { + pub(crate) fn handle(&self, callback: impl FnOnce(&mut (dyn ApplicationHandler + '_))) { match self.inner.try_borrow_mut().as_deref_mut() { - Ok(Some(user_app)) => { + Ok(Some(ref mut user_app)) => { // It is important that we keep the reference borrowed here, // so that `in_use` can properly detect that the handler is // still in use. // // If the handler unwinds, the `RefMut` will ensure that the // handler is no longer borrowed. - callback(*user_app); + callback(&mut **user_app); }, Ok(None) => { // `NSApplication`, our app state and this handler are all @@ -133,4 +136,21 @@ impl EventHandler { }, } } + + pub(crate) fn terminate(&self) { + match self.inner.try_borrow_mut().as_deref_mut() { + Ok(data @ Some(_)) => { + let handler = data.take(); + // Explicitly `Drop` the application handler. + drop(handler); + }, + Ok(None) => { + // When terminating, we expect the application handler to still be registered. + tracing::error!("tried to clear handler, but no handler was set"); + }, + Err(_) => { + panic!("tried to clear handler while an event is currently being handled"); + }, + } + } } diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 4ba639f5a5..ca497cb5fd 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -305,8 +305,8 @@ pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Retained(self, mut app: A) -> ! { + pub fn run_app(self, app: A) -> ! { let application: Option> = unsafe { msg_send![UIApplication::class(), sharedApplication] }; assert!( @@ -259,7 +259,7 @@ impl EventLoop { fn _NSGetArgv() -> *mut *mut *mut c_char; } - app_state::launch(self.mtm, &mut app, || unsafe { + app_state::launch(self.mtm, app, || unsafe { UIApplicationMain( *_NSGetArgc(), NonNull::new(*_NSGetArgv()).unwrap(), diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 061ff3c33a..8024df16c5 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -203,11 +203,10 @@ impl EventLoop { if !self.exiting() { self.poll_events_with_timeout(timeout, &mut app); } + if let Some(code) = self.exit_code() { self.loop_running = false; - app.exiting(&self.active_event_loop); - PumpStatus::Exit(code) } else { PumpStatus::Continue diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 33b5060bc7..44c68e8ec8 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -498,8 +498,6 @@ impl EventLoop { if let Some(code) = self.exit_code() { self.loop_running = false; - app.exiting(self.window_target()); - PumpStatus::Exit(code) } else { PumpStatus::Continue diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 29b0e43070..0eef8a8db5 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -650,8 +650,6 @@ impl EventLoop { } } - app.exiting(&self.window_target); - Ok(()) } diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index 3a6db3a6b0..fb87586fae 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -158,7 +158,6 @@ impl Runner { Event::Resumed => self.app.resumed(&self.event_loop), Event::CreateSurfaces => self.app.can_create_surfaces(&self.event_loop), Event::AboutToWait => self.app.about_to_wait(&self.event_loop), - Event::LoopExiting => self.app.exiting(&self.event_loop), } } } @@ -639,7 +638,9 @@ impl Shared { self.apply_control_flow(); // We don't call `handle_loop_destroyed` here because we don't need to // perform cleanup when the Web browser is going to destroy the page. - self.handle_event(Event::LoopExiting); + // + // We do want to run the application handler's `Drop` impl. + *self.0.runner.borrow_mut() = RunnerEnum::Destroyed; } // handle_event takes in events and either queues them or applies a callback @@ -737,7 +738,6 @@ impl Shared { } fn handle_loop_destroyed(&self) { - self.handle_event(Event::LoopExiting); let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut()); *self.0.page_transition_event_handle.borrow_mut() = None; *self.0.on_mouse_move.borrow_mut() = None; @@ -879,6 +879,5 @@ pub(crate) enum Event { CreateSurfaces, Resumed, AboutToWait, - LoopExiting, UserWakeUp, } diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index ab6516544a..2f86701c65 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -333,7 +333,6 @@ impl EventLoopRunner { self.call_new_events(true); self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop)); self.last_events_cleared.set(Instant::now()); - self.call_event_handler(|app, event_loop| app.exiting(event_loop)); }, (_, Uninitialized) => panic!("cannot move state to Uninitialized"), @@ -341,9 +340,7 @@ impl EventLoopRunner { (Idle, HandlingMainEvents) => { self.call_new_events(false); }, - (Idle, Destroyed) => { - self.call_event_handler(|app, event_loop| app.exiting(event_loop)); - }, + (Idle, Destroyed) => {}, (HandlingMainEvents, Idle) => { // This is always the last event we dispatch before waiting for new events @@ -353,7 +350,6 @@ impl EventLoopRunner { (HandlingMainEvents, Destroyed) => { self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop)); self.last_events_cleared.set(Instant::now()); - self.call_event_handler(|app, event_loop| app.exiting(event_loop)); }, (Destroyed, _) => panic!("cannot move state from Destroyed"),