Skip to main content

spell_framework/
slint_adapter.rs

1//! This module contains relevent structs for slint side backend configurations.
2//! All structs mentioned are either internal or not used anymore. Still their
3//! implementation is public because they had to be set by the user of library
4//! in intial iterations of spell_framework.
5use crate::configure::LayerConf;
6use slint::platform::{EventLoopProxy, Platform, WindowAdapter};
7use std::{
8    cell::RefCell,
9    rc::Rc,
10    sync::{Arc, Mutex},
11};
12use tracing::{Level, info, span, warn};
13
14thread_local! {
15    pub(crate) static ADAPTERS: RefCell<Vec<Rc<SpellSkiaWinAdapter>>> = const { RefCell::new(Vec::new()) };
16}
17
18#[cfg(not(docsrs))]
19#[cfg(feature = "i-slint-renderer-skia")]
20use crate::skia_non_docs::SpellSkiaWinAdapterReal;
21
22/// It is the main struct handling the rendering of pixels in the wayland window. It implements slint's
23/// [WindowAdapter](https://docs.rs/slint/latest/slint/platform/trait.WindowAdapter.html) trait.
24/// It is used internally by [SpellMultiWinHandler] and previously by [SpellLayerShell]. This
25/// adapter internally uses [Skia](https://skia.org/) 2D graphics library for rendering.
26#[cfg(not(docsrs))]
27#[cfg(feature = "i-slint-renderer-skia")]
28pub type SpellSkiaWinAdapter = SpellSkiaWinAdapterReal;
29
30#[cfg(docsrs)]
31use crate::dummy_skia_docs::SpellSkiaWinAdapterDummy;
32
33/// It is the main struct handling the rendering of pixels in the wayland window. It implements slint's
34/// [WindowAdapter](https://docs.rs/slint/latest/slint/platform/trait.WindowAdapter.html) trait.
35/// It is used internally by [SpellMultiWinHandler] and previously by [SpellLayerShell]. This
36/// adapter internally uses [Skia](https://skia.org/) 2D graphics library for rendering.
37#[cfg(docsrs)]
38pub type SpellSkiaWinAdapter = SpellSkiaWinAdapterDummy;
39/// Previously needed to be implemented, now this struct is called and set internally
40/// when [`invoke_spell`](crate::wayland_adapter::SpellWin::invoke_spell) is called.
41pub struct SpellLayerShell {
42    /// Span storing the logging context for `debug`` statements of slint.
43    pub span: span::Span,
44}
45
46impl Default for SpellLayerShell {
47    /// Creates an instance of this Platform implementation, for internal use.
48    fn default() -> Self {
49        SpellLayerShell {
50            span: span!(Level::INFO, "slint-log",),
51        }
52    }
53}
54
55impl Platform for SpellLayerShell {
56    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
57        let adapter = ADAPTERS.with(|v| v.borrow().last().unwrap().clone());
58        Ok(adapter)
59    }
60
61    fn debug_log(&self, arguments: core::fmt::Arguments) {
62        self.span.in_scope(|| {
63            if let Some(val) = arguments.as_str() {
64                info!(val);
65            } else {
66                info!("{}", arguments.to_string());
67            }
68        })
69    }
70
71    fn new_event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {
72        Some(Box::new(SlintEventProxy(ADAPTERS.with(|v| {
73            v.borrow().last().unwrap().slint_event_proxy.clone()
74        }))))
75    }
76}
77
78/// This struct is responsible for handling, initialising, updating and maintaining
79/// of various widgets that are being rendered simultaneously across monitors for
80/// your lock. It uses [SpellSkiaWinAdapter] internally. This struct is made public
81/// for documentation purposes (and was previously used by end user of library) but
82/// it is now not to be used directly.
83pub struct SpellMultiWinHandler {
84    pub(crate) windows: Vec<(String, LayerConf)>,
85    pub(crate) adapter: Vec<Rc<SpellSkiaWinAdapter>>,
86    pub(crate) value_given: u32,
87}
88
89impl SpellMultiWinHandler {
90    pub(crate) fn new_lock(lock_outputs: Vec<(String, (u32, u32))>) -> Rc<RefCell<Self>> {
91        let new_locks: Vec<(String, LayerConf)> = lock_outputs
92            .iter()
93            .map(|(output_name, conf)| (output_name.clone(), LayerConf::Lock(conf.0, conf.1)))
94            .collect();
95
96        Rc::new(RefCell::new(SpellMultiWinHandler {
97            windows: new_locks,
98            adapter: Vec::new(),
99            value_given: 0,
100        }))
101    }
102
103    fn request_new_lock(&mut self) -> Rc<dyn WindowAdapter> {
104        self.value_given += 1;
105        let index = self.value_given - 1;
106        self.adapter[index as usize].clone()
107    }
108}
109
110/// Slint Platform implementation for lock screens. This struct is used internally
111/// and it is provided here just for reference.
112pub struct SpellLockShell {
113    /// An instance of [SpellMultiWinHandler].
114    pub window_manager: Rc<RefCell<SpellMultiWinHandler>>,
115    /// Span storing the logging context for `debug`` statements of slint for
116    /// lock screens.
117    pub span: span::Span,
118}
119
120impl SpellLockShell {
121    /// Internal function that creates an instance of layer implementation given
122    /// [`SpellMultiWinHandler`] wrapped in smart pointers.
123    pub fn new(window_manager: Rc<RefCell<SpellMultiWinHandler>>) -> Self {
124        SpellLockShell {
125            window_manager,
126            span: span!(Level::INFO, "slint-lock-log",),
127        }
128    }
129}
130
131impl Platform for SpellLockShell {
132    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
133        let value = self.window_manager.borrow_mut().request_new_lock();
134        Ok(value)
135    }
136
137    fn debug_log(&self, arguments: core::fmt::Arguments) {
138        self.span.in_scope(|| {
139            if let Some(val) = arguments.as_str() {
140                info!(val);
141            } else {
142                info!("{}", arguments.to_string());
143            }
144        })
145    }
146}
147
148#[allow(clippy::type_complexity)]
149struct SlintEventProxy(Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>);
150
151impl EventLoopProxy for SlintEventProxy {
152    fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {
153        Ok(())
154    }
155
156    fn invoke_from_event_loop(
157        &self,
158        event: Box<dyn FnOnce() + Send>,
159    ) -> Result<(), i_slint_core::api::EventLoopError> {
160        if let Ok(mut list_of_event) = self.0.try_lock() {
161            (*list_of_event).push(event);
162        } else {
163            warn!("Slint proxy event could not be processed");
164        }
165        Ok(())
166    }
167}