Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
9 changes: 7 additions & 2 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -70,9 +72,12 @@ fn main() -> Result<(), Box<dyn Error>> {
#[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(())
}
45 changes: 18 additions & 27 deletions src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -162,16 +171,14 @@ 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 || {
/// let mut i = 0;
/// 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.
Expand All @@ -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(())
Expand All @@ -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,
Expand Down Expand Up @@ -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()
///
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -413,11 +414,6 @@ impl<A: ?Sized + ApplicationHandler> 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);
Expand Down Expand Up @@ -487,11 +483,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<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);
Expand Down
2 changes: 2 additions & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
39 changes: 3 additions & 36 deletions src/event.rs
Original file line number Diff line number Diff line change
@@ -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))]
Expand Down Expand Up @@ -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.
Expand Down
66 changes: 61 additions & 5 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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.
Expand Down
32 changes: 22 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event>`-based event loop
//! model, since that can't be implemented properly on some platforms (e.g Web, iOS) and works
Expand Down Expand Up @@ -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");
Expand All @@ -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<dyn std::error::Error>> {
//! // 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.
Expand All @@ -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(())
//! }
//! ```
//!
Expand Down Expand Up @@ -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.
Expand Down
Loading
Loading