1use crate::{
6 IpcController, SpellAssociated, State,
7 configure::{HomeHandle, LayerConf, WindowConf, set_up_tracing},
8 dbus_window_state::InternalHandle,
9 delegate_fractional_scale, delegate_viewporter, helper_fn_for_deploy,
10 slint_adapter::{SpellLayerShell, SpellLockShell, SpellMultiWinHandler, SpellSkiaWinAdapter},
11 wayland_adapter::{
12 fractional_scaling::{FractionalScaleHandler, FractionalScaleState},
13 viewporter::{Viewport, ViewporterState},
14 way_helper::{
15 FingerprintInfo, KeyboardState, PointerState, UsernamePassConvo, set_config,
16 set_event_sources,
17 },
18 },
19};
20pub use lock_impl::SpellSlintLock;
21use nonstick::{
22 AuthnFlags, ConversationAdapter, Result as PamResult, Transaction, TransactionBuilder,
23};
24use slint::{
25 PhysicalSize,
26 platform::{Key, WindowAdapter},
27};
28use smithay_client_toolkit::{
29 compositor::{CompositorHandler, CompositorState, Region},
30 delegate_compositor,
31 delegate_keyboard,
32 delegate_layer,
33 delegate_output,
34 delegate_pointer,
35 delegate_registry,
36 delegate_seat,
37 delegate_session_lock,
38 delegate_shm, output::{self, OutputHandler, OutputState},
40 reexports::{
41 calloop::{
42 EventLoop, LoopHandle, RegistrationToken,
43 channel::Event,
44 timer::{TimeoutAction, Timer},
45 },
46 calloop_wayland_source::WaylandSource,
47 client::{
48 Connection, EventQueue, QueueHandle,
49 globals::registry_queue_init,
50 protocol::{wl_output, wl_shm, wl_surface},
51 },
52 },
53 registry::RegistryState,
54 seat::{SeatState, pointer::cursor_shape::CursorShapeManager},
55 session_lock::{SessionLock, SessionLockState, SessionLockSurface},
56 shell::{
57 WaylandSurface,
58 wlr_layer::{
59 KeyboardInteractivity, LayerShell, LayerShellHandler, LayerSurface,
60 LayerSurfaceConfigure,
61 },
62 },
63 shm::{
64 Shm, ShmHandler,
65 slot::{Buffer, Slot, SlotPool},
66 },
67};
68use std::{
69 cell::{Cell, RefCell},
70 collections::HashMap,
71 process::Command,
72 rc::Rc,
73 sync::{Arc, Mutex, OnceLock, RwLock},
74 time::Duration,
75};
76use tracing::{Level, info, span, trace, warn};
77
78mod fractional_scaling;
79mod lock_impl;
80mod viewporter;
81mod way_helper;
82mod win_impl;
83
84static AVAILABLE_MONITORS: OnceLock<RwLock<HashMap<String, wl_output::WlOutput>>> = OnceLock::new();
85
86#[derive(Debug)]
87pub(crate) struct States {
88 pub(crate) registry_state: RegistryState,
89 pub(crate) seat_state: SeatState,
90 pub(crate) output_state: OutputState,
91 pub(crate) pointer_state: PointerState,
92 pub(crate) keyboard_state: KeyboardState,
93 pub(crate) shm: Shm,
94 pub(crate) viewporter: Option<Viewport>,
95}
96
97pub struct SpellWin {
108 pub(crate) adapter: Rc<SpellSkiaWinAdapter>,
109 pub loop_handle: LoopHandle<'static, SpellWin>,
111 pub(crate) queue: QueueHandle<SpellWin>,
112 pub(crate) buffer: Buffer,
113 pub(crate) states: States,
114 pub(crate) layer: Option<LayerSurface>,
115 pub(crate) first_configure: Cell<bool>,
116 pub(crate) natural_scroll: bool,
117 pub(crate) is_hidden: Cell<bool>,
118 pub layer_name: String,
119 pub(crate) config: WindowConf,
120 pub(crate) input_region: Region,
121 pub(crate) opaque_region: Region,
122 pub event_loop: Rc<RefCell<EventLoop<'static, SpellWin>>>,
123 pub span: span::Span,
125 }
128
129impl std::fmt::Debug for SpellWin {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.debug_struct("SpellWin")
132 .field("adapter", &self.adapter)
133 .field("first_configure", &self.first_configure)
134 .field("is_hidden", &self.is_hidden)
135 .field("config", &self.config)
136 .finish()
137 }
138}
139
140impl SpellWin {
141 pub(crate) fn create_window(
142 conn: &Connection,
143 window_conf: WindowConf,
144 layer_name: String,
145 if_single: bool,
146 handle: HomeHandle,
147 ) -> Self {
148 let (globals, mut event_queue) = registry_queue_init(conn).unwrap();
149 let qh: QueueHandle<SpellWin> = event_queue.handle();
150
151 let compositor =
152 CompositorState::bind(&globals, &qh).expect("wl_compositor is not available");
153 let event_loop: EventLoop<'static, SpellWin> =
154 EventLoop::try_new().expect("Failed to initialize the event loop!");
155 let layer_shell = LayerShell::bind(&globals, &qh).expect("layer shell is not available");
156 let shm = Shm::bind(&globals, &qh).expect("wl_shm is not available");
157 let mut pool = SlotPool::new((window_conf.width * window_conf.height * 4) as usize, &shm)
158 .expect("Failed to create pool");
159 let input_region = Region::new(&compositor).expect("Couldn't create region");
160 let opaque_region = Region::new(&compositor).expect("Couldn't create opaque region");
161 input_region.add(0, 0, window_conf.width as i32, window_conf.height as i32);
162 let cursor_manager =
163 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
164 let fractional_scale_state: FractionalScaleState =
165 FractionalScaleState::bind(&globals, &qh).expect("Fractional Scale couldn't be set");
166 let stride = window_conf.width as i32 * 4;
167
168 let surface = compositor.create_surface(&qh);
169 let viewporter_state =
170 ViewporterState::bind(&globals, &qh).expect("Couldn't set viewporter");
171
172 let (way_pri_buffer, _) = pool
173 .create_buffer(
174 window_conf.width as i32,
175 window_conf.height as i32,
176 stride,
177 wl_shm::Format::Argb8888,
178 )
179 .expect("Creating Buffer");
180
181 let primary_slot = way_pri_buffer.slot();
182
183 let pointer_state = PointerState {
184 pointer: None,
185 pointer_data: None,
186 cursor_shape: cursor_manager,
187 };
188
189 let keyboard_state = KeyboardState {
190 board: None,
191 };
193
194 #[allow(clippy::type_complexity)]
195 let slint_proxy: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>> =
196 Arc::new(Mutex::new(Vec::new()));
197 let adapter_value: Rc<SpellSkiaWinAdapter> = SpellSkiaWinAdapter::new(
198 Rc::new(RefCell::new(pool)),
199 RefCell::new(primary_slot),
200 window_conf.width,
201 window_conf.height,
202 slint_proxy.clone(),
203 );
204
205 if if_single {
206 trace!("Single window layer platform set");
207 let _ = slint::platform::set_platform(Box::new(SpellLayerShell::new(
208 adapter_value.clone(),
209 )));
210 }
211 set_event_sources(&event_loop, handle);
212
213 let mut win = SpellWin {
214 adapter: adapter_value,
215 loop_handle: event_loop.handle(),
216 queue: qh.clone(),
217 buffer: way_pri_buffer,
218 states: States {
219 registry_state: RegistryState::new(&globals),
220 seat_state: SeatState::new(&globals, &qh),
221 output_state: OutputState::new(&globals, &qh),
222 pointer_state,
223 keyboard_state,
224 shm,
225 viewporter: None,
226 },
227 layer: None,
228 first_configure: Cell::new(true),
229 natural_scroll: window_conf.natural_scroll,
230 is_hidden: Cell::new(false),
231 layer_name: layer_name.clone(),
232 config: window_conf.clone(),
233 input_region,
234 opaque_region,
235 event_loop: Rc::new(RefCell::new(event_loop)),
236 span: span!(Level::INFO, "widget", name = layer_name.as_str(),),
237 };
238
239 if AVAILABLE_MONITORS.get().is_none() {
240 match SpellWin::get_available_monitors(&mut event_queue, &mut win) {
241 Some(monitors) => {
242 let _ = AVAILABLE_MONITORS.get_or_init(|| RwLock::new(monitors));
243 }
244 None => warn!("Failed to get available monitors"),
245 }
246 }
247
248 let target_output: Option<wl_output::WlOutput> =
249 if let Some(name) = &window_conf.monitor_name {
250 let output = AVAILABLE_MONITORS
251 .get()
252 .and_then(|monitors| monitors.read().ok())
253 .and_then(|monitors| monitors.get(name).cloned());
254 if output.is_none() {
255 warn!("Monitor '{}' not found, using default monitor", name);
256 }
257 output
258 } else {
259 None
260 };
261
262 let layer = layer_shell.create_layer_surface(
263 &qh,
264 surface,
265 window_conf.layer_type,
266 Some(layer_name.clone()),
267 target_output.as_ref(),
268 );
269 let fractional_scale = fractional_scale_state.get_scale(layer.wl_surface(), &qh);
270
271 let viewporter = viewporter_state.get_viewport(layer.wl_surface(), &qh, fractional_scale);
272
273 set_config(
274 &win.config,
275 &layer,
276 Some(win.input_region.wl_region()),
278 None,
279 );
280 layer.commit();
281
282 win.layer = Some(layer);
283 win.states.viewporter = Some(viewporter);
284
285 info!("Win: {} layer created successfully.", layer_name);
286
287 WaylandSource::new(conn.clone(), event_queue)
288 .insert(win.loop_handle.clone())
289 .unwrap();
290 win
291 }
292
293 fn get_available_monitors(
303 event_queue: &mut EventQueue<SpellWin>,
304 win: &mut SpellWin,
305 ) -> Option<HashMap<String, wl_output::WlOutput>> {
306 event_queue.roundtrip(win).ok()?;
308
309 Some(
310 win.states
311 .output_state
312 .outputs()
313 .filter_map(|output| {
314 let info = win.states.output_state.info(&output)?;
315 Some((info.name?, output))
316 })
317 .collect(),
318 )
319 }
320
321 pub fn get_handler(&self) -> WinHandle {
323 info!("Win: Handle provided.");
324 WinHandle(self.loop_handle.clone())
325 }
326
327 pub fn invoke_spell(name: &str, window_conf: WindowConf) -> Self {
335 let handle = set_up_tracing(name);
336 let conn = Connection::connect_to_env().unwrap();
337 SpellWin::create_window(&conn, window_conf.clone(), name.to_string(), true, handle)
338 }
339
340 pub fn hide(&self) {
342 if !self.is_hidden.replace(true) {
343 info!("Win: Hiding window");
344 self.layer.as_ref().unwrap().wl_surface().attach(None, 0, 0);
345 }
346 }
347
348 pub fn show_again(&self) {
350 if self.is_hidden.replace(false) {
351 info!("Win: Showing window again");
352 let qh = self.queue.clone();
353 self.converter(&qh);
354 }
363 }
364
365 pub fn toggle(&mut self) {
367 info!("Win: view toggled");
368 if self.is_hidden.get() {
369 self.show_again();
370 } else {
371 self.hide();
372 }
373 }
374
375 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
381 info!(
382 "Win: input region added: [x: {}, y: {}, width: {}, height: {}]",
383 x, y, width, height
384 );
385 self.input_region.add(x, y, width, height);
386 self.set_config_internal();
387 self.layer.as_ref().unwrap().commit();
388 }
389
390 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
395 info!(
396 "Win: input region removed: [x: {}, y: {}, width: {}, height: {}]",
397 x, y, width, height
398 );
399 self.input_region.subtract(x, y, width, height);
400 self.set_config_internal();
401 self.layer.as_ref().unwrap().commit();
402 }
403
404 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
410 info!(
411 "Win: opaque region added: [x: {}, y: {}, width: {}, height: {}]",
412 x, y, width, height
413 );
414 self.opaque_region.add(x, y, width, height);
415 self.set_config_internal();
416 self.layer.as_ref().unwrap().commit();
417 }
418
419 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
424 info!(
425 "Win: opaque region removed: [x: {}, y: {}, width: {}, height: {}]",
426 x, y, width, height
427 );
428 self.opaque_region.subtract(x, y, width, height);
429 self.set_config_internal();
430 self.layer.as_ref().unwrap().commit();
431 }
432
433 fn set_config_internal(&self) {
434 set_config(
435 &self.config,
436 self.layer.as_ref().unwrap(),
437 Some(self.input_region.wl_region()),
439 Some(self.opaque_region.wl_region()),
440 );
441 }
442
443 fn converter(&self, qh: &QueueHandle<Self>) {
444 slint::platform::update_timers_and_animations();
445 let width: u32 = self.adapter.size.get().width;
446 let height: u32 = self.adapter.size.get().height;
447 let window_adapter = self.adapter.clone();
448
449 if !self.is_hidden.get() {
451 let skia_now = std::time::Instant::now();
452 let redraw_val: bool = window_adapter.draw_if_needed();
453 let elasped_time = skia_now.elapsed().as_millis();
454 if elasped_time != 0 {
455 }
457
458 let buffer = &self.buffer;
459 if self.first_configure.get() || redraw_val {
460 self.first_configure.set(false);
462 self.layer.as_ref().unwrap().wl_surface().damage_buffer(
463 0,
464 0,
465 width as i32,
466 height as i32,
467 );
468 self.layer
486 .as_ref()
487 .unwrap()
488 .wl_surface()
489 .attach(Some(buffer.wl_buffer()), 0, 0);
490 }
491 } else {
492 }
494
495 self.layer
496 .as_ref()
497 .unwrap()
498 .wl_surface()
499 .frame(qh, self.layer.as_ref().unwrap().wl_surface().clone());
500 self.layer.as_ref().unwrap().commit();
501 }
502
503 pub fn grab_focus(&self) {
506 self.config
507 .board_interactivity
508 .set(KeyboardInteractivity::Exclusive);
509 self.layer
510 .as_ref()
511 .unwrap()
512 .set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
513 self.layer.as_ref().unwrap().commit();
514 }
515
516 pub fn remove_focus(&self) {
518 self.config
519 .board_interactivity
520 .set(KeyboardInteractivity::None);
521 self.layer
522 .as_ref()
523 .unwrap()
524 .set_keyboard_interactivity(KeyboardInteractivity::None);
525 self.layer.as_ref().unwrap().commit();
526 }
527
528 pub fn set_exclusive_zone(&mut self, val: i32) {
531 self.config.exclusive_zone = Some(val);
533 self.layer.as_ref().unwrap().set_exclusive_zone(val);
534 self.layer.as_ref().unwrap().commit();
535 }
536}
537
538impl SpellAssociated for SpellWin {
539 fn on_call(
540 &mut self,
541 state: Option<State>,
542 set_callback: Option<Box<dyn FnMut(State)>>,
543 span_log: tracing::span::Span,
544 ) -> Result<(), Box<dyn std::error::Error>> {
545 let rx = helper_fn_for_deploy(self.layer_name.clone(), &state, span_log);
546 let event_loop = self.event_loop.clone();
547 if let Some(mut callback) = set_callback {
548 self.event_loop
549 .borrow()
550 .handle()
551 .insert_source(rx, move |event_msg, _, state_data| {
552 trace!("Internal event recieved");
553 match event_msg {
554 Event::Msg(int_handle) => match int_handle {
555 InternalHandle::StateValChange((key, data_type)) => {
556 trace!("Internal variable change called");
557 {
558 let mut state_inst = state.as_ref().unwrap().write().unwrap();
559 state_inst.change_val(&key, data_type);
560 }
561 callback(state.as_ref().unwrap().clone());
562 }
563 InternalHandle::ShowWinAgain => {
564 trace!("Internal show Called");
565 state_data.show_again();
566 }
567 InternalHandle::HideWindow => {
568 trace!("Internal hide called");
569 state_data.hide();
570 }
571 },
572 Event::Closed => {
574 info!("Internal Channel closed");
575 }
576 }
577 })
578 .unwrap();
579 }
580 info!("Internal reciever set with start of event loop.");
581 loop {
582 event_loop
583 .borrow_mut()
584 .dispatch(std::time::Duration::from_millis(1), self)
585 .unwrap();
586 }
587 }
588
589 fn get_span(&self) -> tracing::span::Span {
590 self.span.clone()
591 }
592}
593
594delegate_compositor!(SpellWin);
595delegate_registry!(SpellWin);
596delegate_output!(SpellWin);
597delegate_shm!(SpellWin);
598delegate_seat!(SpellWin);
599delegate_keyboard!(SpellWin);
600delegate_pointer!(SpellWin);
601delegate_layer!(SpellWin);
603delegate_fractional_scale!(SpellWin);
604delegate_viewporter!(SpellWin);
605
606impl ShmHandler for SpellWin {
607 fn shm_state(&mut self) -> &mut Shm {
608 &mut self.states.shm
609 }
610}
611
612impl OutputHandler for SpellWin {
613 fn output_state(&mut self) -> &mut OutputState {
614 &mut self.states.output_state
615 }
616
617 fn new_output(
618 &mut self,
619 _conn: &Connection,
620 _qh: &QueueHandle<Self>,
621 _output: wl_output::WlOutput,
622 ) {
623 trace!("New output Source Added");
624 }
625
626 fn update_output(
627 &mut self,
628 _conn: &Connection,
629 _qh: &QueueHandle<Self>,
630 _output: wl_output::WlOutput,
631 ) {
632 trace!("Existing output is updated");
633 }
634
635 fn output_destroyed(
636 &mut self,
637 _conn: &Connection,
638 _qh: &QueueHandle<Self>,
639 _output: wl_output::WlOutput,
640 ) {
641 trace!("Output is destroyed");
642 }
643}
644
645impl CompositorHandler for SpellWin {
646 fn scale_factor_changed(
647 &mut self,
648 _: &Connection,
649 _: &QueueHandle<Self>,
650 _: &wl_surface::WlSurface,
651 _: i32,
652 ) {
653 info!("Scale factor changed, compositor msg");
654 }
655
656 fn transform_changed(
657 &mut self,
658 _conn: &Connection,
659 _qh: &QueueHandle<Self>,
660 _surface: &wl_surface::WlSurface,
661 _new_transform: wl_output::Transform,
662 ) {
663 trace!("Compositor transformation changed");
664 }
665
666 fn frame(
667 &mut self,
668 _conn: &Connection,
669 qh: &QueueHandle<Self>,
670 _surface: &wl_surface::WlSurface,
671 _time: u32,
672 ) {
673 self.converter(qh);
674 }
675
676 fn surface_enter(
677 &mut self,
678 _conn: &Connection,
679 _qh: &QueueHandle<Self>,
680 _surface: &wl_surface::WlSurface,
681 _output: &wl_output::WlOutput,
682 ) {
683 trace!("Surface entered");
684 }
685
686 fn surface_leave(
687 &mut self,
688 _conn: &Connection,
689 _qh: &QueueHandle<Self>,
690 _surface: &wl_surface::WlSurface,
691 _output: &wl_output::WlOutput,
692 ) {
693 trace!("Surface left");
694 }
695}
696
697impl FractionalScaleHandler for SpellWin {
698 fn preferred_scale(
699 &mut self,
700 _: &Connection,
701 _: &QueueHandle<Self>,
702 _: &wl_surface::WlSurface,
703 scale: u32,
704 ) {
705 info!("Scale factor changed, invoked from custom trait. {}", scale);
706
707 self.layer.as_ref().unwrap().wl_surface().damage_buffer(
708 0,
709 0,
710 self.adapter.size.get().width as i32,
711 self.adapter.size.get().height as i32,
712 );
713 let scale_factor: f32 = scale as f32 / 120.0;
715 let width: u32 = (self.adapter.size.get().width * scale + 60) / 120;
716 let height: u32 = (self.adapter.size.get().height * scale + 60) / 120;
717 info!("Physical Size: width: {}, height: {}", width, height);
718
719 self.adapter.scale_factor.set(scale_factor);
720 self.adapter
736 .try_dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged { scale_factor })
737 .unwrap();
738 self.adapter.request_redraw();
739 self.layer.as_ref().unwrap().commit();
740 }
741}
742
743impl LayerShellHandler for SpellWin {
744 fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
745 trace!("Closure of layer called");
746 }
747
748 fn configure(
749 &mut self,
750 _conn: &Connection,
751 qh: &QueueHandle<Self>,
752 _layer: &LayerSurface,
753 _configure: LayerSurfaceConfigure,
754 _serial: u32,
755 ) {
756 self.converter(qh);
757 }
758}
759
760#[derive(Clone, Debug)]
764pub struct WinHandle(pub LoopHandle<'static, SpellWin>);
765
766impl WinHandle {
767 pub fn hide(&self) {
769 self.0.insert_idle(|win| win.hide());
770 }
771
772 pub fn show_again(&self) {
774 self.0.insert_idle(|win| win.show_again());
775 }
776
777 pub fn toggle(&self) {
779 self.0.insert_idle(|win| win.toggle());
780 }
781
782 pub fn grab_focus(&self) {
784 self.0.insert_idle(|win| win.grab_focus());
785 }
786
787 pub fn remove_focus(&self) {
789 self.0.insert_idle(|win| win.remove_focus());
790 }
791
792 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
794 self.0
795 .insert_idle(move |win| win.add_input_region(x, y, width, height));
796 }
797
798 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
800 self.0
801 .insert_idle(move |win| win.subtract_input_region(x, y, width, height));
802 }
803
804 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
806 self.0
807 .insert_idle(move |win| win.add_opaque_region(x, y, width, height));
808 }
809
810 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
812 self.0
813 .insert_idle(move |win| win.subtract_opaque_region(x, y, width, height));
814 }
815
816 pub fn set_exclusive_zone(&self, val: i32) {
818 self.0.insert_idle(move |win| win.set_exclusive_zone(val));
819 }
820}
821
822pub struct SpellLock {
869 pub(crate) loop_handle: LoopHandle<'static, SpellLock>,
870 pub(crate) conn: Connection,
871 pub(crate) compositor_state: CompositorState,
872 pub(crate) registry_state: RegistryState,
873 pub(crate) output_state: OutputState,
874 pub(crate) keyboard_state: KeyboardState,
875 pub(crate) pointer_state: PointerState,
876 pub(crate) seat_state: SeatState,
877 pub(crate) shm: Shm,
878 pub(crate) session_lock: Option<SessionLock>,
879 pub(crate) lock_surfaces: Vec<SessionLockSurface>,
880 pub(crate) slint_part: Option<SpellSlintLock>,
881 pub(crate) is_locked: bool,
882 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellLock>>>,
884 pub(crate) backspace: Option<RegistrationToken>,
885}
886
887impl std::fmt::Debug for SpellLock {
888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
889 f.debug_struct("SpellLock")
890 .field("is_locked", &self.is_locked)
891 .finish()
892 }
893}
894impl SpellLock {
895 pub fn invoke_lock_spell() -> Self {
898 let conn = Connection::connect_to_env().unwrap();
899 let _ = set_up_tracing("SpellLock");
900 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
901 let qh: QueueHandle<SpellLock> = event_queue.handle();
902 let registry_state = RegistryState::new(&globals);
903 let shm = Shm::bind(&globals, &qh).unwrap();
904 let event_loop: EventLoop<'static, SpellLock> =
905 EventLoop::try_new().expect("Failed to initialize the event loop!");
906 let output_state = OutputState::new(&globals, &qh);
907 let session_lock_state = SessionLockState::new(&globals, &qh);
908 let compositor_state =
909 CompositorState::bind(&globals, &qh).expect("Faild to create compositor state");
910 let cursor_manager =
911 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
912 let mut win_handler_vec: Vec<(String, (u32, u32))> = Vec::new();
913 let lock_surfaces = Vec::new();
914
915 let keyboard_state = KeyboardState {
916 board: None,
917 };
919 let pointer_state = PointerState {
920 pointer: None,
921 pointer_data: None,
922 cursor_shape: cursor_manager,
923 };
924 let mut spell_lock = SpellLock {
925 loop_handle: event_loop.handle().clone(),
926 conn: conn.clone(),
927 compositor_state,
928 output_state,
929 keyboard_state,
930 pointer_state,
931 registry_state,
932 seat_state: SeatState::new(&globals, &qh),
933 slint_part: None,
934 shm,
935 session_lock: None,
936 lock_surfaces,
937 is_locked: true,
938 event_loop: Rc::new(RefCell::new(event_loop)),
939 backspace: None,
940 };
941
942 let _ = event_queue.roundtrip(&mut spell_lock);
943
944 let session_lock = Some(
945 session_lock_state
946 .lock(&qh)
947 .expect("ext-session-lock not supported"),
948 );
949
950 spell_lock.session_lock = session_lock;
951 for output in spell_lock.output_state.outputs() {
952 let output_info: output::OutputInfo = spell_lock.output_state.info(&output).unwrap();
953 let output_name: String = output_info.name.unwrap_or_else(|| "SomeOutput".to_string());
954 let dimensions = (
955 output_info.logical_size.unwrap().0 as u32,
956 output_info.logical_size.unwrap().1 as u32,
957 );
958 win_handler_vec.push((output_name, dimensions));
959
960 let session_lock = spell_lock.session_lock.as_ref().unwrap();
961 let surface = spell_lock.compositor_state.create_surface(&qh);
962
963 let lock_surface = session_lock.create_lock_surface(surface, &output, &qh);
966 spell_lock.lock_surfaces.push(lock_surface);
967 }
968 let multi_handler = SpellMultiWinHandler::new_lock(win_handler_vec);
969 let sizes: Vec<PhysicalSize> = multi_handler
970 .borrow()
971 .windows
972 .iter()
973 .map(|(_, conf)| {
974 if let LayerConf::Lock(width, height) = conf {
975 PhysicalSize {
976 width: *width,
977 height: *height,
978 }
979 } else {
980 panic!("Shouldn't enter here");
981 }
982 })
983 .collect();
984
985 let mut pool = SlotPool::new(
986 (sizes[0].width * sizes[0].height * 4) as usize,
987 &spell_lock.shm,
988 )
989 .expect("Couldn't create pool");
990 let mut buffer_slots: Vec<RefCell<Slot>> = Vec::new();
991 let buffers: Vec<Buffer> = sizes
992 .iter()
993 .map(|physical_size| {
994 let stride = physical_size.width as i32 * 4;
995 let (wayland_buffer, _) = pool
996 .create_buffer(
997 physical_size.width as i32,
998 physical_size.height as i32,
999 stride,
1000 wl_shm::Format::Argb8888,
1001 )
1002 .expect("Creating Buffer");
1003 buffer_slots.push(RefCell::new(wayland_buffer.slot()));
1004 wayland_buffer
1005 })
1006 .collect();
1007 let slint_proxy = Arc::new(Mutex::new(Vec::new()));
1008 let pool: Rc<RefCell<SlotPool>> = Rc::new(RefCell::new(pool));
1009 let mut adapters: Vec<Rc<SpellSkiaWinAdapter>> = Vec::new();
1010 buffer_slots
1011 .into_iter()
1012 .enumerate()
1013 .for_each(|(index, slot)| {
1014 let adapter = SpellSkiaWinAdapter::new(
1015 pool.clone(),
1016 slot,
1017 sizes[index].width,
1018 sizes[index].height,
1019 slint_proxy.clone(),
1020 );
1021 adapters.push(adapter);
1022 });
1023
1024 multi_handler.borrow_mut().adapter = adapters.clone();
1025 spell_lock.slint_part = Some(SpellSlintLock {
1026 adapters,
1027 size: sizes,
1028 wayland_buffer: buffers,
1029 });
1030
1031 spell_lock.backspace = Some(
1032 spell_lock
1033 .loop_handle
1034 .insert_source(
1035 Timer::from_duration(Duration::from_millis(1500)),
1036 |_, _, data| {
1037 data.slint_part.as_ref().unwrap().adapters[0]
1038 .try_dispatch_event(slint::platform::WindowEvent::KeyPressed {
1039 text: Key::Backspace.into(),
1040 })
1041 .unwrap();
1042 TimeoutAction::ToDuration(Duration::from_millis(1500))
1043 },
1044 )
1045 .unwrap(),
1046 );
1047
1048 spell_lock
1049 .loop_handle
1050 .disable(&spell_lock.backspace.unwrap())
1051 .unwrap();
1052 let _ = slint::platform::set_platform(Box::new(SpellLockShell::new(multi_handler)));
1053
1054 WaylandSource::new(spell_lock.conn.clone(), event_queue)
1055 .insert(spell_lock.loop_handle.clone())
1056 .unwrap();
1057 spell_lock
1058 }
1059
1060 fn converter_lock(&mut self, qh: &QueueHandle<Self>) {
1061 slint::platform::update_timers_and_animations();
1062 let width: u32 = self.slint_part.as_ref().unwrap().size[0].width;
1063 let height: u32 = self.slint_part.as_ref().unwrap().size[0].height;
1064 let window_adapter = self.slint_part.as_ref().unwrap().adapters[0].clone();
1065
1066 let _redraw_val: bool = window_adapter.draw_if_needed();
1070 let buffer = &self.slint_part.as_ref().unwrap().wayland_buffer[0];
1073 self.lock_surfaces[0]
1077 .wl_surface()
1078 .damage_buffer(0, 0, width as i32, height as i32);
1079 self.lock_surfaces[0]
1097 .wl_surface()
1098 .frame(qh, self.lock_surfaces[0].wl_surface().clone());
1099 self.lock_surfaces[0]
1100 .wl_surface()
1101 .attach(Some(buffer.wl_buffer()), 0, 0);
1102 self.lock_surfaces[0].wl_surface().commit();
1107 }
1114
1115 fn unlock_finger(&mut self) -> PamResult<()> {
1116 let finger = FingerprintInfo;
1117 let output = Command::new("sh")
1118 .arg("-c")
1119 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1120 .output()
1121 .expect("Couldn't retrive username");
1122
1123 let val = String::from_utf8_lossy(&output.stdout);
1124 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1125 let user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1126
1127 let mut txn = TransactionBuilder::new_with_service("login")
1128 .username(user_name)
1129 .build(finger.into_conversation())?;
1130 txn.authenticate(AuthnFlags::empty())?;
1133 txn.account_management(AuthnFlags::empty())?;
1134 if let Some(locked_val) = self.session_lock.take() {
1135 locked_val.unlock();
1136 } else {
1137 warn!("Authentication verified but couldn't unlock");
1138 }
1139 self.is_locked = false;
1140 self.conn.roundtrip().unwrap();
1141 Ok(())
1142 }
1143
1144 fn unlock(
1145 &mut self,
1146 username: Option<&str>,
1147 password: &str,
1148 on_unlock_callback: Box<dyn FnOnce()>,
1149 ) -> PamResult<()> {
1150 let user_name;
1151 if let Some(username) = username {
1152 user_name = username.to_string();
1153 } else {
1154 let output = Command::new("sh")
1155 .arg("-c")
1156 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1157 .output()
1158 .expect("Couldn't retrive username");
1159
1160 let val = String::from_utf8_lossy(&output.stdout);
1161 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1162 user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1163 }
1164
1165 let user_pass = UsernamePassConvo {
1166 username: user_name.clone(),
1167 password: password.into(),
1168 };
1169
1170 let mut txn = TransactionBuilder::new_with_service("login")
1171 .username(user_name)
1172 .build(user_pass.into_conversation())?;
1173 txn.authenticate(AuthnFlags::empty())?;
1176 txn.account_management(AuthnFlags::empty())?;
1177
1178 on_unlock_callback();
1179 if let Some(locked_val) = self.session_lock.take() {
1180 locked_val.unlock();
1181 } else {
1182 warn!("Authentication verified but couldn't unlock");
1183 }
1184 self.is_locked = false;
1185 self.conn.roundtrip().unwrap();
1186 Ok(())
1187 }
1188
1189 pub fn get_handler(&self) -> LockHandle {
1193 LockHandle(self.loop_handle.clone())
1194 }
1195}
1196
1197impl SpellAssociated for SpellLock {
1198 fn on_call(
1199 &mut self,
1200 _: Option<State>,
1201 _: Option<Box<dyn FnMut(State)>>,
1202 _: tracing::span::Span,
1203 ) -> Result<(), Box<dyn std::error::Error>> {
1204 let event_loop = self.event_loop.clone();
1205 while self.is_locked {
1206 event_loop
1207 .borrow_mut()
1208 .dispatch(std::time::Duration::from_millis(1), self)
1209 .unwrap();
1210 }
1211 Ok(())
1212 }
1213}
1214
1215#[derive(Debug, Clone)]
1218pub struct LockHandle(LoopHandle<'static, SpellLock>);
1219
1220impl LockHandle {
1221 pub fn unlock(
1226 &self,
1227 username: Option<String>,
1228 password: String,
1229 on_err_callback: Box<dyn FnOnce()>,
1230 on_unlock_callback: Box<dyn FnOnce()>,
1231 ) {
1232 self.0.insert_idle(move |app_data| {
1233 if app_data
1234 .unlock(username.as_deref(), &password, on_unlock_callback)
1235 .is_err()
1236 {
1237 on_err_callback();
1238 }
1239 });
1240 }
1241
1242 pub fn verify_fingerprint(&self, error_callback: Box<dyn FnOnce()>) {
1243 self.0.insert_idle(move |app_data| {
1244 if let Err(err) = app_data.unlock_finger() {
1245 println!("{:?}", err);
1246 error_callback();
1247 } else {
1248 println!("Passed");
1249 }
1250 });
1251 }
1252}
1253delegate_keyboard!(SpellLock);
1254delegate_compositor!(SpellLock);
1255delegate_output!(SpellLock);
1256delegate_shm!(SpellLock);
1257delegate_registry!(SpellLock);
1258delegate_pointer!(SpellLock);
1259delegate_session_lock!(SpellLock);
1260delegate_seat!(SpellLock);
1261
1262pub struct SpellBoard;