floem_winit/platform/
run_on_demand.rs

1use crate::{
2    error::EventLoopError,
3    event::Event,
4    event_loop::{EventLoop, EventLoopWindowTarget},
5};
6
7#[cfg(doc)]
8use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
9
10/// Additional methods on [`EventLoop`] to return control flow to the caller.
11pub trait EventLoopExtRunOnDemand {
12    /// A type provided by the user that can be passed through [`Event::UserEvent`].
13    type UserEvent;
14
15    /// Runs the event loop in the calling thread and calls the given `event_handler` closure
16    /// to dispatch any window system events.
17    ///
18    /// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`) closures
19    /// and it is possible to return control back to the caller without
20    /// consuming the `EventLoop` (by using [`exit()`]) and
21    /// so the event loop can be re-run after it has exit.
22    ///
23    /// It's expected that each run of the loop will be for orthogonal instantiations of your
24    /// Winit application, but internally each instantiation may re-use some common window
25    /// system resources, such as a display server connection.
26    ///
27    /// This API is not designed to run an event loop in bursts that you can exit from and return
28    /// to while maintaining the full state of your application. (If you need something like this
29    /// you can look at the [`EventLoopExtPumpEvents::pump_events()`] API)
30    ///
31    /// Each time `run_on_demand` is called the `event_handler` can expect to receive a
32    /// `NewEvents(Init)` and `Resumed` event (even on platforms that have no suspend/resume
33    /// lifecycle) - which can be used to consistently initialize application state.
34    ///
35    /// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
36    ///
37    /// # Caveats
38    /// - This extension isn't available on all platforms, since it's not always possible to return
39    ///   to the caller (specifically this is impossible on iOS and Web - though with the Web
40    ///   backend it is possible to use `EventLoopExtWebSys::spawn()`[^1] more than once instead).
41    /// - No [`Window`] state can be carried between separate runs of the event loop.
42    ///
43    /// You are strongly encouraged to use [`EventLoop::run()`] for portability, unless you specifically need
44    /// the ability to re-run a single event loop more than once
45    ///
46    /// # Supported Platforms
47    /// - Windows
48    /// - Linux
49    /// - macOS
50    /// - Android
51    ///
52    /// # Unsupported Platforms
53    /// - **Web:**  This API is fundamentally incompatible with the event-based way in which
54    ///   Web browsers work because it's not possible to have a long-running external
55    ///   loop that would block the browser and there is nothing that can be
56    ///   polled to ask for new events. Events are delivered via callbacks based
57    ///   on an event loop that is internal to the browser itself.
58    /// - **iOS:** It's not possible to stop and start an `NSApplication` repeatedly on iOS.
59    ///
60    #[cfg_attr(
61        not(wasm_platform),
62        doc = "[^1]: `spawn()` is only available on `wasm` platforms."
63    )]
64    ///
65    /// [`exit()`]: EventLoopWindowTarget::exit()
66    /// [`set_control_flow()`]: EventLoopWindowTarget::set_control_flow()
67    fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
68    where
69        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>);
70}
71
72impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
73    type UserEvent = T;
74
75    fn run_on_demand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
76    where
77        F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>),
78    {
79        self.event_loop.run_on_demand(event_handler)
80    }
81}