diff options
Diffstat (limited to 'waybar-record/src/main.rs')
| -rw-r--r-- | waybar-record/src/main.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/waybar-record/src/main.rs b/waybar-record/src/main.rs new file mode 100644 index 0000000..8ceb6c7 --- /dev/null +++ b/waybar-record/src/main.rs @@ -0,0 +1,66 @@ +use std::fs; +use std::io::{Read, Write}; +use std::time::Duration; + +const TARGET: &str = "gpu-screen-recorder"; +const POLL_INTERVAL: Duration = Duration::from_secs(2); + +/// Scans /proc for a process whose argv[0] basename matches the target. +/// Reads cmdline (not the truncated `comm`) to avoid false positives +/// from the 15-char comm truncation matching an unrelated binary. +fn is_recording() -> bool { + let entries = match fs::read_dir("/proc") { + Ok(d) => d, + Err(_) => return false, + }; + + for entry in entries.flatten() { + let name = entry.file_name(); + let Some(pid_str) = name.to_str() else { + continue; + }; + if !pid_str.bytes().all(|b| b.is_ascii_digit()) { + continue; + } + + let mut buf = Vec::with_capacity(64); + if fs::File::open(format!("/proc/{pid_str}/cmdline")) + .and_then(|mut f| f.read_to_end(&mut buf)) + .is_err() + { + continue; + } + + // cmdline is NUL-separated; argv[0] is everything before the first NUL + let argv0 = buf.split(|&b| b == 0).next().unwrap_or(&[]); + let argv0 = String::from_utf8_lossy(argv0); + let basename = argv0.rsplit('/').next().unwrap_or(&argv0); + + if basename == TARGET { + return true; + } + } + false +} + +fn emit(recording: bool) { + let json = if recording { + r#"{"text":" <span color='#aaaaaa'>Recording</span>","class":"recording","alt":"recording","tooltip":"gpu-screen-recorder is running"}"# + } else { + r#"{"text":"","class":"idle","alt":"idle","tooltip":""}"# + }; + println!("{json}"); + let _ = std::io::stdout().flush(); +} + +fn main() { + let mut last: Option<bool> = None; + loop { + let now = is_recording(); + if last != Some(now) { + emit(now); + last = Some(now); + } + std::thread::sleep(POLL_INTERVAL); + } +} |
