1use std::mem;
2use std::os::unix::io::OwnedFd;
3use std::sync::MutexGuard;
4use std::sync::{
5 atomic::{AtomicI32, Ordering},
6 Arc, Mutex,
7};
8
9use wayland_client::{
10 globals::{BindError, GlobalList},
11 protocol::{
12 wl_callback, wl_compositor, wl_output, wl_region,
13 wl_surface::{self, WlSurface},
14 },
15 Connection, Dispatch, Proxy, QueueHandle, WEnum,
16};
17
18use crate::{
19 error::GlobalError,
20 globals::{GlobalData, ProvidesBoundGlobal},
21 output::{OutputData, OutputHandler, OutputState, ScaleWatcherHandle},
22};
23
24pub trait CompositorHandler: Sized {
25 fn scale_factor_changed(
27 &mut self,
28 conn: &Connection,
29 qh: &QueueHandle<Self>,
30 surface: &wl_surface::WlSurface,
31 new_factor: i32,
32 );
33
34 fn transform_changed(
36 &mut self,
37 conn: &Connection,
38 qh: &QueueHandle<Self>,
39 surface: &wl_surface::WlSurface,
40 new_transform: wl_output::Transform,
41 );
42
43 fn frame(
54 &mut self,
55 conn: &Connection,
56 qh: &QueueHandle<Self>,
57 surface: &wl_surface::WlSurface,
58 time: u32,
59 );
60
61 fn surface_enter(
63 &mut self,
64 conn: &Connection,
65 qh: &QueueHandle<Self>,
66 surface: &wl_surface::WlSurface,
67 output: &wl_output::WlOutput,
68 );
69
70 fn surface_leave(
72 &mut self,
73 conn: &Connection,
74 qh: &QueueHandle<Self>,
75 surface: &wl_surface::WlSurface,
76 output: &wl_output::WlOutput,
77 );
78}
79
80pub trait SurfaceDataExt: Send + Sync {
81 fn surface_data(&self) -> &SurfaceData;
82}
83
84impl SurfaceDataExt for SurfaceData {
85 fn surface_data(&self) -> &SurfaceData {
86 self
87 }
88}
89
90#[derive(Clone, Debug)]
91pub struct CompositorState {
92 wl_compositor: wl_compositor::WlCompositor,
93}
94
95impl CompositorState {
96 pub const API_VERSION_MAX: u32 = 6;
101
102 pub fn bind<State>(
103 globals: &GlobalList,
104 qh: &QueueHandle<State>,
105 ) -> Result<CompositorState, BindError>
106 where
107 State: Dispatch<wl_compositor::WlCompositor, GlobalData, State> + 'static,
108 {
109 let wl_compositor = globals.bind(qh, 1..=Self::API_VERSION_MAX, GlobalData)?;
110 Ok(CompositorState { wl_compositor })
111 }
112
113 pub fn wl_compositor(&self) -> &wl_compositor::WlCompositor {
114 &self.wl_compositor
115 }
116
117 pub fn create_surface<D>(&self, qh: &QueueHandle<D>) -> wl_surface::WlSurface
118 where
119 D: Dispatch<wl_surface::WlSurface, SurfaceData> + 'static,
120 {
121 self.create_surface_with_data(qh, Default::default())
122 }
123
124 pub fn create_surface_with_data<D, U>(
125 &self,
126 qh: &QueueHandle<D>,
127 data: U,
128 ) -> wl_surface::WlSurface
129 where
130 D: Dispatch<wl_surface::WlSurface, U> + 'static,
131 U: SurfaceDataExt + 'static,
132 {
133 self.wl_compositor.create_surface(qh, data)
134 }
135}
136
137#[derive(Debug)]
139pub struct SurfaceData {
140 pub(crate) scale_factor: AtomicI32,
142
143 pub(crate) parent_surface: Option<WlSurface>,
147
148 inner: Mutex<SurfaceDataInner>,
150}
151
152impl SurfaceData {
153 pub fn new(parent_surface: Option<WlSurface>, scale_factor: i32) -> Self {
155 Self {
156 scale_factor: AtomicI32::new(scale_factor),
157 parent_surface,
158 inner: Default::default(),
159 }
160 }
161
162 pub fn scale_factor(&self) -> i32 {
164 self.scale_factor.load(Ordering::Relaxed)
165 }
166
167 pub fn transform(&self) -> wl_output::Transform {
169 self.inner.lock().unwrap().transform
170 }
171
172 pub fn parent_surface(&self) -> Option<&WlSurface> {
177 self.parent_surface.as_ref()
178 }
179
180 pub fn outputs(&self) -> impl Iterator<Item = wl_output::WlOutput> {
182 self.inner.lock().unwrap().outputs.clone().into_iter()
183 }
184}
185
186impl Default for SurfaceData {
187 fn default() -> Self {
188 Self::new(None, 1)
189 }
190}
191
192#[derive(Debug)]
193struct SurfaceDataInner {
194 transform: wl_output::Transform,
196
197 outputs: Vec<wl_output::WlOutput>,
199
200 watcher: Option<ScaleWatcherHandle>,
202}
203
204impl Default for SurfaceDataInner {
205 fn default() -> Self {
206 Self { transform: wl_output::Transform::Normal, outputs: Vec::new(), watcher: None }
207 }
208}
209
210#[derive(Debug)]
214pub struct Surface(wl_surface::WlSurface);
215
216impl Surface {
217 pub fn new<D>(
218 compositor: &impl ProvidesBoundGlobal<
219 wl_compositor::WlCompositor,
220 { CompositorState::API_VERSION_MAX },
221 >,
222 qh: &QueueHandle<D>,
223 ) -> Result<Self, GlobalError>
224 where
225 D: Dispatch<wl_surface::WlSurface, SurfaceData> + 'static,
226 {
227 Self::with_data(compositor, qh, Default::default())
228 }
229
230 pub fn with_data<D, U>(
231 compositor: &impl ProvidesBoundGlobal<
232 wl_compositor::WlCompositor,
233 { CompositorState::API_VERSION_MAX },
234 >,
235 qh: &QueueHandle<D>,
236 data: U,
237 ) -> Result<Self, GlobalError>
238 where
239 D: Dispatch<wl_surface::WlSurface, U> + 'static,
240 U: Send + Sync + 'static,
241 {
242 Ok(Surface(compositor.bound_global()?.create_surface(qh, data)))
243 }
244
245 pub fn wl_surface(&self) -> &wl_surface::WlSurface {
246 &self.0
247 }
248}
249
250impl From<wl_surface::WlSurface> for Surface {
251 fn from(surface: wl_surface::WlSurface) -> Self {
252 Surface(surface)
253 }
254}
255
256impl Drop for Surface {
257 fn drop(&mut self) {
258 self.0.destroy();
259 }
260}
261
262#[macro_export]
263macro_rules! delegate_compositor {
264 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
265 $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface: []);
266 $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface-only: $crate::compositor::SurfaceData);
267 };
268 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, surface: [$($surface: ty),*$(,)?]) => {
269 $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface: [ $($surface),* ]);
270 };
271 (@{$($ty:tt)*}; surface: []) => {
272 $crate::reexports::client::delegate_dispatch!($($ty)*:
273 [
274 $crate::reexports::client::protocol::wl_compositor::WlCompositor: $crate::globals::GlobalData
275 ] => $crate::compositor::CompositorState
276 );
277 $crate::reexports::client::delegate_dispatch!($($ty)*:
278 [
279 $crate::reexports::client::protocol::wl_callback::WlCallback: $crate::reexports::client::protocol::wl_surface::WlSurface
280 ] => $crate::compositor::CompositorState
281 );
282 };
283 (@{$($ty:tt)*}; surface-only: $surface:ty) => {
284 $crate::reexports::client::delegate_dispatch!($($ty)*:
285 [
286 $crate::reexports::client::protocol::wl_surface::WlSurface: $surface
287 ] => $crate::compositor::CompositorState
288 );
289 };
290 (@$ty:tt; surface: [ $($surface:ty),+ ]) => {
291 $crate::delegate_compositor!(@$ty; surface: []);
292 $(
293 $crate::delegate_compositor!(@$ty; surface-only: $surface);
294 )*
295 };
296}
297
298impl<D, U> Dispatch<wl_surface::WlSurface, U, D> for CompositorState
299where
300 D: Dispatch<wl_surface::WlSurface, U> + CompositorHandler + OutputHandler + 'static,
301 U: SurfaceDataExt + 'static,
302{
303 fn event(
304 state: &mut D,
305 surface: &wl_surface::WlSurface,
306 event: wl_surface::Event,
307 data: &U,
308 conn: &Connection,
309 qh: &QueueHandle<D>,
310 ) {
311 let data = data.surface_data();
312 let mut inner = data.inner.lock().unwrap();
313
314 let mut enter_or_leave_output: Option<(wl_output::WlOutput, bool)> = None;
315
316 match event {
317 wl_surface::Event::Enter { output } => {
318 inner.outputs.push(output.clone());
319 enter_or_leave_output.replace((output, true));
320 }
321 wl_surface::Event::Leave { output } => {
322 inner.outputs.retain(|o| o != &output);
323 enter_or_leave_output.replace((output, false));
324 }
325 wl_surface::Event::PreferredBufferScale { factor } => {
326 let current_scale = data.scale_factor.load(Ordering::Relaxed);
327 drop(inner);
328 data.scale_factor.store(factor, Ordering::Relaxed);
329 if current_scale != factor {
330 state.scale_factor_changed(conn, qh, surface, factor);
331 }
332 return;
333 }
334 wl_surface::Event::PreferredBufferTransform { transform } => {
335 if let WEnum::Value(transform) = transform {
337 let old_transform = std::mem::replace(&mut inner.transform, transform);
338 drop(inner);
339 if old_transform != transform {
340 state.transform_changed(conn, qh, surface, transform);
341 }
342 }
343 return;
344 }
345 _ => unreachable!(),
346 }
347
348 if surface.version() >= 6 {
351 drop(inner);
352 match enter_or_leave_output {
353 Some((output, true)) => state.surface_enter(conn, qh, surface, &output),
354 Some((output, false)) => state.surface_leave(conn, qh, surface, &output),
355 None => {}
356 };
357
358 return;
359 }
360
361 inner.watcher.get_or_insert_with(|| {
362 let id = surface.id();
365 OutputState::add_scale_watcher(state, move |state, conn, qh, _| {
366 let id = id.clone();
367 if let Ok(surface) = wl_surface::WlSurface::from_id(conn, id) {
368 if let Some(data) = surface.data::<U>() {
369 let data = data.surface_data();
370 let inner = data.inner.lock().unwrap();
371 dispatch_surface_state_updates(state, conn, qh, &surface, data, inner);
372 }
373 }
374 })
375 });
376
377 dispatch_surface_state_updates(state, conn, qh, surface, data, inner);
378
379 match enter_or_leave_output {
380 Some((output, true)) => state.surface_enter(conn, qh, surface, &output),
381 Some((output, false)) => state.surface_leave(conn, qh, surface, &output),
382 None => {}
383 };
384 }
385}
386
387fn dispatch_surface_state_updates<D, U>(
388 state: &mut D,
389 conn: &Connection,
390 qh: &QueueHandle<D>,
391 surface: &WlSurface,
392 data: &SurfaceData,
393 mut inner: MutexGuard<SurfaceDataInner>,
394) where
395 D: Dispatch<wl_surface::WlSurface, U> + CompositorHandler + OutputHandler + 'static,
396 U: SurfaceDataExt + 'static,
397{
398 let current_scale = data.scale_factor.load(Ordering::Relaxed);
399 let (factor, transform) = match inner
400 .outputs
401 .iter()
402 .filter_map(|output| {
403 output
404 .data::<OutputData>()
405 .map(|data| data.with_output_info(|info| (info.scale_factor, info.transform)))
406 })
407 .reduce(|acc, props| (acc.0.max(props.0), wl_output::Transform::Normal))
411 {
412 None => return,
413 Some(props) => props,
414 };
415
416 data.scale_factor.store(factor, Ordering::Relaxed);
417 let old_transform = mem::replace(&mut inner.transform, transform);
418 drop(inner);
420
421 if factor != current_scale {
422 state.scale_factor_changed(conn, qh, surface, factor);
423 }
424
425 if transform != old_transform {
426 state.transform_changed(conn, qh, surface, transform);
427 }
428}
429
430#[derive(Debug)]
434pub struct Region(wl_region::WlRegion);
435
436impl Region {
437 pub fn new(
438 compositor: &impl ProvidesBoundGlobal<
439 wl_compositor::WlCompositor,
440 { CompositorState::API_VERSION_MAX },
441 >,
442 ) -> Result<Region, GlobalError> {
443 compositor
444 .bound_global()
445 .map(|c| {
446 c.send_constructor(wl_compositor::Request::CreateRegion {}, Arc::new(RegionData))
447 .unwrap_or_else(|_| Proxy::inert(c.backend().clone()))
448 })
449 .map(Region)
450 }
451
452 pub fn add(&self, x: i32, y: i32, width: i32, height: i32) {
453 self.0.add(x, y, width, height)
454 }
455
456 pub fn subtract(&self, x: i32, y: i32, width: i32, height: i32) {
457 self.0.subtract(x, y, width, height)
458 }
459
460 pub fn wl_region(&self) -> &wl_region::WlRegion {
461 &self.0
462 }
463}
464
465impl Drop for Region {
466 fn drop(&mut self) {
467 self.0.destroy()
468 }
469}
470
471struct RegionData;
472
473impl wayland_client::backend::ObjectData for RegionData {
474 fn event(
475 self: Arc<Self>,
476 _: &wayland_client::backend::Backend,
477 _: wayland_client::backend::protocol::Message<wayland_client::backend::ObjectId, OwnedFd>,
478 ) -> Option<Arc<(dyn wayland_client::backend::ObjectData + 'static)>> {
479 unreachable!("wl_region has no events");
480 }
481 fn destroyed(&self, _: wayland_client::backend::ObjectId) {}
482}
483
484impl<D> Dispatch<wl_compositor::WlCompositor, GlobalData, D> for CompositorState
485where
486 D: Dispatch<wl_compositor::WlCompositor, GlobalData> + CompositorHandler,
487{
488 fn event(
489 _: &mut D,
490 _: &wl_compositor::WlCompositor,
491 _: wl_compositor::Event,
492 _: &GlobalData,
493 _: &Connection,
494 _: &QueueHandle<D>,
495 ) {
496 unreachable!("wl_compositor has no events")
497 }
498}
499
500impl ProvidesBoundGlobal<wl_compositor::WlCompositor, { CompositorState::API_VERSION_MAX }>
501 for CompositorState
502{
503 fn bound_global(&self) -> Result<wl_compositor::WlCompositor, GlobalError> {
504 Ok(self.wl_compositor.clone())
505 }
506}
507
508impl<D> Dispatch<wl_callback::WlCallback, wl_surface::WlSurface, D> for CompositorState
509where
510 D: Dispatch<wl_callback::WlCallback, wl_surface::WlSurface> + CompositorHandler,
511{
512 fn event(
513 state: &mut D,
514 _: &wl_callback::WlCallback,
515 event: wl_callback::Event,
516 surface: &wl_surface::WlSurface,
517 conn: &Connection,
518 qh: &QueueHandle<D>,
519 ) {
520 match event {
521 wl_callback::Event::Done { callback_data } => {
522 state.frame(conn, qh, surface, callback_data);
523 }
524
525 _ => unreachable!(),
526 }
527 }
528}