penrose_ui/bar/
schedule.rs1use crate::bar::widgets::Text;
3use penrose::util::spawn_with_args;
4use std::{
5 cmp::max,
6 fmt,
7 sync::{Arc, Mutex},
8 thread,
9 time::{Duration, Instant},
10};
11use tracing::trace;
12
13pub const MIN_DURATION: Duration = Duration::from_secs(1);
15
16pub struct UpdateSchedule {
21 pub(crate) next: Instant,
22 pub(crate) interval: Duration,
23 pub(crate) get_text: Box<dyn Fn() -> Option<String> + Send + 'static>,
24 pub(crate) txt: Arc<Mutex<Text>>,
25}
26
27impl fmt::Debug for UpdateSchedule {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.debug_struct("UpdateSchedule")
30 .field("next", &self.next)
31 .field("interval", &self.interval)
32 .field("txt", &self.txt)
33 .finish()
34 }
35}
36
37impl UpdateSchedule {
38 pub fn new(
44 interval: Duration,
45 get_text: Box<dyn Fn() -> Option<String> + Send + 'static>,
46 txt: Arc<Mutex<Text>>,
47 ) -> Self {
48 if interval < MIN_DURATION {
49 panic!("UpdateSchedule interval is too small: {interval:?} < {MIN_DURATION:?}");
50 }
51
52 Self {
53 next: Instant::now(),
54 interval,
55 get_text,
56 txt,
57 }
58 }
59
60 fn update_text(&mut self) {
67 trace!("running UpdateSchedule get_text");
68 let s = (self.get_text)();
69 trace!(?s, "ouput from running get_text");
70
71 if let Some(s) = s {
72 let mut t = match self.txt.lock() {
73 Ok(inner) => inner,
74 Err(poisoned) => poisoned.into_inner(),
75 };
76 t.set_text(s);
77 }
78
79 let next = self.next + self.interval;
80 let now = Instant::now();
81 self.next = max(next, now);
82 trace!(next = ?self.next, "next update at");
83 }
84}
85
86pub(crate) fn run_update_schedules(mut schedules: Vec<UpdateSchedule>) {
89 thread::spawn(move || {
90 loop {
91 trace!("running UpdateSchedule updates for all pending widgets");
92 while schedules[0].next < Instant::now() {
93 schedules[0].update_text();
94 schedules.sort_by(|a, b| a.next.cmp(&b.next));
95 }
96
97 let _ = spawn_with_args("xsetroot", &["-name", ""]);
100
101 let interval = schedules[0].next - Instant::now();
102 trace!(?interval, "sleeping until next update point");
103 thread::sleep(interval);
104 }
105 });
106}