winit/platform_impl/linux/wayland/event_loop/
mod.rs

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