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