1use crate::{
2 backend_interface::*,
3 error::{InitError, SwResultExt},
4 util, Rect, SoftBufferError,
5};
6use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
7use std::{
8 num::{NonZeroI32, NonZeroU32},
9 sync::{Arc, Mutex},
10};
11use wayland_client::{
12 backend::{Backend, ObjectId},
13 globals::{registry_queue_init, GlobalListContents},
14 protocol::{wl_registry, wl_shm, wl_surface},
15 Connection, Dispatch, EventQueue, Proxy, QueueHandle,
16};
17
18mod buffer;
19use buffer::WaylandBuffer;
20
21struct State;
22
23pub struct WaylandDisplayImpl<D: ?Sized> {
24 conn: Option<Connection>,
25 event_queue: Mutex<EventQueue<State>>,
26 qh: QueueHandle<State>,
27 shm: wl_shm::WlShm,
28
29 /// The object that owns the display handle.
30 ///
31 /// This has to be dropped *after* the `conn` field, because the `conn` field implicitly borrows
32 /// this.
33 _display: D,
34}
35
36impl<D: HasDisplayHandle + ?Sized> WaylandDisplayImpl<D> {
37 fn conn(&self) -> &Connection {
38 self.conn.as_ref().unwrap()
39 }
40}
41
42impl<D: HasDisplayHandle + ?Sized> ContextInterface<D> for Arc<WaylandDisplayImpl<D>> {
43 fn new(display: D) -> Result<Self, InitError<D>>
44 where
45 D: Sized,
46 {
47 let raw = display.display_handle()?.as_raw();
48 let wayland_handle = match raw {
49 RawDisplayHandle::Wayland(w) => w.display,
50 _ => return Err(InitError::Unsupported(display)),
51 };
52
53 let backend = unsafe { Backend::from_foreign_display(wayland_handle.as_ptr().cast()) };
54 let conn = Connection::from_backend(backend);
55 let (globals, event_queue) =
56 registry_queue_init(&conn).swbuf_err("Failed to make round trip to server")?;
57 let qh = event_queue.handle();
58 let shm: wl_shm::WlShm = globals
59 .bind(&qh, 1..=1, ())
60 .swbuf_err("Failed to instantiate Wayland Shm")?;
61 Ok(Arc::new(WaylandDisplayImpl {
62 conn: Some(conn),
63 event_queue: Mutex::new(event_queue),
64 qh,
65 shm,
66 _display: display,
67 }))
68 }
69}
70
71impl<D: ?Sized> Drop for WaylandDisplayImpl<D> {
72 fn drop(&mut self) {
73 // Make sure the connection is dropped first.
74 self.conn = None;
75 }
76}
77
78pub struct WaylandImpl<D: ?Sized, W: ?Sized> {
79 display: Arc<WaylandDisplayImpl<D>>,
80 surface: Option<wl_surface::WlSurface>,
81 buffers: Option<(WaylandBuffer, WaylandBuffer)>,
82 size: Option<(NonZeroI32, NonZeroI32)>,
83
84 /// The pointer to the window object.
85 ///
86 /// This has to be dropped *after* the `surface` field, because the `surface` field implicitly
87 /// borrows this.
88 window_handle: W,
89}
90
91impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> WaylandImpl<D, W> {
92 fn surface(&self) -> &wl_surface::WlSurface {
93 self.surface.as_ref().unwrap()
94 }
95
96 fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
97 let _ = self
98 .display
99 .event_queue
100 .lock()
101 .unwrap_or_else(|x| x.into_inner())
102 .dispatch_pending(&mut State);
103
104 if let Some((front, back)) = &mut self.buffers {
105 // Swap front and back buffer
106 std::mem::swap(front, back);
107
108 front.age = 1;
109 if back.age != 0 {
110 back.age += 1;
111 }
112
113 front.attach(self.surface.as_ref().unwrap());
114
115 // Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if
116 // the compositor doesn't support `damage_buffer`.
117 // https://bugs.freedesktop.org/show_bug.cgi?id=78190
118 if self.surface().version() < 4 {
119 self.surface().damage(0, 0, i32::MAX, i32::MAX);
120 } else {
121 for rect in damage {
122 // Introduced in version 4, it is an error to use this request in version 3 or lower.
123 let (x, y, width, height) = (|| {
124 Some((
125 i32::try_from(rect.x).ok()?,
126 i32::try_from(rect.y).ok()?,
127 i32::try_from(rect.width.get()).ok()?,
128 i32::try_from(rect.height.get()).ok()?,
129 ))
130 })()
131 .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
132 self.surface().damage_buffer(x, y, width, height);
133 }
134 }
135
136 self.surface().commit();
137 }
138
139 let _ = self
140 .display
141 .event_queue
142 .lock()
143 .unwrap_or_else(|x| x.into_inner())
144 .flush();
145
146 Ok(())
147 }
148}
149
150impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W>
151 for WaylandImpl<D, W>
152{
153 type Context = Arc<WaylandDisplayImpl<D>>;
154 type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a;
155
156 fn new(window: W, display: &Arc<WaylandDisplayImpl<D>>) -> Result<Self, InitError<W>> {
157 // Get the raw Wayland window.
158 let raw = window.window_handle()?.as_raw();
159 let wayland_handle = match raw {
160 RawWindowHandle::Wayland(w) => w.surface,
161 _ => return Err(InitError::Unsupported(window)),
162 };
163
164 let surface_id = unsafe {
165 ObjectId::from_ptr(
166 wl_surface::WlSurface::interface(),
167 wayland_handle.as_ptr().cast(),
168 )
169 }
170 .swbuf_err("Failed to create proxy for surface ID.")?;
171 let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id)
172 .swbuf_err("Failed to create proxy for surface ID.")?;
173 Ok(Self {
174 display: display.clone(),
175 surface: Some(surface),
176 buffers: Default::default(),
177 size: None,
178 window_handle: window,
179 })
180 }
181
182 #[inline]
183 fn window(&self) -> &W {
184 &self.window_handle
185 }
186
187 fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
188 self.size = Some(
189 (|| {
190 let width = NonZeroI32::try_from(width).ok()?;
191 let height = NonZeroI32::try_from(height).ok()?;
192 Some((width, height))
193 })()
194 .ok_or(SoftBufferError::SizeOutOfRange { width, height })?,
195 );
196 Ok(())
197 }
198
199 fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
200 let (width, height) = self
201 .size
202 .expect("Must set size of surface before calling `buffer_mut()`");
203
204 if let Some((_front, back)) = &mut self.buffers {
205 // Block if back buffer not released yet
206 if !back.released() {
207 let mut event_queue = self
208 .display
209 .event_queue
210 .lock()
211 .unwrap_or_else(|x| x.into_inner());
212 while !back.released() {
213 event_queue.blocking_dispatch(&mut State).map_err(|err| {
214 SoftBufferError::PlatformError(
215 Some("Wayland dispatch failure".to_string()),
216 Some(Box::new(err)),
217 )
218 })?;
219 }
220 }
221
222 // Resize, if buffer isn't large enough
223 back.resize(width.get(), height.get());
224 } else {
225 // Allocate front and back buffer
226 self.buffers = Some((
227 WaylandBuffer::new(
228 &self.display.shm,
229 width.get(),
230 height.get(),
231 &self.display.qh,
232 ),
233 WaylandBuffer::new(
234 &self.display.shm,
235 width.get(),
236 height.get(),
237 &self.display.qh,
238 ),
239 ));
240 };
241
242 let age = self.buffers.as_mut().unwrap().1.age;
243 Ok(BufferImpl {
244 stack: util::BorrowStack::new(self, |buffer| {
245 Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() })
246 })?,
247 age,
248 })
249 }
250}
251
252impl<D: ?Sized, W: ?Sized> Drop for WaylandImpl<D, W> {
253 fn drop(&mut self) {
254 // Make sure the surface is dropped first.
255 self.surface = None;
256 }
257}
258
259pub struct BufferImpl<'a, D: ?Sized, W> {
260 stack: util::BorrowStack<'a, WaylandImpl<D, W>, [u32]>,
261 age: u8,
262}
263
264impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferInterface
265 for BufferImpl<'a, D, W>
266{
267 #[inline]
268 fn pixels(&self) -> &[u32] {
269 self.stack.member()
270 }
271
272 #[inline]
273 fn pixels_mut(&mut self) -> &mut [u32] {
274 self.stack.member_mut()
275 }
276
277 fn age(&self) -> u8 {
278 self.age
279 }
280
281 fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
282 self.stack.into_container().present_with_damage(damage)
283 }
284
285 fn present(self) -> Result<(), SoftBufferError> {
286 let imp = self.stack.into_container();
287 let (width, height) = imp
288 .size
289 .expect("Must set size of surface before calling `present()`");
290 imp.present_with_damage(&[Rect {
291 x: 0,
292 y: 0,
293 // We know width/height will be non-negative
294 width: width.try_into().unwrap(),
295 height: height.try_into().unwrap(),
296 }])
297 }
298}
299
300impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
301 fn event(
302 _: &mut State,
303 _: &wl_registry::WlRegistry,
304 _: wl_registry::Event,
305 _: &GlobalListContents,
306 _: &Connection,
307 _: &QueueHandle<State>,
308 ) {
309 // Ignore globals added after initialization
310 }
311}
312
313impl Dispatch<wl_shm::WlShm, ()> for State {
314 fn event(
315 _: &mut State,
316 _: &wl_shm::WlShm,
317 _: wl_shm::Event,
318 _: &(),
319 _: &Connection,
320 _: &QueueHandle<State>,
321 ) {
322 }
323}
324