1use log::{debug, error};
2use smithay_client_toolkit::{
3 compositor::{CompositorHandler, CompositorState, Region},
4 delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer,
5 delegate_registry, delegate_seat, delegate_simple, delegate_touch,
6 output::{OutputHandler, OutputState},
7 reexports::{
8 client::{
9 globals::GlobalList,
10 protocol::{
11 wl_buffer::{self, WlBuffer},
12 wl_keyboard,
13 wl_output::WlOutput,
14 wl_pointer, wl_touch,
15 },
16 Connection, Dispatch, QueueHandle,
17 },
18 protocols::wp::{
19 single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1::{
20 self, WpSinglePixelBufferManagerV1,
21 },
22 viewporter::client::{
23 wp_viewport::{self, WpViewport},
24 wp_viewporter::{self, WpViewporter},
25 },
26 },
27 },
28 registry::{ProvidesRegistryState, RegistryState, SimpleGlobal},
29 registry_handlers,
30 seat::{
31 keyboard::KeyboardHandler,
32 pointer::{PointerEvent, PointerEventKind, PointerHandler},
33 touch::TouchHandler,
34 Capability, SeatHandler, SeatState,
35 },
36 shell::{
37 wlr_layer::{KeyboardInteractivity, Layer, LayerShell, LayerShellHandler, LayerSurface},
38 WaylandSurface,
39 },
40};
41
42use crate::INIT_SIZE;
43
44pub struct DimData {
45 compositor: CompositorState,
46 registry_state: RegistryState,
47 seat_state: SeatState,
48 output_state: OutputState,
49 layer_shell: LayerShell,
50 pixel_buffer_mgr: SimpleGlobal<WpSinglePixelBufferManagerV1, 1>,
51 viewporter: SimpleGlobal<WpViewporter, 1>,
52
53 alpha: f32,
54 passthrough: bool,
55 views: Vec<DimView>,
56
57 keyboard: Option<wl_keyboard::WlKeyboard>,
58 pointer: Option<wl_pointer::WlPointer>,
59 touch: Option<wl_touch::WlTouch>,
60 exit: bool,
61}
62
63struct DimView {
64 first_configure: bool,
65 width: u32,
66 height: u32,
67 buffer: WlBuffer,
68 viewport: WpViewport,
69 layer: LayerSurface,
70 output: WlOutput,
71}
72
73impl DimData {
74 pub fn new(
75 compositor: CompositorState,
76 globals: &GlobalList,
77 qh: &QueueHandle<Self>,
78 layer_shell: LayerShell,
79 alpha: f32,
80 passthrough: bool,
81 ) -> Self {
82 Self {
83 compositor,
84 registry_state: RegistryState::new(globals),
85 seat_state: SeatState::new(globals, qh),
86 output_state: OutputState::new(globals, qh),
87 layer_shell,
88 pixel_buffer_mgr: SimpleGlobal::<WpSinglePixelBufferManagerV1, 1>::bind(globals, qh)
89 .expect("wp_single_pixel_buffer_manager_v1 not available!"),
90 viewporter: SimpleGlobal::<wp_viewporter::WpViewporter, 1>::bind(globals, qh)
91 .expect("wp_viewporter not available"),
92
93 alpha,
94 passthrough,
95 views: Vec::new(),
96
97 exit: false,
98 keyboard: None,
99 pointer: None,
100 touch: None,
101 }
102 }
103
104 pub fn should_exit(&self) -> bool {
105 self.exit
106 }
107
108 fn create_view(&self, qh: &QueueHandle<Self>, output: WlOutput) -> DimView {
109 let layer = self.layer_shell.create_layer_surface(
110 qh,
111 self.compositor.create_surface(qh),
112 Layer::Overlay,
113 Some("dim_layer"),
114 Some(&output),
115 );
116
117 let (width, height) = if let Some((width, height)) = self
118 .output_state
119 .info(&output)
120 .and_then(|info| info.logical_size)
121 {
122 (width as u32, height as u32)
123 } else {
124 (INIT_SIZE, INIT_SIZE)
125 };
126
127 if self.passthrough {
128 let input_region = Region::new(&self.compositor).expect("Failed to get a wl_region");
129 layer.set_keyboard_interactivity(KeyboardInteractivity::None);
130 layer.set_input_region(Some(input_region.wl_region()));
131 } else {
132 layer.set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
133 }
134
135 layer.set_exclusive_zone(-1);
136 layer.set_size(width, height);
137 layer.commit();
138
139 let viewport = self
140 .viewporter
141 .get()
142 .expect("wp_viewporter failed")
143 .get_viewport(layer.wl_surface(), qh, ());
144
145 let alpha = (u32::MAX as f32 * self.alpha) as u32;
147 let buffer = self
148 .pixel_buffer_mgr
149 .get()
150 .expect("failed to get buffer")
151 .create_u32_rgba_buffer(0, 0, 0, alpha, qh, ());
152
153 DimView::new(qh, buffer, viewport, layer, output)
154 }
155}
156
157impl DimView {
158 fn new(
159 _qh: &QueueHandle<DimData>,
160 buffer: WlBuffer,
161 viewport: WpViewport,
162 layer: LayerSurface,
163 output: WlOutput,
164 ) -> Self {
165 Self {
166 first_configure: true,
167 width: INIT_SIZE,
168 height: INIT_SIZE,
169 buffer,
170 viewport,
171 layer,
172 output,
173 }
174 }
175
176 fn draw(&mut self, _qh: &QueueHandle<DimData>) {
177 debug!("Requesting draw");
178 if !self.first_configure {
179 return;
181 }
182
183 self.layer.wl_surface().attach(Some(&self.buffer), 0, 0);
184 self.layer.commit();
185
186 debug!("Drawn");
187 }
188}
189
190impl LayerShellHandler for DimData {
191 fn closed(
192 &mut self,
193 _conn: &smithay_client_toolkit::reexports::client::Connection,
194 _qh: &QueueHandle<Self>,
195 _layer: &LayerSurface,
196 ) {
197 debug!("Closed");
198 self.exit = true;
199 }
200
201 fn configure(
202 &mut self,
203 _conn: &smithay_client_toolkit::reexports::client::Connection,
204 qh: &QueueHandle<Self>,
205 layer: &LayerSurface,
206 configure: smithay_client_toolkit::shell::wlr_layer::LayerSurfaceConfigure,
207 _serial: u32,
208 ) {
209 let Some(view) = self.views.iter_mut().find(|view| &view.layer == layer) else {
210 error!("Configuring layer not in self.views?");
211 return;
212 };
213
214 (view.width, view.height) = configure.new_size;
215
216 view.viewport
217 .set_destination(view.width as _, view.height as _);
218
219 if view.first_configure {
220 view.draw(qh);
221 view.first_configure = false;
222 }
223 }
224}
225
226impl CompositorHandler for DimData {
227 fn scale_factor_changed(
228 &mut self,
229 _conn: &smithay_client_toolkit::reexports::client::Connection,
230 _qh: &QueueHandle<Self>,
231 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
232 _new_factor: i32,
233 ) {
234 }
235
236 fn transform_changed(
237 &mut self,
238 _conn: &smithay_client_toolkit::reexports::client::Connection,
239 _qh: &QueueHandle<Self>,
240 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
241 _new_transform: smithay_client_toolkit::reexports::client::protocol::wl_output::Transform,
242 ) {
243 }
244
245 fn frame(
246 &mut self,
247 _conn: &smithay_client_toolkit::reexports::client::Connection,
248 _qh: &QueueHandle<Self>,
249 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
250 _time: u32,
251 ) {
252 }
253
254 fn surface_enter(
255 &mut self,
256 _conn: &Connection,
257 _qh: &QueueHandle<Self>,
258 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
259 _output: &smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput,
260 ) {
261 }
262
263 fn surface_leave(
264 &mut self,
265 _conn: &Connection,
266 _qh: &QueueHandle<Self>,
267 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
268 _output: &smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput,
269 ) {
270 }
271}
272
273impl OutputHandler for DimData {
274 fn output_state(&mut self) -> &mut OutputState {
275 &mut self.output_state
276 }
277
278 fn new_output(
279 &mut self,
280 _conn: &smithay_client_toolkit::reexports::client::Connection,
281 qh: &QueueHandle<Self>,
282 output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput,
283 ) {
284 self.views.push(self.create_view(qh, output));
285 }
286
287 fn update_output(
288 &mut self,
289 _conn: &smithay_client_toolkit::reexports::client::Connection,
290 qh: &QueueHandle<Self>,
291 output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput,
292 ) {
293 let new_view = self.create_view(qh, output);
294
295 if let Some(view) = self.views.iter_mut().find(|v| v.output == new_view.output) {
296 *view = new_view;
297 } else {
298 error!("Updating output not in views list??");
299 }
300 }
301
302 fn output_destroyed(
303 &mut self,
304 _conn: &smithay_client_toolkit::reexports::client::Connection,
305 _qh: &QueueHandle<Self>,
306 output: smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput,
307 ) {
308 self.views.retain(|v| v.output != output);
309 }
310}
311
312impl SeatHandler for DimData {
313 fn seat_state(&mut self) -> &mut SeatState {
314 &mut self.seat_state
315 }
316
317 fn new_seat(
318 &mut self,
319 _conn: &smithay_client_toolkit::reexports::client::Connection,
320 _qh: &QueueHandle<Self>,
321 _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat,
322 ) {
323 }
324
325 fn new_capability(
326 &mut self,
327 _conn: &smithay_client_toolkit::reexports::client::Connection,
328 qh: &QueueHandle<Self>,
329 seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat,
330 capability: Capability,
331 ) {
332 match capability {
333 Capability::Keyboard => {
334 self.keyboard = Some(
335 self.seat_state
336 .get_keyboard(qh, &seat, None)
337 .expect("Failed to get keyboard"),
338 )
339 }
340 Capability::Pointer => {
341 self.pointer = Some(
342 self.seat_state
343 .get_pointer(qh, &seat)
344 .expect("Failed to get pointer"),
345 )
346 }
347 Capability::Touch => {
348 self.touch = Some(
349 self.seat_state
350 .get_touch(qh, &seat)
351 .expect("Failed to get touch device!"),
352 )
353 }
354 _ => debug!("Unknown capability found: {capability}"),
355 }
356 }
357
358 fn remove_capability(
359 &mut self,
360 _conn: &smithay_client_toolkit::reexports::client::Connection,
361 _qh: &QueueHandle<Self>,
362 _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat,
363 capability: Capability,
364 ) {
365 match capability {
366 Capability::Keyboard => self
367 .keyboard
368 .take()
369 .expect("Failed to remove keyboard!")
370 .release(),
371 Capability::Pointer => self
372 .pointer
373 .take()
374 .expect("Failed to remove pointer!")
375 .release(),
376 Capability::Touch => self
377 .touch
378 .take()
379 .expect("Failed to remove touch device!")
380 .release(),
381 _ => debug!("Unknown capability removed: {capability}"),
382 }
383 }
384
385 fn remove_seat(
386 &mut self,
387 _conn: &smithay_client_toolkit::reexports::client::Connection,
388 _qh: &QueueHandle<Self>,
389 _seat: smithay_client_toolkit::reexports::client::protocol::wl_seat::WlSeat,
390 ) {
391 }
392}
393
394impl KeyboardHandler for DimData {
395 fn enter(
396 &mut self,
397 _conn: &smithay_client_toolkit::reexports::client::Connection,
398 _qh: &QueueHandle<Self>,
399 _keyboard: &wl_keyboard::WlKeyboard,
400 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
401 _serial: u32,
402 _raw: &[u32],
403 _keysyms: &[smithay_client_toolkit::seat::keyboard::Keysym],
404 ) {
405 }
406
407 fn leave(
408 &mut self,
409 _conn: &smithay_client_toolkit::reexports::client::Connection,
410 _qh: &QueueHandle<Self>,
411 _keyboard: &wl_keyboard::WlKeyboard,
412 _surface: &smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
413 _serial: u32,
414 ) {
415 }
416
417 fn press_key(
418 &mut self,
419 _conn: &smithay_client_toolkit::reexports::client::Connection,
420 _qh: &QueueHandle<Self>,
421 _keyboard: &wl_keyboard::WlKeyboard,
422 _serial: u32,
423 _event: smithay_client_toolkit::seat::keyboard::KeyEvent,
424 ) {
425 debug!("Key pressed");
426 self.exit = true;
427 }
428
429 fn release_key(
430 &mut self,
431 _conn: &smithay_client_toolkit::reexports::client::Connection,
432 _qh: &QueueHandle<Self>,
433 _keyboard: &wl_keyboard::WlKeyboard,
434 _serial: u32,
435 _event: smithay_client_toolkit::seat::keyboard::KeyEvent,
436 ) {
437 debug!("Key released");
438 }
439
440 fn update_modifiers(
441 &mut self,
442 _conn: &smithay_client_toolkit::reexports::client::Connection,
443 _qh: &QueueHandle<Self>,
444 _keyboard: &wl_keyboard::WlKeyboard,
445 _serial: u32,
446 _modifiers: smithay_client_toolkit::seat::keyboard::Modifiers,
447 _layout: u32,
448 ) {
449 debug!("Modifiers updated");
450 }
451}
452
453impl PointerHandler for DimData {
454 fn pointer_frame(
455 &mut self,
456 _conn: &smithay_client_toolkit::reexports::client::Connection,
457 _qh: &QueueHandle<Self>,
458 pointer: &wl_pointer::WlPointer,
459 events: &[PointerEvent],
460 ) {
461 for e in events {
462 match e.kind {
463 PointerEventKind::Enter { serial } => {
464 if self.alpha == 1.0 {
465 pointer.set_cursor(serial, None, 0, 0);
466 }
467 }
468 PointerEventKind::Leave { .. } => {}
469 _ => {
470 debug!("Mouse event");
471 self.exit = true;
472 }
473 }
474 }
475 }
476}
477
478impl TouchHandler for DimData {
479 fn down(
480 &mut self,
481 _conn: &Connection,
482 _qh: &QueueHandle<Self>,
483 _touch: &wl_touch::WlTouch,
484 _serial: u32,
485 _time: u32,
486 _surface: smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface,
487 _id: i32,
488 _position: (f64, f64),
489 ) {
490 self.exit = true;
491 }
492
493 fn up(
494 &mut self,
495 _conn: &Connection,
496 _qh: &QueueHandle<Self>,
497 _touch: &wl_touch::WlTouch,
498 _serial: u32,
499 _time: u32,
500 _id: i32,
501 ) {
502 }
503
504 fn motion(
505 &mut self,
506 _conn: &Connection,
507 _qh: &QueueHandle<Self>,
508 _touch: &wl_touch::WlTouch,
509 _time: u32,
510 _id: i32,
511 _position: (f64, f64),
512 ) {
513 }
514
515 fn shape(
516 &mut self,
517 _conn: &Connection,
518 _qh: &QueueHandle<Self>,
519 _touch: &wl_touch::WlTouch,
520 _id: i32,
521 _major: f64,
522 _minor: f64,
523 ) {
524 }
525
526 fn orientation(
527 &mut self,
528 _conn: &Connection,
529 _qh: &QueueHandle<Self>,
530 _touch: &wl_touch::WlTouch,
531 _id: i32,
532 _orientation: f64,
533 ) {
534 }
535
536 fn cancel(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _touch: &wl_touch::WlTouch) {}
537}
538
539delegate_compositor!(DimData);
540delegate_touch!(DimData);
541delegate_layer!(DimData);
542delegate_registry!(DimData);
543delegate_pointer!(DimData);
544delegate_keyboard!(DimData);
545delegate_output!(DimData);
546delegate_seat!(DimData);
547delegate_simple!(DimData, WpViewporter, 1);
548
549impl ProvidesRegistryState for DimData {
550 fn registry(&mut self) -> &mut RegistryState {
551 &mut self.registry_state
552 }
553
554 registry_handlers![OutputState, SeatState];
555}
556
557impl Dispatch<WpViewport, ()> for DimData {
558 fn event(
559 _: &mut Self,
560 _: &WpViewport,
561 _: wp_viewport::Event,
562 _: &(),
563 _: &Connection,
564 _: &QueueHandle<Self>,
565 ) {
566 unreachable!("wp_single_pixel_buffer_manager_v1::Event is empty in version 1")
567 }
568}
569
570impl Dispatch<WpSinglePixelBufferManagerV1, ()> for DimData {
571 fn event(
572 _: &mut Self,
573 _: &WpSinglePixelBufferManagerV1,
574 _: wp_single_pixel_buffer_manager_v1::Event,
575 _: &(),
576 _: &Connection,
577 _: &QueueHandle<Self>,
578 ) {
579 unreachable!("wp_single_pixel_buffer_manager_v1::Event is empty in version 1")
580 }
581}
582impl Dispatch<WlBuffer, ()> for DimData {
583 fn event(
584 _: &mut Self,
585 _: &WlBuffer,
586 event: wl_buffer::Event,
587 _: &(),
588 _: &Connection,
589 _: &QueueHandle<Self>,
590 ) {
591 match event {
592 wl_buffer::Event::Release => debug!("WlBuffer released"),
593 _ => unreachable!("WlBuffer only has Release event"),
594 }
595 }
596}
597
598impl Drop for DimView {
599 fn drop(&mut self) {
600 self.viewport.destroy();
601 self.buffer.destroy();
602 }
603}