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