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