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