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