1use crate::{
6 configure::{LayerConf, WindowConf, set_up_tracing},
7 wayland_adapter::SpellWin,
8};
9use slint::{
10 PhysicalSize, Window,
11 platform::{
12 Platform, WindowAdapter,
13 software_renderer::{
14 RepaintBufferType::{self},
15 SoftwareRenderer,
16 },
17 },
18};
19use smithay_client_toolkit::reexports::client::Connection;
20use std::{
21 cell::{Cell, RefCell},
22 rc::Rc,
23};
24use tracing::{Level, info, span, warn};
25
26#[cfg(not(docsrs))]
27#[cfg(feature = "i-slint-renderer-skia")]
28use crate::skia_non_docs::SpellSkiaWinAdapterReal;
29
30#[cfg(not(docsrs))]
35#[cfg(feature = "i-slint-renderer-skia")]
36pub type SpellSkiaWinAdapter = SpellSkiaWinAdapterReal;
37
38#[cfg(docsrs)]
39use crate::dummy_skia_docs::SpellSkiaWinAdapterDummy;
40
41#[cfg(docsrs)]
46pub type SpellSkiaWinAdapter = SpellSkiaWinAdapterDummy;
47
48pub struct SpellWinAdapter {
52 pub window: Window,
53 pub rendered: SoftwareRenderer,
54 pub size: PhysicalSize, pub needs_redraw: Cell<bool>,
56}
57
58#[allow(dead_code)]
60impl SpellWinAdapter {
61 fn new(width: u32, height: u32) -> Rc<Self> {
62 Rc::<SpellWinAdapter>::new_cyclic(|adapter| SpellWinAdapter {
63 window: Window::new(adapter.clone()),
64 rendered: SoftwareRenderer::new_with_repaint_buffer_type(
65 RepaintBufferType::ReusedBuffer,
66 ),
67 size: PhysicalSize { width, height },
68 needs_redraw: Default::default(),
69 })
70 }
71
72 fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
73 if self.needs_redraw.replace(false) {
74 render_callback(&self.rendered);
75 true
76 } else {
77 false
78 }
79 }
80}
81
82impl WindowAdapter for SpellWinAdapter {
83 fn window(&self) -> &Window {
84 &self.window
85 }
86
87 fn size(&self) -> PhysicalSize {
88 PhysicalSize {
90 width: self.size.width,
91 height: self.size.height,
92 }
93 }
94
95 fn renderer(&self) -> &dyn slint::platform::Renderer {
96 &self.rendered
97 }
98
99 fn request_redraw(&self) {
100 self.needs_redraw.set(true);
101 }
102}
103
104pub struct SpellLayerShell {
107 pub window_adapter: Rc<SpellSkiaWinAdapter>,
109 pub span: span::Span,
110}
111
112impl SpellLayerShell {
113 pub fn new(window_adapter: Rc<SpellSkiaWinAdapter>) -> Self {
115 SpellLayerShell {
116 window_adapter,
117 span: span!(Level::INFO, "slint-log",),
118 }
119 }
120}
121
122impl Platform for SpellLayerShell {
123 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
124 Ok(self.window_adapter.clone())
125 }
126
127 fn debug_log(&self, arguments: core::fmt::Arguments) {
128 self.span.in_scope(|| {
129 if let Some(val) = arguments.as_str() {
130 info!(val);
131 } else {
132 info!("{}", arguments.to_string());
133 }
134 })
135 }
136}
137
138pub struct SpellMultiLayerShell {
143 pub window_manager: Rc<RefCell<SpellMultiWinHandler>>,
145 pub span: span::Span,
146}
147
148impl SpellMultiLayerShell {
149 fn new(window_manager: Rc<RefCell<SpellMultiWinHandler>>) -> Self {
150 SpellMultiLayerShell {
151 window_manager,
152 span: span!(Level::INFO, "slint-log",),
153 }
154 }
155}
156
157impl Platform for SpellMultiLayerShell {
158 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
159 let value = self.window_manager.borrow_mut().request_new_window();
160 Ok(value)
161 }
162
163 fn debug_log(&self, arguments: core::fmt::Arguments) {
164 self.span.in_scope(|| {
165 if let Some(val) = arguments.as_str() {
166 info!(val);
167 } else {
168 info!("{}", arguments.to_string());
169 }
170 })
171 }
172}
173
174pub struct SpellMultiWinHandler {
178 pub(crate) windows: Vec<(String, LayerConf)>,
179 pub(crate) adapter: Vec<Rc<SpellSkiaWinAdapter>>,
180 pub(crate) value_given: u32,
181}
182
183impl SpellMultiWinHandler {
184 pub fn conjure_spells(windows: Vec<(&str, WindowConf)>) -> Vec<SpellWin> {
189 tracing_subscriber::fmt()
190 .without_time()
191 .with_target(false)
192 .with_env_filter(tracing_subscriber::EnvFilter::new(
193 "spell_framework=trace,info",
194 ))
195 .init();
196 let handle = set_up_tracing("multi-window");
197 let conn = Connection::connect_to_env().unwrap();
198 let new_windows: Vec<(String, LayerConf)> = windows
199 .iter()
200 .map(|(layer_name, conf)| (layer_name.to_string(), LayerConf::Window(conf.clone())))
201 .collect();
202
203 let mut new_adapters: Vec<Rc<SpellSkiaWinAdapter>> = Vec::new();
204 let mut windows_spell: Vec<SpellWin> = Vec::new();
205 windows.iter().for_each(|(layer_name, conf)| {
206 let window = SpellWin::create_window(
207 &conn,
208 conf.clone(),
209 layer_name.to_string(),
210 false,
211 handle.clone(),
212 );
213 let adapter = window.adapter.clone();
214 windows_spell.push(window);
215 new_adapters.push(adapter);
216 });
217 let windows_handler = Rc::new(RefCell::new(SpellMultiWinHandler {
218 windows: new_windows,
219 adapter: new_adapters,
220 value_given: 0,
221 }));
222
223 if let Err(error) =
224 slint::platform::set_platform(Box::new(SpellMultiLayerShell::new(windows_handler)))
225 {
226 warn!("Error setting multilayer platform: {}", error);
227 }
228 windows_spell
229 }
230
231 pub(crate) fn new_lock(lock_outputs: Vec<(String, (u32, u32))>) -> Rc<RefCell<Self>> {
232 let new_locks: Vec<(String, LayerConf)> = lock_outputs
233 .iter()
234 .map(|(output_name, conf)| (output_name.clone(), LayerConf::Lock(conf.0, conf.1)))
235 .collect();
236
237 Rc::new(RefCell::new(SpellMultiWinHandler {
238 windows: new_locks,
239 adapter: Vec::new(),
240 value_given: 0,
241 }))
242 }
243
244 fn request_new_window(&mut self) -> Rc<dyn WindowAdapter> {
245 self.value_given += 1;
246 let index = self.value_given - 1;
247 self.adapter[index as usize].clone()
248 }
249
250 fn request_new_lock(&mut self) -> Rc<dyn WindowAdapter> {
251 self.value_given += 1;
252 let index = self.value_given - 1;
253 self.adapter[index as usize].clone()
254 }
255}
256
257pub struct SpellLockShell {
258 pub window_manager: Rc<RefCell<SpellMultiWinHandler>>,
260 pub span: span::Span,
261}
262
263impl SpellLockShell {
264 pub fn new(window_manager: Rc<RefCell<SpellMultiWinHandler>>) -> Self {
265 SpellLockShell {
266 window_manager,
267 span: span!(Level::INFO, "slint-lock-log",),
268 }
269 }
270}
271
272impl Platform for SpellLockShell {
273 fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
274 let value = self.window_manager.borrow_mut().request_new_lock();
275 Ok(value)
276 }
277}