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