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 = 6;
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
131#[derive(Debug)]
133pub struct SurfaceData<U> {
134 pub(crate) scale_factor: AtomicI32,
136
137 pub(crate) parent_surface: Option<WlSurface>,
141
142 inner: Mutex<SurfaceDataInner>,
144
145 udata: U,
146}
147
148impl<U> SurfaceData<U> {
149 pub fn new(parent_surface: Option<WlSurface>, scale_factor: i32, udata: U) -> Self {
151 Self {
152 scale_factor: AtomicI32::new(scale_factor),
153 parent_surface,
154 inner: Default::default(),
155 udata,
156 }
157 }
158
159 pub fn data(&self) -> &U {
160 &self.udata
161 }
162
163 pub fn data_mut(&mut self) -> &mut U {
164 &mut self.udata
165 }
166
167 pub fn scale_factor(&self) -> i32 {
169 self.scale_factor.load(Ordering::Relaxed)
170 }
171
172 pub fn transform(&self) -> wl_output::Transform {
174 self.inner.lock().unwrap().transform
175 }
176
177 pub fn parent_surface(&self) -> Option<&WlSurface> {
182 self.parent_surface.as_ref()
183 }
184
185 pub fn outputs(&self) -> impl Iterator<Item = wl_output::WlOutput> {
187 self.inner.lock().unwrap().outputs.clone().into_iter()
188 }
189}
190
191#[derive(Debug)]
200struct SurfaceDataInner {
201 transform: wl_output::Transform,
203
204 outputs: Vec<wl_output::WlOutput>,
206
207 watcher: Option<ScaleWatcherHandle>,
209}
210
211impl Default for SurfaceDataInner {
212 fn default() -> Self {
213 Self { transform: wl_output::Transform::Normal, outputs: Vec::new(), watcher: None }
214 }
215}
216
217#[derive(Debug)]
221pub struct Surface(wl_surface::WlSurface);
222
223impl Surface {
224 pub fn new<D>(
225 compositor: &impl ProvidesBoundGlobal<
226 wl_compositor::WlCompositor,
227 { CompositorState::API_VERSION_MAX },
228 >,
229 qh: &QueueHandle<D>,
230 ) -> Result<Self, GlobalError>
231 where
232 D: Dispatch<wl_surface::WlSurface, SurfaceData<()>> + 'static,
233 {
234 Self::with_data(compositor, qh, None, 1, ())
235 }
236
237 pub fn with_data<D, U>(
238 compositor: &impl ProvidesBoundGlobal<
239 wl_compositor::WlCompositor,
240 { CompositorState::API_VERSION_MAX },
241 >,
242 qh: &QueueHandle<D>,
243 parent_surface: Option<WlSurface>,
244 scale_factor: i32,
245 data: U,
246 ) -> Result<Self, GlobalError>
247 where
248 D: Dispatch<wl_surface::WlSurface, SurfaceData<U>> + 'static,
249 U: Send + Sync + 'static,
250 {
251 let data = SurfaceData::new(parent_surface, scale_factor, data);
252 Ok(Surface(compositor.bound_global()?.create_surface(qh, data)))
253 }
254
255 pub fn wl_surface(&self) -> &wl_surface::WlSurface {
256 &self.0
257 }
258}
259
260impl From<wl_surface::WlSurface> for Surface {
261 fn from(surface: wl_surface::WlSurface) -> Self {
262 Surface(surface)
263 }
264}
265
266impl Drop for Surface {
267 fn drop(&mut self) {
268 self.0.destroy();
269 }
270}
271
272impl<D, U> Dispatch2<wl_surface::WlSurface, D> for SurfaceData<U>
273where
274 D: CompositorHandler + OutputHandler + 'static,
275 U: Send + Sync + 'static,
276{
277 fn event(
278 &self,
279 state: &mut D,
280 surface: &wl_surface::WlSurface,
281 event: wl_surface::Event,
282 conn: &Connection,
283 qh: &QueueHandle<D>,
284 ) {
285 let mut inner = self.inner.lock().unwrap();
286
287 let mut enter_or_leave_output: Option<(wl_output::WlOutput, bool)> = None;
288
289 match event {
290 wl_surface::Event::Enter { output } => {
291 inner.outputs.push(output.clone());
292 enter_or_leave_output.replace((output, true));
293 }
294 wl_surface::Event::Leave { output } => {
295 inner.outputs.retain(|o| o != &output);
296 enter_or_leave_output.replace((output, false));
297 }
298 wl_surface::Event::PreferredBufferScale { factor } => {
299 let current_scale = self.scale_factor.load(Ordering::Relaxed);
300 drop(inner);
301 self.scale_factor.store(factor, Ordering::Relaxed);
302 if current_scale != factor {
303 state.scale_factor_changed(conn, qh, surface, factor);
304 }
305 return;
306 }
307 wl_surface::Event::PreferredBufferTransform { transform } => {
308 if let WEnum::Value(transform) = transform {
310 let old_transform = std::mem::replace(&mut inner.transform, transform);
311 drop(inner);
312 if old_transform != transform {
313 state.transform_changed(conn, qh, surface, transform);
314 }
315 }
316 return;
317 }
318 _ => unreachable!(),
319 }
320
321 if surface.version() >= 6 {
324 drop(inner);
325 match enter_or_leave_output {
326 Some((output, true)) => state.surface_enter(conn, qh, surface, &output),
327 Some((output, false)) => state.surface_leave(conn, qh, surface, &output),
328 None => {}
329 };
330
331 return;
332 }
333
334 inner.watcher.get_or_insert_with(|| {
335 let id = surface.id();
338 OutputState::add_scale_watcher(state, move |state, conn, qh, _| {
339 let id = id.clone();
340 if let Ok(surface) = wl_surface::WlSurface::from_id(conn, id) {
341 if let Some(data) = surface.data::<SurfaceData<U>>() {
342 let inner = data.inner.lock().unwrap();
343 dispatch_surface_state_updates(state, conn, qh, &surface, data, inner);
344 }
345 }
346 })
347 });
348
349 dispatch_surface_state_updates(state, conn, qh, surface, self, inner);
350
351 match enter_or_leave_output {
352 Some((output, true)) => state.surface_enter(conn, qh, surface, &output),
353 Some((output, false)) => state.surface_leave(conn, qh, surface, &output),
354 None => {}
355 };
356 }
357}
358
359fn dispatch_surface_state_updates<D, U>(
360 state: &mut D,
361 conn: &Connection,
362 qh: &QueueHandle<D>,
363 surface: &WlSurface,
364 data: &SurfaceData<U>,
365 mut inner: MutexGuard<SurfaceDataInner>,
366) where
367 D: CompositorHandler + OutputHandler + 'static,
368{
369 let current_scale = data.scale_factor.load(Ordering::Relaxed);
370 let (factor, transform) = match inner
371 .outputs
372 .iter()
373 .filter_map(|output| {
374 output
375 .data::<OutputData>()
376 .map(|data| data.with_output_info(|info| (info.scale_factor, info.transform)))
377 })
378 .reduce(|acc, props| (acc.0.max(props.0), wl_output::Transform::Normal))
382 {
383 None => return,
384 Some(props) => props,
385 };
386
387 data.scale_factor.store(factor, Ordering::Relaxed);
388 let old_transform = mem::replace(&mut inner.transform, transform);
389 drop(inner);
391
392 if factor != current_scale {
393 state.scale_factor_changed(conn, qh, surface, factor);
394 }
395
396 if transform != old_transform {
397 state.transform_changed(conn, qh, surface, transform);
398 }
399}
400
401#[derive(Debug)]
405pub struct Region(wl_region::WlRegion);
406
407impl Region {
408 pub fn new(
409 compositor: &impl ProvidesBoundGlobal<
410 wl_compositor::WlCompositor,
411 { CompositorState::API_VERSION_MAX },
412 >,
413 ) -> Result<Region, GlobalError> {
414 compositor
415 .bound_global()
416 .map(|c| {
417 c.send_constructor(wl_compositor::Request::CreateRegion {}, Arc::new(RegionData))
418 .unwrap_or_else(|_| Proxy::inert(c.backend().clone()))
419 })
420 .map(Region)
421 }
422
423 pub fn add(&self, x: i32, y: i32, width: i32, height: i32) {
424 self.0.add(x, y, width, height)
425 }
426
427 pub fn subtract(&self, x: i32, y: i32, width: i32, height: i32) {
428 self.0.subtract(x, y, width, height)
429 }
430
431 pub fn wl_region(&self) -> &wl_region::WlRegion {
432 &self.0
433 }
434}
435
436impl Drop for Region {
437 fn drop(&mut self) {
438 self.0.destroy()
439 }
440}
441
442struct RegionData;
443
444impl wayland_client::backend::ObjectData for RegionData {
445 fn event(
446 self: Arc<Self>,
447 _: &wayland_client::backend::Backend,
448 _: wayland_client::backend::protocol::Message<wayland_client::backend::ObjectId, OwnedFd>,
449 ) -> Option<Arc<dyn wayland_client::backend::ObjectData + 'static>> {
450 unreachable!("wl_region has no events");
451 }
452 fn destroyed(&self, _: wayland_client::backend::ObjectId) {}
453}
454
455impl<D> Dispatch2<wl_compositor::WlCompositor, D> for GlobalData
456where
457 D: CompositorHandler,
458{
459 fn event(
460 &self,
461 _: &mut D,
462 _: &wl_compositor::WlCompositor,
463 _: wl_compositor::Event,
464 _: &Connection,
465 _: &QueueHandle<D>,
466 ) {
467 unreachable!("wl_compositor has no events")
468 }
469}
470
471impl ProvidesBoundGlobal<wl_compositor::WlCompositor, { CompositorState::API_VERSION_MAX }>
472 for CompositorState
473{
474 fn bound_global(&self) -> Result<wl_compositor::WlCompositor, GlobalError> {
475 Ok(self.wl_compositor.clone())
476 }
477}
478
479#[derive(Debug)]
480pub struct FrameCallbackData(pub wl_surface::WlSurface);
481
482impl<D> Dispatch2<wl_callback::WlCallback, D> for FrameCallbackData
483where
484 D: CompositorHandler,
485{
486 fn event(
487 &self,
488 state: &mut D,
489 _: &wl_callback::WlCallback,
490 event: wl_callback::Event,
491 conn: &Connection,
492 qh: &QueueHandle<D>,
493 ) {
494 match event {
495 wl_callback::Event::Done { callback_data } => {
496 state.frame(conn, qh, &self.0, callback_data);
497 }
498
499 _ => unreachable!(),
500 }
501 }
502}