Skip to content

Commit f9e99a1

Browse files
committed
Drop application handler on run loop exit
Instead of the explicit `ApplicationHandler::exiting` event.
1 parent 4687942 commit f9e99a1

20 files changed

Lines changed: 170 additions & 143 deletions

File tree

examples/application.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -578,18 +578,18 @@ impl ApplicationHandler for Application {
578578
}
579579
}
580580

581-
#[cfg(not(android_platform))]
582-
fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) {
583-
// We must drop the context here.
584-
self.context = None;
585-
}
586-
587581
#[cfg(target_os = "macos")]
588582
fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> {
589583
Some(self)
590584
}
591585
}
592586

587+
impl Drop for Application {
588+
fn drop(&mut self) {
589+
info!("Application exited");
590+
}
591+
}
592+
593593
#[cfg(target_os = "macos")]
594594
impl ApplicationHandlerExtMacOS for Application {
595595
fn standard_key_binding(

examples/window.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use winit::window::{Window, WindowAttributes, WindowId};
1111

1212
#[path = "util/fill.rs"]
1313
mod fill;
14+
#[path = "util/tracing.rs"]
15+
mod tracing;
1416

1517
#[derive(Default)]
1618
struct App {
@@ -70,9 +72,12 @@ fn main() -> Result<(), Box<dyn Error>> {
7072
#[cfg(web_platform)]
7173
console_error_panic_hook::set_once();
7274

75+
tracing::init();
76+
7377
let event_loop = EventLoop::new()?;
74-
let mut app = App::default();
7578

7679
// For alternative loop run options see `pump_events` and `run_on_demand` examples.
77-
event_loop.run_app(&mut app).map_err(Into::into)
80+
event_loop.run_app(App::default())?;
81+
82+
Ok(())
7883
}

src/application.rs

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,17 @@ use crate::event_loop::ActiveEventLoop;
66
use crate::platform::macos::ApplicationHandlerExtMacOS;
77
use crate::window::WindowId;
88

9-
/// The handler of the application events.
9+
/// The handler of application-level events.
10+
///
11+
/// See [the top-level docs] for example usage, and [`EventLoop::run_app`] for an overview of when
12+
/// events are delivered.
13+
///
14+
/// This is [dropped] when the event loop is shut down. Note that this only works if you're passing
15+
/// the entire state to [`EventLoop::run_app`] (passing `&mut app` won't work).
16+
///
17+
/// [the top-level docs]: crate
18+
/// [`EventLoop::run_app`]: crate::event_loop::EventLoop::run_app
19+
/// [dropped]: std::ops::Drop
1020
pub trait ApplicationHandler {
1121
/// Emitted when new events arrive from the OS to be processed.
1222
///
@@ -57,7 +67,6 @@ pub trait ApplicationHandler {
5767
///
5868
/// [`resumed()`]: Self::resumed()
5969
/// [`suspended()`]: Self::suspended()
60-
/// [`exiting()`]: Self::exiting()
6170
fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) {
6271
let _ = event_loop;
6372
}
@@ -162,16 +171,14 @@ pub trait ApplicationHandler {
162171
///
163172
/// let (sender, receiver) = mpsc::channel();
164173
///
165-
/// let mut app = MyApp { receiver };
166-
///
167174
/// // Send an event in a loop
168175
/// let proxy = event_loop.create_proxy();
169176
/// let background_thread = thread::spawn(move || {
170177
/// let mut i = 0;
171178
/// loop {
172179
/// println!("sending: {i}");
173180
/// if sender.send(i).is_err() {
174-
/// // Stop sending once `MyApp` is dropped
181+
/// // Stop sending once the receiver is dropped
175182
/// break;
176183
/// }
177184
/// // Trigger the wake-up _after_ we placed the event in the channel.
@@ -182,9 +189,8 @@ pub trait ApplicationHandler {
182189
/// }
183190
/// });
184191
///
185-
/// event_loop.run_app(&mut app)?;
192+
/// event_loop.run_app(MyApp { receiver })?;
186193
///
187-
/// drop(app);
188194
/// background_thread.join().unwrap();
189195
///
190196
/// Ok(())
@@ -203,6 +209,10 @@ pub trait ApplicationHandler {
203209
);
204210

205211
/// Emitted when the OS sends an event to a device.
212+
///
213+
/// For this to be called, it must be enabled with [`EventLoop::listen_device_events`].
214+
///
215+
/// [`EventLoop::listen_device_events`]: crate::event_loop::EventLoop::listen_device_events
206216
fn device_event(
207217
&mut self,
208218
event_loop: &dyn ActiveEventLoop,
@@ -258,7 +268,7 @@ pub trait ApplicationHandler {
258268
/// to the user. This is a good place to stop refreshing UI, running animations and other visual
259269
/// things. It is driven by Android's [`onStop()`] method.
260270
///
261-
/// After this event the application either receives [`resumed()`] again, or [`exiting()`].
271+
/// After this event the application either receives [`resumed()`] again, or will exit.
262272
///
263273
/// [`onStop()`]: https://developer.android.com/reference/android/app/Activity#onStop()
264274
///
@@ -268,7 +278,6 @@ pub trait ApplicationHandler {
268278
///
269279
/// [`resumed()`]: Self::resumed()
270280
/// [`suspended()`]: Self::suspended()
271-
/// [`exiting()`]: Self::exiting()
272281
fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) {
273282
let _ = event_loop;
274283
}
@@ -310,14 +319,6 @@ pub trait ApplicationHandler {
310319
let _ = event_loop;
311320
}
312321

313-
/// Emitted when the event loop is being shut down.
314-
///
315-
/// This is irreversible - if this method is called, it is guaranteed that the event loop
316-
/// will exit right after.
317-
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
318-
let _ = event_loop;
319-
}
320-
321322
/// Emitted when the application has received a memory warning.
322323
///
323324
/// ## Platform-specific
@@ -413,11 +414,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
413414
(**self).destroy_surfaces(event_loop);
414415
}
415416

416-
#[inline]
417-
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
418-
(**self).exiting(event_loop);
419-
}
420-
421417
#[inline]
422418
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
423419
(**self).memory_warning(event_loop);
@@ -487,11 +483,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
487483
(**self).destroy_surfaces(event_loop);
488484
}
489485

490-
#[inline]
491-
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
492-
(**self).exiting(event_loop);
493-
}
494-
495486
#[inline]
496487
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
497488
(**self).memory_warning(event_loop);

src/changelog/unreleased.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ changelog entry.
221221
`ButtonSource` as part of the new pointer event overhaul.
222222
- Remove `Force::altitude_angle`.
223223
- Removed `Window::inner_position`, use the new `Window::surface_position` instead.
224+
- Removed `ApplicationHandler::exited`, the event loop being shut down can now be listened to in
225+
the `Drop` impl on the application handler.
224226

225227
### Fixed
226228

src/event.rs

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,4 @@
11
//! The event enums and assorted supporting types.
2-
//!
3-
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
4-
//! processed and used to modify the program state. For more details, see the root-level
5-
//! documentation.
6-
//!
7-
//! Some of these events represent different "parts" of a traditional event-handling loop. You could
8-
//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this:
9-
//!
10-
//! ```rust,ignore
11-
//! let mut start_cause = StartCause::Init;
12-
//!
13-
//! while !elwt.exiting() {
14-
//! app.new_events(event_loop, start_cause);
15-
//!
16-
//! for event in (window events, user events, device events) {
17-
//! // This will pick the right method on the application based on the event.
18-
//! app.handle_event(event_loop, event);
19-
//! }
20-
//!
21-
//! for window_id in (redraw windows) {
22-
//! app.window_event(event_loop, window_id, RedrawRequested);
23-
//! }
24-
//!
25-
//! app.about_to_wait(event_loop);
26-
//! start_cause = wait_if_necessary();
27-
//! }
28-
//!
29-
//! app.exiting(event_loop);
30-
//! ```
31-
//!
32-
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
33-
//! describes what happens in what order.
34-
//!
35-
//! [`EventLoop::run_app(...)`]: crate::event_loop::EventLoop::run_app
36-
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
372
use std::path::PathBuf;
383
use std::sync::{Mutex, Weak};
394
#[cfg(not(web_platform))]
@@ -99,11 +64,6 @@ pub(crate) enum Event {
9964
/// [`ApplicationHandler::about_to_wait()`]: crate::application::ApplicationHandler::about_to_wait()
10065
AboutToWait,
10166

102-
/// See [`ApplicationHandler::exiting()`] for details.
103-
///
104-
/// [`ApplicationHandler::exiting()`]: crate::application::ApplicationHandler::exiting()
105-
LoopExiting,
106-
10767
/// See [`ApplicationHandler::memory_warning()`] for details.
10868
///
10969
/// [`ApplicationHandler::memory_warning()`]: crate::application::ApplicationHandler::memory_warning()
@@ -701,10 +661,12 @@ impl FingerId {
701661
///
702662
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera
703663
/// or first-person game controls. Many physical actions, such as mouse movement, can produce both
704-
/// device and window events. Because window events typically arise from virtual devices
664+
/// device and [window events]. Because window events typically arise from virtual devices
705665
/// (corresponding to GUI pointers and keyboard focus) the device IDs may not match.
706666
///
707667
/// Note that these events are delivered regardless of input focus.
668+
///
669+
/// [window events]: WindowEvent
708670
#[derive(Clone, Copy, Debug, PartialEq)]
709671
pub enum DeviceEvent {
710672
/// Change in physical position of a pointing device.
@@ -1236,7 +1198,6 @@ mod tests {
12361198
let wid = WindowId::from_raw(0);
12371199
x(NewEvents(event::StartCause::Init));
12381200
x(AboutToWait);
1239-
x(LoopExiting);
12401201
x(Suspended);
12411202
x(Resumed);
12421203

src/event_loop.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,56 @@ impl EventLoop {
197197
impl EventLoop {
198198
/// Run the application with the event loop on the calling thread.
199199
///
200-
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
200+
/// ## Event loop flow
201+
///
202+
/// This function internally handles the different parts of a traditional event-handling loop.
203+
/// You can imagine this method as being implemented like this:
204+
///
205+
/// ```rust,ignore
206+
/// let mut start_cause = StartCause::Init;
207+
///
208+
/// // Run the event loop.
209+
/// while !event_loop.exiting() {
210+
/// // Wake up.
211+
/// app.new_events(event_loop, start_cause);
212+
///
213+
/// // Indicate that surfaces can now safely be created.
214+
/// if start_cause == StartCause::Init {
215+
/// app.can_create_surfaces(event_loop);
216+
/// }
217+
///
218+
/// // Handle proxy wake-up event.
219+
/// if event_loop.proxy_wake_up_set() {
220+
/// event_loop.proxy_wake_up_clear();
221+
/// app.proxy_wake_up(event_loop);
222+
/// }
223+
///
224+
/// // Handle actions done by the user / system such as moving the cursor, resizing the
225+
/// // window, changing the window theme, etc.
226+
/// for event in event_loop.events() {
227+
/// match event {
228+
/// window event => app.window_event(event_loop, window_id, event),
229+
/// device event => app.device_event(event_loop, device_id, event),
230+
/// }
231+
/// }
232+
///
233+
/// // Handle redraws.
234+
/// for window_id in event_loop.pending_redraws() {
235+
/// app.window_event(event_loop, window_id, WindowEvent::RedrawRequested);
236+
/// }
237+
///
238+
/// // Done handling events, wait until we're woken up again.
239+
/// app.about_to_wait(event_loop);
240+
/// start_cause = event_loop.wait_if_necessary();
241+
/// }
242+
///
243+
/// // Finished running, drop application state.
244+
/// drop(app);
245+
/// ```
246+
///
247+
/// This is of course a very coarse-grained overview, and leaves out timing details like
248+
/// [`ControlFlow::WaitUntil`] and life-cycle methods like [`ApplicationHandler::resumed`], but
249+
/// it should give you an idea of how things fit together.
201250
///
202251
/// ## Platform-specific
203252
///
@@ -392,14 +441,21 @@ pub trait ActiveEventLoop: AsAny {
392441
/// Gets the current [`ControlFlow`].
393442
fn control_flow(&self) -> ControlFlow;
394443

395-
/// This exits the event loop.
444+
/// Stop the event loop.
396445
///
397-
/// See [`exiting`][crate::application::ApplicationHandler::exiting].
446+
/// ## Platform-specific
447+
///
448+
/// ### iOS
449+
///
450+
/// It is not possible to programmatically exit/quit an application on iOS, so this function is
451+
/// a no-op there. See also [this technical Q&A][qa1561].
452+
///
453+
/// [qa1561]: https://developer.apple.com/library/archive/qa/qa1561/_index.html
398454
fn exit(&self);
399455

400-
/// Returns if the [`EventLoop`] is about to stop.
456+
/// Returns whether the [`EventLoop`] is about to stop.
401457
///
402-
/// See [`exit()`][Self::exit].
458+
/// Set by [`exit()`][Self::exit].
403459
fn exiting(&self) -> bool;
404460

405461
/// Gets a persistent reference to the underlying platform display.

0 commit comments

Comments
 (0)