1use crate::{
6 SpellAssociated, State,
7 configure::{HomeHandle, LayerConf, WindowConf, set_up_tracing},
8 dbus_window_state::InternalHandle,
9 helper_fn_for_deploy,
10 slint_adapter::{SpellLayerShell, SpellLockShell, SpellMultiWinHandler, SpellSkiaWinAdapter},
11 wayland_adapter::way_helper::{KeyboardState, PointerState, set_config},
12};
13pub use lock_impl::SpellSlintLock;
14use nonstick::{
15 AuthnFlags, ConversationAdapter, Result as PamResult, Transaction, TransactionBuilder,
16};
17use slint::{PhysicalSize, platform::Key};
18use smithay_client_toolkit::{
19 compositor::{CompositorHandler, CompositorState, Region},
20 delegate_compositor, delegate_keyboard, delegate_layer, delegate_output, delegate_pointer,
21 delegate_registry, delegate_seat, delegate_session_lock, delegate_shm,
22 output::{self, OutputHandler, OutputState},
23 reexports::{
24 calloop::{
25 self, EventLoop, LoopHandle, RegistrationToken,
26 channel::Event,
27 timer::{TimeoutAction, Timer},
28 },
29 calloop_wayland_source::WaylandSource,
30 client::{
31 Connection, QueueHandle,
32 globals::registry_queue_init,
33 protocol::{wl_output, wl_shm, wl_surface},
34 },
35 },
36 registry::RegistryState,
37 seat::{SeatState, pointer::cursor_shape::CursorShapeManager},
38 session_lock::{SessionLock, SessionLockState, SessionLockSurface},
39 shell::{
40 WaylandSurface,
41 wlr_layer::{
42 KeyboardInteractivity, LayerShell, LayerShellHandler, LayerSurface,
43 LayerSurfaceConfigure,
44 },
45 },
46 shm::{
47 Shm, ShmHandler,
48 slot::{Buffer, Slot, SlotPool},
49 },
50};
51use std::{
52 cell::{Cell, RefCell},
53 fs,
56 io::{BufReader, prelude::*},
57
58 process::Command,
59 rc::Rc,
60 time::Duration,
61};
62use tracing::{Level, info, level_filters::LevelFilter, span, trace, warn};
63use tracing_subscriber::EnvFilter;
64
65mod lock_impl;
66mod way_helper;
67mod win_impl;
68
69#[derive(Debug)]
70pub(crate) struct States {
71 pub(crate) registry_state: RegistryState,
72 pub(crate) seat_state: SeatState,
73 pub(crate) output_state: OutputState,
74 pub(crate) pointer_state: PointerState,
75 pub(crate) keyboard_state: KeyboardState,
76 pub(crate) shm: Shm,
77}
78
79pub struct SpellWin {
90 pub(crate) adapter: Rc<SpellSkiaWinAdapter>,
91 pub(crate) loop_handle: LoopHandle<'static, SpellWin>,
92 pub(crate) queue: QueueHandle<SpellWin>,
93 pub(crate) size: PhysicalSize,
94 pub(crate) buffer: Buffer,
95 pub(crate) states: States,
96 pub(crate) layer: LayerSurface,
97 pub(crate) first_configure: bool,
98 pub(crate) is_hidden: Cell<bool>,
99 pub(crate) layer_name: String,
100 pub(crate) config: WindowConf,
101 pub(crate) input_region: Region,
102 pub(crate) opaque_region: Region,
103 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellWin>>>,
104 pub(crate) span: span::Span,
105 #[allow(dead_code)]
106 pub(crate) backspace: calloop::RegistrationToken,
107}
108
109impl std::fmt::Debug for SpellWin {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.debug_struct("SpellWin")
112 .field("adapter", &self.adapter)
113 .field("first_configure", &self.first_configure)
114 .field("is_hidden", &self.is_hidden)
115 .field("config", &self.config)
116 .finish()
117 }
118}
119
120impl SpellWin {
121 pub(crate) fn create_window(
122 conn: &Connection,
123 window_conf: WindowConf,
124 layer_name: String,
125 if_single: bool,
126 handle: HomeHandle,
127 ) -> Self {
128 let (globals, event_queue) = registry_queue_init(conn).unwrap();
129 let qh: QueueHandle<SpellWin> = event_queue.handle();
130 let compositor =
131 CompositorState::bind(&globals, &qh).expect("wl_compositor is not available");
132 let event_loop: EventLoop<'static, SpellWin> =
133 EventLoop::try_new().expect("Failed to initialize the event loop!");
134 let layer_shell = LayerShell::bind(&globals, &qh).expect("layer shell is not available");
135 let shm = Shm::bind(&globals, &qh).expect("wl_shm is not available");
136 let mut pool = SlotPool::new((window_conf.width * window_conf.height * 4) as usize, &shm)
137 .expect("Failed to create pool");
138 let input_region = Region::new(&compositor).expect("Couldn't create region");
139 let opaque_region = Region::new(&compositor).expect("Couldn't create opaque region");
140 input_region.add(0, 0, window_conf.width as i32, window_conf.height as i32);
141 let cursor_manager =
142 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
143 let stride = window_conf.width as i32 * 4;
144 let surface = compositor.create_surface(&qh);
145 let layer = layer_shell.create_layer_surface(
146 &qh,
147 surface,
148 window_conf.layer_type,
149 Some(layer_name.clone()),
150 None,
151 );
152 set_config(
153 &window_conf,
154 &layer,
155 Some(input_region.wl_region()),
157 None,
158 );
159 layer.commit();
160 let (way_pri_buffer, _) = pool
161 .create_buffer(
162 window_conf.width as i32,
163 window_conf.height as i32,
164 stride,
165 wl_shm::Format::Argb8888,
166 )
167 .expect("Creating Buffer");
168
169 let primary_slot = way_pri_buffer.slot();
170
171 let pointer_state = PointerState {
172 pointer: None,
173 pointer_data: None,
174 cursor_shape: cursor_manager,
175 };
176
177 let keyboard_state = KeyboardState {
178 board: None,
179 };
181
182 let adapter_value: Rc<SpellSkiaWinAdapter> = SpellSkiaWinAdapter::new(
183 Rc::new(RefCell::new(pool)),
184 RefCell::new(primary_slot),
185 window_conf.width,
186 window_conf.height,
187 );
188
189 if if_single {
190 trace!("Single window layer platform set");
191 let _ = slint::platform::set_platform(Box::new(SpellLayerShell::new(
192 adapter_value.clone(),
193 )));
194 }
195
196 let backspace_event = event_loop
197 .handle()
198 .insert_source(
199 Timer::from_duration(Duration::from_millis(1500)),
200 |_, _, data| {
201 data.adapter
202 .try_dispatch_event(slint::platform::WindowEvent::KeyPressed {
203 text: Key::Backspace.into(),
204 })
205 .unwrap();
206 TimeoutAction::ToDuration(Duration::from_millis(1500))
207 },
208 )
209 .unwrap();
210 event_loop.handle().disable(&backspace_event).unwrap();
211
212 let runtime_dir = std::env::var("XDG_RUNTIME_DIR").expect("runtime dir is not set");
214 let logging_dir = runtime_dir + "/spell/";
215 let socket_cli_dir = logging_dir.clone() + "/spell_cli";
216
217 event_loop
221 .handle()
222 .insert_source(
223 Timer::from_duration(Duration::from_secs(2)),
224 move |_, _, _| {
225 let file = fs::File::open(&socket_cli_dir).unwrap();
228 let buf = BufReader::new(file);
229 let file_contents: Vec<String> = buf
230 .lines()
231 .map(|l| l.expect("Could not parse line"))
232 .collect();
233 if file_contents.len() > 1 {
234 match file_contents[0].as_str() {
235 "slint_log" => handle
236 .modify(|layer| {
237 *layer = EnvFilter::from_default_env().add_directive(
238 "[slint-log]=info,warn"
239 .parse()
240 .unwrap_or(LevelFilter::INFO.into()),
241 );
242 })
243 .unwrap_or_else(|error| {
244 warn!("Error when setting slint_log: {}", error);
245 }),
246 "debug" => handle
247 .modify(|layer| {
248 *layer = EnvFilter::from_default_env().add_directive(
249 "[slint-log]=info,warn"
250 .parse()
251 .unwrap_or(LevelFilter::INFO.into()),
252 );
253 })
254 .unwrap_or_else(|error| {
255 warn!("Error when setting slint_log: {}", error);
256 }),
257 "dump" => handle
258 .modify(|layer| {
259 *layer = EnvFilter::from_default_env().add_directive(
260 "[slint-log]=info,warn"
261 .parse()
262 .unwrap_or(LevelFilter::INFO.into()),
263 );
264 })
265 .unwrap_or_else(|error| {
266 warn!("Error when setting slint_log: {}", error);
267 }),
268 "dev" => handle
269 .modify(|layer| {
270 *layer = EnvFilter::from_default_env().add_directive(
271 "[slint-log]=info,warn"
272 .parse()
273 .unwrap_or(LevelFilter::INFO.into()),
274 );
275 })
276 .unwrap_or_else(|error| {
277 warn!("Error when setting slint_log: {}", error);
278 }),
279
280 _ => {}
281 }
282 }
283 TimeoutAction::ToDuration(Duration::from_secs(2))
284 },
285 )
286 .unwrap();
287
288 let win = SpellWin {
289 adapter: adapter_value,
290 loop_handle: event_loop.handle(),
291 queue: qh.clone(),
292 size: PhysicalSize {
293 width: window_conf.width,
294 height: window_conf.height,
295 },
296 buffer: way_pri_buffer,
297 states: States {
298 registry_state: RegistryState::new(&globals),
299 seat_state: SeatState::new(&globals, &qh),
300 output_state: OutputState::new(&globals, &qh),
301 pointer_state,
302 keyboard_state,
303 shm,
304 },
305 layer,
306 first_configure: true,
307 is_hidden: Cell::new(false),
308 layer_name: layer_name.clone(),
309 config: window_conf,
310 input_region,
311 opaque_region,
312 event_loop: Rc::new(RefCell::new(event_loop)),
313 span: span!(Level::INFO, "widget", name = layer_name.as_str(),),
314 backspace: backspace_event,
315 };
316
317 info!("Win: {} layer created successfully.", layer_name);
318
319 WaylandSource::new(conn.clone(), event_queue)
320 .insert(win.loop_handle.clone())
321 .unwrap();
322 win
323 }
324
325 pub fn get_handler(&mut self) -> WinHandle {
327 info!("Win: Handle provided.");
328 WinHandle(self.loop_handle.clone())
329 }
330
331 pub fn invoke_spell(name: &str, window_conf: WindowConf) -> Self {
339 let handle = set_up_tracing(name);
340 let conn = Connection::connect_to_env().unwrap();
341 SpellWin::create_window(&conn, window_conf.clone(), name.to_string(), true, handle)
342 }
343
344 pub fn hide(&self) {
346 if !self.is_hidden.replace(true) {
347 info!("Win: Hiding window");
348 self.layer.wl_surface().attach(None, 0, 0);
349 }
350 }
351
352 pub fn show_again(&mut self) {
354 if self.is_hidden.replace(false) {
355 info!("Win: Showing window again");
356 let qh = self.queue.clone();
357 self.converter(&qh);
358 }
367 }
368
369 pub fn toggle(&mut self) {
371 info!("Win: view toggled");
372 if self.is_hidden.get() {
373 self.show_again();
374 } else {
375 self.hide();
376 }
377 }
378
379 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
385 info!(
386 "Win: input region added: [x: {}, y: {}, width: {}, height: {}]",
387 x, y, width, height
388 );
389 self.input_region.add(x, y, width, height);
390 self.set_config_internal();
391 self.layer.commit();
392 }
393
394 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
399 info!(
400 "Win: input region removed: [x: {}, y: {}, width: {}, height: {}]",
401 x, y, width, height
402 );
403 self.input_region.subtract(x, y, width, height);
404 self.set_config_internal();
405 self.layer.commit();
406 }
407
408 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
414 info!(
415 "Win: opaque region added: [x: {}, y: {}, width: {}, height: {}]",
416 x, y, width, height
417 );
418 self.opaque_region.add(x, y, width, height);
419 self.set_config_internal();
420 self.layer.commit();
421 }
422
423 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
428 info!(
429 "Win: opaque region removed: [x: {}, y: {}, width: {}, height: {}]",
430 x, y, width, height
431 );
432 self.opaque_region.subtract(x, y, width, height);
433 self.set_config_internal();
434 self.layer.commit();
435 }
436
437 fn set_config_internal(&self) {
438 set_config(
440 &self.config,
441 &self.layer,
442 Some(self.input_region.wl_region()),
444 Some(self.opaque_region.wl_region()),
445 );
446 }
450
451 fn converter(&mut self, qh: &QueueHandle<Self>) {
452 slint::platform::update_timers_and_animations();
453 let width: u32 = self.size.width;
454 let height: u32 = self.size.height;
455 let window_adapter = self.adapter.clone();
456
457 if !self.is_hidden.get() {
459 let skia_now = std::time::Instant::now();
460 let redraw_val: bool = window_adapter.draw_if_needed();
461 let elasped_time = skia_now.elapsed().as_millis();
462 if elasped_time != 0 {
463 }
465
466 let buffer = &self.buffer;
467 if self.first_configure || redraw_val {
468 self.first_configure = false;
470 self.layer
471 .wl_surface()
472 .damage_buffer(0, 0, width as i32, height as i32);
473 self.layer
491 .wl_surface()
492 .attach(Some(buffer.wl_buffer()), 0, 0);
493 }
494 } else {
495 }
497
498 self.layer
499 .wl_surface()
500 .frame(qh, self.layer.wl_surface().clone());
501 self.layer.commit();
502 }
503
504 pub fn grab_focus(&self) {
507 self.config
508 .board_interactivity
509 .set(KeyboardInteractivity::Exclusive);
510 self.layer
511 .set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
512 self.layer.commit();
513 }
514
515 pub fn remove_focus(&self) {
517 self.config
518 .board_interactivity
519 .set(KeyboardInteractivity::None);
520 self.layer
521 .set_keyboard_interactivity(KeyboardInteractivity::None);
522 self.layer.commit();
523 }
524
525 pub fn set_exclusive_zone(&mut self, val: i32) {
528 self.config.exclusive_zone = Some(val);
530 self.layer.set_exclusive_zone(val);
531 self.layer.commit();
532 }
533}
534
535impl SpellAssociated for SpellWin {
536 fn on_call(
537 &mut self,
538 state: Option<State>,
539 set_callback: Option<Box<dyn FnMut(State)>>,
540 span_log: tracing::span::Span,
541 ) -> Result<(), Box<dyn std::error::Error>> {
542 let rx = helper_fn_for_deploy(self.layer_name.clone(), &state, span_log);
543 let event_loop = self.event_loop.clone();
544 if let Some(mut callback) = set_callback {
545 self.event_loop
546 .borrow()
547 .handle()
548 .insert_source(rx, move |event_msg, _, state_data| {
549 trace!("Internal event recieved");
550 match event_msg {
551 Event::Msg(int_handle) => match int_handle {
552 InternalHandle::StateValChange((key, data_type)) => {
553 trace!("Internal variable change called");
554 {
555 let mut state_inst = state.as_ref().unwrap().write().unwrap();
556 state_inst.change_val(&key, data_type);
557 }
558 callback(state.as_ref().unwrap().clone());
559 }
560 InternalHandle::ShowWinAgain => {
561 trace!("Internal show Called");
562 state_data.show_again();
563 }
564 InternalHandle::HideWindow => {
565 trace!("Internal hide called");
566 state_data.hide();
567 }
568 },
569 Event::Closed => {
571 info!("Internal Channel closed");
572 }
573 }
574 })
575 .unwrap();
576 }
577 info!("Internal reciever set with start of event loop.");
578 loop {
579 event_loop
580 .borrow_mut()
581 .dispatch(std::time::Duration::from_millis(1), self)
582 .unwrap();
583 }
584 }
585
586 fn get_span(&self) -> tracing::span::Span {
587 self.span.clone()
588 }
589}
590
591delegate_compositor!(SpellWin);
592delegate_registry!(SpellWin);
593delegate_output!(SpellWin);
594delegate_shm!(SpellWin);
595delegate_seat!(SpellWin);
596delegate_keyboard!(SpellWin);
597delegate_pointer!(SpellWin);
598delegate_layer!(SpellWin);
599
600impl ShmHandler for SpellWin {
601 fn shm_state(&mut self) -> &mut Shm {
602 &mut self.states.shm
603 }
604}
605
606impl OutputHandler for SpellWin {
607 fn output_state(&mut self) -> &mut OutputState {
608 &mut self.states.output_state
609 }
610
611 fn new_output(
612 &mut self,
613 _conn: &Connection,
614 _qh: &QueueHandle<Self>,
615 _output: wl_output::WlOutput,
616 ) {
617 trace!("New output Source Added");
618 }
619
620 fn update_output(
621 &mut self,
622 _conn: &Connection,
623 _qh: &QueueHandle<Self>,
624 _output: wl_output::WlOutput,
625 ) {
626 trace!("Existing output is updated");
627 }
628
629 fn output_destroyed(
630 &mut self,
631 _conn: &Connection,
632 _qh: &QueueHandle<Self>,
633 _output: wl_output::WlOutput,
634 ) {
635 trace!("Output is destroyed");
636 }
637}
638
639impl CompositorHandler for SpellWin {
640 fn scale_factor_changed(
641 &mut self,
642 _conn: &Connection,
643 _qh: &QueueHandle<Self>,
644 _surface: &wl_surface::WlSurface,
645 _new_factor: i32,
646 ) {
647 trace!("Scale factor changed");
648 }
649
650 fn transform_changed(
651 &mut self,
652 _conn: &Connection,
653 _qh: &QueueHandle<Self>,
654 _surface: &wl_surface::WlSurface,
655 _new_transform: wl_output::Transform,
656 ) {
657 trace!("Compositor transformation changed");
658 }
659
660 fn frame(
661 &mut self,
662 _conn: &Connection,
663 qh: &QueueHandle<Self>,
664 _surface: &wl_surface::WlSurface,
665 _time: u32,
666 ) {
667 self.converter(qh);
668 }
669
670 fn surface_enter(
671 &mut self,
672 _conn: &Connection,
673 _qh: &QueueHandle<Self>,
674 _surface: &wl_surface::WlSurface,
675 _output: &wl_output::WlOutput,
676 ) {
677 trace!("Surface entered");
678 }
679
680 fn surface_leave(
681 &mut self,
682 _conn: &Connection,
683 _qh: &QueueHandle<Self>,
684 _surface: &wl_surface::WlSurface,
685 _output: &wl_output::WlOutput,
686 ) {
687 trace!("Surface left");
688 }
689}
690
691impl LayerShellHandler for SpellWin {
692 fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
693 trace!("Closure of layer called");
694 }
695
696 fn configure(
697 &mut self,
698 _conn: &Connection,
699 qh: &QueueHandle<Self>,
700 _layer: &LayerSurface,
701 _configure: LayerSurfaceConfigure,
702 _serial: u32,
703 ) {
704 if !self.first_configure {
712 self.first_configure = true;
714 } else {
715 }
717 self.converter(qh);
718 }
719}
720
721#[derive(Clone, Debug)]
725pub struct WinHandle(pub(crate) LoopHandle<'static, SpellWin>);
726
727impl WinHandle {
728 pub fn hide(&self) {
730 self.0.insert_idle(|win| win.hide());
731 }
732
733 pub fn show_again(&self) {
735 self.0.insert_idle(|win| win.show_again());
736 }
737
738 pub fn toggle(&self) {
740 self.0.insert_idle(|win| win.toggle());
741 }
742
743 pub fn grab_focus(&self) {
745 self.0.insert_idle(|win| win.grab_focus());
746 }
747
748 pub fn remove_focus(&self) {
750 self.0.insert_idle(|win| win.remove_focus());
751 }
752
753 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
755 self.0
756 .insert_idle(move |win| win.add_input_region(x, y, width, height));
757 }
758
759 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
761 self.0
762 .insert_idle(move |win| win.subtract_input_region(x, y, width, height));
763 }
764
765 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
767 self.0
768 .insert_idle(move |win| win.add_opaque_region(x, y, width, height));
769 }
770
771 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
773 self.0
774 .insert_idle(move |win| win.subtract_opaque_region(x, y, width, height));
775 }
776}
777
778pub struct SpellLock {
831 pub(crate) loop_handle: LoopHandle<'static, SpellLock>,
832 pub(crate) conn: Connection,
833 pub(crate) compositor_state: CompositorState,
834 pub(crate) registry_state: RegistryState,
835 pub(crate) output_state: OutputState,
836 pub(crate) keyboard_state: KeyboardState,
837 pub(crate) seat_state: SeatState,
838 pub(crate) shm: Shm,
839 pub(crate) session_lock: Option<SessionLock>,
840 pub(crate) lock_surfaces: Vec<SessionLockSurface>,
841 pub(crate) slint_part: Option<SpellSlintLock>,
842 pub(crate) is_locked: bool,
843 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellLock>>>,
844 pub(crate) backspace: Option<RegistrationToken>,
845}
846
847impl std::fmt::Debug for SpellLock {
848 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
849 f.debug_struct("SpellLock")
850 .field("is_locked", &self.is_locked)
851 .finish()
852 }
853}
854impl SpellLock {
855 pub fn invoke_lock_spell() -> Self {
856 let conn = Connection::connect_to_env().unwrap();
857
858 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
859 let qh: QueueHandle<SpellLock> = event_queue.handle();
860 let registry_state = RegistryState::new(&globals);
861 let shm = Shm::bind(&globals, &qh).unwrap();
862 let event_loop: EventLoop<'static, SpellLock> =
863 EventLoop::try_new().expect("Failed to initialize the event loop!");
864 let output_state = OutputState::new(&globals, &qh);
865 let session_lock_state = SessionLockState::new(&globals, &qh);
866 let compositor_state =
867 CompositorState::bind(&globals, &qh).expect("Faild to create compositor state");
868 let mut win_handler_vec: Vec<(String, (u32, u32))> = Vec::new();
869 let lock_surfaces = Vec::new();
870
871 let keyboard_state = KeyboardState {
872 board: None,
873 };
875 let mut spell_lock = SpellLock {
876 loop_handle: event_loop.handle().clone(),
877 conn: conn.clone(),
878 compositor_state,
879 output_state,
880 keyboard_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
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 );
970 adapters.push(adapter);
971 });
972
973 multi_handler.borrow_mut().adapter = adapters.clone();
974 spell_lock.slint_part = Some(SpellSlintLock {
975 adapters,
976 size: sizes,
977 wayland_buffer: buffers,
978 });
979
980 spell_lock.backspace = Some(
981 spell_lock
982 .loop_handle
983 .insert_source(
984 Timer::from_duration(Duration::from_millis(1500)),
985 |_, _, data| {
986 data.slint_part.as_ref().unwrap().adapters[0]
987 .try_dispatch_event(slint::platform::WindowEvent::KeyPressed {
988 text: Key::Backspace.into(),
989 })
990 .unwrap();
991 TimeoutAction::ToDuration(Duration::from_millis(1500))
992 },
993 )
994 .unwrap(),
995 );
996
997 spell_lock
998 .loop_handle
999 .disable(&spell_lock.backspace.unwrap())
1000 .unwrap();
1001 let _ = slint::platform::set_platform(Box::new(SpellLockShell::new(multi_handler)));
1002
1003 WaylandSource::new(spell_lock.conn.clone(), event_queue)
1004 .insert(spell_lock.loop_handle.clone())
1005 .unwrap();
1006 spell_lock
1007 }
1008
1009 fn converter_lock(&mut self, qh: &QueueHandle<Self>) {
1010 slint::platform::update_timers_and_animations();
1011 let width: u32 = self.slint_part.as_ref().unwrap().size[0].width;
1012 let height: u32 = self.slint_part.as_ref().unwrap().size[0].height;
1013 let window_adapter = self.slint_part.as_ref().unwrap().adapters[0].clone();
1014
1015 let _redraw_val: bool = window_adapter.draw_if_needed();
1019 let buffer = &self.slint_part.as_ref().unwrap().wayland_buffer[0];
1022 self.lock_surfaces[0]
1026 .wl_surface()
1027 .damage_buffer(0, 0, width as i32, height as i32);
1028 self.lock_surfaces[0]
1046 .wl_surface()
1047 .frame(qh, self.lock_surfaces[0].wl_surface().clone());
1048 self.lock_surfaces[0]
1049 .wl_surface()
1050 .attach(Some(buffer.wl_buffer()), 0, 0);
1051 self.lock_surfaces[0].wl_surface().commit();
1056 }
1063
1064 fn unlock(
1065 &mut self,
1066 username: Option<&str>,
1067 password: &str,
1068 on_unlock_callback: Box<dyn FnOnce()>,
1069 ) -> PamResult<()> {
1070 let user_name;
1071 if let Some(username) = username {
1072 user_name = username.to_string();
1073 } else {
1074 let output = Command::new("sh")
1075 .arg("-c")
1076 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1077 .output()
1078 .expect("Couldn't retrive username");
1079
1080 let val = String::from_utf8_lossy(&output.stdout);
1081 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1082 user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1083 }
1084
1085 let user_pass = UsernamePassConvo {
1086 username: user_name.clone(),
1087 password: password.into(),
1088 };
1089
1090 let mut txn = TransactionBuilder::new_with_service("login")
1091 .username(user_name)
1092 .build(user_pass.into_conversation())?;
1093 txn.authenticate(AuthnFlags::empty())?;
1096 txn.account_management(AuthnFlags::empty())?;
1097
1098 on_unlock_callback();
1099 if let Some(locked_val) = self.session_lock.take() {
1100 locked_val.unlock();
1101 }
1102 self.is_locked = false;
1103 self.conn.roundtrip().unwrap();
1104 Ok(())
1105 }
1106
1107 pub fn get_handler(&self) -> LockHandle {
1108 LockHandle(self.loop_handle.clone())
1109 }
1110}
1111
1112impl SpellAssociated for SpellLock {
1113 fn on_call(
1114 &mut self,
1115 _: Option<State>,
1116 _: Option<Box<dyn FnMut(State)>>,
1117 _: tracing::span::Span,
1118 ) -> Result<(), Box<dyn std::error::Error>> {
1119 let event_loop = self.event_loop.clone();
1120 while self.is_locked {
1121 event_loop
1122 .borrow_mut()
1123 .dispatch(std::time::Duration::from_millis(1), self)
1124 .unwrap();
1125 }
1126 Ok(())
1127 }
1128
1129 fn get_span(&self) -> tracing::span::Span {
1130 span!(Level::INFO, "widget")
1131 }
1132}
1133
1134pub struct LockHandle(LoopHandle<'static, SpellLock>);
1136
1137impl LockHandle {
1138 pub fn unlock(
1143 &self,
1144 username: Option<String>,
1145 password: String,
1146 on_err_callback: Box<dyn FnOnce()>,
1147 on_unlock_callback: Box<dyn FnOnce()>,
1148 ) {
1149 self.0.insert_idle(move |app_data| {
1150 if app_data
1151 .unlock(username.as_deref(), &password, on_unlock_callback)
1152 .is_err()
1153 {
1154 on_err_callback();
1155 }
1156 });
1157 }
1158}
1159
1160delegate_keyboard!(SpellLock);
1161delegate_compositor!(SpellLock);
1162delegate_output!(SpellLock);
1163delegate_shm!(SpellLock);
1164delegate_registry!(SpellLock);
1165delegate_session_lock!(SpellLock);
1166delegate_seat!(SpellLock);
1167struct UsernamePassConvo {
1175 username: String,
1176 password: String,
1177}
1178
1179impl ConversationAdapter for UsernamePassConvo {
1182 fn prompt(&self, _request: impl AsRef<std::ffi::OsStr>) -> PamResult<std::ffi::OsString> {
1183 Ok(std::ffi::OsString::from(&self.username))
1184 }
1185
1186 fn masked_prompt(
1187 &self,
1188 _request: impl AsRef<std::ffi::OsStr>,
1189 ) -> PamResult<std::ffi::OsString> {
1190 Ok(std::ffi::OsString::from(&self.password))
1191 }
1192
1193 fn error_msg(&self, _message: impl AsRef<std::ffi::OsStr>) {}
1194
1195 fn info_msg(&self, _message: impl AsRef<std::ffi::OsStr>) {}
1196}
1197
1198pub struct SpellBoard;