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
12 use instant::Instant;
13 use std::ops::Deref;
14 use std::{error, fmt};
15 
16 use 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 ///
32 pub 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`.
43 pub 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 
48 impl<T> fmt::Debug for EventLoop<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result49     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50         f.pad("EventLoop { .. }")
51     }
52 }
53 
54 impl<T> fmt::Debug for EventLoopWindowTarget<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result55     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)]
73 pub 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 
94 impl Default for ControlFlow {
95     #[inline(always)]
default() -> ControlFlow96     fn default() -> ControlFlow {
97         ControlFlow::Poll
98     }
99 }
100 
101 impl 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.
new() -> EventLoop<()>119     pub fn new() -> EventLoop<()> {
120         EventLoop::<()>::with_user_event()
121     }
122 }
123 
124 impl<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.
with_user_event() -> EventLoop<T>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]
run<F>(self, event_handler: F) -> ! where F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),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.
create_proxy(&self) -> EventLoopProxy<T>158     pub fn create_proxy(&self) -> EventLoopProxy<T> {
159         EventLoopProxy {
160             event_loop_proxy: self.event_loop.create_proxy(),
161         }
162     }
163 }
164 
165 impl<T> Deref for EventLoop<T> {
166     type Target = EventLoopWindowTarget<T>;
deref(&self) -> &EventLoopWindowTarget<T>167     fn deref(&self) -> &EventLoopWindowTarget<T> {
168         self.event_loop.window_target()
169     }
170 }
171 
172 impl<T> EventLoopWindowTarget<T> {
173     /// Returns the list of all the monitors available on the system.
174     #[inline]
available_monitors(&self) -> impl Iterator<Item = MonitorHandle>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]
primary_monitor(&self) -> Option<MonitorHandle>190     pub fn primary_monitor(&self) -> Option<MonitorHandle> {
191         self.p.primary_monitor()
192     }
193 }
194 
195 /// Used to send custom events to `EventLoop`.
196 pub struct EventLoopProxy<T: 'static> {
197     event_loop_proxy: platform_impl::EventLoopProxy<T>,
198 }
199 
200 impl<T: 'static> Clone for EventLoopProxy<T> {
clone(&self) -> Self201     fn clone(&self) -> Self {
202         Self {
203             event_loop_proxy: self.event_loop_proxy.clone(),
204         }
205     }
206 }
207 
208 impl<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.
send_event(&self, event: T) -> Result<(), EventLoopClosed<T>>214     pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
215         self.event_loop_proxy.send_event(event)
216     }
217 }
218 
219 impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result220     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)]
228 pub struct EventLoopClosed<T>(pub T);
229 
230 impl<T> fmt::Display for EventLoopClosed<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result231     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232         f.write_str("Tried to wake up a closed `EventLoop`")
233     }
234 }
235 
236 impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
237