1use smithay_client_toolkit::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer};
2use std::{cell::Cell, fs, io::Write, os::unix::net::UnixDatagram, path::Path, sync::Mutex};
3use tracing_appender::rolling::{RollingFileAppender, Rotation};
4use tracing_subscriber::{
5 EnvFilter, Layer as TracingTraitLayer,
6 filter::Filtered,
7 fmt::{self, format::DefaultFields},
8 layer::{Layered, SubscriberExt},
9 registry::Registry,
10 reload::Layer as LoadLayer,
11};
12
13#[derive(Debug, Clone)]
20pub struct WindowConf {
21 pub width: u32,
26 pub height: u32,
31 pub anchor: [Option<Anchor>; 4],
35 pub margin: (i32, i32, i32, i32),
39 pub layer_type: Layer,
42 pub board_interactivity: Cell<KeyboardInteractivity>,
45 pub exclusive_zone: Option<i32>,
48 pub monitor_name: Option<String>,
51 pub natural_scroll: bool,
55}
56
57impl WindowConf {
58 pub fn builder() -> WindowConfBuilder {
61 WindowConfBuilder::default()
62 }
63}
64
65#[derive(Default)]
68pub struct WindowConfBuilder {
69 max_width: u32,
70 max_height: u32,
71 anchor: [Option<Anchor>; 4],
72 margin: (i32, i32, i32, i32),
73 layer_type: Option<Layer>,
74 board_interactivity: KeyboardInteractivity,
75 exclusive_zone: Option<i32>,
76 monitor_name: Option<String>,
77 natural_scroll: bool,
78}
79
80impl WindowConfBuilder {
81 pub fn width<I: Into<u32>>(&mut self, width: I) -> &mut Self {
83 let new = self;
84 new.max_width = width.into();
85 new
86 }
87
88 pub fn height<I: Into<u32>>(&mut self, height: I) -> &mut Self {
90 let x = self;
91 x.max_height = height.into();
92 x
93 }
94
95 pub fn anchor_1(&mut self, anchor: Anchor) -> &mut Self {
97 let x = self;
98 x.anchor[0] = Some(anchor);
99 x
100 }
101
102 pub fn anchor_2(&mut self, anchor: Anchor) -> &mut Self {
104 let x = self;
105 x.anchor[1] = Some(anchor);
106 x
107 }
108
109 pub fn anchor_3(&mut self, anchor: Anchor) -> &mut Self {
111 let x = self;
112 x.anchor[2] = Some(anchor);
113 x
114 }
115
116 pub fn anchor_4(&mut self, anchor: Anchor) -> &mut Self {
118 let x = self;
119 x.anchor[3] = Some(anchor);
120 x
121 }
122
123 pub fn margins(&mut self, top: i32, right: i32, bottom: i32, left: i32) -> &mut Self {
125 let x = self;
126 x.margin = (top, right, bottom, left);
127 x
128 }
129
130 pub fn layer_type(&mut self, layer: Layer) -> &mut Self {
132 let x = self;
133 x.layer_type = Some(layer);
134 x
135 }
136
137 pub fn board_interactivity(&mut self, board: KeyboardInteractivity) -> &mut Self {
139 let x = self;
140 x.board_interactivity = board;
141 x
142 }
143
144 pub fn exclusive_zone(&mut self, dimention: i32) -> &mut Self {
146 let x = self;
147 x.exclusive_zone = Some(dimention);
148 x
149 }
150
151 pub fn monitor(&mut self, name: String) -> &mut Self {
153 let x = self;
154 x.monitor_name = Some(name);
155 x
156 }
157
158 pub fn natural_scroll(&mut self, scroll: bool) -> &mut Self {
160 let x = self;
161 x.natural_scroll = scroll;
162 x
163 }
164
165 pub fn build(&self) -> Result<WindowConf, Box<dyn std::error::Error>> {
169 Ok(WindowConf {
170 width: if self.max_width != 0 {
171 self.max_width
172 } else {
173 return Err("width is either not defined or set to zero".into());
174 },
175 height: if self.max_height != 0 {
176 self.max_height
177 } else {
178 return Err("height is either not defined or set to zero".into());
179 },
180 anchor: self.anchor,
181 margin: self.margin,
182 layer_type: match self.layer_type {
183 None => Layer::Top,
184 Some(val) => val,
185 },
186 board_interactivity: Cell::new(self.board_interactivity),
187 exclusive_zone: self.exclusive_zone,
188 monitor_name: self.monitor_name.clone(),
189 natural_scroll: self.natural_scroll,
190 })
191 }
192}
193
194pub(crate) type HomeHandle = tracing_subscriber::reload::Handle<
195 Filtered<
196 tracing_subscriber::fmt::Layer<
197 Layered<
198 Filtered<
199 tracing_subscriber::fmt::Layer<
200 Layered<
201 Filtered<
202 tracing_subscriber::fmt::Layer<
203 Registry,
204 DefaultFields,
205 tracing_subscriber::fmt::format::Format<
206 tracing_subscriber::fmt::format::Full,
207 (),
208 >,
209 >,
210 EnvFilter,
211 Registry,
212 >,
213 Registry,
214 >,
215 DefaultFields,
216 tracing_subscriber::fmt::format::Format<
217 tracing_subscriber::fmt::format::Full,
218 (),
219 >,
220 RollingFileAppender,
221 >,
222 EnvFilter,
223 Layered<
224 Filtered<
225 tracing_subscriber::fmt::Layer<
226 Registry,
227 DefaultFields,
228 tracing_subscriber::fmt::format::Format<
229 tracing_subscriber::fmt::format::Full,
230 (),
231 >,
232 >,
233 EnvFilter,
234 Registry,
235 >,
236 Registry,
237 >,
238 >,
239 Layered<
240 Filtered<
241 tracing_subscriber::fmt::Layer<
242 Registry,
243 DefaultFields,
244 tracing_subscriber::fmt::format::Format<
245 tracing_subscriber::fmt::format::Full,
246 (),
247 >,
248 >,
249 EnvFilter,
250 Registry,
251 >,
252 Registry,
253 >,
254 >,
255 DefaultFields,
256 tracing_subscriber::fmt::format::Format<tracing_subscriber::fmt::format::Full, ()>,
257 std::sync::Mutex<SocketWriter>,
258 >,
259 EnvFilter,
260 Layered<
261 Filtered<
262 tracing_subscriber::fmt::Layer<
263 Layered<
264 Filtered<
265 tracing_subscriber::fmt::Layer<
266 Registry,
267 DefaultFields,
268 tracing_subscriber::fmt::format::Format<
269 tracing_subscriber::fmt::format::Full,
270 (),
271 >,
272 >,
273 EnvFilter,
274 Registry,
275 >,
276 Registry,
277 >,
278 DefaultFields,
279 tracing_subscriber::fmt::format::Format<
280 tracing_subscriber::fmt::format::Full,
281 (),
282 >,
283 RollingFileAppender,
284 >,
285 EnvFilter,
286 Layered<
287 Filtered<
288 tracing_subscriber::fmt::Layer<
289 Registry,
290 DefaultFields,
291 tracing_subscriber::fmt::format::Format<
292 tracing_subscriber::fmt::format::Full,
293 (),
294 >,
295 >,
296 EnvFilter,
297 Registry,
298 >,
299 Registry,
300 >,
301 >,
302 Layered<
303 Filtered<
304 tracing_subscriber::fmt::Layer<
305 Registry,
306 DefaultFields,
307 tracing_subscriber::fmt::format::Format<
308 tracing_subscriber::fmt::format::Full,
309 (),
310 >,
311 >,
312 EnvFilter,
313 Registry,
314 >,
315 Registry,
316 >,
317 >,
318 >,
319 Layered<
320 Filtered<
321 tracing_subscriber::fmt::Layer<
322 Layered<
323 Filtered<
324 tracing_subscriber::fmt::Layer<
325 Registry,
326 DefaultFields,
327 tracing_subscriber::fmt::format::Format<
328 tracing_subscriber::fmt::format::Full,
329 (),
330 >,
331 >,
332 EnvFilter,
333 Registry,
334 >,
335 Registry,
336 >,
337 DefaultFields,
338 tracing_subscriber::fmt::format::Format<tracing_subscriber::fmt::format::Full, ()>,
339 RollingFileAppender,
340 >,
341 EnvFilter,
342 Layered<
343 Filtered<
344 tracing_subscriber::fmt::Layer<
345 Registry,
346 DefaultFields,
347 tracing_subscriber::fmt::format::Format<
348 tracing_subscriber::fmt::format::Full,
349 (),
350 >,
351 >,
352 EnvFilter,
353 Registry,
354 >,
355 Registry,
356 >,
357 >,
358 Layered<
359 Filtered<
360 tracing_subscriber::fmt::Layer<
361 Registry,
362 DefaultFields,
363 tracing_subscriber::fmt::format::Format<
364 tracing_subscriber::fmt::format::Full,
365 (),
366 >,
367 >,
368 EnvFilter,
369 Registry,
370 >,
371 Registry,
372 >,
373 >,
374>;
375pub(crate) fn set_up_tracing(widget_name: &str) -> HomeHandle {
376 let runtime_dir = std::env::var("XDG_RUNTIME_DIR").expect("runtime dir is not set");
377 let logging_dir = runtime_dir + "/spell/";
378 let socket_dir = logging_dir.clone() + "/spell.sock";
379 let _ = fs::create_dir(Path::new(&logging_dir));
382 let _ = fs::remove_file(&socket_dir);
383 let stream = UnixDatagram::unbound().unwrap();
386 stream
387 .set_nonblocking(true)
388 .expect("Non blocking couldn't be set");
389
390 let writer = RollingFileAppender::builder()
391 .rotation(Rotation::HOURLY) .filename_prefix(widget_name) .filename_suffix("log") .build(&logging_dir) .expect("initializing rolling file appender failed");
396
397 let layer_writer = fmt::layer()
399 .without_time()
400 .with_target(false)
401 .with_writer(writer)
402 .with_filter(EnvFilter::new("spell_framework=trace,info"));
403
404 let layer_socket = fmt::Layer::default()
406 .without_time()
407 .with_target(false)
408 .with_writer(Mutex::new(SocketWriter::new(stream)))
409 .with_filter(EnvFilter::new("spell_framework=info, warn"));
410
411 let (layer_env, handle) = LoadLayer::new(layer_socket);
412 let subs = tracing_subscriber::registry()
413 .with(
415 fmt::layer()
416 .without_time()
417 .with_target(false)
418 .with_filter(EnvFilter::new("spell_framework=info, warn")),
419 )
420 .with(layer_writer)
422 .with(layer_env);
424 let _ = tracing::subscriber::set_global_default(subs);
425 handle
426}
427
428pub(crate) struct SocketWriter {
429 socket: UnixDatagram,
430 }
432
433impl SocketWriter {
434 fn new(socket: UnixDatagram) -> Self {
435 SocketWriter { socket }
436 }
437}
438
439impl Write for SocketWriter {
440 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
441 let runtime_dir = std::env::var("XDG_RUNTIME_DIR").expect("runtime dir is not set");
442 let logging_dir = runtime_dir + "/spell/";
443 let socket_dir = logging_dir.clone() + "/spell.sock";
444
445 self.socket.send_to(buf, Path::new(&socket_dir))
446 }
447
448 fn flush(&mut self) -> std::io::Result<()> {
449 Ok(())
450 }
451}
452
453#[allow(dead_code)]
456pub enum LayerConf {
457 Window(WindowConf),
458 Windows(Vec<WindowConf>),
459 Lock(u32, u32),
460}