1use slint::platform::software_renderer::TargetPixel;
2use smithay_client_toolkit::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer};
3use std::{cell::Cell, fs, io::Write, os::unix::net::UnixDatagram, path::Path, sync::Mutex};
4use tracing::warn;
5use tracing_appender::rolling::{RollingFileAppender, Rotation};
6use tracing_subscriber::{
7 EnvFilter, Layer as TracingTraitLayer,
8 filter::Filtered,
9 fmt::{self, format::DefaultFields},
10 layer::{Layered, SubscriberExt},
11 registry::Registry,
12 reload::Layer as LoadLayer,
13};
14
15#[allow(dead_code)]
18#[derive(Default)]
19pub struct Rgba8Pixel {
20 pub a: u8,
21 pub r: u8,
22 pub g: u8,
23 pub b: u8,
24}
25
26impl Rgba8Pixel {
27 pub fn new(a: u8, r: u8, g: u8, b: u8) -> Self {
28 Rgba8Pixel { a, r, g, b }
29 }
30}
31
32impl TargetPixel for Rgba8Pixel {
33 fn blend(&mut self, color: slint::platform::software_renderer::PremultipliedRgbaColor) {
34 let a: u16 = (u8::MAX - color.alpha) as u16;
35 let out_a = color.alpha as u16 + (self.a as u16 * (255 - color.alpha) as u16) / 255;
37 self.a = out_a as u8;
38 self.r = (self.r as u16 * a / 255) as u8 + color.red;
39 self.g = (self.g as u16 * a / 255) as u8 + color.green;
40 self.b = (self.b as u16 * a / 255) as u8 + color.blue;
41 }
42
43 fn from_rgb(red: u8, green: u8, blue: u8) -> Self {
44 let a = 0xFF;
45 Self::new(a, red, green, blue)
46 }
47
48 fn background() -> Self {
49 let a: u8 = 0x00;
53 Self::new(a, 0, 0, 0)
54 }
55}
56
57impl std::marker::Copy for Rgba8Pixel {}
58impl std::clone::Clone for Rgba8Pixel {
59 fn clone(&self) -> Self {
60 *self
61 }
62}
63
64#[derive(Debug, Clone)]
71pub struct WindowConf {
72 pub width: u32,
77 pub height: u32,
82 pub anchor: (Option<Anchor>, Option<Anchor>),
86 pub margin: (i32, i32, i32, i32),
90 pub layer_type: Layer,
92 pub board_interactivity: Cell<KeyboardInteractivity>,
95 pub exclusive_zone: Option<i32>,
98}
99
100impl WindowConf {
101 #[allow(clippy::too_many_arguments)]
103 pub fn new(
104 max_width: u32,
105 max_height: u32,
106 anchor: (Option<Anchor>, Option<Anchor>),
107 margin: (i32, i32, i32, i32),
108 layer_type: Layer,
109 board_interactivity: KeyboardInteractivity,
110 exclusive_zone: Option<i32>,
111 ) -> Self {
112 WindowConf {
113 width: max_width,
114 height: max_height,
115 anchor,
116 margin,
117 layer_type,
118 board_interactivity: Cell::new(board_interactivity),
119 exclusive_zone,
120 }
121 }
122}
123
124pub(crate) type HomeHandle = tracing_subscriber::reload::Handle<
125 Filtered<
126 tracing_subscriber::fmt::Layer<
127 Layered<
128 Filtered<
129 tracing_subscriber::fmt::Layer<
130 Layered<
131 Filtered<
132 tracing_subscriber::fmt::Layer<
133 Registry,
134 DefaultFields,
135 tracing_subscriber::fmt::format::Format<
136 tracing_subscriber::fmt::format::Full,
137 (),
138 >,
139 >,
140 EnvFilter,
141 Registry,
142 >,
143 Registry,
144 >,
145 DefaultFields,
146 tracing_subscriber::fmt::format::Format<
147 tracing_subscriber::fmt::format::Full,
148 (),
149 >,
150 RollingFileAppender,
151 >,
152 EnvFilter,
153 Layered<
154 Filtered<
155 tracing_subscriber::fmt::Layer<
156 Registry,
157 DefaultFields,
158 tracing_subscriber::fmt::format::Format<
159 tracing_subscriber::fmt::format::Full,
160 (),
161 >,
162 >,
163 EnvFilter,
164 Registry,
165 >,
166 Registry,
167 >,
168 >,
169 Layered<
170 Filtered<
171 tracing_subscriber::fmt::Layer<
172 Registry,
173 DefaultFields,
174 tracing_subscriber::fmt::format::Format<
175 tracing_subscriber::fmt::format::Full,
176 (),
177 >,
178 >,
179 EnvFilter,
180 Registry,
181 >,
182 Registry,
183 >,
184 >,
185 DefaultFields,
186 tracing_subscriber::fmt::format::Format<tracing_subscriber::fmt::format::Full, ()>,
187 std::sync::Mutex<SocketWriter>,
188 >,
189 EnvFilter,
190 Layered<
191 Filtered<
192 tracing_subscriber::fmt::Layer<
193 Layered<
194 Filtered<
195 tracing_subscriber::fmt::Layer<
196 Registry,
197 DefaultFields,
198 tracing_subscriber::fmt::format::Format<
199 tracing_subscriber::fmt::format::Full,
200 (),
201 >,
202 >,
203 EnvFilter,
204 Registry,
205 >,
206 Registry,
207 >,
208 DefaultFields,
209 tracing_subscriber::fmt::format::Format<
210 tracing_subscriber::fmt::format::Full,
211 (),
212 >,
213 RollingFileAppender,
214 >,
215 EnvFilter,
216 Layered<
217 Filtered<
218 tracing_subscriber::fmt::Layer<
219 Registry,
220 DefaultFields,
221 tracing_subscriber::fmt::format::Format<
222 tracing_subscriber::fmt::format::Full,
223 (),
224 >,
225 >,
226 EnvFilter,
227 Registry,
228 >,
229 Registry,
230 >,
231 >,
232 Layered<
233 Filtered<
234 tracing_subscriber::fmt::Layer<
235 Registry,
236 DefaultFields,
237 tracing_subscriber::fmt::format::Format<
238 tracing_subscriber::fmt::format::Full,
239 (),
240 >,
241 >,
242 EnvFilter,
243 Registry,
244 >,
245 Registry,
246 >,
247 >,
248 >,
249 Layered<
250 Filtered<
251 tracing_subscriber::fmt::Layer<
252 Layered<
253 Filtered<
254 tracing_subscriber::fmt::Layer<
255 Registry,
256 DefaultFields,
257 tracing_subscriber::fmt::format::Format<
258 tracing_subscriber::fmt::format::Full,
259 (),
260 >,
261 >,
262 EnvFilter,
263 Registry,
264 >,
265 Registry,
266 >,
267 DefaultFields,
268 tracing_subscriber::fmt::format::Format<tracing_subscriber::fmt::format::Full, ()>,
269 RollingFileAppender,
270 >,
271 EnvFilter,
272 Layered<
273 Filtered<
274 tracing_subscriber::fmt::Layer<
275 Registry,
276 DefaultFields,
277 tracing_subscriber::fmt::format::Format<
278 tracing_subscriber::fmt::format::Full,
279 (),
280 >,
281 >,
282 EnvFilter,
283 Registry,
284 >,
285 Registry,
286 >,
287 >,
288 Layered<
289 Filtered<
290 tracing_subscriber::fmt::Layer<
291 Registry,
292 DefaultFields,
293 tracing_subscriber::fmt::format::Format<
294 tracing_subscriber::fmt::format::Full,
295 (),
296 >,
297 >,
298 EnvFilter,
299 Registry,
300 >,
301 Registry,
302 >,
303 >,
304>;
305pub(crate) fn set_up_tracing(widget_name: &str) -> HomeHandle {
306 let runtime_dir = std::env::var("XDG_RUNTIME_DIR").expect("runtime dir is not set");
307 let logging_dir = runtime_dir + "/spell/";
308 let socket_dir = logging_dir.clone() + "/spell.sock";
309 let _ = fs::create_dir(Path::new(&logging_dir));
312 let _ = fs::remove_file(&socket_dir);
313 let stream = UnixDatagram::unbound().unwrap();
316 stream
317 .set_nonblocking(true)
318 .expect("Non blocking couldn't be set");
319
320 let writer = RollingFileAppender::builder()
321 .rotation(Rotation::HOURLY) .filename_prefix(widget_name) .filename_suffix("log") .build(&logging_dir) .expect("initializing rolling file appender failed");
326
327 let layer_writer = fmt::layer()
329 .without_time()
330 .with_target(false)
331 .with_writer(writer)
332 .with_filter(EnvFilter::new("spell_framework=trace,info"));
333
334 let layer_socket = fmt::Layer::default()
336 .without_time()
337 .with_target(false)
338 .with_writer(Mutex::new(SocketWriter::new(stream)))
339 .with_filter(EnvFilter::new("spell_framework=info, warn"));
340
341 let (layer_env, handle) = LoadLayer::new(layer_socket);
342 let subs = tracing_subscriber::registry()
343 .with(
345 fmt::layer()
346 .without_time()
347 .with_target(false)
348 .with_filter(EnvFilter::new("spell_framework=info, warn")),
349 )
350 .with(layer_writer)
352 .with(layer_env);
354 let _ = tracing::subscriber::set_global_default(subs);
355 handle
356}
357
358pub(crate) struct SocketWriter {
359 socket: UnixDatagram,
360 }
362
363impl SocketWriter {
364 fn new(socket: UnixDatagram) -> Self {
365 SocketWriter { socket }
366 }
367}
368
369impl Write for SocketWriter {
370 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
371 let runtime_dir = std::env::var("XDG_RUNTIME_DIR").expect("runtime dir is not set");
372 let logging_dir = runtime_dir + "/spell/";
373 let socket_dir = logging_dir.clone() + "/spell.sock";
374
375 self.socket.send_to(buf, Path::new(&socket_dir))
376 }
377
378 fn flush(&mut self) -> std::io::Result<()> {
379 Ok(())
380 }
381}
382
383#[allow(dead_code)]
386pub enum LayerConf {
387 Window(WindowConf),
388 Windows(Vec<WindowConf>),
389 Lock(u32, u32),
390}