api: add ApplicationHandler and matching run APIs

Add a simple `ApplicationHandler` trait since winit is moving towards
trait based API. Add `run_app` group of APIs to accept `&mut impl
ApplicationHandler` deprecating the old `run` APIs.

Part-of: https://github.com/rust-windowing/winit/issues/3432
This commit is contained in:
Kirill Chibisov 2024-02-23 14:37:21 +04:00
parent fc8a008b25
commit d123cd2f8e
18 changed files with 821 additions and 651 deletions

View file

@ -1,22 +1,13 @@
use std::time::Duration;
use crate::{
event::Event,
event_loop::{ActiveEventLoop, EventLoop},
};
/// The return status for `pump_events`
pub enum PumpStatus {
/// Continue running external loop.
Continue,
/// Exit external loop.
Exit(i32),
}
use crate::application::ApplicationHandler;
use crate::event::Event;
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
/// Additional methods on [`EventLoop`] for pumping events within an external event loop
pub trait EventLoopExtPumpEvents {
/// A type provided by the user that can be passed through [`Event::UserEvent`].
type UserEvent;
type UserEvent: 'static;
/// Pump the `EventLoop` to check for and dispatch pending events.
///
@ -113,6 +104,21 @@ pub trait EventLoopExtPumpEvents {
/// If you render outside of Winit you are likely to see window resizing artifacts
/// since MacOS expects applications to render synchronously during any `drawRect`
/// callback.
fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
&mut self,
timeout: Option<Duration>,
app: &mut A,
) -> PumpStatus {
#[allow(deprecated)]
self.pump_events(timeout, |event, event_loop| {
event_loop::dispatch_event_for_app(app, event_loop, event)
})
}
/// See [`pump_app_events`].
///
/// [`pump_app_events`]: Self::pump_app_events
#[deprecated = "use EventLoopExtPumpEvents::pump_app_events"]
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
where
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
@ -128,3 +134,11 @@ impl<T> EventLoopExtPumpEvents for EventLoop<T> {
self.event_loop.pump_events(timeout, event_handler)
}
}
/// The return status for `pump_events`
pub enum PumpStatus {
/// Continue running external loop.
Continue,
/// Exit external loop.
Exit(i32),
}

View file

@ -1,8 +1,7 @@
use crate::{
error::EventLoopError,
event::Event,
event_loop::{ActiveEventLoop, EventLoop},
};
use crate::application::ApplicationHandler;
use crate::error::EventLoopError;
use crate::event::Event;
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
#[cfg(doc)]
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
@ -10,12 +9,19 @@ use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
/// Additional methods on [`EventLoop`] to return control flow to the caller.
pub trait EventLoopExtRunOnDemand {
/// A type provided by the user that can be passed through [`Event::UserEvent`].
type UserEvent;
type UserEvent: 'static;
/// Runs the event loop in the calling thread and calls the given `event_handler` closure
/// to dispatch any window system events.
/// See [`run_app_on_demand`].
///
/// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`) closures
/// [`run_app_on_demand`]: Self::run_app_on_demand
#[deprecated = "use EventLoopExtRunOnDemand::run_app_on_demand"]
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
/// Run the application with the event loop on the calling thread.
///
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`) closures
/// and it is possible to return control back to the caller without
/// consuming the `EventLoop` (by using [`exit()`]) and
/// so the event loop can be re-run after it has exit.
@ -26,11 +32,10 @@ pub trait EventLoopExtRunOnDemand {
///
/// This API is not designed to run an event loop in bursts that you can exit from and return
/// to while maintaining the full state of your application. (If you need something like this
/// you can look at the [`EventLoopExtPumpEvents::pump_events()`] API)
/// you can look at the [`EventLoopExtPumpEvents::pump_app_events()`] API)
///
/// Each time `run_on_demand` is called the `event_handler` can expect to receive a
/// `NewEvents(Init)` and `Resumed` event (even on platforms that have no suspend/resume
/// lifecycle) - which can be used to consistently initialize application state.
/// Each time `run_app_on_demand` is called the startup sequence of `init`, followed by
/// `resume` is being preserved.
///
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
///
@ -40,8 +45,8 @@ pub trait EventLoopExtRunOnDemand {
/// backend it is possible to use `EventLoopExtWebSys::spawn()`[^1] more than once instead).
/// - No [`Window`] state can be carried between separate runs of the event loop.
///
/// You are strongly encouraged to use [`EventLoop::run()`] for portability, unless you specifically need
/// the ability to re-run a single event loop more than once
/// You are strongly encouraged to use [`EventLoop::run_app()`] for portability, unless you
/// specifically need the ability to re-run a single event loop more than once
///
/// # Supported Platforms
/// - Windows
@ -64,9 +69,15 @@ pub trait EventLoopExtRunOnDemand {
///
/// [`exit()`]: ActiveEventLoop::exit()
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
&mut self,
app: &mut A,
) -> Result<(), EventLoopError> {
#[allow(deprecated)]
self.run_on_demand(|event, event_loop| {
event_loop::dispatch_event_for_app(app, event_loop, event)
})
}
}
impl<T> EventLoopExtRunOnDemand for EventLoop<T> {

View file

@ -53,9 +53,10 @@ use std::time::Duration;
#[cfg(web_platform)]
use web_sys::HtmlCanvasElement;
use crate::application::ApplicationHandler;
use crate::cursor::CustomCursorSource;
use crate::event::Event;
use crate::event_loop::{ActiveEventLoop, EventLoop};
use crate::event_loop::{self, ActiveEventLoop, EventLoop};
#[cfg(web_platform)]
use crate::platform_impl::CustomCursorFuture as PlatformCustomCursorFuture;
use crate::platform_impl::PlatformCustomCursorSource;
@ -160,18 +161,18 @@ impl WindowAttributesExtWebSys for WindowAttributes {
/// Additional methods on `EventLoop` that are specific to the web.
pub trait EventLoopExtWebSys {
/// A type provided by the user that can be passed through `Event::UserEvent`.
type UserEvent;
type UserEvent: 'static;
/// Initializes the winit event loop.
///
/// Unlike
#[cfg_attr(
all(web_platform, target_feature = "exception-handling"),
doc = "`run()`"
doc = "`run_app()`"
)]
#[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")),
doc = "[`run()`]"
doc = "[`run_app()`]"
)]
/// [^1], this returns immediately, and doesn't throw an exception in order to
/// satisfy its [`!`] return type.
@ -183,9 +184,15 @@ pub trait EventLoopExtWebSys {
///
#[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")),
doc = "[`run()`]: EventLoop::run()"
doc = "[`run_app()`]: EventLoop::run_app()"
)]
/// [^1]: `run()` is _not_ available on WASM when the target supports `exception-handling`.
/// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`.
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A);
/// See [`spawn_app`].
///
/// [`spawn_app`]: Self::spawn_app
#[deprecated = "use EventLoopExtWebSys::spawn_app"]
fn spawn<F>(self, event_handler: F)
where
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop);
@ -194,6 +201,12 @@ pub trait EventLoopExtWebSys {
impl<T> EventLoopExtWebSys for EventLoop<T> {
type UserEvent = T;
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, mut app: A) {
self.event_loop.spawn(move |event, event_loop| {
event_loop::dispatch_event_for_app(&mut app, event_loop, event)
});
}
fn spawn<F>(self, event_handler: F)
where
F: 'static + FnMut(Event<Self::UserEvent>, &ActiveEventLoop),