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}