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    /// Sets the [`ControlFlow`].
322    pub fn set_control_flow(&self, control_flow: ControlFlow) {
323        self.event_loop
324            .window_target()
325            .p
326            .set_control_flow(control_flow)
327    }
328
329    /// Create a window.
330    ///
331    /// Creating window without event loop running often leads to improper window creation;
332    /// use [`ActiveEventLoop::create_window`] instead.
333    #[deprecated = "use `ActiveEventLoop::create_window` instead"]
334    #[inline]
335    pub fn create_window(
336        &self,
337        window_attributes: WindowAttributes,
338    ) -> Result<Window, OsError> {
339        let _span = tracing::debug_span!(
340            "rio_window::EventLoop::create_window",
341            window_attributes = ?window_attributes
342        )
343        .entered();
344
345        let window = platform_impl::Window::new(
346            &self.event_loop.window_target().p,
347            window_attributes,
348        )?;
349        Ok(Window { window })
350    }
351
352    /// Create custom cursor.
353    pub fn create_custom_cursor(
354        &self,
355        custom_cursor: CustomCursorSource,
356    ) -> CustomCursor {
357        self.event_loop
358            .window_target()
359            .p
360            .create_custom_cursor(custom_cursor)
361    }
362}
363
364impl<T> raw_window_handle::HasDisplayHandle for EventLoop<T> {
365    fn display_handle(
366        &self,
367    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
368    {
369        raw_window_handle::HasDisplayHandle::display_handle(
370            self.event_loop.window_target(),
371        )
372    }
373}
374
375#[cfg(any(x11_platform, wayland_platform))]
376impl<T> AsFd for EventLoop<T> {
377    /// Get the underlying [EventLoop]'s `fd` which you can register
378    /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
379    /// loop must be polled with the [`pump_app_events`] API.
380    ///
381    /// [`calloop`]: https://crates.io/crates/calloop
382    /// [`mio`]: https://crates.io/crates/mio
383    /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
384    fn as_fd(&self) -> BorrowedFd<'_> {
385        self.event_loop.as_fd()
386    }
387}
388
389#[cfg(any(x11_platform, wayland_platform))]
390impl<T> AsRawFd for EventLoop<T> {
391    /// Get the underlying [EventLoop]'s raw `fd` which you can register
392    /// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
393    /// loop must be polled with the [`pump_app_events`] API.
394    ///
395    /// [`calloop`]: https://crates.io/crates/calloop
396    /// [`mio`]: https://crates.io/crates/mio
397    /// [`pump_app_events`]: crate::platform::pump_events::EventLoopExtPumpEvents::pump_app_events
398    fn as_raw_fd(&self) -> RawFd {
399        self.event_loop.as_raw_fd()
400    }
401}
402
403impl ActiveEventLoop {
404    /// Create the window.
405    ///
406    /// Possible causes of error include denied permission, incompatible system, and lack of memory.
407    ///
408    /// ## Platform-specific
409    ///
410    /// - **Web:** The window is created but not inserted into the web page automatically. Please
411    ///   see the web platform module for more information.
412    #[inline]
413    pub fn create_window(
414        &self,
415        window_attributes: WindowAttributes,
416    ) -> Result<Window, OsError> {
417        let _span = tracing::debug_span!(
418            "rio_window::ActiveEventLoop::create_window",
419            window_attributes = ?window_attributes
420        )
421        .entered();
422
423        let window = platform_impl::Window::new(&self.p, window_attributes)?;
424        Ok(Window { window })
425    }
426
427    /// Create custom cursor.
428    pub fn create_custom_cursor(
429        &self,
430        custom_cursor: CustomCursorSource,
431    ) -> CustomCursor {
432        let _span =
433            tracing::debug_span!("rio_window::ActiveEventLoop::create_custom_cursor",)
434                .entered();
435
436        self.p.create_custom_cursor(custom_cursor)
437    }
438
439    /// Returns the list of all the monitors available on the system.
440    #[inline]
441    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
442        let _span =
443            tracing::debug_span!("rio_window::ActiveEventLoop::available_monitors",)
444                .entered();
445
446        #[allow(clippy::useless_conversion)] // false positive on some platforms
447        self.p
448            .available_monitors()
449            .into_iter()
450            .map(|inner| MonitorHandle { inner })
451    }
452
453    /// Returns the primary monitor of the system.
454    ///
455    /// Returns `None` if it can't identify any monitor as a primary one.
456    ///
457    /// ## Platform-specific
458    ///
459    /// **Wayland / Web:** Always returns `None`.
460    #[inline]
461    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
462        let _span = tracing::debug_span!("rio_window::ActiveEventLoop::primary_monitor",)
463            .entered();
464
465        self.p
466            .primary_monitor()
467            .map(|inner| MonitorHandle { inner })
468    }
469
470    /// Change if or when [`DeviceEvent`]s are captured.
471    ///
472    /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
473    /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing
474    /// this at runtime to explicitly capture them again.
475    ///
476    /// ## Platform-specific
477    ///
478    /// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported.
479    ///
480    /// [`DeviceEvent`]: crate::event::DeviceEvent
481    pub fn listen_device_events(&self, allowed: DeviceEvents) {
482        let _span = tracing::debug_span!(
483            "rio_window::ActiveEventLoop::listen_device_events",
484            allowed = ?allowed
485        )
486        .entered();
487
488        self.p.listen_device_events(allowed);
489    }
490
491    /// Returns the current system theme.
492    ///
493    /// Returns `None` if it cannot be determined on the current platform.
494    ///
495    /// ## Platform-specific
496    ///
497    /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
498    pub fn system_theme(&self) -> Option<Theme> {
499        self.p.system_theme()
500    }
501
502    /// Sets the [`ControlFlow`].
503    pub fn set_control_flow(&self, control_flow: ControlFlow) {
504        self.p.set_control_flow(control_flow)
505    }
506
507    /// Gets the current [`ControlFlow`].
508    pub fn control_flow(&self) -> ControlFlow {
509        self.p.control_flow()
510    }
511
512    /// This exits the event loop.
513    ///
514    /// See [`LoopExiting`][Event::LoopExiting].
515    pub fn exit(&self) {
516        let _span = tracing::debug_span!("rio_window::ActiveEventLoop::exit",).entered();
517
518        self.p.exit()
519    }
520
521    /// Returns if the [`EventLoop`] is about to stop.
522    ///
523    /// See [`exit()`][Self::exit].
524    pub fn exiting(&self) -> bool {
525        self.p.exiting()
526    }
527
528    /// Gets a persistent reference to the underlying platform display.
529    ///
530    /// See the [`OwnedDisplayHandle`] type for more information.
531    pub fn owned_display_handle(&self) -> OwnedDisplayHandle {
532        OwnedDisplayHandle {
533            platform: self.p.owned_display_handle(),
534        }
535    }
536}
537
538impl raw_window_handle::HasDisplayHandle for ActiveEventLoop {
539    fn display_handle(
540        &self,
541    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
542    {
543        let raw = self.p.raw_display_handle_raw_window_handle()?;
544        // SAFETY: The display will never be deallocated while the event loop is alive.
545        Ok(unsafe { raw_window_handle::DisplayHandle::borrow_raw(raw) })
546    }
547}
548
549/// A proxy for the underlying display handle.
550///
551/// The purpose of this type is to provide a cheaply clonable handle to the underlying
552/// display handle. This is often used by graphics APIs to connect to the underlying APIs.
553/// It is difficult to keep a handle to the [`EventLoop`] type or the [`ActiveEventLoop`]
554/// type. In contrast, this type involves no lifetimes and can be persisted for as long as
555/// needed.
556///
557/// For all platforms, this is one of the following:
558///
559/// - A zero-sized type that is likely optimized out.
560/// - A reference-counted pointer to the underlying type.
561#[derive(Clone)]
562pub struct OwnedDisplayHandle {
563    #[allow(dead_code)]
564    platform: platform_impl::OwnedDisplayHandle,
565}
566
567impl fmt::Debug for OwnedDisplayHandle {
568    #[inline]
569    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570        f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive()
571    }
572}
573
574impl raw_window_handle::HasDisplayHandle for OwnedDisplayHandle {
575    #[inline]
576    fn display_handle(
577        &self,
578    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
579    {
580        let raw = self.platform.raw_display_handle_raw_window_handle()?;
581
582        // SAFETY: The underlying display handle should be safe.
583        let handle = unsafe { raw_window_handle::DisplayHandle::borrow_raw(raw) };
584
585        Ok(handle)
586    }
587}
588
589/// Used to send custom events to [`EventLoop`].
590pub struct EventLoopProxy<T: 'static> {
591    event_loop_proxy: platform_impl::EventLoopProxy<T>,
592}
593
594impl<T: 'static> Clone for EventLoopProxy<T> {
595    fn clone(&self) -> Self {
596        Self {
597            event_loop_proxy: self.event_loop_proxy.clone(),
598        }
599    }
600}
601
602impl<T: 'static> EventLoopProxy<T> {
603    /// Send an event to the [`EventLoop`] from which this proxy was created. This emits a
604    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
605    /// function.
606    ///
607    /// Returns an `Err` if the associated [`EventLoop`] no longer exists.
608    ///
609    /// [`UserEvent(event)`]: Event::UserEvent
610    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
611        let _span =
612            tracing::debug_span!("rio_window::EventLoopProxy::send_event",).entered();
613
614        self.event_loop_proxy.send_event(event)
615    }
616}
617
618impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
619    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620        f.pad("EventLoopProxy { .. }")
621    }
622}
623
624/// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that
625/// no longer exists.
626///
627/// Contains the original event given to [`EventLoopProxy::send_event`].
628#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
629pub struct EventLoopClosed<T>(pub T);
630
631impl<T> fmt::Display for EventLoopClosed<T> {
632    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
633        f.write_str("Tried to wake up a closed `EventLoop`")
634    }
635}
636
637impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
638
639/// Control when device events are captured.
640#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
641pub enum DeviceEvents {
642    /// Report device events regardless of window focus.
643    Always,
644    /// Only capture device events while the window is focused.
645    #[default]
646    WhenFocused,
647    /// Never capture device events.
648    Never,
649}
650
651/// A unique identifier of the winit's async request.
652///
653/// This could be used to identify the async request once it's done
654/// and a specific action must be taken.
655///
656/// One of the handling scenarios could be to maintain a working list
657/// containing [`AsyncRequestSerial`] and some closure associated with it.
658/// Then once event is arriving the working list is being traversed and a job
659/// executed and removed from the list.
660#[derive(Debug, Clone, Copy, PartialEq, Eq)]
661pub struct AsyncRequestSerial {
662    serial: usize,
663}
664
665impl AsyncRequestSerial {
666    // TODO(kchibisov): Remove `cfg` when the clipboard will be added.
667    #[allow(dead_code)]
668    pub(crate) fn get() -> Self {
669        static CURRENT_SERIAL: AtomicUsize = AtomicUsize::new(0);
670        // NOTE: We rely on wrap around here, while the user may just request
671        // in the loop usize::MAX times that's issue is considered on them.
672        let serial = CURRENT_SERIAL.fetch_add(1, Ordering::Relaxed);
673        Self { serial }
674    }
675}
676
677/// Shim for various run APIs.
678#[inline(always)]
679pub(crate) fn dispatch_event_for_app<T: 'static, A: ApplicationHandler<T>>(
680    app: &mut A,
681    event_loop: &ActiveEventLoop,
682    event: Event<T>,
683) {
684    match event {
685        Event::NewEvents(cause) => app.new_events(event_loop, cause),
686        Event::WindowEvent { window_id, event } => {
687            app.window_event(event_loop, window_id, event)
688        }
689        Event::DeviceEvent { device_id, event } => {
690            app.device_event(event_loop, device_id, event)
691        }
692        Event::UserEvent(event) => app.user_event(event_loop, event),
693        Event::Suspended => app.suspended(event_loop),
694        Event::Resumed => app.resumed(event_loop),
695        Event::AboutToWait => app.about_to_wait(event_loop),
696        Event::LoopExiting => app.exiting(event_loop),
697        Event::MemoryWarning => app.memory_warning(event_loop),
698        Event::Opened { urls } => app.open_urls(event_loop, urls),
699        Event::HookEvent(hook) => app.hook_event(event_loop, &hook),
700        Event::OpenConfig => app.open_config(event_loop),
701    }
702}