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