atagen

monolith

public
Star0
Watch0
47b86d08d05a97fea42c27b6ed194c0ceaa30374
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/monolith/src/launch.rsRust47 lines1.3 KB
1
//! Launch context. A window goes to the output and tag the user was on when
2
//! its launch began, found by matching its process or an ancestor against
3
//! the programs monolith spawned.
4
5
use monolith_layout::{OutputId, TagId};
6
use std::time::{Duration, Instant};
7
8
const KEEP: Duration = Duration::from_secs(120);
9
10
struct Launch {
11
    pid: u32,
12
    output: Option<OutputId>,
13
    tag: TagId,
14
    at: Instant,
15
}
16
17
#[derive(Default)]
18
pub struct Launches(Vec<Launch>);
19
20
impl Launches {
21
    pub fn record(&mut self, pid: u32, output: Option<OutputId>, tag: TagId) {
22
        self.0.retain(|l| l.at.elapsed() < KEEP);
23
        self.0.push(Launch {
24
            pid,
25
            output,
26
            tag,
27
            at: Instant::now(),
28
        });
29
    }
30
31
    pub fn find(&self, pid: u32) -> Option<(Option<OutputId>, TagId)> {
32
        let mut pid = pid;
33
        for _ in 0..32 {
34
            if let Some(l) = self.0.iter().find(|l| l.pid == pid) {
35
                return Some((l.output, l.tag));
36
            }
37
            pid = parent(pid).filter(|&p| p > 1)?;
38
        }
39
        None
40
    }
41
}
42
43
fn parent(pid: u32) -> Option<u32> {
44
    let stat = std::fs::read_to_string(format!("/proc/{pid}/stat")).ok()?;
45
    let rest = stat.get(stat.rfind(')')? + 2..)?;
46
    rest.split(' ').nth(1)?.parse().ok()
47
}