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;
11use std::ops::Deref;
12use std::{error, fmt};
13
14use instant::{Duration, Instant};
15use once_cell::sync::OnceCell;
16use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
17
18use crate::{event::Event, monitor::MonitorHandle, platform_impl};
19
20/// Provides a way to retrieve events from the system and from the windows that were registered to
21/// the events loop.
22///
23/// An `EventLoop` can be seen more or less as a "context". Calling [`EventLoop::new`]
24/// initializes everything that will be required to create windows. For example on Linux creating
25/// an event loop opens a connection to the X or Wayland server.
26///
27/// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs.
28///
29/// Note that this cannot be shared across threads (due to platform-dependant logic
30/// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access, the
31/// [`Window`] created from this _can_ be sent to an other thread, and the
32/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
33///
34/// [`Window`]: crate::window::Window
35pub struct EventLoop<T: 'static> {
36    pub(crate) event_loop: platform_impl::EventLoop<T>,
37    pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
38}
39
40/// Target that associates windows with an [`EventLoop`].
41///
42/// This type exists to allow you to create new windows while Winit executes
43/// your callback. [`EventLoop`] will coerce into this type (`impl<T> Deref for
44/// EventLoop<T>`), so functions that take this as a parameter can also take
45/// `&EventLoop`.
46pub struct EventLoopWindowTarget<T: 'static> {
47    pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
48    pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
49}
50
51/// Object that allows building the event loop.
52///
53/// This is used to make specifying options that affect the whole application
54/// easier. But note that constructing multiple event loops is not supported.
55#[derive(Default)]
56pub struct EventLoopBuilder<T: 'static> {
57    pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
58    _p: PhantomData<T>,
59}
60
61impl EventLoopBuilder<()> {
62    /// Start building a new event loop.
63    #[inline]
64    pub fn new() -> Self {
65        Self::with_user_event()
66    }
67}
68
69impl<T> EventLoopBuilder<T> {
70    /// Start building a new event loop, with the given type as the user event
71    /// type.
72    #[inline]
73    pub fn with_user_event() -> Self {
74        Self {
75            platform_specific: Default::default(),
76            _p: PhantomData,
77        }
78    }
79
80    /// Builds a new event loop.
81    ///
82    /// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
83    /// and only once per application.***
84    ///
85    /// Attempting to create the event loop on a different thread, or multiple event loops in
86    /// the same application, will panic. This restriction isn't
87    /// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
88    /// porting to platforms that require it. `EventLoopBuilderExt::any_thread` functions are exposed
89    /// in the relevant [`platform`] module if the target platform supports creating an event loop on
90    /// any thread.
91    ///
92    /// Calling this function will result in display backend initialisation.
93    ///
94    /// ## Platform-specific
95    ///
96    /// - **Linux:** Backend type can be controlled using an environment variable
97    ///   `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
98    ///   If it is not set, winit will try to connect to a Wayland connection, and if that fails,
99    ///   will fall back on X11. If this variable is set with any other value, winit will panic.
100    /// - **Android:** Must be configured with an `AndroidApp` from `android_main()` by calling
101    ///     [`.with_android_app(app)`] before calling `.build()`.
102    ///
103    /// [`platform`]: crate::platform
104    #[cfg_attr(
105        android,
106        doc = "[`.with_android_app(app)`]: crate::platform::android::EventLoopBuilderExtAndroid::with_android_app"
107    )]
108    #[cfg_attr(
109        not(android),
110        doc = "[`.with_android_app(app)`]: #only-available-on-android"
111    )]
112    #[inline]
113    pub fn build(&mut self) -> EventLoop<T> {
114        static EVENT_LOOP_CREATED: OnceCell<()> = OnceCell::new();
115        if EVENT_LOOP_CREATED.set(()).is_err() {
116            panic!("Creating EventLoop multiple times is not supported.");
117        }
118        // Certain platforms accept a mutable reference in their API.
119        #[allow(clippy::unnecessary_mut_passed)]
120        EventLoop {
121            event_loop: platform_impl::EventLoop::new(&mut self.platform_specific),
122            _marker: PhantomData,
123        }
124    }
125}
126
127impl<T> fmt::Debug for EventLoop<T> {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        f.pad("EventLoop { .. }")
130    }
131}
132
133impl<T> fmt::Debug for EventLoopWindowTarget<T> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.pad("EventLoopWindowTarget { .. }")
136    }
137}
138
139/// Set by the user callback given to the [`EventLoop::run`] method.
140///
141/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`] is emitted.
142///
143/// Defaults to [`Poll`].
144///
145/// ## Persistency
146///
147/// Almost every change is persistent between multiple calls to the event loop closure within a
148/// given run loop. The only exception to this is [`ExitWithCode`] which, once set, cannot be unset.
149/// Changes are **not** persistent between multiple calls to `run_return` - issuing a new call will
150/// reset the control flow to [`Poll`].
151///
152/// [`ExitWithCode`]: Self::ExitWithCode
153/// [`Poll`]: Self::Poll
154#[derive(Copy, Clone, Debug, PartialEq, Eq)]
155pub enum ControlFlow {
156    /// When the current loop iteration finishes, immediately begin a new iteration regardless of
157    /// whether or not new events are available to process.
158    ///
159    /// ## Platform-specific
160    ///
161    /// - **Web:** Events are queued and usually sent when `requestAnimationFrame` fires but sometimes
162    ///   the events in the queue may be sent before the next `requestAnimationFrame` callback, for
163    ///   example when the scaling of the page has changed. This should be treated as an implementation
164    ///   detail which should not be relied on.
165    Poll,
166
167    /// When the current loop iteration finishes, suspend the thread until another event arrives.
168    Wait,
169
170    /// When the current loop iteration finishes, suspend the thread until either another event
171    /// arrives or the given time is reached.
172    ///
173    /// Useful for implementing efficient timers. Applications which want to render at the display's
174    /// native refresh rate should instead use [`Poll`] and the VSync functionality of a graphics API
175    /// to reduce odds of missed frames.
176    ///
177    /// [`Poll`]: Self::Poll
178    WaitUntil(Instant),
179
180    /// Send a [`LoopDestroyed`] event and stop the event loop. This variant is *sticky* - once set,
181    /// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will
182    /// result in the `control_flow` parameter being reset to `ExitWithCode`.
183    ///
184    /// The contained number will be used as exit code. The [`Exit`] constant is a shortcut for this
185    /// with exit code 0.
186    ///
187    /// ## Platform-specific
188    ///
189    /// - **Android / iOS / WASM:** The supplied exit code is unused.
190    /// - **Unix:** On most Unix-like platforms, only the 8 least significant bits will be used,
191    ///   which can cause surprises with negative exit values (`-42` would end up as `214`). See
192    ///   [`std::process::exit`].
193    ///
194    /// [`LoopDestroyed`]: Event::LoopDestroyed
195    /// [`Exit`]: ControlFlow::Exit
196    ExitWithCode(i32),
197}
198
199impl ControlFlow {
200    /// Alias for [`ExitWithCode`]`(0)`.
201    ///
202    /// [`ExitWithCode`]: Self::ExitWithCode
203    #[allow(non_upper_case_globals)]
204    pub const Exit: Self = Self::ExitWithCode(0);
205
206    /// Sets this to [`Poll`].
207    ///
208    /// [`Poll`]: Self::Poll
209    pub fn set_poll(&mut self) {
210        *self = Self::Poll;
211    }
212
213    /// Sets this to [`Wait`].
214    ///
215    /// [`Wait`]: Self::Wait
216    pub fn set_wait(&mut self) {
217        *self = Self::Wait;
218    }
219
220    /// Sets this to [`WaitUntil`]`(instant)`.
221    ///
222    /// [`WaitUntil`]: Self::WaitUntil
223    pub fn set_wait_until(&mut self, instant: Instant) {
224        *self = Self::WaitUntil(instant);
225    }
226
227    /// Sets this to wait until a timeout has expired.
228    ///
229    /// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is
230    /// instead set to [`Wait`].
231    ///
232    /// [`WaitUntil`]: Self::WaitUntil
233    /// [`Wait`]: Self::Wait
234    pub fn set_wait_timeout(&mut self, timeout: Duration) {
235        match Instant::now().checked_add(timeout) {
236            Some(instant) => self.set_wait_until(instant),
237            None => self.set_wait(),
238        }
239    }
240
241    /// Sets this to [`ExitWithCode`]`(code)`.
242    ///
243    /// [`ExitWithCode`]: Self::ExitWithCode
244    pub fn set_exit_with_code(&mut self, code: i32) {
245        *self = Self::ExitWithCode(code);
246    }
247
248    /// Sets this to [`Exit`].
249    ///
250    /// [`Exit`]: Self::Exit
251    pub fn set_exit(&mut self) {
252        *self = Self::Exit;
253    }
254}
255
256impl Default for ControlFlow {
257    #[inline(always)]
258    fn default() -> Self {
259        Self::Poll
260    }
261}
262
263impl EventLoop<()> {
264    /// Alias for [`EventLoopBuilder::new().build()`].
265    ///
266    /// [`EventLoopBuilder::new().build()`]: EventLoopBuilder::build
267    #[inline]
268    pub fn new() -> EventLoop<()> {
269        EventLoopBuilder::new().build()
270    }
271}
272
273impl Default for EventLoop<()> {
274    fn default() -> Self {
275        Self::new()
276    }
277}
278
279impl<T> EventLoop<T> {
280    #[deprecated = "Use `EventLoopBuilder::<T>::with_user_event().build()` instead."]
281    pub fn with_user_event() -> EventLoop<T> {
282        EventLoopBuilder::<T>::with_user_event().build()
283    }
284
285    /// Hijacks the calling thread and initializes the winit event loop with the provided
286    /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
287    /// access any data from the calling context.
288    ///
289    /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
290    /// event loop's behavior.
291    ///
292    /// Any values not passed to this function will *not* be dropped.
293    ///
294    /// ## Platform-specific
295    ///
296    /// - **X11 / Wayland:** The program terminates with exit code 1 if the display server
297    ///   disconnects.
298    ///
299    /// [`ControlFlow`]: crate::event_loop::ControlFlow
300    #[inline]
301    pub fn run<F>(self, event_handler: F) -> !
302    where
303        F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
304    {
305        self.event_loop.run(event_handler)
306    }
307
308    /// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop.
309    pub fn create_proxy(&self) -> EventLoopProxy<T> {
310        EventLoopProxy {
311            event_loop_proxy: self.event_loop.create_proxy(),
312        }
313    }
314}
315
316unsafe impl<T> HasRawDisplayHandle for EventLoop<T> {
317    /// Returns a [`raw_window_handle::RawDisplayHandle`] for the event loop.
318    fn raw_display_handle(&self) -> RawDisplayHandle {
319        self.event_loop.window_target().p.raw_display_handle()
320    }
321}
322
323impl<T> Deref for EventLoop<T> {
324    type Target = EventLoopWindowTarget<T>;
325    fn deref(&self) -> &EventLoopWindowTarget<T> {
326        self.event_loop.window_target()
327    }
328}
329
330impl<T> EventLoopWindowTarget<T> {
331    /// Returns the list of all the monitors available on the system.
332    #[inline]
333    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
334        self.p
335            .available_monitors()
336            .into_iter()
337            .map(|inner| MonitorHandle { inner })
338    }
339
340    /// Returns the primary monitor of the system.
341    ///
342    /// Returns `None` if it can't identify any monitor as a primary one.
343    ///
344    /// ## Platform-specific
345    ///
346    /// **Wayland:** Always returns `None`.
347    #[inline]
348    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
349        self.p
350            .primary_monitor()
351            .map(|inner| MonitorHandle { inner })
352    }
353
354    /// Change [`DeviceEvent`] filter mode.
355    ///
356    /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
357    /// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing
358    /// this filter at runtime to explicitly capture them again.
359    ///
360    /// ## Platform-specific
361    ///
362    /// - **Wayland / macOS / iOS / Android / Web / Orbital:** Unsupported.
363    ///
364    /// [`DeviceEvent`]: crate::event::DeviceEvent
365    pub fn set_device_event_filter(&self, _filter: DeviceEventFilter) {
366        #[cfg(any(x11_platform, wayland_platform, windows))]
367        self.p.set_device_event_filter(_filter);
368    }
369}
370
371unsafe impl<T> HasRawDisplayHandle for EventLoopWindowTarget<T> {
372    /// Returns a [`raw_window_handle::RawDisplayHandle`] for the event loop.
373    fn raw_display_handle(&self) -> RawDisplayHandle {
374        self.p.raw_display_handle()
375    }
376}
377
378/// Used to send custom events to [`EventLoop`].
379pub struct EventLoopProxy<T: 'static> {
380    event_loop_proxy: platform_impl::EventLoopProxy<T>,
381}
382
383impl<T: 'static> Clone for EventLoopProxy<T> {
384    fn clone(&self) -> Self {
385        Self {
386            event_loop_proxy: self.event_loop_proxy.clone(),
387        }
388    }
389}
390
391impl<T: 'static> EventLoopProxy<T> {
392    /// Send an event to the [`EventLoop`] from which this proxy was created. This emits a
393    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
394    /// function.
395    ///
396    /// Returns an `Err` if the associated [`EventLoop`] no longer exists.
397    ///
398    /// [`UserEvent(event)`]: Event::UserEvent
399    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
400        self.event_loop_proxy.send_event(event)
401    }
402}
403
404impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
405    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406        f.pad("EventLoopProxy { .. }")
407    }
408}
409
410/// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that
411/// no longer exists.
412///
413/// Contains the original event given to [`EventLoopProxy::send_event`].
414#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
415pub struct EventLoopClosed<T>(pub T);
416
417impl<T> fmt::Display for EventLoopClosed<T> {
418    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419        f.write_str("Tried to wake up a closed `EventLoop`")
420    }
421}
422
423impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
424
425/// Filter controlling the propagation of device events.
426#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
427pub enum DeviceEventFilter {
428    /// Always filter out device events.
429    Always,
430    /// Filter out device events while the window is not focused.
431    Unfocused,
432    /// Report all device events regardless of window focus.
433    Never,
434}
435
436impl Default for DeviceEventFilter {
437    fn default() -> Self {
438        Self::Unfocused
439    }
440}