winit/event_loop: Add register_app and run_app_never_return
To allow users to explicitly choose the run semantics that they want.
This commit is contained in:
parent
f69b601abb
commit
4c5bf0ee08
16 changed files with 102 additions and 71 deletions
|
|
@ -500,10 +500,6 @@ impl EventLoop {
|
||||||
input_status
|
input_status
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
self.run_app_on_demand(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
mut app: A,
|
||||||
|
|
|
||||||
|
|
@ -232,10 +232,6 @@ impl EventLoop {
|
||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
self.run_app_on_demand(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
|
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
|
||||||
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
||||||
// time and so a layered implementation would end up using a lot of CPU due to
|
// time and so a layered implementation would end up using a lot of CPU due to
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
pub mod never_return;
|
||||||
pub mod pump_events;
|
pub mod pump_events;
|
||||||
|
pub mod register;
|
||||||
pub mod run_on_demand;
|
pub mod run_on_demand;
|
||||||
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
|
||||||
14
winit-core/src/event_loop/never_return.rs
Normal file
14
winit-core/src/event_loop/never_return.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
use crate::application::ApplicationHandler;
|
||||||
|
|
||||||
|
/// Additional methods on `EventLoop` for platforms whose run method never return.
|
||||||
|
pub trait EventLoopExtNeverReturn {
|
||||||
|
/// Run the event loop and call `process::exit` once finished.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **iOS**: This registers the callbacks with the system and calls `UIApplicationMain`.
|
||||||
|
/// - **macOS**: Unimplemented (TODO: Should call `NSApplicationMain`).
|
||||||
|
/// - **Android/Orbital/Wayland/Windows/X11**: Unsupported.
|
||||||
|
/// - **Web**: Impossible to support properly.
|
||||||
|
fn run_app_never_return<A: ApplicationHandler + 'static>(self, app: A) -> !;
|
||||||
|
}
|
||||||
17
winit-core/src/event_loop/register.rs
Normal file
17
winit-core/src/event_loop/register.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
use crate::application::ApplicationHandler;
|
||||||
|
|
||||||
|
/// Additional methods on `EventLoop` that registers it with the system event loop.
|
||||||
|
pub trait EventLoopExtRegister {
|
||||||
|
/// Initialize and register the application with the system's event loop, such that the
|
||||||
|
/// callbacks will be run later.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **Web**: Once the event loop has been destroyed, it's possible to reinitialize another
|
||||||
|
/// event loop by calling this function again. This can be useful if you want to recreate the
|
||||||
|
/// event loop while the WebAssembly module is still loaded. For example, this can be used to
|
||||||
|
/// recreate the event loop when switching between tabs on a single page application.
|
||||||
|
/// - **iOS/macOS**: Unimplemented.
|
||||||
|
/// - **Android/Orbital/Wayland/Windows/X11**: Unsupported.
|
||||||
|
fn register_app<A: ApplicationHandler + 'static>(self, app: A);
|
||||||
|
}
|
||||||
|
|
@ -6,15 +6,13 @@ use crate::{
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(rustdoc::broken_intra_doc_links)] // FIXME(madsmtm): Fix these.
|
|
||||||
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
||||||
pub trait EventLoopExtRunOnDemand {
|
pub trait EventLoopExtRunOnDemand {
|
||||||
/// Run the application with the event loop on the calling thread.
|
/// Run the application with the event loop on the calling thread.
|
||||||
///
|
///
|
||||||
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
|
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
|
||||||
/// state and it is possible to return control back to the caller without
|
/// state and it is possible to return control back to the caller without consuming the
|
||||||
/// consuming the `EventLoop` (by using [`exit()`]) and
|
/// `EventLoop` (by using [`exit()`]) and so the event loop can be re-run after it has exit.
|
||||||
/// so the event loop can be re-run after it has exit.
|
|
||||||
///
|
///
|
||||||
/// It's expected that each run of the loop will be for orthogonal instantiations of your
|
/// It's expected that each run of the loop will be for orthogonal instantiations of your
|
||||||
/// Winit application, but internally each instantiation may re-use some common window
|
/// Winit application, but internally each instantiation may re-use some common window
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,10 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, mut app: A) -> Result<(), EventLoopError> {
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
|
&mut self,
|
||||||
|
mut app: A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
let mut start_cause = StartCause::Init;
|
let mut start_cause = StartCause::Init;
|
||||||
loop {
|
loop {
|
||||||
app.new_events(&self.window_target, start_cause);
|
app.new_events(&self.window_target, start_cause);
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Require `'static` for correctness, we won't be able to `Drop` the user's state otherwise.
|
// Require `'static` for correctness, we won't be able to `Drop` the user's state otherwise.
|
||||||
pub fn run_app<A: ApplicationHandler + 'static>(self, app: A) -> ! {
|
pub fn run_app_never_return<A: ApplicationHandler + 'static>(self, app: A) -> ! {
|
||||||
let application: Option<Retained<UIApplication>> =
|
let application: Option<Retained<UIApplication>> =
|
||||||
unsafe { msg_send![UIApplication::class(), sharedApplication] };
|
unsafe { msg_send![UIApplication::class(), sharedApplication] };
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,6 @@ impl EventLoop {
|
||||||
Ok(event_loop)
|
Ok(event_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
self.run_app_on_demand(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
mut app: A,
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,8 @@ impl EventLoop {
|
||||||
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
|
EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler + 'static>(self, app: A) -> Result<(), EventLoopError> {
|
pub fn register_app<A: ApplicationHandler + 'static>(self, app: A) {
|
||||||
self.elw.run(Box::new(app));
|
self.elw.run(Box::new(app));
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_target(&self) -> &dyn RootActiveEventLoop {
|
pub fn window_target(&self) -> &dyn RootActiveEventLoop {
|
||||||
|
|
|
||||||
|
|
@ -247,10 +247,6 @@ impl EventLoop {
|
||||||
ActiveEventLoop::from_ref(&self.runner)
|
ActiveEventLoop::from_ref(&self.runner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
self.run_app_on_demand(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
mut app: A,
|
||||||
|
|
|
||||||
|
|
@ -427,10 +427,6 @@ impl EventLoop {
|
||||||
&self.event_processor.target
|
&self.event_processor.target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
self.run_app_on_demand(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
mut app: A,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::single_match)]
|
#![allow(clippy::single_match)]
|
||||||
|
|
||||||
// Limit this example to only compatible platforms.
|
// Limit this example to only compatible platforms.
|
||||||
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform,))]
|
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform, orbital_platform))]
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
@ -93,7 +93,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(windows_platform, macos_platform, x11_platform, wayland_platform,)))]
|
#[cfg(not(any(
|
||||||
|
windows_platform,
|
||||||
|
macos_platform,
|
||||||
|
x11_platform,
|
||||||
|
wayland_platform,
|
||||||
|
orbital_platform
|
||||||
|
)))]
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("This example is not supported on this platform");
|
println!("This example is not supported on this platform");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ changelog entry.
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `EventLoopExtRegister::register_app` for being explicit about how the event loop runs on Web.
|
||||||
|
- Add `EventLoopExtNeverReturn::run_app_never_return` for being explicit about how the event loop runs on iOS.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- On Web, avoid throwing an exception in `EventLoop::run_app`, instead preferring to return to the caller.
|
- On Web, avoid throwing an exception in `EventLoop::run_app`, instead preferring to return to the caller.
|
||||||
|
|
|
||||||
|
|
@ -178,22 +178,28 @@ impl EventLoop {
|
||||||
/// The semantics of this function can be a bit confusing, because the way different platforms
|
/// The semantics of this function can be a bit confusing, because the way different platforms
|
||||||
/// control their event loop varies significantly.
|
/// control their event loop varies significantly.
|
||||||
///
|
///
|
||||||
/// On most platforms (Android, X11, Wayland, Windows, macOS), this blocks the caller, runs the
|
/// On most platforms (Android, macOS, Orbital, X11, Wayland, Windows), this blocks the caller,
|
||||||
/// event loop internally, and then returns once [`ActiveEventLoop::exit`] is called.
|
/// runs the event loop internally, and then returns once [`ActiveEventLoop::exit`] is called.
|
||||||
|
/// See [`run_app_on_demand`] for more detailed semantics.
|
||||||
///
|
///
|
||||||
/// On iOS, this will register the application handler, and then call [`UIApplicationMain`]
|
/// On iOS, this will register the application handler, and then call [`UIApplicationMain`]
|
||||||
/// (which is the only way to run the system event loop), which never returns to the caller
|
/// (which is the only way to run the system event loop), which never returns to the caller
|
||||||
/// (the process instead exits after the handler has been dropped).
|
/// (the process instead exits after the handler has been dropped). See also
|
||||||
|
/// [`run_app_never_return`].
|
||||||
///
|
///
|
||||||
/// On the web, this works by registering the application handler, and then immediately
|
/// On the web, this works by registering the application handler, and then immediately
|
||||||
/// returning to the caller. This is necessary because WebAssembly (and JavaScript) is always
|
/// returning to the caller. This is necessary because WebAssembly (and JavaScript) is always
|
||||||
/// executed in the context of the browser's own (internal) event loop, and thus we need to
|
/// executed in the context of the browser's own (internal) event loop, and thus we need to
|
||||||
/// return to avoid blocking that and allow events to later be delivered asynchronously.
|
/// return to avoid blocking that and allow events to later be delivered asynchronously. See
|
||||||
|
/// also [`register_app`].
|
||||||
///
|
///
|
||||||
/// If you call this function inside `fn main`, you usually do not need to think about these
|
/// If you call this function inside `fn main`, you usually do not need to think about these
|
||||||
/// details.
|
/// details.
|
||||||
///
|
///
|
||||||
/// [`UIApplicationMain`]: https://developer.apple.com/documentation/uikit/uiapplicationmain(_:_:_:_:)-1yub7?language=objc
|
/// [`UIApplicationMain`]: https://developer.apple.com/documentation/uikit/uiapplicationmain(_:_:_:_:)-1yub7?language=objc
|
||||||
|
/// [`run_app_on_demand`]: crate::event_loop::run_on_demand::EventLoopExtRunOnDemand::run_app_on_demand
|
||||||
|
/// [`run_app_never_return`]: crate::event_loop::never_return::EventLoopExtNeverReturn::run_app_never_return
|
||||||
|
/// [`register_app`]: crate::event_loop::register::EventLoopExtRegister::register_app
|
||||||
///
|
///
|
||||||
/// ## Static
|
/// ## Static
|
||||||
///
|
///
|
||||||
|
|
@ -204,40 +210,37 @@ impl EventLoop {
|
||||||
/// To be clear, you should avoid doing e.g. `event_loop.run_app(&mut app)?`, and prefer
|
/// To be clear, you should avoid doing e.g. `event_loop.run_app(&mut app)?`, and prefer
|
||||||
/// `event_loop.run_app(app)?` instead.
|
/// `event_loop.run_app(app)?` instead.
|
||||||
///
|
///
|
||||||
/// If this requirement is prohibitive for you, consider using
|
/// If this requirement is prohibitive for you, consider using [`run_app_on_demand`] instead
|
||||||
#[cfg_attr(
|
/// (though note that this is not available on iOS and web).
|
||||||
any(
|
|
||||||
windows_platform,
|
|
||||||
macos_platform,
|
|
||||||
android_platform,
|
|
||||||
x11_platform,
|
|
||||||
wayland_platform,
|
|
||||||
docsrs,
|
|
||||||
),
|
|
||||||
doc = "[`EventLoopExtRunOnDemand::run_app_on_demand`](crate::event_loop::run_on_demand::EventLoopExtRunOnDemand::run_app_on_demand)"
|
|
||||||
)]
|
|
||||||
#[cfg_attr(
|
|
||||||
not(any(
|
|
||||||
windows_platform,
|
|
||||||
macos_platform,
|
|
||||||
android_platform,
|
|
||||||
x11_platform,
|
|
||||||
wayland_platform,
|
|
||||||
docsrs,
|
|
||||||
)),
|
|
||||||
doc = "`EventLoopExtRunOnDemand::run_app_on_demand`"
|
|
||||||
)]
|
|
||||||
/// instead (though note that this is not available on iOS and web).
|
|
||||||
///
|
|
||||||
/// ## Platform-specific
|
|
||||||
///
|
|
||||||
/// - **Web** Once your handler has been dropped, it's possible to reinitialize another event
|
|
||||||
/// loop by calling this function again. This can be useful if you want to recreate the event
|
|
||||||
/// loop while the WebAssembly module is still loaded. For example, this can be used to
|
|
||||||
/// recreate the event loop when switching between tabs on a single page application.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run_app<A: ApplicationHandler + 'static>(self, app: A) -> Result<(), EventLoopError> {
|
#[allow(unused_mut)]
|
||||||
self.event_loop.run_app(app)
|
pub fn run_app<A: ApplicationHandler + 'static>(
|
||||||
|
mut self,
|
||||||
|
mut app: A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
#[cfg(any(
|
||||||
|
windows_platform,
|
||||||
|
macos_platform,
|
||||||
|
android_platform,
|
||||||
|
orbital_platform,
|
||||||
|
x11_platform,
|
||||||
|
wayland_platform,
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
let result = self.event_loop.run_app_on_demand(&mut app);
|
||||||
|
// SAFETY: unsure that the state is dropped before the exit from the event loop.
|
||||||
|
drop(app);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
#[cfg(web_platform)]
|
||||||
|
{
|
||||||
|
self.event_loop.register_app(app);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(ios_platform)]
|
||||||
|
{
|
||||||
|
self.event_loop.run_app_never_return(app)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
||||||
|
|
@ -342,6 +345,7 @@ impl winit_core::event_loop::pump_events::EventLoopExtPumpEvents for EventLoop {
|
||||||
windows_platform,
|
windows_platform,
|
||||||
macos_platform,
|
macos_platform,
|
||||||
android_platform,
|
android_platform,
|
||||||
|
orbital_platform,
|
||||||
x11_platform,
|
x11_platform,
|
||||||
wayland_platform,
|
wayland_platform,
|
||||||
docsrs,
|
docsrs,
|
||||||
|
|
@ -352,6 +356,13 @@ impl winit_core::event_loop::run_on_demand::EventLoopExtRunOnDemand for EventLoo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(web_platform, docsrs))]
|
||||||
|
impl winit_core::event_loop::register::EventLoopExtRegister for EventLoop {
|
||||||
|
fn register_app<A: ApplicationHandler + 'static>(self, app: A) {
|
||||||
|
self.event_loop.register_app(app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(android_platform)]
|
#[cfg(android_platform)]
|
||||||
impl winit_android::EventLoopExtAndroid for EventLoop {
|
impl winit_android::EventLoopExtAndroid for EventLoop {
|
||||||
fn android_app(&self) -> &winit_android::activity::AndroidApp {
|
fn android_app(&self) -> &winit_android::activity::AndroidApp {
|
||||||
|
|
|
||||||
|
|
@ -147,10 +147,6 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
|
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: A,
|
app: A,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue