spell_framework/
configure.rs

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/// Unused Internal struct representation of a pixel, it is similar to slint's
16/// representation of [pixel]() but implement few more trait. Currently, redundent
17#[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        // self.a = a as u8;
36        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        // TODO This needs to be decided to see how it should be 0xFF or 0x00;
50        // I think there is a bug in slint which is causing the leak of This
51        // value.
52        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/// WindowConf is an essential struct passed on to widget constructor functions (like [invoke_spell](crate::wayland_adapter::SpellWin::invoke_spell))
65/// for defining the specifications of the widget.
66///
67/// ## Panics
68///
69/// event loops like [cast_spell](crate::cast_spell) and [encahnt_spells](crate::enchant_spells) will panic if 0 is provided as width or height.
70#[derive(Debug, Clone)]
71pub struct WindowConf {
72    /// Defines the widget width in pixels. On setting values greater than the provided pixels of
73    /// monitor, the widget offsets from monitor's rectangular monitor space. It is important to
74    /// note that the value should be the maximum width the widget will ever attain, not the
75    /// current width in case of resizeable widgets.
76    pub width: u32,
77    /// Defines the widget height in pixels. On setting values greater than the provided pixels of
78    /// monitor, the widget offsets from monitor's rectangular monitor space. It is important to
79    /// note that the value should be the maximum height the widget will ever attain, not the
80    /// current height in case of resizeable widgets.
81    pub height: u32,
82    /// Defines the Anchors to which the window needs to be attached. View [`Anchor`] for
83    /// related explaination of usage. If both values are None, then widget is displayed in the
84    /// center of screen.
85    pub anchor: (Option<Anchor>, Option<Anchor>),
86    /// Defines the margin of widget from monitor edges, negative values make the widget go outside
87    /// of monitor pixels if anchored to some edge(s). Otherwise, the widget moves to the opposite
88    /// direction to the given pixels.
89    pub margin: (i32, i32, i32, i32),
90    /// Defines the possible layer on which to define the widget. View [`Layer`] for more details.
91    pub layer_type: Layer,
92    /// Defines the relation of widget with Keyboard. View [`KeyboardInteractivity`] for more
93    /// details.
94    pub board_interactivity: Cell<KeyboardInteractivity>,
95    /// Defines if the widget is exclusive of not,if not set to None, else set to number of pixels to
96    /// set as exclusive zone as i32.
97    pub exclusive_zone: Option<i32>,
98}
99
100impl WindowConf {
101    /// constructor method for initialising an instance of WindowConf.
102    #[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 socket_cli_dir = logging_dir.clone() + "/spell_cli";
310
311    let _ = fs::create_dir(Path::new(&logging_dir));
312    let _ = fs::remove_file(&socket_dir);
313    // let _ = fs::File::create(&socket_cli_dir);
314
315    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) // rotate log files once every hour
322        .filename_prefix(widget_name) // log file names will be prefixed with `myapp.`
323        .filename_suffix("log") // log file names will be suffixed with `.log`
324        .build(&logging_dir) // try to build an appender that stores log files in `/var/log`
325        .expect("initializing rolling file appender failed");
326
327    // Logs to be stored in case of debugging.
328    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    // Logs on socket read by cli.
335    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        // Logs shown in stdout when program runs.
344        .with(
345            fmt::layer()
346                .without_time()
347                .with_target(false)
348                .with_filter(EnvFilter::new("spell_framework=info, warn")),
349        )
350        // Logs for file.
351        .with(layer_writer)
352        // Logs for cli
353        .with(layer_env);
354    let _ = tracing::subscriber::set_global_default(subs);
355    handle
356}
357
358pub(crate) struct SocketWriter {
359    socket: UnixDatagram,
360    // formatter: Format<DefaultFields>,
361}
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// TODO this will be made public when multiple widgets in the same layer is supported.
384// Likely it will be easy after the resize action is implemented
385#[allow(dead_code)]
386pub enum LayerConf {
387    Window(WindowConf),
388    Windows(Vec<WindowConf>),
389    Lock(u32, u32),
390}