1//! The event-loop routines.
2
3use std::cell::{Cell, RefCell};
4use std::io::Result as IOResult;
5use std::marker::PhantomData;
6use std::mem;
7use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
8use std::rc::Rc;
9use std::sync::atomic::Ordering;
10use std::sync::{Arc, Mutex};
11use std::time::{Duration, Instant};
12
13use sctk::reexports::calloop::Error as CalloopError;
14use sctk::reexports::calloop_wayland_source::WaylandSource;
15use sctk::reexports::client::globals;
16use sctk::reexports::client::{Connection, QueueHandle};
17
18use crate::dpi::LogicalSize;
19use crate::error::{EventLoopError, OsError as RootOsError};
20use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
21use crate::event_loop::{
22 ControlFlow, DeviceEvents, EventLoopWindowTarget as RootEventLoopWindowTarget,
23};
24use crate::platform::pump_events::PumpStatus;
25use crate::platform_impl::platform::min_timeout;
26use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError};
27
28mod proxy;
29pub mod sink;
30
31pub use proxy::EventLoopProxy;
32use sink::EventSink;
33
34use super::state::{WindowCompositorUpdate, WinitState};
35use super::window::state::FrameCallbackState;
36use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId};
37
38type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
39
40/// The Wayland event loop.
41pub struct EventLoop<T: 'static> {
42 /// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop
43 loop_running: bool,
44
45 buffer_sink: EventSink,
46 compositor_updates: Vec<WindowCompositorUpdate>,
47 window_ids: Vec<WindowId>,
48
49 /// Sender of user events.
50 user_events_sender: calloop::channel::Sender<T>,
51
52 // XXX can't remove RefCell out of here, unless we can plumb generics into the `Window`, which
53 // we don't really want, since it'll break public API by a lot.
54 /// Pending events from the user.
55 pending_user_events: Rc<RefCell<Vec<T>>>,
56
57 /// The Wayland dispatcher to has raw access to the queue when needed, such as
58 /// when creating a new window.
59 wayland_dispatcher: WaylandDispatcher,
60
61 /// Connection to the wayland server.
62 connection: Connection,
63
64 /// Event loop window target.
65 window_target: RootEventLoopWindowTarget<T>,
66
67 // XXX drop after everything else, just to be safe.
68 /// Calloop's event loop.
69 event_loop: calloop::EventLoop<'static, WinitState>,
70}
71
72impl<T: 'static> EventLoop<T> {
73 pub fn new() -> Result<EventLoop<T>, EventLoopError> {
74 macro_rules! map_err {
75 ($e:expr, $err:expr) => {
76 $e.map_err(|error| os_error!($err(error).into()))
77 };
78 }
79
80 let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?;
81
82 let (globals, mut event_queue) = map_err!(
83 globals::registry_queue_init(&connection),
84 WaylandError::Global
85 )?;
86 let queue_handle = event_queue.handle();
87
88 let event_loop = map_err!(
89 calloop::EventLoop::<WinitState>::try_new(),
90 WaylandError::Calloop
91 )?;
92
93 let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())
94 .map_err(|error| os_error!(error))?;
95
96 // NOTE: do a roundtrip after binding the globals to prevent potential
97 // races with the server.
98 map_err!(
99 event_queue.roundtrip(&mut winit_state),
100 WaylandError::Dispatch
101 )?;
102
103 // Register Wayland source.
104 let wayland_source = WaylandSource::new(connection.clone(), event_queue);
105 let wayland_dispatcher =
106 calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
107 let result = queue.dispatch_pending(winit_state);
108 if result.is_ok()
109 && (!winit_state.events_sink.is_empty()
110 || !winit_state.window_compositor_updates.is_empty())
111 {
112 winit_state.dispatched_events = true;
113 }
114 result
115 });
116
117 map_err!(
118 event_loop
119 .handle()
120 .register_dispatcher(wayland_dispatcher.clone()),
121 WaylandError::Calloop
122 )?;
123
124 // Setup the user proxy.
125 let pending_user_events = Rc::new(RefCell::new(Vec::new()));
126 let pending_user_events_clone = pending_user_events.clone();
127 let (user_events_sender, user_events_channel) = calloop::channel::channel();
128 let result = event_loop
129 .handle()
130 .insert_source(
131 user_events_channel,
132 move |event, _, winit_state: &mut WinitState| {
133 if let calloop::channel::Event::Msg(msg) = event {
134 winit_state.dispatched_events = true;
135 pending_user_events_clone.borrow_mut().push(msg);
136 }
137 },
138 )
139 .map_err(|error| error.error);
140 map_err!(result, WaylandError::Calloop)?;
141
142 // An event's loop awakener to wake up for window events from winit's windows.
143 let (event_loop_awakener, event_loop_awakener_source) = map_err!(
144 calloop::ping::make_ping()
145 .map_err(|error| CalloopError::OtherError(Box::new(error).into())),
146 WaylandError::Calloop
147 )?;
148
149 let result = event_loop
150 .handle()
151 .insert_source(
152 event_loop_awakener_source,
153 move |_, _, winit_state: &mut WinitState| {
154 // Mark that we have something to dispatch.
155 winit_state.dispatched_events = true;
156 },
157 )
158 .map_err(|error| error.error);
159 map_err!(result, WaylandError::Calloop)?;
160
161 let window_target = EventLoopWindowTarget {
162 connection: connection.clone(),
163 wayland_dispatcher: wayland_dispatcher.clone(),
164 event_loop_awakener,
165 queue_handle,
166 control_flow: Cell::new(ControlFlow::default()),
167 exit: Cell::new(None),
168 state: RefCell::new(winit_state),
169 _marker: PhantomData,
170 };
171
172 let event_loop = Self {
173 loop_running: false,
174 compositor_updates: Vec::new(),
175 buffer_sink: EventSink::default(),
176 window_ids: Vec::new(),
177 connection,
178 wayland_dispatcher,
179 user_events_sender,
180 pending_user_events,
181 event_loop,
182 window_target: RootEventLoopWindowTarget {
183 p: PlatformEventLoopWindowTarget::Wayland(window_target),
184 _marker: PhantomData,
185 },
186 };
187
188 Ok(event_loop)
189 }
190
191 pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
192 where
193 F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
194 {
195 if self.loop_running {
196 return Err(EventLoopError::AlreadyRunning);
197 }
198
199 let exit = loop {
200 match self.pump_events(None, &mut event_handler) {
201 PumpStatus::Exit(0) => {
202 break Ok(());
203 }
204 PumpStatus::Exit(code) => {
205 break Err(EventLoopError::ExitFailure(code));
206 }
207 _ => {
208 continue;
209 }
210 }
211 };
212
213 // Applications aren't allowed to carry windows between separate
214 // `run_on_demand` calls but if they have only just dropped their
215 // windows we need to make sure those last requests are sent to the
216 // compositor.
217 let _ = self.roundtrip().map_err(EventLoopError::Os);
218
219 exit
220 }
221
222 pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
223 where
224 F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
225 {
226 if !self.loop_running {
227 self.loop_running = true;
228
229 // Run the initial loop iteration.
230 self.single_iteration(&mut callback, StartCause::Init);
231 }
232
233 // Consider the possibility that the `StartCause::Init` iteration could
234 // request to Exit.
235 if !self.exiting() {
236 self.poll_events_with_timeout(timeout, &mut callback);
237 }
238 if let Some(code) = self.exit_code() {
239 self.loop_running = false;
240
241 callback(Event::LoopExiting, self.window_target());
242
243 PumpStatus::Exit(code)
244 } else {
245 PumpStatus::Continue
246 }
247 }
248
249 pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
250 where
251 F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
252 {
253 let cause = loop {
254 let start = Instant::now();
255
256 timeout = {
257 let control_flow_timeout = match self.control_flow() {
258 ControlFlow::Wait => None,
259 ControlFlow::Poll => Some(Duration::ZERO),
260 ControlFlow::WaitUntil(wait_deadline) => {
261 Some(wait_deadline.saturating_duration_since(start))
262 }
263 };
264 min_timeout(control_flow_timeout, timeout)
265 };
266
267 // NOTE Ideally we should flush as the last thing we do before polling
268 // to wait for events, and this should be done by the calloop
269 // WaylandSource but we currently need to flush writes manually.
270 //
271 // Checking for flush error is essential to perform an exit with error, since
272 // once we have a protocol error, we could get stuck retrying...
273 if self.connection.flush().is_err() {
274 self.set_exit_code(1);
275 return;
276 }
277
278 if let Err(error) = self.loop_dispatch(timeout) {
279 // NOTE We exit on errors from dispatches, since if we've got protocol error
280 // libwayland-client/wayland-rs will inform us anyway, but crashing downstream is not
281 // really an option. Instead we inform that the event loop got destroyed. We may
282 // communicate an error that something was terminated, but winit doesn't provide us
283 // with an API to do that via some event.
284 // Still, we set the exit code to the error's OS error code, or to 1 if not possible.
285 let exit_code = error.raw_os_error().unwrap_or(1);
286 self.set_exit_code(exit_code);
287 return;
288 }
289
290 // NB: `StartCause::Init` is handled as a special case and doesn't need
291 // to be considered here
292 let cause = match self.control_flow() {
293 ControlFlow::Poll => StartCause::Poll,
294 ControlFlow::Wait => StartCause::WaitCancelled {
295 start,
296 requested_resume: None,
297 },
298 ControlFlow::WaitUntil(deadline) => {
299 if Instant::now() < deadline {
300 StartCause::WaitCancelled {
301 start,
302 requested_resume: Some(deadline),
303 }
304 } else {
305 StartCause::ResumeTimeReached {
306 start,
307 requested_resume: deadline,
308 }
309 }
310 }
311 };
312
313 // Reduce spurious wake-ups.
314 let dispatched_events = self.with_state(|state| state.dispatched_events);
315 if matches!(cause, StartCause::WaitCancelled { .. }) && !dispatched_events {
316 continue;
317 }
318
319 break cause;
320 };
321
322 self.single_iteration(&mut callback, cause);
323 }
324
325 fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
326 where
327 F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
328 {
329 // NOTE currently just indented to simplify the diff
330
331 // We retain these grow-only scratch buffers as part of the EventLoop
332 // for the sake of avoiding lots of reallocs. We take them here to avoid
333 // trying to mutably borrow `self` more than once and we swap them back
334 // when finished.
335 let mut compositor_updates = std::mem::take(&mut self.compositor_updates);
336 let mut buffer_sink = std::mem::take(&mut self.buffer_sink);
337 let mut window_ids = std::mem::take(&mut self.window_ids);
338
339 callback(Event::NewEvents(cause), &self.window_target);
340
341 // NB: For consistency all platforms must emit a 'resumed' event even though Wayland
342 // applications don't themselves have a formal suspend/resume lifecycle.
343 if cause == StartCause::Init {
344 callback(Event::Resumed, &self.window_target);
345 }
346
347 // Handle pending user events. We don't need back buffer, since we can't dispatch
348 // user events indirectly via callback to the user.
349 for user_event in self.pending_user_events.borrow_mut().drain(..) {
350 callback(Event::UserEvent(user_event), &self.window_target);
351 }
352
353 // Drain the pending compositor updates.
354 self.with_state(|state| compositor_updates.append(&mut state.window_compositor_updates));
355
356 for mut compositor_update in compositor_updates.drain(..) {
357 let window_id = compositor_update.window_id;
358 if compositor_update.scale_changed {
359 let (physical_size, scale_factor) = self.with_state(|state| {
360 let windows = state.windows.get_mut();
361 let window = windows.get(&window_id).unwrap().lock().unwrap();
362 let scale_factor = window.scale_factor();
363 let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
364 (size, scale_factor)
365 });
366
367 // Stash the old window size.
368 let old_physical_size = physical_size;
369
370 let new_inner_size = Arc::new(Mutex::new(physical_size));
371 callback(
372 Event::WindowEvent {
373 window_id: crate::window::WindowId(window_id),
374 event: WindowEvent::ScaleFactorChanged {
375 scale_factor,
376 inner_size_writer: InnerSizeWriter::new(Arc::downgrade(
377 &new_inner_size,
378 )),
379 },
380 },
381 &self.window_target,
382 );
383
384 let physical_size = *new_inner_size.lock().unwrap();
385 drop(new_inner_size);
386
387 // Resize the window when user altered the size.
388 if old_physical_size != physical_size {
389 self.with_state(|state| {
390 let windows = state.windows.get_mut();
391 let mut window = windows.get(&window_id).unwrap().lock().unwrap();
392
393 let new_logical_size: LogicalSize<f64> =
394 physical_size.to_logical(scale_factor);
395 window.request_inner_size(new_logical_size.into());
396 });
397
398 // Make it queue resize.
399 compositor_update.resized = true;
400 }
401 }
402
403 // NOTE: Rescale changed the physical size which winit operates in, thus we should
404 // resize.
405 if compositor_update.resized || compositor_update.scale_changed {
406 let physical_size = self.with_state(|state| {
407 let windows = state.windows.get_mut();
408 let window = windows.get(&window_id).unwrap().lock().unwrap();
409
410 let scale_factor = window.scale_factor();
411 let size = logical_to_physical_rounded(window.inner_size(), scale_factor);
412
413 // Mark the window as needed a redraw.
414 state
415 .window_requests
416 .get_mut()
417 .get_mut(&window_id)
418 .unwrap()
419 .redraw_requested
420 .store(true, Ordering::Relaxed);
421
422 size
423 });
424
425 callback(
426 Event::WindowEvent {
427 window_id: crate::window::WindowId(window_id),
428 event: WindowEvent::Resized(physical_size),
429 },
430 &self.window_target,
431 );
432 }
433
434 if compositor_update.close_window {
435 callback(
436 Event::WindowEvent {
437 window_id: crate::window::WindowId(window_id),
438 event: WindowEvent::CloseRequested,
439 },
440 &self.window_target,
441 );
442 }
443 }
444
445 // Push the events directly from the window.
446 self.with_state(|state| {
447 buffer_sink.append(&mut state.window_events_sink.lock().unwrap());
448 });
449 for event in buffer_sink.drain() {
450 let event = event.map_nonuser_event().unwrap();
451 callback(event, &self.window_target);
452 }
453
454 // Handle non-synthetic events.
455 self.with_state(|state| {
456 buffer_sink.append(&mut state.events_sink);
457 });
458 for event in buffer_sink.drain() {
459 let event = event.map_nonuser_event().unwrap();
460 callback(event, &self.window_target);
461 }
462
463 // Collect the window ids
464 self.with_state(|state| {
465 window_ids.extend(state.window_requests.get_mut().keys());
466 });
467
468 for window_id in window_ids.iter() {
469 let event = self.with_state(|state| {
470 let window_requests = state.window_requests.get_mut();
471 if window_requests.get(window_id).unwrap().take_closed() {
472 mem::drop(window_requests.remove(window_id));
473 mem::drop(state.windows.get_mut().remove(window_id));
474 return Some(WindowEvent::Destroyed);
475 }
476
477 let mut window = state
478 .windows
479 .get_mut()
480 .get_mut(window_id)
481 .unwrap()
482 .lock()
483 .unwrap();
484
485 if window.frame_callback_state() == FrameCallbackState::Requested {
486 return None;
487 }
488
489 // Reset the frame callbacks state.
490 window.frame_callback_reset();
491 let mut redraw_requested = window_requests
492 .get(window_id)
493 .unwrap()
494 .take_redraw_requested();
495
496 // Redraw the frame while at it.
497 redraw_requested |= window.refresh_frame();
498
499 redraw_requested.then_some(WindowEvent::RedrawRequested)
500 });
501
502 if let Some(event) = event {
503 callback(
504 Event::WindowEvent {
505 window_id: crate::window::WindowId(*window_id),
506 event,
507 },
508 &self.window_target,
509 );
510 }
511 }
512
513 // Reset the hint that we've dispatched events.
514 self.with_state(|state| {
515 state.dispatched_events = false;
516 });
517
518 // This is always the last event we dispatch before poll again
519 callback(Event::AboutToWait, &self.window_target);
520
521 // Update the window frames and schedule redraws.
522 let mut wake_up = false;
523 for window_id in window_ids.drain(..) {
524 wake_up |= self.with_state(|state| match state.windows.get_mut().get_mut(&window_id) {
525 Some(window) => {
526 let refresh = window.lock().unwrap().refresh_frame();
527 if refresh {
528 state
529 .window_requests
530 .get_mut()
531 .get_mut(&window_id)
532 .unwrap()
533 .redraw_requested
534 .store(true, Ordering::Relaxed);
535 }
536
537 refresh
538 }
539 None => false,
540 });
541 }
542
543 // Wakeup event loop if needed.
544 //
545 // If the user draws from the `AboutToWait` this is likely not required, however
546 // we can't do much about it.
547 if wake_up {
548 match &self.window_target.p {
549 PlatformEventLoopWindowTarget::Wayland(window_target) => {
550 window_target.event_loop_awakener.ping();
551 }
552 #[cfg(x11_platform)]
553 PlatformEventLoopWindowTarget::X(_) => unreachable!(),
554 }
555 }
556
557 std::mem::swap(&mut self.compositor_updates, &mut compositor_updates);
558 std::mem::swap(&mut self.buffer_sink, &mut buffer_sink);
559 std::mem::swap(&mut self.window_ids, &mut window_ids);
560 }
561
562 #[inline]
563 pub fn create_proxy(&self) -> EventLoopProxy<T> {
564 EventLoopProxy::new(self.user_events_sender.clone())
565 }
566
567 #[inline]
568 pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
569 &self.window_target
570 }
571
572 fn with_state<'a, U: 'a, F: FnOnce(&'a mut WinitState) -> U>(&'a mut self, callback: F) -> U {
573 let state = match &mut self.window_target.p {
574 PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(),
575 #[cfg(x11_platform)]
576 _ => unreachable!(),
577 };
578
579 callback(state)
580 }
581
582 fn loop_dispatch<D: Into<Option<std::time::Duration>>>(&mut self, timeout: D) -> IOResult<()> {
583 let state = match &mut self.window_target.p {
584 PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(),
585 #[cfg(feature = "x11")]
586 _ => unreachable!(),
587 };
588
589 self.event_loop.dispatch(timeout, state).map_err(|error| {
590 error!("Error dispatching event loop: {}", error);
591 error.into()
592 })
593 }
594
595 fn roundtrip(&mut self) -> Result<usize, RootOsError> {
596 let state = match &mut self.window_target.p {
597 PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(),
598 #[cfg(feature = "x11")]
599 _ => unreachable!(),
600 };
601
602 let mut wayland_source = self.wayland_dispatcher.as_source_mut();
603 let event_queue = wayland_source.queue();
604 event_queue.roundtrip(state).map_err(|error| {
605 os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
606 error
607 ))))
608 })
609 }
610
611 fn control_flow(&self) -> ControlFlow {
612 self.window_target.p.control_flow()
613 }
614
615 fn exiting(&self) -> bool {
616 self.window_target.p.exiting()
617 }
618
619 fn set_exit_code(&self, code: i32) {
620 self.window_target.p.set_exit_code(code)
621 }
622
623 fn exit_code(&self) -> Option<i32> {
624 self.window_target.p.exit_code()
625 }
626}
627
628impl<T> AsFd for EventLoop<T> {
629 fn as_fd(&self) -> BorrowedFd<'_> {
630 self.event_loop.as_fd()
631 }
632}
633
634impl<T> AsRawFd for EventLoop<T> {
635 fn as_raw_fd(&self) -> RawFd {
636 self.event_loop.as_raw_fd()
637 }
638}
639
640pub struct EventLoopWindowTarget<T> {
641 /// The event loop wakeup source.
642 pub event_loop_awakener: calloop::ping::Ping,
643
644 /// The main queue used by the event loop.
645 pub queue_handle: QueueHandle<WinitState>,
646
647 /// The application's latest control_flow state
648 pub(crate) control_flow: Cell<ControlFlow>,
649
650 /// The application's exit state.
651 pub(crate) exit: Cell<Option<i32>>,
652
653 // TODO remove that RefCell once we can pass `&mut` in `Window::new`.
654 /// Winit state.
655 pub state: RefCell<WinitState>,
656
657 /// Dispatcher of Wayland events.
658 pub wayland_dispatcher: WaylandDispatcher,
659
660 /// Connection to the wayland server.
661 pub connection: Connection,
662
663 _marker: std::marker::PhantomData<T>,
664}
665
666impl<T> EventLoopWindowTarget<T> {
667 pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
668 self.control_flow.set(control_flow)
669 }
670
671 pub(crate) fn control_flow(&self) -> ControlFlow {
672 self.control_flow.get()
673 }
674
675 pub(crate) fn exit(&self) {
676 self.exit.set(Some(0))
677 }
678
679 pub(crate) fn clear_exit(&self) {
680 self.exit.set(None)
681 }
682
683 pub(crate) fn exiting(&self) -> bool {
684 self.exit.get().is_some()
685 }
686
687 pub(crate) fn set_exit_code(&self, code: i32) {
688 self.exit.set(Some(code))
689 }
690
691 pub(crate) fn exit_code(&self) -> Option<i32> {
692 self.exit.get()
693 }
694
695 #[inline]
696 pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
697
698 #[cfg(feature = "rwh_05")]
699 #[inline]
700 pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
701 use sctk::reexports::client::Proxy;
702
703 let mut display_handle = rwh_05::WaylandDisplayHandle::empty();
704 display_handle.display = self.connection.display().id().as_ptr() as *mut _;
705 rwh_05::RawDisplayHandle::Wayland(display_handle)
706 }
707
708 #[cfg(feature = "rwh_06")]
709 #[inline]
710 pub fn raw_display_handle_rwh_06(
711 &self,
712 ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
713 use sctk::reexports::client::Proxy;
714
715 Ok(rwh_06::WaylandDisplayHandle::new({
716 let ptr = self.connection.display().id().as_ptr();
717 std::ptr::NonNull::new(ptr as *mut _).expect("wl_display should never be null")
718 })
719 .into())
720 }
721}
722