spell_framework/
slint_adapter.rs1use crate::{
6 configure::{LayerConf, WindowConf, set_up_tracing},
7 wayland_adapter::SpellWin,
8};
9use slint::platform::{EventLoopProxy, Platform, WindowAdapter};
10use smithay_client_toolkit::reexports::client::Connection;
11use std::{
12 cell::RefCell,
13 rc::Rc,
14 sync::{Arc, Mutex},
15};
16use tracing::{Level, info, span, warn};
17
18#[cfg(not(docsrs))]
19#[cfg(feature = "i-slint-renderer-skia")]
20use crate::skia_non_docs::SpellSkiaWinAdapterReal;
21
22#[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#[cfg(docsrs)]
38pub type SpellSkiaWinAdapter = SpellSkiaWinAdapterDummy;
39pub struct SpellLayerShell {
42 pub window_adapter: Rc<SpellSkiaWinAdapter>,
44 pub span: span::Span,
45}
46
47impl SpellLayerShell {
48 pub fn new(window_adapter: Rc<SpellSkiaWinAdapter>) -> Self {
50 SpellLayerShell {
51 window_adapter,
52 span: span!(Level::INFO, "slint-log",),
53 }
54 }
55}
56
57impl Platform for SpellLayerShell {
58 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
59 Ok(self.window_adapter.clone())
60 }
61
62 fn debug_log(&self, arguments: core::fmt::Arguments) {
63 self.span.in_scope(|| {
64 if let Some(val) = arguments.as_str() {
65 info!(val);
66 } else {
67 info!("{}", arguments.to_string());
68 }
69 })
70 }
71
72 fn new_event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {
73 Some(Box::new(SlintEventProxy(
74 self.window_adapter.slint_event_proxy.clone(),
75 )))
76 }
77}
78
79pub struct SpellMultiLayerShell {
84 pub window_manager: Rc<RefCell<SpellMultiWinHandler>>,
86 pub span: span::Span,
87}
88
89impl SpellMultiLayerShell {
90 fn new(window_manager: Rc<RefCell<SpellMultiWinHandler>>) -> Self {
91 SpellMultiLayerShell {
92 window_manager,
93 span: span!(Level::INFO, "slint-log",),
94 }
95 }
96}
97
98impl Platform for SpellMultiLayerShell {
99 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
100 let value = self.window_manager.borrow_mut().request_new_window();
101 Ok(value)
102 }
103
104 fn debug_log(&self, arguments: core::fmt::Arguments) {
105 self.span.in_scope(|| {
106 if let Some(val) = arguments.as_str() {
107 info!(val);
108 } else {
109 info!("{}", arguments.to_string());
110 }
111 })
112 }
113}
114
115pub struct SpellMultiWinHandler {
119 pub(crate) windows: Vec<(String, LayerConf)>,
120 pub(crate) adapter: Vec<Rc<SpellSkiaWinAdapter>>,
121 pub(crate) value_given: u32,
122}
123
124impl SpellMultiWinHandler {
125 pub fn conjure_spells(windows: Vec<(&str, WindowConf)>) -> Vec<SpellWin> {
130 tracing_subscriber::fmt()
131 .without_time()
132 .with_target(false)
133 .with_env_filter(tracing_subscriber::EnvFilter::new(
134 "spell_framework=trace,info",
135 ))
136 .init();
137 let handle = set_up_tracing("multi-window");
138 let conn = Connection::connect_to_env().unwrap();
139 let new_windows: Vec<(String, LayerConf)> = windows
140 .iter()
141 .map(|(layer_name, conf)| (layer_name.to_string(), LayerConf::Window(conf.clone())))
142 .collect();
143
144 let mut new_adapters: Vec<Rc<SpellSkiaWinAdapter>> = Vec::new();
145 let mut windows_spell: Vec<SpellWin> = Vec::new();
146 windows.iter().for_each(|(layer_name, conf)| {
147 let window = SpellWin::create_window(
148 &conn,
149 conf.clone(),
150 layer_name.to_string(),
151 false,
152 handle.clone(),
153 );
154 new_adapters.push(window.adapter.clone());
155 windows_spell.push(window);
156 });
157 let windows_handler = Rc::new(RefCell::new(SpellMultiWinHandler {
158 windows: new_windows,
159 adapter: new_adapters,
160 value_given: 0,
161 }));
162
163 if let Err(error) =
164 slint::platform::set_platform(Box::new(SpellMultiLayerShell::new(windows_handler)))
165 {
166 warn!("Error setting multilayer platform: {}", error);
167 }
168 windows_spell
169 }
170
171 pub(crate) fn new_lock(lock_outputs: Vec<(String, (u32, u32))>) -> Rc<RefCell<Self>> {
172 let new_locks: Vec<(String, LayerConf)> = lock_outputs
173 .iter()
174 .map(|(output_name, conf)| (output_name.clone(), LayerConf::Lock(conf.0, conf.1)))
175 .collect();
176
177 Rc::new(RefCell::new(SpellMultiWinHandler {
178 windows: new_locks,
179 adapter: Vec::new(),
180 value_given: 0,
181 }))
182 }
183
184 fn request_new_window(&mut self) -> Rc<dyn WindowAdapter> {
185 self.value_given += 1;
186 let index = self.value_given - 1;
187 self.adapter[index as usize].clone()
188 }
189
190 fn request_new_lock(&mut self) -> Rc<dyn WindowAdapter> {
191 self.value_given += 1;
192 let index = self.value_given - 1;
193 self.adapter[index as usize].clone()
194 }
195}
196
197pub struct SpellLockShell {
198 pub window_manager: Rc<RefCell<SpellMultiWinHandler>>,
200 pub span: span::Span,
201}
202
203impl SpellLockShell {
204 pub fn new(window_manager: Rc<RefCell<SpellMultiWinHandler>>) -> Self {
205 SpellLockShell {
206 window_manager,
207 span: span!(Level::INFO, "slint-lock-log",),
208 }
209 }
210}
211
212impl Platform for SpellLockShell {
213 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
214 let value = self.window_manager.borrow_mut().request_new_lock();
215 Ok(value)
216 }
217
218 fn debug_log(&self, arguments: core::fmt::Arguments) {
219 self.span.in_scope(|| {
220 if let Some(val) = arguments.as_str() {
221 info!(val);
222 } else {
223 info!("{}", arguments.to_string());
224 }
225 })
226 }
227}
228
229#[allow(clippy::type_complexity)]
230struct SlintEventProxy(Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>);
231
232impl EventLoopProxy for SlintEventProxy {
233 fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {
234 Ok(())
235 }
236
237 fn invoke_from_event_loop(
238 &self,
239 event: Box<dyn FnOnce() + Send>,
240 ) -> Result<(), i_slint_core::api::EventLoopError> {
241 if let Ok(mut list_of_event) = self.0.try_lock() {
242 (*list_of_event).push(event);
243 } else {
244 warn!("Slint proxy event could not be processed");
245 }
246 Ok(())
247 }
248}