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}