winit/
event_loop.rs

1//! The `EventLoop` struct and assorted supporting types, including `ControlFlow`.
2//!
3//! If you want to send custom events to the event loop, use [`EventLoop::create_proxy()`][create_proxy]
4//! to acquire an [`EventLoopProxy`][event_loop_proxy] and call its [`send_event`][send_event] method.
5//!
6//! See the root-level documentation for information on how to create and use an event loop to
7//! handle events.
8//!
9//! [create_proxy]: crate::event_loop::EventLoop::create_proxy
10//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
11//! [send_event]: crate::event_loop::EventLoopProxy::send_event
12use instant::Instant;
13use std::ops::Deref;
14use std::{error, fmt};
15
16use crate::{event::Event, monitor::MonitorHandle, platform_impl};
17
18/// Provides a way to retrieve events from the system and from the windows that were registered to
19/// the events loop.
20///
21/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()`
22/// initializes everything that will be required to create windows. For example on Linux creating
23/// an event loop opens a connection to the X or Wayland server.
24///
25/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs.
26///
27/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic
28/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
29/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
30/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread.
31///
32pub struct EventLoop<T: 'static> {
33    pub(crate) event_loop: platform_impl::EventLoop<T>,
34    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
35}
36
37/// Target that associates windows with an `EventLoop`.
38///
39/// This type exists to allow you to create new windows while Winit executes
40/// your callback. `EventLoop` will coerce into this type (`impl<T> Deref for
41/// EventLoop<T>`), so functions that take this as a parameter can also take
42/// `&EventLoop`.
43pub struct EventLoopWindowTarget<T: 'static> {
44    pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
45    pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
46}
47
48impl<T> fmt::Debug for EventLoop<T> {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.pad("EventLoop { .. }")
51    }
52}
53
54impl<T> fmt::Debug for EventLoopWindowTarget<T> {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        f.pad("EventLoopWindowTarget { .. }")
57    }
58}
59
60/// Set by the user callback given to the `EventLoop::run` method.
61///
62/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`][events_cleared]
63/// is emitted. Defaults to `Poll`.
64///
65/// ## Persistency
66/// Almost every change is persistent between multiple calls to the event loop closure within a
67/// given run loop. The only exception to this is `Exit` which, once set, cannot be unset. Changes
68/// are **not** persistent between multiple calls to `run_return` - issuing a new call will reset
69/// the control flow to `Poll`.
70///
71/// [events_cleared]: crate::event::Event::RedrawEventsCleared
72#[derive(Copy, Clone, Debug, PartialEq, Eq)]
73pub enum ControlFlow {
74    /// When the current loop iteration finishes, immediately begin a new iteration regardless of
75    /// whether or not new events are available to process.
76    ///
77    /// ## Platform-specific
78    /// - **Web:** Events are queued and usually sent when `requestAnimationFrame` fires but sometimes
79    ///   the events in the queue may be sent before the next `requestAnimationFrame` callback, for
80    ///   example when the scaling of the page has changed. This should be treated as an implementation
81    ///   detail which should not be relied on.
82    Poll,
83    /// When the current loop iteration finishes, suspend the thread until another event arrives.
84    Wait,
85    /// When the current loop iteration finishes, suspend the thread until either another event
86    /// arrives or the given time is reached.
87    WaitUntil(Instant),
88    /// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
89    /// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
90    /// in the `control_flow` parameter being reset to `Exit`.
91    Exit,
92}
93
94impl Default for ControlFlow {
95    #[inline(always)]
96    fn default() -> ControlFlow {
97        ControlFlow::Poll
98    }
99}
100
101impl EventLoop<()> {
102    /// Builds a new event loop with a `()` as the user event type.
103    ///
104    /// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
105    /// Attempting to create the event loop on a different thread will panic. This restriction isn't
106    /// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
107    /// porting to platforms that require it. `EventLoopExt::new_any_thread` functions are exposed
108    /// in the relevant `platform` module if the target platform supports creating an event loop on
109    /// any thread.
110    ///
111    /// Usage will result in display backend initialisation, this can be controlled on linux
112    /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
113    /// If it is not set, winit will try to connect to a wayland connection, and if it fails will
114    /// fallback on x11. If this variable is set with any other value, winit will panic.
115    ///
116    /// ## Platform-specific
117    ///
118    /// - **iOS:** Can only be called on the main thread.
119    pub fn new() -> EventLoop<()> {
120        EventLoop::<()>::with_user_event()
121    }
122}
123
124impl<T> EventLoop<T> {
125    /// Builds a new event loop.
126    ///
127    /// All caveats documented in [`EventLoop::new`] apply to this function.
128    ///
129    /// ## Platform-specific
130    ///
131    /// - **iOS:** Can only be called on the main thread.
132    pub fn with_user_event() -> EventLoop<T> {
133        EventLoop {
134            event_loop: platform_impl::EventLoop::new(),
135            _marker: ::std::marker::PhantomData,
136        }
137    }
138
139    /// Hijacks the calling thread and initializes the winit event loop with the provided
140    /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
141    /// access any data from the calling context.
142    ///
143    /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
144    /// event loop's behavior.
145    ///
146    /// Any values not passed to this function will *not* be dropped.
147    ///
148    /// [`ControlFlow`]: crate::event_loop::ControlFlow
149    #[inline]
150    pub fn run<F>(self, event_handler: F) -> !
151    where
152        F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
153    {
154        self.event_loop.run(event_handler)
155    }
156
157    /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
158    pub fn create_proxy(&self) -> EventLoopProxy<T> {
159        EventLoopProxy {
160            event_loop_proxy: self.event_loop.create_proxy(),
161        }
162    }
163}
164
165impl<T> Deref for EventLoop<T> {
166    type Target = EventLoopWindowTarget<T>;
167    fn deref(&self) -> &EventLoopWindowTarget<T> {
168        self.event_loop.window_target()
169    }
170}
171
172impl<T> EventLoopWindowTarget<T> {
173    /// Returns the list of all the monitors available on the system.
174    #[inline]
175    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
176        self.p
177            .available_monitors()
178            .into_iter()
179            .map(|inner| MonitorHandle { inner })
180    }
181
182    /// Returns the primary monitor of the system.
183    ///
184    /// Returns `None` if it can't identify any monitor as a primary one.
185    ///
186    /// ## Platform-specific
187    ///
188    /// **Wayland:** Always returns `None`.
189    #[inline]
190    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
191        self.p.primary_monitor()
192    }
193}
194
195/// Used to send custom events to `EventLoop`.
196pub struct EventLoopProxy<T: 'static> {
197    event_loop_proxy: platform_impl::EventLoopProxy<T>,
198}
199
200impl<T: 'static> Clone for EventLoopProxy<T> {
201    fn clone(&self) -> Self {
202        Self {
203            event_loop_proxy: self.event_loop_proxy.clone(),
204        }
205    }
206}
207
208impl<T: 'static> EventLoopProxy<T> {
209    /// Send an event to the `EventLoop` from which this proxy was created. This emits a
210    /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
211    /// function.
212    ///
213    /// Returns an `Err` if the associated `EventLoop` no longer exists.
214    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
215        self.event_loop_proxy.send_event(event)
216    }
217}
218
219impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        f.pad("EventLoopProxy { .. }")
222    }
223}
224
225/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that
226/// no longer exists. Contains the original event given to `send_event`.
227#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
228pub struct EventLoopClosed<T>(pub T);
229
230impl<T> fmt::Display for EventLoopClosed<T> {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        f.write_str("Tried to wake up a closed `EventLoop`")
233    }
234}
235
236impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}