1use crate::{
6 SpellAssociatedNew,
7 configure::{HomeHandle, LayerConf, WindowConf, set_up_tracing},
8 slint_adapter::{
9 ADAPTERS, SpellLayerShell, SpellLockShell, SpellMultiWinHandler, SpellSkiaWinAdapter,
10 },
11 wayland_adapter::{
12 fractional_scaling::{
13 FractionalScaleHandler, FractionalScaleState, delegate_fractional_scale,
14 },
15 viewporter::{Viewport, ViewporterState, delegate_viewporter},
16 way_helper::{
17 FingerprintInfo, PointerState, UsernamePassConvo, set_config, set_event_sources,
18 },
19 },
20};
21use i_slint_core::items::MouseCursor;
22pub use lock_impl::SpellSlintLock;
23use nonstick::{
24 AuthnFlags, ConversationAdapter, Result as PamResult, Transaction, TransactionBuilder,
25};
26use slint::{
27 PhysicalSize,
28 platform::{Key, WindowAdapter},
29};
30use smithay_client_toolkit::{
31 compositor::{CompositorHandler, CompositorState, Region},
32 delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer,
33 delegate_registry, delegate_seat, delegate_session_lock, delegate_shm, delegate_touch,
34 output::{self, OutputHandler, OutputState},
35 reexports::{
36 calloop::{
37 EventLoop, LoopHandle, RegistrationToken,
38 timer::{TimeoutAction, Timer},
39 },
40 calloop_wayland_source::WaylandSource,
41 client::{
42 Connection, EventQueue, QueueHandle,
43 globals::registry_queue_init,
44 protocol::{wl_keyboard::WlKeyboard, wl_output, wl_shm, wl_surface, wl_touch::WlTouch},
45 },
46 },
47 registry::RegistryState,
48 seat::{SeatState, pointer::cursor_shape::CursorShapeManager},
49 session_lock::{SessionLock, SessionLockState, SessionLockSurface},
50 shell::{
51 WaylandSurface,
52 wlr_layer::{
53 KeyboardInteractivity, LayerShell, LayerShellHandler, LayerSurface,
54 LayerSurfaceConfigure,
55 },
56 },
57 shm::{
58 Shm, ShmHandler,
59 slot::{Buffer, Slot, SlotPool},
60 },
61};
62use std::{
63 cell::{Cell, RefCell},
64 collections::HashMap,
65 os::unix::net::UnixListener,
66 process::Command,
67 rc::Rc,
68 sync::{Arc, Mutex, Once, OnceLock, RwLock},
69 time::Duration,
70};
71use tracing::{Level, info, span, trace, warn};
72
73mod fractional_scaling;
74mod lock_impl;
75mod slint_to_wl_cursor_mapping;
76mod viewporter;
77mod way_helper;
78mod win_impl;
79
80static AVAILABLE_MONITORS: OnceLock<RwLock<HashMap<String, wl_output::WlOutput>>> = OnceLock::new();
81static SET_SLINT_PLATFORM: Once = Once::new();
82
83#[derive(Debug)]
84pub(crate) struct States {
85 pub(crate) registry_state: RegistryState,
86 pub(crate) seat_state: SeatState,
87 pub(crate) output_state: OutputState,
88 pub(crate) pointer_state: PointerState,
89 pub(crate) keyboard_state: Option<WlKeyboard>,
90 pub(crate) touch_state: Option<WlTouch>,
91 pub(crate) shm: Shm,
92 pub(crate) viewporter: Option<Viewport>,
93}
94
95pub struct SpellWin {
98 pub(crate) adapter: Rc<SpellSkiaWinAdapter>,
99 pub loop_handle: LoopHandle<'static, SpellWin>,
101 pub ipc_handler: Option<UnixListener>,
103 pub(crate) buffer: Buffer,
105 pub(crate) states: States,
106 pub(crate) layer: Option<LayerSurface>,
107 pub(crate) first_configure: Cell<bool>,
108 pub(crate) natural_scroll: bool,
109 pub(crate) is_hidden: Cell<bool>,
110 pub layer_name: String,
112 pub(crate) config: WindowConf,
113 pub(crate) input_region: Region,
114 pub(crate) opaque_region: Region,
115 pub event_loop: Rc<RefCell<EventLoop<'static, SpellWin>>>,
117 pub span: span::Span,
119 }
122
123impl std::fmt::Debug for SpellWin {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 f.debug_struct("SpellWin")
126 .field("adapter", &self.adapter)
127 .field("first_configure", &self.first_configure)
128 .field("is_hidden", &self.is_hidden)
129 .field("config", &self.config)
130 .finish()
131 }
132}
133
134impl SpellWin {
135 pub(crate) fn create_window(
136 conn: &Connection,
137 window_conf: WindowConf,
138 layer_name: String,
139 handle: HomeHandle,
140 ) -> Self {
141 let (globals, mut event_queue) = registry_queue_init(conn).unwrap();
142 let qh: QueueHandle<SpellWin> = event_queue.handle();
143
144 let compositor =
145 CompositorState::bind(&globals, &qh).expect("wl_compositor is not available");
146 let event_loop: EventLoop<'static, SpellWin> =
147 EventLoop::try_new().expect("Failed to initialize the event loop!");
148 let layer_shell = LayerShell::bind(&globals, &qh).expect("layer shell is not available");
149 let shm = Shm::bind(&globals, &qh).expect("wl_shm is not available");
150 let mut pool = SlotPool::new((window_conf.width * window_conf.height * 4) as usize, &shm)
151 .expect("Failed to create pool");
152 let input_region = Region::new(&compositor).expect("Couldn't create region");
153 let opaque_region = Region::new(&compositor).expect("Couldn't create opaque region");
154 input_region.add(0, 0, window_conf.width as i32, window_conf.height as i32);
155 let cursor_manager =
156 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
157 let fractional_scale_state: FractionalScaleState =
158 FractionalScaleState::bind(&globals, &qh).expect("Fractional Scale couldn't be set");
159 let stride = window_conf.width as i32 * 4;
160
161 let surface = compositor.create_surface(&qh);
162 let viewporter_state =
163 ViewporterState::bind(&globals, &qh).expect("Couldn't set viewporter");
164
165 let (way_pri_buffer, _) = pool
166 .create_buffer(
167 window_conf.width as i32,
168 window_conf.height as i32,
169 stride,
170 wl_shm::Format::Argb8888,
171 )
172 .expect("Creating Buffer");
173
174 let primary_slot = way_pri_buffer.slot();
175
176 let pointer_state = PointerState {
177 pointer: None,
178 pointer_data: None,
179 cursor_shape: cursor_manager,
180 current_wayland_cursor: MouseCursor::Default,
181 last_cursor_enter_serial: None,
182 };
183
184 #[allow(clippy::type_complexity)]
185 let slint_proxy: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>> =
186 Arc::new(Mutex::new(Vec::new()));
187 let adapter_value: Rc<SpellSkiaWinAdapter> = SpellSkiaWinAdapter::new(
188 Rc::new(RefCell::new(pool)),
189 RefCell::new(primary_slot),
190 window_conf.width,
191 window_conf.height,
192 slint_proxy.clone(),
193 );
194
195 ADAPTERS.with_borrow_mut(|v| v.push(adapter_value.clone()));
196 SET_SLINT_PLATFORM.call_once(|| {
197 trace!("Slint platform set");
198 if let Err(err) = slint::platform::set_platform(Box::new(SpellLayerShell::default())) {
199 warn!("Error setting slint platform: {err}");
200 }
201 });
202 set_event_sources(&event_loop, handle);
203
204 let mut win = SpellWin {
205 adapter: adapter_value,
206 loop_handle: event_loop.handle(),
207 ipc_handler: None,
208 buffer: way_pri_buffer,
210 states: States {
211 registry_state: RegistryState::new(&globals),
212 seat_state: SeatState::new(&globals, &qh),
213 output_state: OutputState::new(&globals, &qh),
214 pointer_state,
215 keyboard_state: None,
216 touch_state: None,
217 shm,
218 viewporter: None,
219 },
220 layer: None,
221 first_configure: Cell::new(true),
222 natural_scroll: window_conf.natural_scroll,
223 is_hidden: Cell::new(false),
224 layer_name: layer_name.clone(),
225 config: window_conf.clone(),
226 input_region,
227 opaque_region,
228 event_loop: Rc::new(RefCell::new(event_loop)),
229 span: span!(Level::INFO, "widget", name = layer_name.as_str(),),
230 };
231
232 if AVAILABLE_MONITORS.get().is_none() {
233 match SpellWin::get_available_monitors(&mut event_queue, &mut win) {
234 Some(monitors) => {
235 let _ = AVAILABLE_MONITORS.get_or_init(|| RwLock::new(monitors));
236 }
237 None => warn!("Failed to get available monitors"),
238 }
239 }
240
241 let target_output: Option<wl_output::WlOutput> =
242 if let Some(name) = &window_conf.monitor_name {
243 let output = AVAILABLE_MONITORS
244 .get()
245 .and_then(|monitors| monitors.read().ok())
246 .and_then(|monitors| monitors.get(name).cloned());
247 if output.is_none() {
248 warn!("Monitor '{}' not found, using default monitor", name);
249 }
250 output
251 } else {
252 None
253 };
254
255 let layer = layer_shell.create_layer_surface(
256 &qh,
257 surface,
258 window_conf.layer_type,
259 Some(layer_name.clone()),
260 target_output.as_ref(),
261 );
262 let fractional_scale = fractional_scale_state.get_scale(layer.wl_surface(), &qh);
263
264 let viewporter = viewporter_state.get_viewport(layer.wl_surface(), &qh, fractional_scale);
265
266 set_config(
267 &win.config,
268 &layer,
269 Some(win.input_region.wl_region()),
271 None,
272 );
273 layer.commit();
274
275 win.layer = Some(layer);
276 win.states.viewporter = Some(viewporter);
277
278 info!("Win: {} layer created successfully.", layer_name);
279
280 WaylandSource::new(conn.clone(), event_queue)
281 .insert(win.loop_handle.clone())
282 .unwrap();
283 win
284 }
285
286 fn get_available_monitors(
296 event_queue: &mut EventQueue<SpellWin>,
297 win: &mut SpellWin,
298 ) -> Option<HashMap<String, wl_output::WlOutput>> {
299 event_queue.roundtrip(win).ok()?;
301
302 Some(
303 win.states
304 .output_state
305 .outputs()
306 .filter_map(|output| {
307 let info = win.states.output_state.info(&output)?;
308 Some((info.name?, output))
309 })
310 .collect(),
311 )
312 }
313
314 pub fn get_handler(&self) -> WinHandle {
316 info!("Win: Handle provided.");
317 WinHandle(self.loop_handle.clone())
318 }
319
320 pub fn invoke_spell(name: &str, window_conf: WindowConf) -> Self {
328 let handle = set_up_tracing(name);
329 let conn = Connection::connect_to_env().unwrap();
330 SpellWin::create_window(&conn, window_conf.clone(), name.to_string(), handle)
331 }
332
333 pub fn hide(&self) {
335 if !self.is_hidden.replace(true) {
336 info!("Win: Hiding window");
337 self.layer.as_ref().unwrap().wl_surface().attach(None, 0, 0);
338 }
339 }
340
341 pub fn show_again(&self) {
343 if self.is_hidden.replace(false) {
344 info!("Win: Showing window again");
345 self.set_config_internal();
346 self.first_configure.set(true);
347 self.layer.as_ref().unwrap().commit();
348 }
349 }
350
351 pub fn toggle(&self) {
353 info!("Win: view toggled");
354 if self.is_hidden.get() {
355 self.show_again();
356 } else {
357 self.hide();
358 }
359 }
360
361 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
367 info!(
368 "Win: input region added: [x: {}, y: {}, width: {}, height: {}]",
369 x, y, width, height
370 );
371 self.input_region.add(x, y, width, height);
372 self.set_config_internal();
373 self.layer.as_ref().unwrap().commit();
374 }
375
376 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
381 info!(
382 "Win: input region removed: [x: {}, y: {}, width: {}, height: {}]",
383 x, y, width, height
384 );
385 self.input_region.subtract(x, y, width, height);
386 self.set_config_internal();
387 self.layer.as_ref().unwrap().commit();
388 }
389
390 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
396 info!(
397 "Win: opaque region added: [x: {}, y: {}, width: {}, height: {}]",
398 x, y, width, height
399 );
400 self.opaque_region.add(x, y, width, height);
401 self.set_config_internal();
402 self.layer.as_ref().unwrap().commit();
403 }
404
405 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
410 info!(
411 "Win: opaque region removed: [x: {}, y: {}, width: {}, height: {}]",
412 x, y, width, height
413 );
414 self.opaque_region.subtract(x, y, width, height);
415 self.set_config_internal();
416 self.layer.as_ref().unwrap().commit();
417 }
418
419 fn set_config_internal(&self) {
420 set_config(
421 &self.config,
422 self.layer.as_ref().unwrap(),
423 Some(self.input_region.wl_region()),
424 Some(self.opaque_region.wl_region()),
425 );
426 }
427
428 fn converter(&mut self, qh: &QueueHandle<Self>) {
429 slint::platform::update_timers_and_animations();
430 let width: u32 = self.adapter.size.get().width;
431 let height: u32 = self.adapter.size.get().height;
432 let window_adapter = self.adapter.clone();
433
434 if !self.is_hidden.get() {
436 let redraw_val: bool = window_adapter.draw_if_needed();
438 self.states
444 .pointer_state
445 .update_cursor(self.adapter.current_cursor.get(), &qh);
446
447 let buffer = &self.buffer;
448 if self.first_configure.get() || redraw_val {
449 self.first_configure.set(false);
451 self.layer.as_ref().unwrap().wl_surface().damage_buffer(
452 0,
453 0,
454 width as i32,
455 height as i32,
456 );
457 self.layer
475 .as_ref()
476 .unwrap()
477 .wl_surface()
478 .attach(Some(buffer.wl_buffer()), 0, 0);
479 }
480
481 self.layer
482 .as_ref()
483 .unwrap()
484 .wl_surface()
485 .frame(qh, self.layer.as_ref().unwrap().wl_surface().clone());
486 self.layer.as_ref().unwrap().commit();
487 } else {
488 self.layer.as_ref().unwrap().commit();
489 }
490 }
491
492 pub fn grab_focus(&self) {
495 if !self.is_hidden.get()
496 && self.config.board_interactivity.get() != KeyboardInteractivity::Exclusive
497 {
498 self.config
499 .board_interactivity
500 .set(KeyboardInteractivity::Exclusive);
501 self.layer
502 .as_ref()
503 .unwrap()
504 .set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
505 self.layer.as_ref().unwrap().commit();
506 }
507 }
508
509 pub fn remove_focus(&self) {
511 if !self.is_hidden.get()
512 && self.config.board_interactivity.get() != KeyboardInteractivity::None
513 {
514 self.config
515 .board_interactivity
516 .set(KeyboardInteractivity::None);
517 self.layer
518 .as_ref()
519 .unwrap()
520 .set_keyboard_interactivity(KeyboardInteractivity::None);
521 self.layer.as_ref().unwrap().commit();
522 }
523 }
524
525 pub fn set_exclusive_zone(&mut self, val: i32) {
528 self.config.exclusive_zone = Some(val);
530 self.layer.as_ref().unwrap().set_exclusive_zone(val);
531 self.layer.as_ref().unwrap().commit();
532 }
533}
534
535impl SpellAssociatedNew for SpellWin {
536 fn on_call(&mut self) -> Result<(), Box<dyn std::error::Error>> {
537 let event_loop = self.event_loop.clone();
538 event_loop
539 .borrow_mut()
540 .dispatch(std::time::Duration::from_millis(1), self)?;
541 Ok(())
542 }
543
544 fn get_span(&self) -> tracing::span::Span {
545 self.span.clone()
546 }
547}
548
549delegate_compositor!(SpellWin);
550delegate_registry!(SpellWin);
551delegate_output!(SpellWin);
552delegate_shm!(SpellWin);
553delegate_seat!(SpellWin);
554delegate_keyboard!(SpellWin);
555delegate_pointer!(SpellWin);
556delegate_touch!(SpellWin);
557delegate_layer!(SpellWin);
558delegate_fractional_scale!(SpellWin);
559delegate_viewporter!(SpellWin);
560
561impl ShmHandler for SpellWin {
562 fn shm_state(&mut self) -> &mut Shm {
563 &mut self.states.shm
564 }
565}
566
567impl OutputHandler for SpellWin {
568 fn output_state(&mut self) -> &mut OutputState {
569 &mut self.states.output_state
570 }
571
572 fn new_output(
573 &mut self,
574 _conn: &Connection,
575 _qh: &QueueHandle<Self>,
576 _output: wl_output::WlOutput,
577 ) {
578 trace!("New output Source Added");
579 }
580
581 fn update_output(
582 &mut self,
583 _conn: &Connection,
584 _qh: &QueueHandle<Self>,
585 _output: wl_output::WlOutput,
586 ) {
587 trace!("Existing output is updated");
588 }
589
590 fn output_destroyed(
591 &mut self,
592 _conn: &Connection,
593 _qh: &QueueHandle<Self>,
594 _output: wl_output::WlOutput,
595 ) {
596 trace!("Output is destroyed");
597 }
598}
599
600impl CompositorHandler for SpellWin {
601 fn scale_factor_changed(
602 &mut self,
603 _: &Connection,
604 _: &QueueHandle<Self>,
605 _: &wl_surface::WlSurface,
606 _: i32,
607 ) {
608 info!("Scale factor changed, compositor msg");
609 }
610
611 fn transform_changed(
612 &mut self,
613 _conn: &Connection,
614 _qh: &QueueHandle<Self>,
615 _surface: &wl_surface::WlSurface,
616 _new_transform: wl_output::Transform,
617 ) {
618 trace!("Compositor transformation changed");
619 }
620
621 fn frame(
622 &mut self,
623 _conn: &Connection,
624 qh: &QueueHandle<Self>,
625 _surface: &wl_surface::WlSurface,
626 _time: u32,
627 ) {
628 self.converter(qh);
629 }
630
631 fn surface_enter(
632 &mut self,
633 _conn: &Connection,
634 _qh: &QueueHandle<Self>,
635 _surface: &wl_surface::WlSurface,
636 _output: &wl_output::WlOutput,
637 ) {
638 trace!("Surface entered");
639 }
640
641 fn surface_leave(
642 &mut self,
643 _conn: &Connection,
644 _qh: &QueueHandle<Self>,
645 _surface: &wl_surface::WlSurface,
646 _output: &wl_output::WlOutput,
647 ) {
648 trace!("Surface left");
649 }
650}
651
652impl FractionalScaleHandler for SpellWin {
653 fn preferred_scale(
654 &mut self,
655 _: &Connection,
656 _: &QueueHandle<Self>,
657 _: &wl_surface::WlSurface,
658 scale: u32,
659 ) {
660 info!("Scale factor changed, invoked from custom trait. {}", scale);
661 let width_old = self.adapter.size_original.get().width;
662 let height_old = self.adapter.size_original.get().height;
663 self.layer.as_ref().unwrap().wl_surface().damage_buffer(
664 0,
665 0,
666 self.adapter.size.get().width as i32,
667 self.adapter.size.get().height as i32,
668 );
669 let (buffer, width, height, scale_factor) = self.adapter.changed_scale_factor(scale);
670 self.config.width = width;
671 self.config.height = height;
672 self.buffer = buffer;
673 self.adapter
674 .try_dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor })
675 .unwrap();
676 self.states.viewporter.as_ref().unwrap().set_source(
677 0.,
678 0.,
679 self.adapter.size.get().width.into(),
680 self.adapter.size.get().height.into(),
681 );
682
683 self.states
684 .viewporter
685 .as_ref()
686 .unwrap()
687 .set_destination(width_old as i32, height_old as i32);
688 self.adapter.request_redraw();
689 self.layer.as_ref().unwrap().commit();
690 }
691}
692
693impl LayerShellHandler for SpellWin {
694 fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
695 trace!("Closure of layer called");
696 }
697
698 fn configure(
699 &mut self,
700 _conn: &Connection,
701 qh: &QueueHandle<Self>,
702 _layer: &LayerSurface,
703 _configure: LayerSurfaceConfigure,
704 _serial: u32,
705 ) {
706 self.converter(qh);
707 }
708}
709
710#[derive(Clone, Debug)]
714pub struct WinHandle(pub LoopHandle<'static, SpellWin>);
715
716impl WinHandle {
717 pub fn hide(&self) {
719 self.0.insert_idle(|win| win.hide());
720 }
721
722 pub fn show_again(&self) {
724 self.0.insert_idle(|win| win.show_again());
725 }
726
727 pub fn toggle(&self) {
729 self.0.insert_idle(|win| win.toggle());
730 }
731
732 pub fn grab_focus(&self) {
734 self.0.insert_idle(|win| win.grab_focus());
735 }
736
737 pub fn remove_focus(&self) {
739 self.0.insert_idle(|win| win.remove_focus());
740 }
741
742 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
744 self.0
745 .insert_idle(move |win| win.add_input_region(x, y, width, height));
746 }
747
748 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
750 self.0
751 .insert_idle(move |win| win.subtract_input_region(x, y, width, height));
752 }
753
754 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
756 self.0
757 .insert_idle(move |win| win.add_opaque_region(x, y, width, height));
758 }
759
760 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
762 self.0
763 .insert_idle(move |win| win.subtract_opaque_region(x, y, width, height));
764 }
765
766 pub fn set_exclusive_zone(&self, val: i32) {
768 self.0.insert_idle(move |win| win.set_exclusive_zone(val));
769 }
770}
771
772pub struct SpellLock {
819 pub(crate) loop_handle: LoopHandle<'static, SpellLock>,
820 pub(crate) conn: Connection,
821 pub(crate) compositor_state: CompositorState,
822 pub(crate) registry_state: RegistryState,
823 pub(crate) output_state: OutputState,
824 pub(crate) keyboard_state: Option<WlKeyboard>,
825 pub(crate) pointer_state: PointerState,
826 pub(crate) touch_state: Option<WlTouch>,
827 pub(crate) seat_state: SeatState,
828 pub(crate) shm: Shm,
829 pub(crate) session_lock: Option<SessionLock>,
830 pub(crate) lock_surfaces: Vec<SessionLockSurface>,
831 pub(crate) slint_part: Option<SpellSlintLock>,
832 pub(crate) is_locked: bool,
833 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellLock>>>,
835 pub(crate) backspace: Option<RegistrationToken>,
836}
837
838impl std::fmt::Debug for SpellLock {
839 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
840 f.debug_struct("SpellLock")
841 .field("is_locked", &self.is_locked)
842 .finish()
843 }
844}
845impl SpellLock {
846 pub fn invoke_lock_spell() -> Self {
849 let conn = Connection::connect_to_env().unwrap();
850 let _ = set_up_tracing("SpellLock");
851 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
852 let qh: QueueHandle<SpellLock> = event_queue.handle();
853 let registry_state = RegistryState::new(&globals);
854 let shm = Shm::bind(&globals, &qh).unwrap();
855 let event_loop: EventLoop<'static, SpellLock> =
856 EventLoop::try_new().expect("Failed to initialize the event loop!");
857 let output_state = OutputState::new(&globals, &qh);
858 let session_lock_state = SessionLockState::new(&globals, &qh);
859 let compositor_state =
860 CompositorState::bind(&globals, &qh).expect("Faild to create compositor state");
861 let cursor_manager =
862 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
863 let mut win_handler_vec: Vec<(String, (u32, u32))> = Vec::new();
864 let lock_surfaces = Vec::new();
865
866 let pointer_state = PointerState {
867 pointer: None,
868 pointer_data: None,
869 cursor_shape: cursor_manager,
870 last_cursor_enter_serial: None,
871 current_wayland_cursor: MouseCursor::Default,
872 };
873 let mut spell_lock = SpellLock {
874 loop_handle: event_loop.handle().clone(),
875 conn: conn.clone(),
876 compositor_state,
877 output_state,
878 keyboard_state: None,
879 touch_state: None,
880 pointer_state,
881 registry_state,
882 seat_state: SeatState::new(&globals, &qh),
883 slint_part: None,
884 shm,
885 session_lock: None,
886 lock_surfaces,
887 is_locked: true,
888 event_loop: Rc::new(RefCell::new(event_loop)),
889 backspace: None,
890 };
891
892 let _ = event_queue.roundtrip(&mut spell_lock);
893
894 let session_lock = Some(
895 session_lock_state
896 .lock(&qh)
897 .expect("ext-session-lock not supported"),
898 );
899
900 spell_lock.session_lock = session_lock;
901 for output in spell_lock.output_state.outputs() {
902 let output_info: output::OutputInfo = spell_lock.output_state.info(&output).unwrap();
903 let output_name: String = output_info.name.unwrap_or_else(|| "SomeOutput".to_string());
904 let dimensions = (
905 output_info.logical_size.unwrap().0 as u32,
906 output_info.logical_size.unwrap().1 as u32,
907 );
908 win_handler_vec.push((output_name, dimensions));
909
910 let session_lock = spell_lock.session_lock.as_ref().unwrap();
911 let surface = spell_lock.compositor_state.create_surface(&qh);
912
913 let lock_surface = session_lock.create_lock_surface(surface, &output, &qh);
916 spell_lock.lock_surfaces.push(lock_surface);
917 }
918 let multi_handler = SpellMultiWinHandler::new_lock(win_handler_vec);
919 let sizes: Vec<PhysicalSize> = multi_handler
920 .borrow()
921 .windows
922 .iter()
923 .map(|(_, conf)| {
924 if let LayerConf::Lock(width, height) = conf {
925 PhysicalSize {
926 width: *width,
927 height: *height,
928 }
929 } else {
930 panic!("Shouldn't enter here");
931 }
932 })
933 .collect();
934
935 let mut pool = SlotPool::new(
936 (sizes[0].width * sizes[0].height * 4) as usize,
937 &spell_lock.shm,
938 )
939 .expect("Couldn't create pool");
940 let mut buffer_slots: Vec<RefCell<Slot>> = Vec::new();
941 let buffers: Vec<Buffer> = sizes
942 .iter()
943 .map(|physical_size| {
944 let stride = physical_size.width as i32 * 4;
945 let (wayland_buffer, _) = pool
946 .create_buffer(
947 physical_size.width as i32,
948 physical_size.height as i32,
949 stride,
950 wl_shm::Format::Argb8888,
951 )
952 .expect("Creating Buffer");
953 buffer_slots.push(RefCell::new(wayland_buffer.slot()));
954 wayland_buffer
955 })
956 .collect();
957 let slint_proxy = Arc::new(Mutex::new(Vec::new()));
958 let pool: Rc<RefCell<SlotPool>> = Rc::new(RefCell::new(pool));
959 let mut adapters: Vec<Rc<SpellSkiaWinAdapter>> = Vec::new();
960 buffer_slots
961 .into_iter()
962 .enumerate()
963 .for_each(|(index, slot)| {
964 let adapter = SpellSkiaWinAdapter::new(
965 pool.clone(),
966 slot,
967 sizes[index].width,
968 sizes[index].height,
969 slint_proxy.clone(),
970 );
971 adapters.push(adapter);
972 });
973
974 multi_handler.borrow_mut().adapter = adapters.clone();
975 spell_lock.slint_part = Some(SpellSlintLock {
976 adapters,
977 size: sizes,
978 wayland_buffer: buffers,
979 });
980
981 spell_lock.backspace = Some(
982 spell_lock
983 .loop_handle
984 .insert_source(
985 Timer::from_duration(Duration::from_millis(1500)),
986 |_, _, data| {
987 data.slint_part.as_ref().unwrap().adapters[0]
988 .try_dispatch_event(slint::platform::WindowEvent::KeyPressed {
989 text: Key::Backspace.into(),
990 })
991 .unwrap();
992 TimeoutAction::ToDuration(Duration::from_millis(1500))
993 },
994 )
995 .unwrap(),
996 );
997
998 spell_lock
999 .loop_handle
1000 .disable(&spell_lock.backspace.unwrap())
1001 .unwrap();
1002 let _ = slint::platform::set_platform(Box::new(SpellLockShell::new(multi_handler)));
1003
1004 WaylandSource::new(spell_lock.conn.clone(), event_queue)
1005 .insert(spell_lock.loop_handle.clone())
1006 .unwrap();
1007 spell_lock
1008 }
1009
1010 fn converter_lock(&mut self, qh: &QueueHandle<Self>) {
1011 slint::platform::update_timers_and_animations();
1012 let width: u32 = self.slint_part.as_ref().unwrap().size[0].width;
1013 let height: u32 = self.slint_part.as_ref().unwrap().size[0].height;
1014 let window_adapter = self.slint_part.as_ref().unwrap().adapters[0].clone();
1015
1016 let _redraw_val: bool = window_adapter.draw_if_needed();
1020 let buffer = &self.slint_part.as_ref().unwrap().wayland_buffer[0];
1023 self.lock_surfaces[0]
1027 .wl_surface()
1028 .damage_buffer(0, 0, width as i32, height as i32);
1029 self.lock_surfaces[0]
1047 .wl_surface()
1048 .frame(qh, self.lock_surfaces[0].wl_surface().clone());
1049 self.lock_surfaces[0]
1050 .wl_surface()
1051 .attach(Some(buffer.wl_buffer()), 0, 0);
1052 self.lock_surfaces[0].wl_surface().commit();
1057 }
1064
1065 fn unlock_finger(&mut self) -> PamResult<()> {
1066 let finger = FingerprintInfo;
1067 let output = Command::new("sh")
1068 .arg("-c")
1069 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1070 .output()
1071 .expect("Couldn't retrive username");
1072
1073 let val = String::from_utf8_lossy(&output.stdout);
1074 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1075 let user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1076
1077 let mut txn = TransactionBuilder::new_with_service("login")
1078 .username(user_name)
1079 .build(finger.into_conversation())?;
1080 txn.authenticate(AuthnFlags::empty())?;
1083 txn.account_management(AuthnFlags::empty())?;
1084 if let Some(locked_val) = self.session_lock.take() {
1085 locked_val.unlock();
1086 } else {
1087 warn!("Authentication verified but couldn't unlock");
1088 }
1089 self.is_locked = false;
1090 self.conn.roundtrip().unwrap();
1091 Ok(())
1092 }
1093
1094 fn unlock(
1095 &mut self,
1096 username: Option<&str>,
1097 password: &str,
1098 on_unlock_callback: Box<dyn FnOnce()>,
1099 ) -> PamResult<()> {
1100 let user_name;
1101 if let Some(username) = username {
1102 user_name = username.to_string();
1103 } else {
1104 let output = Command::new("sh")
1105 .arg("-c")
1106 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1107 .output()
1108 .expect("Couldn't retrive username");
1109
1110 let val = String::from_utf8_lossy(&output.stdout);
1111 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1112 user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1113 }
1114
1115 let user_pass = UsernamePassConvo {
1116 username: user_name.clone(),
1117 password: password.into(),
1118 };
1119
1120 let mut txn = TransactionBuilder::new_with_service("login")
1121 .username(user_name)
1122 .build(user_pass.into_conversation())?;
1123 txn.authenticate(AuthnFlags::empty())?;
1126 txn.account_management(AuthnFlags::empty())?;
1127
1128 on_unlock_callback();
1129 if let Some(locked_val) = self.session_lock.take() {
1130 locked_val.unlock();
1131 } else {
1132 warn!("Authentication verified but couldn't unlock");
1133 }
1134 self.is_locked = false;
1135 self.conn.roundtrip().unwrap();
1136 Ok(())
1137 }
1138
1139 pub fn get_handler(&self) -> LockHandle {
1143 LockHandle(self.loop_handle.clone())
1144 }
1145}
1146
1147impl SpellAssociatedNew for SpellLock {
1148 fn on_call(&mut self) -> Result<(), Box<dyn std::error::Error>> {
1149 let event_loop = self.event_loop.clone();
1150 event_loop
1151 .borrow_mut()
1152 .dispatch(std::time::Duration::from_millis(1), self)?;
1153 Ok(())
1154 }
1155 fn is_locked(&self) -> bool {
1156 self.is_locked
1157 }
1158}
1159
1160#[derive(Debug, Clone)]
1163pub struct LockHandle(LoopHandle<'static, SpellLock>);
1164
1165impl LockHandle {
1166 pub fn unlock(
1171 &self,
1172 username: Option<String>,
1173 password: String,
1174 on_err_callback: Box<dyn FnOnce()>,
1175 on_unlock_callback: Box<dyn FnOnce()>,
1176 ) {
1177 self.0.insert_idle(move |app_data| {
1178 if app_data
1179 .unlock(username.as_deref(), &password, on_unlock_callback)
1180 .is_err()
1181 {
1182 on_err_callback();
1183 }
1184 });
1185 }
1186
1187 pub fn verify_fingerprint(&self, error_callback: Box<dyn FnOnce()>) {
1191 self.0.insert_idle(move |app_data| {
1192 if let Err(err) = app_data.unlock_finger() {
1193 println!("{:?}", err);
1194 error_callback();
1195 } else {
1196 println!("Passed");
1197 }
1198 });
1199 }
1200}
1201delegate_keyboard!(SpellLock);
1202delegate_compositor!(SpellLock);
1203delegate_output!(SpellLock);
1204delegate_shm!(SpellLock);
1205delegate_registry!(SpellLock);
1206delegate_pointer!(SpellLock);
1207delegate_touch!(SpellLock);
1208delegate_session_lock!(SpellLock);
1209delegate_seat!(SpellLock);
1210
1211pub struct SpellXdg;
1213
1214pub struct SpellBoard;