1use crate::{
6 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::{KeyboardState, PointerState, set_config, set_event_sources},
15 },
16};
17pub use lock_impl::SpellSlintLock;
18use nonstick::{
19 AuthnFlags, ConversationAdapter, Result as PamResult, Transaction, TransactionBuilder,
20};
21use slint::{PhysicalSize, platform::Key};
22use smithay_client_toolkit::{
23 compositor::{CompositorHandler, CompositorState, Region},
24 delegate_compositor,
25 delegate_keyboard,
26 delegate_layer,
27 delegate_output,
28 delegate_pointer,
29 delegate_registry,
30 delegate_seat,
31 delegate_session_lock,
32 delegate_shm, output::{self, OutputHandler, OutputState},
34 reexports::{
35 calloop::{
36 EventLoop, LoopHandle, RegistrationToken,
37 channel::Event,
38 timer::{TimeoutAction, Timer},
39 },
40 calloop_wayland_source::WaylandSource,
41 client::{
42 Connection, QueueHandle,
43 globals::registry_queue_init,
44 protocol::{wl_output, wl_shm, wl_surface},
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 process::Command,
65 rc::Rc,
66 sync::{Arc, Mutex},
67 time::Duration,
68};
69use tracing::{Level, info, span, trace};
70
71mod fractional_scaling;
72mod lock_impl;
73mod viewporter;
74mod way_helper;
75mod win_impl;
76
77#[derive(Debug)]
78pub(crate) struct States {
79 pub(crate) registry_state: RegistryState,
80 pub(crate) seat_state: SeatState,
81 pub(crate) output_state: OutputState,
82 pub(crate) pointer_state: PointerState,
83 pub(crate) keyboard_state: KeyboardState,
84 pub(crate) shm: Shm,
85 pub(crate) viewporter: Viewport,
86}
87
88pub struct SpellWin {
99 pub(crate) adapter: Rc<SpellSkiaWinAdapter>,
100 pub(crate) loop_handle: LoopHandle<'static, SpellWin>,
101 pub(crate) queue: QueueHandle<SpellWin>,
102 pub(crate) buffer: Buffer,
103 pub(crate) states: States,
104 pub(crate) layer: LayerSurface,
105 pub(crate) first_configure: bool,
106 pub(crate) is_hidden: Cell<bool>,
107 pub(crate) layer_name: String,
108 pub(crate) config: WindowConf,
109 pub(crate) input_region: Region,
110 pub(crate) opaque_region: Region,
111 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellWin>>>,
112 pub(crate) span: span::Span,
113 }
116
117impl std::fmt::Debug for SpellWin {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 f.debug_struct("SpellWin")
120 .field("adapter", &self.adapter)
121 .field("first_configure", &self.first_configure)
122 .field("is_hidden", &self.is_hidden)
123 .field("config", &self.config)
124 .finish()
125 }
126}
127
128impl SpellWin {
129 pub(crate) fn create_window(
130 conn: &Connection,
131 window_conf: WindowConf,
132 layer_name: String,
133 if_single: bool,
134 handle: HomeHandle,
135 ) -> Self {
136 let (globals, event_queue) = registry_queue_init(conn).unwrap();
137 let qh: QueueHandle<SpellWin> = event_queue.handle();
138 let compositor =
139 CompositorState::bind(&globals, &qh).expect("wl_compositor is not available");
140 let event_loop: EventLoop<'static, SpellWin> =
141 EventLoop::try_new().expect("Failed to initialize the event loop!");
142 let layer_shell = LayerShell::bind(&globals, &qh).expect("layer shell is not available");
143 let shm = Shm::bind(&globals, &qh).expect("wl_shm is not available");
144 let mut pool = SlotPool::new((window_conf.width * window_conf.height * 4) as usize, &shm)
145 .expect("Failed to create pool");
146 let input_region = Region::new(&compositor).expect("Couldn't create region");
147 let opaque_region = Region::new(&compositor).expect("Couldn't create opaque region");
148 input_region.add(0, 0, window_conf.width as i32, window_conf.height as i32);
149 let cursor_manager =
150 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
151 let fractional_scale_state: FractionalScaleState =
152 FractionalScaleState::bind(&globals, &qh).expect("Fractional Scale couldn't be set");
153 let stride = window_conf.width as i32 * 4;
154 let surface = compositor.create_surface(&qh);
155 let layer = layer_shell.create_layer_surface(
156 &qh,
157 surface,
158 window_conf.layer_type,
159 Some(layer_name.clone()),
160 None,
161 );
162 let fractional_scale = fractional_scale_state.get_scale(layer.wl_surface(), &qh);
163 let viewporter_state =
164 ViewporterState::bind(&globals, &qh).expect("Couldn't set viewporter");
165 let viewporter = viewporter_state.get_viewport(layer.wl_surface(), &qh, fractional_scale);
166 set_config(
167 &window_conf,
168 &layer,
169 Some(input_region.wl_region()),
171 None,
172 );
173 layer.commit();
174 let (way_pri_buffer, _) = pool
175 .create_buffer(
176 window_conf.width as i32,
177 window_conf.height as i32,
178 stride,
179 wl_shm::Format::Argb8888,
180 )
181 .expect("Creating Buffer");
182
183 let primary_slot = way_pri_buffer.slot();
184
185 let pointer_state = PointerState {
186 pointer: None,
187 pointer_data: None,
188 cursor_shape: cursor_manager,
189 };
190
191 let keyboard_state = KeyboardState {
192 board: None,
193 };
195
196 #[allow(clippy::type_complexity)]
197 let slint_proxy: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>> =
198 Arc::new(Mutex::new(Vec::new()));
199 let adapter_value: Rc<SpellSkiaWinAdapter> = SpellSkiaWinAdapter::new(
200 Rc::new(RefCell::new(pool)),
201 RefCell::new(primary_slot),
202 window_conf.width,
203 window_conf.height,
204 slint_proxy.clone(),
205 );
206
207 if if_single {
208 trace!("Single window layer platform set");
209 let _ = slint::platform::set_platform(Box::new(SpellLayerShell::new(
210 adapter_value.clone(),
211 )));
212 }
213 set_event_sources(&event_loop, handle);
214
215 let win = SpellWin {
216 adapter: adapter_value,
217 loop_handle: event_loop.handle(),
218 queue: qh.clone(),
219 buffer: way_pri_buffer,
220 states: States {
221 registry_state: RegistryState::new(&globals),
222 seat_state: SeatState::new(&globals, &qh),
223 output_state: OutputState::new(&globals, &qh),
224 pointer_state,
225 keyboard_state,
226 shm,
227 viewporter,
228 },
229 layer,
230 first_configure: true,
231 is_hidden: Cell::new(false),
232 layer_name: layer_name.clone(),
233 config: window_conf,
234 input_region,
235 opaque_region,
236 event_loop: Rc::new(RefCell::new(event_loop)),
237 span: span!(Level::INFO, "widget", name = layer_name.as_str(),),
238 };
240
241 info!("Win: {} layer created successfully.", layer_name);
242
243 WaylandSource::new(conn.clone(), event_queue)
244 .insert(win.loop_handle.clone())
245 .unwrap();
246 win
247 }
248
249 pub fn get_handler(&mut self) -> WinHandle {
251 info!("Win: Handle provided.");
252 WinHandle(self.loop_handle.clone())
253 }
254
255 pub fn invoke_spell(name: &str, window_conf: WindowConf) -> Self {
263 let handle = set_up_tracing(name);
264 let conn = Connection::connect_to_env().unwrap();
265 SpellWin::create_window(&conn, window_conf.clone(), name.to_string(), true, handle)
266 }
267
268 pub fn hide(&self) {
270 if !self.is_hidden.replace(true) {
271 info!("Win: Hiding window");
272 self.layer.wl_surface().attach(None, 0, 0);
273 }
274 }
275
276 pub fn show_again(&mut self) {
278 if self.is_hidden.replace(false) {
279 info!("Win: Showing window again");
280 let qh = self.queue.clone();
281 self.converter(&qh);
282 }
291 }
292
293 pub fn toggle(&mut self) {
295 info!("Win: view toggled");
296 if self.is_hidden.get() {
297 self.show_again();
298 } else {
299 self.hide();
300 }
301 }
302
303 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
309 info!(
310 "Win: input region added: [x: {}, y: {}, width: {}, height: {}]",
311 x, y, width, height
312 );
313 self.input_region.add(x, y, width, height);
314 self.set_config_internal();
315 self.layer.commit();
316 }
317
318 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
323 info!(
324 "Win: input region removed: [x: {}, y: {}, width: {}, height: {}]",
325 x, y, width, height
326 );
327 self.input_region.subtract(x, y, width, height);
328 self.set_config_internal();
329 self.layer.commit();
330 }
331
332 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
338 info!(
339 "Win: opaque region added: [x: {}, y: {}, width: {}, height: {}]",
340 x, y, width, height
341 );
342 self.opaque_region.add(x, y, width, height);
343 self.set_config_internal();
344 self.layer.commit();
345 }
346
347 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
352 info!(
353 "Win: opaque region removed: [x: {}, y: {}, width: {}, height: {}]",
354 x, y, width, height
355 );
356 self.opaque_region.subtract(x, y, width, height);
357 self.set_config_internal();
358 self.layer.commit();
359 }
360
361 fn set_config_internal(&self) {
362 set_config(
363 &self.config,
364 &self.layer,
365 Some(self.input_region.wl_region()),
367 Some(self.opaque_region.wl_region()),
368 );
369 }
370
371 fn converter(&mut self, qh: &QueueHandle<Self>) {
372 slint::platform::update_timers_and_animations();
373 let width: u32 = self.adapter.size.get().width;
374 let height: u32 = self.adapter.size.get().height;
375 let window_adapter = self.adapter.clone();
376
377 if !self.is_hidden.get() {
379 let skia_now = std::time::Instant::now();
380 let redraw_val: bool = window_adapter.draw_if_needed();
381 let elasped_time = skia_now.elapsed().as_millis();
382 if elasped_time != 0 {
383 }
385
386 let buffer = &self.buffer;
387 if self.first_configure || redraw_val {
388 self.first_configure = false;
390 self.layer
391 .wl_surface()
392 .damage_buffer(0, 0, width as i32, height as i32);
393 self.layer
411 .wl_surface()
412 .attach(Some(buffer.wl_buffer()), 0, 0);
413 }
414 } else {
415 }
417
418 self.layer
419 .wl_surface()
420 .frame(qh, self.layer.wl_surface().clone());
421 self.layer.commit();
422 }
423
424 pub fn grab_focus(&self) {
427 self.config
428 .board_interactivity
429 .set(KeyboardInteractivity::Exclusive);
430 self.layer
431 .set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
432 self.layer.commit();
433 }
434
435 pub fn remove_focus(&self) {
437 self.config
438 .board_interactivity
439 .set(KeyboardInteractivity::None);
440 self.layer
441 .set_keyboard_interactivity(KeyboardInteractivity::None);
442 self.layer.commit();
443 }
444
445 pub fn set_exclusive_zone(&mut self, val: i32) {
448 self.config.exclusive_zone = Some(val);
450 self.layer.set_exclusive_zone(val);
451 self.layer.commit();
452 }
453}
454
455impl SpellAssociated for SpellWin {
456 fn on_call(
457 &mut self,
458 state: Option<State>,
459 set_callback: Option<Box<dyn FnMut(State)>>,
460 span_log: tracing::span::Span,
461 ) -> Result<(), Box<dyn std::error::Error>> {
462 let rx = helper_fn_for_deploy(self.layer_name.clone(), &state, span_log);
463 let event_loop = self.event_loop.clone();
464 if let Some(mut callback) = set_callback {
465 self.event_loop
466 .borrow()
467 .handle()
468 .insert_source(rx, move |event_msg, _, state_data| {
469 trace!("Internal event recieved");
470 match event_msg {
471 Event::Msg(int_handle) => match int_handle {
472 InternalHandle::StateValChange((key, data_type)) => {
473 trace!("Internal variable change called");
474 {
475 let mut state_inst = state.as_ref().unwrap().write().unwrap();
476 state_inst.change_val(&key, data_type);
477 }
478 callback(state.as_ref().unwrap().clone());
479 }
480 InternalHandle::ShowWinAgain => {
481 trace!("Internal show Called");
482 state_data.show_again();
483 }
484 InternalHandle::HideWindow => {
485 trace!("Internal hide called");
486 state_data.hide();
487 }
488 },
489 Event::Closed => {
491 info!("Internal Channel closed");
492 }
493 }
494 })
495 .unwrap();
496 }
497 info!("Internal reciever set with start of event loop.");
498 loop {
499 event_loop
500 .borrow_mut()
501 .dispatch(std::time::Duration::from_millis(1), self)
502 .unwrap();
503 }
504 }
505
506 fn get_span(&self) -> tracing::span::Span {
507 self.span.clone()
508 }
509}
510
511delegate_compositor!(SpellWin);
512delegate_registry!(SpellWin);
513delegate_output!(SpellWin);
514delegate_shm!(SpellWin);
515delegate_seat!(SpellWin);
516delegate_keyboard!(SpellWin);
517delegate_pointer!(SpellWin);
518delegate_layer!(SpellWin);
520delegate_fractional_scale!(SpellWin);
521delegate_viewporter!(SpellWin);
522
523impl ShmHandler for SpellWin {
524 fn shm_state(&mut self) -> &mut Shm {
525 &mut self.states.shm
526 }
527}
528
529impl OutputHandler for SpellWin {
530 fn output_state(&mut self) -> &mut OutputState {
531 &mut self.states.output_state
532 }
533
534 fn new_output(
535 &mut self,
536 _conn: &Connection,
537 _qh: &QueueHandle<Self>,
538 _output: wl_output::WlOutput,
539 ) {
540 trace!("New output Source Added");
541 }
542
543 fn update_output(
544 &mut self,
545 _conn: &Connection,
546 _qh: &QueueHandle<Self>,
547 _output: wl_output::WlOutput,
548 ) {
549 trace!("Existing output is updated");
550 }
551
552 fn output_destroyed(
553 &mut self,
554 _conn: &Connection,
555 _qh: &QueueHandle<Self>,
556 _output: wl_output::WlOutput,
557 ) {
558 trace!("Output is destroyed");
559 }
560}
561
562impl CompositorHandler for SpellWin {
563 fn scale_factor_changed(
564 &mut self,
565 _: &Connection,
566 _: &QueueHandle<Self>,
567 _: &wl_surface::WlSurface,
568 _: i32,
569 ) {
570 info!("Scale factor changed, compositor msg");
571 }
572
573 fn transform_changed(
574 &mut self,
575 _conn: &Connection,
576 _qh: &QueueHandle<Self>,
577 _surface: &wl_surface::WlSurface,
578 _new_transform: wl_output::Transform,
579 ) {
580 trace!("Compositor transformation changed");
581 }
582
583 fn frame(
584 &mut self,
585 _conn: &Connection,
586 qh: &QueueHandle<Self>,
587 _surface: &wl_surface::WlSurface,
588 _time: u32,
589 ) {
590 self.converter(qh);
591 }
592
593 fn surface_enter(
594 &mut self,
595 _conn: &Connection,
596 _qh: &QueueHandle<Self>,
597 _surface: &wl_surface::WlSurface,
598 _output: &wl_output::WlOutput,
599 ) {
600 trace!("Surface entered");
601 }
602
603 fn surface_leave(
604 &mut self,
605 _conn: &Connection,
606 _qh: &QueueHandle<Self>,
607 _surface: &wl_surface::WlSurface,
608 _output: &wl_output::WlOutput,
609 ) {
610 trace!("Surface left");
611 }
612}
613
614impl FractionalScaleHandler for SpellWin {
615 fn preferred_scale(
616 &mut self,
617 _: &Connection,
618 _: &QueueHandle<Self>,
619 _: &wl_surface::WlSurface,
620 scale: u32,
621 ) {
622 info!("Scale factor changed, invoked from custom trait. {}", scale);
623
624 self.layer.wl_surface().damage_buffer(
625 0,
626 0,
627 self.adapter.size.get().width as i32,
628 self.adapter.size.get().height as i32,
629 );
630 let scale_factor: f32 = scale as f32 / 120.0;
632 let width: u32 = (self.adapter.size.get().width * scale + 60) / 120;
633 let height: u32 = (self.adapter.size.get().height * scale + 60) / 120;
634 self.adapter.scale_factor.set(scale_factor);
635 self.states
636 .viewporter
637 .set_destination(width as i32, height as i32);
638 self.states.viewporter.set_source(
639 0.,
640 0.,
641 self.adapter.size.get().width.into(),
642 self.adapter.size.get().height.into(),
643 );
644 self.layer.commit();
648 }
649}
650
651impl LayerShellHandler for SpellWin {
652 fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
653 trace!("Closure of layer called");
654 }
655
656 fn configure(
657 &mut self,
658 _conn: &Connection,
659 qh: &QueueHandle<Self>,
660 _layer: &LayerSurface,
661 _configure: LayerSurfaceConfigure,
662 _serial: u32,
663 ) {
664 if !self.first_configure {
672 self.first_configure = true;
674 } else {
675 }
677 self.converter(qh);
678 }
679}
680
681#[derive(Clone, Debug)]
685pub struct WinHandle(pub(crate) LoopHandle<'static, SpellWin>);
686
687impl WinHandle {
688 pub fn hide(&self) {
690 self.0.insert_idle(|win| win.hide());
691 }
692
693 pub fn show_again(&self) {
695 self.0.insert_idle(|win| win.show_again());
696 }
697
698 pub fn toggle(&self) {
700 self.0.insert_idle(|win| win.toggle());
701 }
702
703 pub fn grab_focus(&self) {
705 self.0.insert_idle(|win| win.grab_focus());
706 }
707
708 pub fn remove_focus(&self) {
710 self.0.insert_idle(|win| win.remove_focus());
711 }
712
713 pub fn add_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
715 self.0
716 .insert_idle(move |win| win.add_input_region(x, y, width, height));
717 }
718
719 pub fn subtract_input_region(&self, x: i32, y: i32, width: i32, height: i32) {
721 self.0
722 .insert_idle(move |win| win.subtract_input_region(x, y, width, height));
723 }
724
725 pub fn add_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
727 self.0
728 .insert_idle(move |win| win.add_opaque_region(x, y, width, height));
729 }
730
731 pub fn subtract_opaque_region(&self, x: i32, y: i32, width: i32, height: i32) {
733 self.0
734 .insert_idle(move |win| win.subtract_opaque_region(x, y, width, height));
735 }
736}
737
738pub struct SpellLock {
791 pub(crate) loop_handle: LoopHandle<'static, SpellLock>,
792 pub(crate) conn: Connection,
793 pub(crate) compositor_state: CompositorState,
794 pub(crate) registry_state: RegistryState,
795 pub(crate) output_state: OutputState,
796 pub(crate) keyboard_state: KeyboardState,
797 pub(crate) pointer_state: PointerState,
798 pub(crate) seat_state: SeatState,
799 pub(crate) shm: Shm,
800 pub(crate) session_lock: Option<SessionLock>,
801 pub(crate) lock_surfaces: Vec<SessionLockSurface>,
802 pub(crate) slint_part: Option<SpellSlintLock>,
803 pub(crate) is_locked: bool,
804 pub(crate) event_loop: Rc<RefCell<EventLoop<'static, SpellLock>>>,
805 pub(crate) backspace: Option<RegistrationToken>,
806}
807
808impl std::fmt::Debug for SpellLock {
809 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
810 f.debug_struct("SpellLock")
811 .field("is_locked", &self.is_locked)
812 .finish()
813 }
814}
815impl SpellLock {
816 pub fn invoke_lock_spell() -> Self {
817 let conn = Connection::connect_to_env().unwrap();
818
819 let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
820 let qh: QueueHandle<SpellLock> = event_queue.handle();
821 let registry_state = RegistryState::new(&globals);
822 let shm = Shm::bind(&globals, &qh).unwrap();
823 let event_loop: EventLoop<'static, SpellLock> =
824 EventLoop::try_new().expect("Failed to initialize the event loop!");
825 let output_state = OutputState::new(&globals, &qh);
826 let session_lock_state = SessionLockState::new(&globals, &qh);
827 let compositor_state =
828 CompositorState::bind(&globals, &qh).expect("Faild to create compositor state");
829 let cursor_manager =
830 CursorShapeManager::bind(&globals, &qh).expect("cursor shape is not available");
831 let mut win_handler_vec: Vec<(String, (u32, u32))> = Vec::new();
832 let lock_surfaces = Vec::new();
833
834 let keyboard_state = KeyboardState {
835 board: None,
836 };
838 let pointer_state = PointerState {
839 pointer: None,
840 pointer_data: None,
841 cursor_shape: cursor_manager,
842 };
843 let mut spell_lock = SpellLock {
844 loop_handle: event_loop.handle().clone(),
845 conn: conn.clone(),
846 compositor_state,
847 output_state,
848 keyboard_state,
849 pointer_state,
850 registry_state,
851 seat_state: SeatState::new(&globals, &qh),
852 slint_part: None,
853 shm,
854 session_lock: None,
855 lock_surfaces,
856 is_locked: true,
857 event_loop: Rc::new(RefCell::new(event_loop)),
858 backspace: None,
859 };
860
861 let _ = event_queue.roundtrip(&mut spell_lock);
862
863 let session_lock = Some(
864 session_lock_state
865 .lock(&qh)
866 .expect("ext-session-lock not supported"),
867 );
868
869 spell_lock.session_lock = session_lock;
870 for output in spell_lock.output_state.outputs() {
871 let output_info: output::OutputInfo = spell_lock.output_state.info(&output).unwrap();
872 let output_name: String = output_info.name.unwrap_or_else(|| "SomeOutput".to_string());
873 let dimensions = (
874 output_info.logical_size.unwrap().0 as u32,
875 output_info.logical_size.unwrap().1 as u32,
876 );
877 win_handler_vec.push((output_name, dimensions));
878
879 let session_lock = spell_lock.session_lock.as_ref().unwrap();
880 let surface = spell_lock.compositor_state.create_surface(&qh);
881
882 let lock_surface = session_lock.create_lock_surface(surface, &output, &qh);
885 spell_lock.lock_surfaces.push(lock_surface);
886 }
887 let multi_handler = SpellMultiWinHandler::new_lock(win_handler_vec);
888 let sizes: Vec<PhysicalSize> = multi_handler
889 .borrow()
890 .windows
891 .iter()
892 .map(|(_, conf)| {
893 if let LayerConf::Lock(width, height) = conf {
894 PhysicalSize {
895 width: *width,
896 height: *height,
897 }
898 } else {
899 panic!("Shouldn't enter here");
900 }
901 })
902 .collect();
903
904 let mut pool = SlotPool::new(
905 (sizes[0].width * sizes[0].height * 4) as usize,
906 &spell_lock.shm,
907 )
908 .expect("Couldn't create pool");
909 let mut buffer_slots: Vec<RefCell<Slot>> = Vec::new();
910 let buffers: Vec<Buffer> = sizes
911 .iter()
912 .map(|physical_size| {
913 let stride = physical_size.width as i32 * 4;
914 let (wayland_buffer, _) = pool
915 .create_buffer(
916 physical_size.width as i32,
917 physical_size.height as i32,
918 stride,
919 wl_shm::Format::Argb8888,
920 )
921 .expect("Creating Buffer");
922 buffer_slots.push(RefCell::new(wayland_buffer.slot()));
923 wayland_buffer
924 })
925 .collect();
926 let slint_proxy = Arc::new(Mutex::new(Vec::new()));
927 let pool: Rc<RefCell<SlotPool>> = Rc::new(RefCell::new(pool));
928 let mut adapters: Vec<Rc<SpellSkiaWinAdapter>> = Vec::new();
929 buffer_slots
930 .into_iter()
931 .enumerate()
932 .for_each(|(index, slot)| {
933 let adapter = SpellSkiaWinAdapter::new(
934 pool.clone(),
935 slot,
936 sizes[index].width,
937 sizes[index].height,
938 slint_proxy.clone(),
939 );
940 adapters.push(adapter);
941 });
942
943 multi_handler.borrow_mut().adapter = adapters.clone();
944 spell_lock.slint_part = Some(SpellSlintLock {
945 adapters,
946 size: sizes,
947 wayland_buffer: buffers,
948 });
949
950 spell_lock.backspace = Some(
951 spell_lock
952 .loop_handle
953 .insert_source(
954 Timer::from_duration(Duration::from_millis(1500)),
955 |_, _, data| {
956 data.slint_part.as_ref().unwrap().adapters[0]
957 .try_dispatch_event(slint::platform::WindowEvent::KeyPressed {
958 text: Key::Backspace.into(),
959 })
960 .unwrap();
961 TimeoutAction::ToDuration(Duration::from_millis(1500))
962 },
963 )
964 .unwrap(),
965 );
966
967 spell_lock
968 .loop_handle
969 .disable(&spell_lock.backspace.unwrap())
970 .unwrap();
971 let _ = slint::platform::set_platform(Box::new(SpellLockShell::new(multi_handler)));
972
973 WaylandSource::new(spell_lock.conn.clone(), event_queue)
974 .insert(spell_lock.loop_handle.clone())
975 .unwrap();
976 spell_lock
977 }
978
979 fn converter_lock(&mut self, qh: &QueueHandle<Self>) {
980 slint::platform::update_timers_and_animations();
981 let width: u32 = self.slint_part.as_ref().unwrap().size[0].width;
982 let height: u32 = self.slint_part.as_ref().unwrap().size[0].height;
983 let window_adapter = self.slint_part.as_ref().unwrap().adapters[0].clone();
984
985 let _redraw_val: bool = window_adapter.draw_if_needed();
989 let buffer = &self.slint_part.as_ref().unwrap().wayland_buffer[0];
992 self.lock_surfaces[0]
996 .wl_surface()
997 .damage_buffer(0, 0, width as i32, height as i32);
998 self.lock_surfaces[0]
1016 .wl_surface()
1017 .frame(qh, self.lock_surfaces[0].wl_surface().clone());
1018 self.lock_surfaces[0]
1019 .wl_surface()
1020 .attach(Some(buffer.wl_buffer()), 0, 0);
1021 self.lock_surfaces[0].wl_surface().commit();
1026 }
1033
1034 fn unlock(
1035 &mut self,
1036 username: Option<&str>,
1037 password: &str,
1038 on_unlock_callback: Box<dyn FnOnce()>,
1039 ) -> PamResult<()> {
1040 let user_name;
1041 if let Some(username) = username {
1042 user_name = username.to_string();
1043 } else {
1044 let output = Command::new("sh")
1045 .arg("-c")
1046 .arg("last | awk '{print $1}' | sort | uniq -c | sort -nr")
1047 .output()
1048 .expect("Couldn't retrive username");
1049
1050 let val = String::from_utf8_lossy(&output.stdout);
1051 let val_2 = val.split('\n').collect::<Vec<_>>()[0].trim();
1052 user_name = val_2.split(" ").collect::<Vec<_>>()[1].to_string();
1053 }
1054
1055 let user_pass = UsernamePassConvo {
1056 username: user_name.clone(),
1057 password: password.into(),
1058 };
1059
1060 let mut txn = TransactionBuilder::new_with_service("login")
1061 .username(user_name)
1062 .build(user_pass.into_conversation())?;
1063 txn.authenticate(AuthnFlags::empty())?;
1066 txn.account_management(AuthnFlags::empty())?;
1067
1068 on_unlock_callback();
1069 if let Some(locked_val) = self.session_lock.take() {
1070 locked_val.unlock();
1071 }
1072 self.is_locked = false;
1073 self.conn.roundtrip().unwrap();
1074 Ok(())
1075 }
1076
1077 pub fn get_handler(&self) -> LockHandle {
1078 LockHandle(self.loop_handle.clone())
1079 }
1080}
1081
1082impl SpellAssociated for SpellLock {
1083 fn on_call(
1084 &mut self,
1085 _: Option<State>,
1086 _: Option<Box<dyn FnMut(State)>>,
1087 _: tracing::span::Span,
1088 ) -> Result<(), Box<dyn std::error::Error>> {
1089 let event_loop = self.event_loop.clone();
1090 while self.is_locked {
1091 event_loop
1092 .borrow_mut()
1093 .dispatch(std::time::Duration::from_millis(1), self)
1094 .unwrap();
1095 }
1096 Ok(())
1097 }
1098
1099 fn get_span(&self) -> tracing::span::Span {
1100 span!(Level::INFO, "lock-screen")
1101 }
1102}
1103
1104pub struct LockHandle(LoopHandle<'static, SpellLock>);
1106
1107impl LockHandle {
1108 pub fn unlock(
1113 &self,
1114 username: Option<String>,
1115 password: String,
1116 on_err_callback: Box<dyn FnOnce()>,
1117 on_unlock_callback: Box<dyn FnOnce()>,
1118 ) {
1119 self.0.insert_idle(move |app_data| {
1120 if app_data
1121 .unlock(username.as_deref(), &password, on_unlock_callback)
1122 .is_err()
1123 {
1124 on_err_callback();
1125 }
1126 });
1127 }
1128}
1129
1130delegate_keyboard!(SpellLock);
1131delegate_compositor!(SpellLock);
1132delegate_output!(SpellLock);
1133delegate_shm!(SpellLock);
1134delegate_registry!(SpellLock);
1135delegate_pointer!(SpellLock);
1136delegate_session_lock!(SpellLock);
1137delegate_seat!(SpellLock);
1138struct UsernamePassConvo {
1146 username: String,
1147 password: String,
1148}
1149
1150impl ConversationAdapter for UsernamePassConvo {
1153 fn prompt(&self, _request: impl AsRef<std::ffi::OsStr>) -> PamResult<std::ffi::OsString> {
1154 Ok(std::ffi::OsString::from(&self.username))
1155 }
1156
1157 fn masked_prompt(
1158 &self,
1159 _request: impl AsRef<std::ffi::OsStr>,
1160 ) -> PamResult<std::ffi::OsString> {
1161 Ok(std::ffi::OsString::from(&self.password))
1162 }
1163
1164 fn error_msg(&self, _message: impl AsRef<std::ffi::OsStr>) {}
1165
1166 fn info_msg(&self, _message: impl AsRef<std::ffi::OsStr>) {}
1167}
1168
1169pub struct SpellBoard;