Skip to main content

rio_window/
event_loop.rs

1//! The [`EventLoop`] struct and assorted supporting types, including
2//! [`ControlFlow`].
3//!
4//! If you want to send custom events to the event loop, use
5//! [`EventLoop::create_proxy`] to acquire an [`EventLoopProxy`] and call its
6//! [`send_event`][EventLoopProxy::send_event] method.
7//!
8//! See the root-level documentation for information on how to create and use an event loop to
9//! handle events.
10use std::marker::PhantomData;
11#[cfg(any(x11_platform, wayland_platform))]
12use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
13use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
14use std::{error, fmt};
15
16#[cfg(not(web_platform))]
17use std::time::{Duration, Instant};
18#[cfg(web_platform)]
19use web_time::{Duration, Instant};
20
21use crate::application::ApplicationHandler;
22use crate::error::{EventLoopError, OsError};
23use crate::event::Event;
24use crate::monitor::MonitorHandle;
25use crate::platform_impl;
26use crate::window::Theme;
27use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
28
29/// Provides a way to retrieve events from the system and from the windows that were registered to
30/// the events loop.
31///
32/// An `EventLoop` can be seen more or less as a "context". Calling [`EventLoop::new`]
33/// initializes everything that will be required to create windows. For example on Linux creating
34/// an event loop opens a connection to the X or Wayland server.
35///
36/// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs.
37///
38/// Note that this cannot be shared across threads (due to platform-dependant logic
39/// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access,
40/// the [`Window`] created from this _can_ be sent to an other thread, and the
41/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
42///
43/// [`Window`]: crate::window::Window
44pub struct EventLoop<T: 'static> {
45    pub(crate) event_loop: platform_impl::EventLoop<T>,
46    pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
47}
48
49/// Target that associates windows with an [`EventLoop`].
50///
51/// This type exists to allow you to create new windows while Winit executes
52/// your callback.
53pub struct ActiveEventLoop {
54    pub(crate) p: platform_impl::ActiveEventLoop,
55    pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
56}
57
58/// Object that allows building the event loop.
59///
60/// This is used to make specifying options that affect the whole application
61/// easier. But note that constructing multiple event loops is not supported.
62///
63/// This can be created using [`EventLoop::new`] or [`EventLoop::with_user_event`].
64#[derive(Default)]
65pub struct EventLoopBuilder<T: 'static> {
66    pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
67    _p: PhantomData<T>,
68}
69
70static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
71
72impl EventLoopBuilder<()> {
73    /// Start building a new event loop.
74    #[inline]
75    #[deprecated = "use `EventLoop::builder` instead"]
76    pub fn new() -> Self {
77        EventLoop::builder()
78    }
79}
80
81impl<T> EventLoopBuilder<T> {
82    /// Builds a new event loop.
83    ///
84    /// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
85    /// and only once per application.***
86    ///
87    /// Calling this function will result in display backend initialisation.
88    ///
89    /// ## Panics
90    ///
91    /// Attempting to create the event loop off the main thread will panic. This
92    /// restriction isn't strictly necessary on all platforms, but is imposed to
93    /// eliminate any nasty surprises when porting to platforms that require it.
94    /// `EventLoopBuilderExt::any_thread` functions are exposed in the relevant
95    /// [`platform`] module if the target platform supports creating an event
96    /// loop on any thread.
97    ///
98    /// ## Platform-specific
99    ///
100    /// - **Wayland/X11:** to prevent running under `Wayland` or `X11` unset `WAYLAND_DISPLAY` or
101    ///   `DISPLAY` respectively when building the event loop.
102    /// - **Android:** must be configured with an `AndroidApp` from `android_main()` by calling
103    ///   [`.with_android_app(app)`] before calling `.build()`, otherwise it'll panic.
104    ///
105    /// [`platform`]: crate::platform
106    #[cfg_attr(
107        android_platform,
108        doc = "[`.with_android_app(app)`]: \
109               crate::platform::android::EventLoopBuilderExtAndroid::with_android_app"
110    )]
111    #[cfg_attr(
112        not(android_platform),
113        doc = "[`.with_android_app(app)`]: #only-available-on-android"
114    )]
115    #[inline]
116    pub fn build(&mut self) -> Result<EventLoop<T>, EventLoopError> {
117        let _span = tracing::debug_span!("rio_window::EventLoopBuilder::build").entered();
118
119        if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
120            return Err(EventLoopError::RecreationAttempt);
121        }
122
123        // Certain platforms accept a mutable reference in their API.
124        #[allow(clippy::unnecessary_mut_passed)]
125        Ok(EventLoop {
126            event_loop: platform_impl::EventLoop::new(&mut self.platform_specific)?,
127            _marker: PhantomData,
128        })
129    }
130
131    #[cfg(web_platform)]
132    pub(crate) fn allow_event_loop_recreation() {
133        EVENT_LOOP_CREATED.store(false, Ordering::Relaxed);
134    }
135}
136
137impl<T> fmt::Debug for EventLoop<T> {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        f.pad("EventLoop { .. }")
140    }
141}
142
143impl fmt::Debug for ActiveEventLoop {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        f.pad("ActiveEventLoop { .. }")
146    }
147}
148
149/// Set through [`ActiveEventLoop::set_control_flow()`].
150///
151/// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted.
152///
153/// Defaults to [`Wait`].
154///
155/// [`Wait`]: Self::Wait
156#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
157pub enum ControlFlow {
158    /// When the current loop iteration finishes, immediately begin a new iteration regardless of
159    /// whether or not new events are available to process.
160    Poll,
161
162    /// When the current loop iteration finishes, suspend the thread until another event arrives.
163    #[default]
164    Wait,
165
166    /// When the current loop iteration finishes, suspend the thread until either another event
167    /// arrives or the given time is reached.
168    ///
169    /// Useful for implementing efficient timers. Applications which want to render at the
170    /// display's native refresh rate should instead use [`Poll`] and the VSync functionality
171    /// of a graphics API to reduce odds of missed frames.
172    ///
173    /// [`Poll`]: Self::Poll
174    WaitUntil(Instant),
175}
176
177impl ControlFlow {
178    /// Creates a [`ControlFlow`] that waits until a timeout has expired.
179    ///
180    /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is
181    /// instead set to [`Wait`].
182    ///
183    /// [`WaitUntil`]: Self::WaitUntil
184    /// [`Wait`]: Self::Wait
185    pub fn wait_duration(timeout: Duration) -> Self {
186        match Instant::now().checked_add(timeout) {
187            Some(instant) => Self::WaitUntil(instant),
188            None => Self::Wait,
189        }
190    }
191}
192
193impl EventLoop<()> {
194    /// Create the event loop.
195    ///
196    /// This is an alias of `EventLoop::builder().build()`.
197    #[inline]
198    pub fn new() -> Result<EventLoop<()>, EventLoopError> {
199        Self::builder().build()
200    }
201
202    /// Start building a new event loop.
203    ///
204    /// This returns an [`EventLoopBuilder`], to allow configuring the event loop before creation.
205    ///
206    /// To get the actual event loop, call [`build`][EventLoopBuilder::build] on that.
207    #[inline]
208    pub fn builder() -> EventLoopBuilder<()> {
209        Self::with_user_event()
210    }
211}
212
213impl<T> EventLoop<T> {
214    /// Start building a new event loop, with the given type as the user event
215    /// type.
216    pub fn with_user_event() -> EventLoopBuilder<T> {
217        EventLoopBuilder {
218            platform_specific: Default::default(),
219            _p: PhantomData,
220        }
221    }
222
223    /// See [`run_app`].
224    ///
225    /// [`run_app`]: Self::run_app
226    #[inline]
227    #[deprecated = "use `EventLoop::run_app` instead"]
228    #[cfg(not(all(web_platform, target_feature = "exception-handling")))]
229    pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError>
230    where
231        F: FnMut(Event<T>, &ActiveEventLoop),
232    {
233        let _span = tracing::debug_span!("rio_window::EventLoop::run").entered();
234
235        self.event_loop.run(event_handler)
236    }
237
238    /// Run the application with the event loop on the calling thread.
239    ///
240    /// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
241    ///
242    /// ## Platform-specific
243    ///
244    /// - **iOS:** Will never return to the caller and so values not passed to this function will
245    ///   *not* be dropped before the process exits.
246    /// - **Web:** Will _act_ as if it never returns to the caller by throwing a Javascript
247    ///   exception (that Rust doesn't see) that will also mean that the rest of the function is
248    ///   never executed and any values not passed to this function will *not* be dropped.
249    ///
250    ///   Web applications are recommended to use
251    #[cfg_attr(
252        web_platform,
253        doc = "[`EventLoopExtWebSys::spawn_app()`][crate::platform::web::EventLoopExtWebSys::spawn_app()]"
254    )]
255    #[cfg_attr(not(web_platform), doc = "`EventLoopExtWebSys::spawn()`")]
256    ///   [^1] instead of [`run_app()`] to avoid the need
257    ///   for the Javascript exception trick, and to make it clearer that the event loop runs
258    ///   asynchronously (via the browser's own, internal, event loop) and doesn't block the
259    ///   current thread of execution like it does on other platforms.
260    ///
261    ///   This function won't be available with `target_feature = "exception-handling"`.
262    ///
263    /// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
264    /// [`run_app()`]: Self::run_app()
265    /// [^1]: `EventLoopExtWebSys::spawn_app()` is only available on Web.
266    #[inline]
267    #[cfg(not(all(web_platform, target_feature = "exception-handling")))]
268    pub fn run_app<A: ApplicationHandler<T>>(
269        self,
270        app: &mut A,
271    ) -> Result<(), EventLoopError> {
272        self.event_loop
273            .run(|event, event_loop| dispatch_event_for_app(app, event_loop, event))
274    }
275
276    /// Creates an [`EventLoopProxy`] that can be used to dispatch user events
277    /// to the main event loop, possibly from another thread.
278    pub fn create_proxy(&self) -> EventLoopProxy<T> {
279        EventLoopProxy {
280            event_loop_proxy: self.event_loop.create_proxy(),
281        }
282    }
283
284    /// Gets a persistent reference to the underlying platform display.
285    ///
286    /// See the [`OwnedDisplayHandle`] type for more information.
287    pub fn owned_display_handle(&self) -> OwnedDisplayHandle {
288        OwnedDisplayHandle {
289            platform: self.event_loop.window_target().p.owned_display_handle(),
290        }
291    }
292
293    /// Change if or when [`DeviceEvent`]s are captured.
294    ///
295    /// See [`ActiveEventLoop::listen_device_events`] for details.
296    ///
297    /// [`DeviceEvent`]: crate::event::DeviceEvent
298    pub fn listen_device_events(&self, allowed: DeviceEvents) {
299        let _span = tracing::debug_span!(
300            "rio_window::EventLoop::listen_device_events",
301            allowed = ?allowed
302        )
303        .entered();
304
305        self.event_loop
306            .window_target()
307            .p
308            .listen_device_events(allowed);
309    }
310
311    #[inline]
312    #[cfg(target_os = "macos")]
313    pub fn set_confirm_before_quit(&self, confirmation: bool) {
314        let _span =
315            tracing::debug_span!("rio_window::EventLoop::set_confirm_before_quit")
316                .entered();
317
318        self.event_loop.set_confirm_before_quit(confirmation)
319    }
320
321    #[inline]
322    #[cfg(target_os = "macos")]
323    pub fn set_use_native_quit_dialog(&self, native: bool) {
324        self.event_loop.set_use_native_quit_dialog(native)
325    }
326
327    /// Sets the [`ControlFlow`].
328    pub fn set_control_flow(&self, control_flow: ControlFlow) {
329        self.event_loop
330            .window_target()
331            .p
332            .set_control_flow(control_flow)
333    }
334
335    /// Create a window.
336    ///
337    /// Creating window without event loop running often leads to improper window creation;
338    /// use [`ActiveEventLoop::create_window`] instead.
339    #[deprecated = "use `ActiveEventLoop::create_window` instead"]
340    #[inline]
341    pub fn create_window(
342        &self,
343        window_attributes: WindowAttributes,
344    ) -> Result<Window, OsError> {
345        let _span = tracing::debug_span!(
346            "rio_window::EventLoop::create_window",
347            window_attributes = ?window_attributes
348        )
349        .entered();
350
351        let window = platform_impl::Window::new(
352            &self.event_loop.window_target().p,
353            window_attributes,
354        )?;
355        Ok(Window { window })
356    }
357
358    /// Create custom cursor.
359    pub fn create_custom_cursor(
360        &self,
361        custom_cursor: CustomCursorSource,
362    ) -> CustomCursor {
363        self.event_loop
364            .window_target()
365            .p
366            .create_custom_cursor(custom_cursor)
367    }
368}
369
370impl<T> raw_window_handle::HasDisplayHandle for EventLoop<T> {
371    fn display_handle(
372        &self,
373    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
374    {
375        raw_window_handle::HasDisplayHandle::display_handle(
376            self.event_loop.window_target(),
377        )
378    }
379}
380
381#[cfg(any(x11_platform, wayland_platform))]
382impl<T> AsFd for EventLoop<T> {
383    /// Get the underlying [EventLoop]'s `fd` which you can register
384    /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
385    /// loop must be polled with the [`pump_app_events`] API.
386    ///
387    /// [`calloop`]: https://crates.io/crates/calloop
388    /// [`mio`]: https://crates.io/crates/mio
389    /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
390    fn as_fd(&self) -> BorrowedFd<'_> {
391        self.event_loop.as_fd()
392    }
393}
394
395#[cfg(any(x11_platform, wayland_platform))]
396impl<T> AsRawFd for EventLoop<T> {
397    /// Get the underlying [EventLoop]'s raw `fd` which you can register
398    /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
399    /// loop must be polled with the [`pump_app_events`] API.
400    ///
401    /// [`calloop`]: https://crates.io/crates/calloop
402    /// [`mio`]: https://crates.io/crates/mio
403    /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
404    fn as_raw_fd(&self) -> RawFd {
405        self.event_loop.as_raw_fd()
406    }
407}
408
409impl ActiveEventLoop {
410    /// Create the window.
411    ///
412    /// Possible causes of error include denied permission, incompatible system, and lack of memory.
413    ///
414    /// ## Platform-specific
415    ///
416    /// - **Web:** The window is created but not inserted into the web page automatically. Please
417    ///   see the web platform module for more information.
418    #[inline]
419    pub fn create_window(
420        &self,
421        window_attributes: WindowAttributes,
422    ) -> Result<Window, OsError> {
423        let _span = tracing::debug_span!(
424            "rio_window::ActiveEventLoop::create_window",
425            window_attributes = ?window_attributes
426        )
427        .entered();
428
429        let window = platform_impl::Window::new(&self.p, window_attributes)?;
430        Ok(Window { window })
431    }
432
433    /// Create custom cursor.
434    pub fn create_custom_cursor(
435        &self,
436        custom_cursor: CustomCursorSource,
437    ) -> CustomCursor {
438        let _span =
439            tracing::debug_span!("rio_window::ActiveEventLoop::create_custom_cursor",)
440                .entered();
441
442        self.p.create_custom_cursor(custom_cursor)
443    }
444
445    /// Returns the list of all the monitors available on the system.
446    #[inline]
447    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
448        let _span =
449            tracing::debug_span!("rio_window::ActiveEventLoop::available_monitors",)
450                .entered();
451
452        #[allow(clippy::useless_conversion)] // false positive on some platforms
453        self.p
454            .available_monitors()
455            .into_iter()
456            .map(|inner| MonitorHandle { inner })
457    }
458
459    /// Returns the primary monitor of the system.
460    ///
461    /// Returns `None` if it can't identify any monitor as a primary one.
462    ///
463    /// ## Platform-specific
464    ///
465    /// **Wayland / Web:** Always returns `None`.
466    #[inline]
467    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
468        let _span = tracing::debug_span!("rio_window::ActiveEventLoop::primary_monitor",)
469            .entered();
470
471        self.p
472            .primary_monitor()
473            .map(|inner| MonitorHandle { inner })
474    }
475
476    /// Change if or when [`DeviceEvent`]s are captured.
477    ///
478    /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
479    /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing
480    /// this at runtime to explicitly capture them again.
481    ///
482    /// ## Platform-specific
483    ///
484    /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported.
485    ///
486    /// [`DeviceEvent`]: crate::event::DeviceEvent
487    pub fn listen_device_events(&self, allowed: DeviceEvents) {
488        let _span = tracing::debug_span!(
489            "rio_window::ActiveEventLoop::listen_device_events",
490            allowed = ?allowed
491        )
492        .entered();
493
494        self.p.listen_device_events(allowed);
495    }
496
497    /// Returns the current system theme.
498    ///
499    /// Returns `None` if it cannot be determined on the current platform.
500    ///
501    /// ## Platform-specific
502    ///
503    /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
504    pub fn system_theme(&self) -> Option<Theme> {
505        self.p.system_theme()
506    }
507
508    /// Sets the [`ControlFlow`].
509    pub fn set_control_flow(&self, control_flow: ControlFlow) {
510        self.p.set_control_flow(control_flow)
511    }
512
513    /// Gets the current [`ControlFlow`].
514    pub fn control_flow(&self) -> ControlFlow {
515        self.p.control_flow()
516    }
517
518    /// This exits the event loop.
519    ///
520    /// See [`LoopExiting`][Event::LoopExiting].
521    pub fn exit(&self) {
522        let _span = tracing::debug_span!("rio_window::ActiveEventLoop::exit",).entered();
523
524        self.p.exit()
525    }
526
527    /// Returns if the [`EventLoop`] is about to stop.
528    ///
529    /// See [`exit()`][Self::exit].
530    pub fn exiting(&self) -> bool {
531        self.p.exiting()
532    }
533
534    /// Gets a persistent reference to the underlying platform display.
535    ///
536    /// See the [`OwnedDisplayHandle`] type for more information.
537    pub fn owned_display_handle(&self) -> OwnedDisplayHandle {
538        OwnedDisplayHandle {
539            platform: self.p.owned_display_handle(),
540        }
541    }
542}
543
544impl raw_window_handle::HasDisplayHandle for ActiveEventLoop {
545    fn display_handle(
546        &self,
547    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
548    {
549        let raw = self.p.raw_display_handle_raw_window_handle()?;
550        // SAFETY: The display will never be deallocated while the event loop is alive.
551        Ok(unsafe { raw_window_handle::DisplayHandle::borrow_raw(raw) })
552    }
553}
554
555/// A proxy for the underlying display handle.
556///
557/// The purpose of this type is to provide a cheaply clonable handle to the underlying
558/// display handle. This is often used by graphics APIs to connect to the underlying APIs.
559/// It is difficult to keep a handle to the [`EventLoop`] type or the [`ActiveEventLoop`]
560/// type. In contrast, this type involves no lifetimes and can be persisted for as long as
561/// needed.
562///
563/// For all platforms, this is one of the following:
564///
565/// - A zero-sized type that is likely optimized out.
566/// - A reference-counted pointer to the underlying type.
567#[derive(Clone)]
568pub struct OwnedDisplayHandle {
569    #[allow(dead_code)]
570    platform: platform_impl::OwnedDisplayHandle,
571}
572
573impl fmt::Debug for OwnedDisplayHandle {
574    #[inline]
575    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576        f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive()
577    }
578}
579
580impl raw_window_handle::HasDisplayHandle for OwnedDisplayHandle {
581    #[inline]
582    fn display_handle(
583        &self,
584    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
585    {
586        let raw = self.platform.raw_display_handle_raw_window_handle()?;
587
588        // SAFETY: The underlying display handle should be safe.
589        let handle = unsafe { raw_window_handle::DisplayHandle::borrow_raw(raw) };
590
591        Ok(handle)
592    }
593}
594
595/// Used to send custom events to [`EventLoop`].
596pub struct EventLoopProxy<T: 'static> {
597    event_loop_proxy: platform_impl::EventLoopProxy<T>,
598}
599
600impl<T: 'static> Clone for EventLoopProxy<T> {
601    fn clone(&self) -> Self {
602        Self {
603            event_loop_proxy: self.event_loop_proxy.clone(),
604        }
605    }
606}
607
608impl<T: 'static> EventLoopProxy<T> {
609    /// Send an event to the [`EventLoop`] from which this proxy was created. This emits a
610    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
611    /// function.
612    ///
613    /// Returns an `Err` if the associated [`EventLoop`] no longer exists.
614    ///
615    /// [`UserEvent(event)`]: Event::UserEvent
616    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
617        let _span =
618            tracing::debug_span!("rio_window::EventLoopProxy::send_event",).entered();
619
620        self.event_loop_proxy.send_event(event)
621    }
622}
623
624impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626        f.pad("EventLoopProxy { .. }")
627    }
628}
629
630/// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that
631/// no longer exists.
632///
633/// Contains the original event given to [`EventLoopProxy::send_event`].
634#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
635pub struct EventLoopClosed<T>(pub T);
636
637impl<T> fmt::Display for EventLoopClosed<T> {
638    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639        f.write_str("Tried to wake up a closed `EventLoop`")
640    }
641}
642
643impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
644
645/// Control when device events are captured.
646#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
647pub enum DeviceEvents {
648    /// Report device events regardless of window focus.
649    Always,
650    /// Only capture device events while the window is focused.
651    #[default]
652    WhenFocused,
653    /// Never capture device events.
654    Never,
655}
656
657/// A unique identifier of the winit's async request.
658///
659/// This could be used to identify the async request once it's done
660/// and a specific action must be taken.
661///
662/// One of the handling scenarios could be to maintain a working list
663/// containing [`AsyncRequestSerial`] and some closure associated with it.
664/// Then once event is arriving the working list is being traversed and a job
665/// executed and removed from the list.
666#[derive(Debug, Clone, Copy, PartialEq, Eq)]
667pub struct AsyncRequestSerial {
668    serial: usize,
669}
670
671impl AsyncRequestSerial {
672    // TODO(kchibisov): Remove `cfg` when the clipboard will be added.
673    #[allow(dead_code)]
674    pub(crate) fn get() -> Self {
675        static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0);
676        // NOTE: We rely on wrap around here, while the user may just request
677        // in the loop usize::MAX times that's issue is considered on them.
678        let serial = CURRENT_SERIAL.fetch_add(1, Ordering::Relaxed);
679        Self { serial }
680    }
681}
682
683/// Shim for various run APIs.
684#[inline(always)]
685pub(crate) fn dispatch_event_for_app<T: 'static, A: ApplicationHandler<T>>(
686    app: &mut A,
687    event_loop: &ActiveEventLoop,
688    event: Event<T>,
689) {
690    match event {
691        Event::NewEvents(cause) => app.new_events(event_loop, cause),
692        Event::WindowEvent { window_id, event } => {
693            app.window_event(event_loop, window_id, event)
694        }
695        Event::DeviceEvent { device_id, event } => {
696            app.device_event(event_loop, device_id, event)
697        }
698        Event::UserEvent(event) => app.user_event(event_loop, event),
699        Event::Suspended => app.suspended(event_loop),
700        Event::Resumed => app.resumed(event_loop),
701        Event::AboutToWait => app.about_to_wait(event_loop),
702        Event::LoopExiting => app.exiting(event_loop),
703        Event::MemoryWarning => app.memory_warning(event_loop),
704        Event::Opened { urls } => app.open_urls(event_loop, urls),
705        Event::HookEvent(hook, modifiers) => {
706            app.hook_event(event_loop, &hook, &modifiers)
707        }
708        Event::OpenConfig => app.open_config(event_loop),
709    }
710}