waybar-modules

extend waybar functionality with custom waybar modules
Log | Files | Refs | README

main.rs (1941B)


      1 use std::fs;
      2 use std::io::{Read, Write};
      3 use std::time::Duration;
      4 
      5 const TARGET: &str = "gpu-screen-recorder";
      6 const POLL_INTERVAL: Duration = Duration::from_secs(2);
      7 
      8 /// Scans /proc for a process whose argv[0] basename matches the target.
      9 /// Reads cmdline (not the truncated `comm`) to avoid false positives
     10 /// from the 15-char comm truncation matching an unrelated binary.
     11 fn is_recording() -> bool {
     12     let entries = match fs::read_dir("/proc") {
     13         Ok(d) => d,
     14         Err(_) => return false,
     15     };
     16 
     17     for entry in entries.flatten() {
     18         let name = entry.file_name();
     19         let Some(pid_str) = name.to_str() else {
     20             continue;
     21         };
     22         if !pid_str.bytes().all(|b| b.is_ascii_digit()) {
     23             continue;
     24         }
     25 
     26         let mut buf = Vec::with_capacity(64);
     27         if fs::File::open(format!("/proc/{pid_str}/cmdline"))
     28             .and_then(|mut f| f.read_to_end(&mut buf))
     29             .is_err()
     30         {
     31             continue;
     32         }
     33 
     34         // cmdline is NUL-separated; argv[0] is everything before the first NUL
     35         let argv0 = buf.split(|&b| b == 0).next().unwrap_or(&[]);
     36         let argv0 = String::from_utf8_lossy(argv0);
     37         let basename = argv0.rsplit('/').next().unwrap_or(&argv0);
     38 
     39         if basename == TARGET {
     40             return true;
     41         }
     42     }
     43     false
     44 }
     45 
     46 fn emit(recording: bool) {
     47     let json = if recording {
     48         r#"{"text":"󰑊 <span color='#aaaaaa'>Recording</span>","class":"recording","alt":"recording","tooltip":"gpu-screen-recorder is running"}"#
     49     } else {
     50         r#"{"text":"","class":"idle","alt":"idle","tooltip":""}"#
     51     };
     52     println!("{json}");
     53     let _ = std::io::stdout().flush();
     54 }
     55 
     56 fn main() {
     57     let mut last: Option<bool> = None;
     58     loop {
     59         let now = is_recording();
     60         if last != Some(now) {
     61             emit(now);
     62             last = Some(now);
     63         }
     64         std::thread::sleep(POLL_INTERVAL);
     65     }
     66 }