aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: b251bab0803fa0baf3f3e33aec569e445841ea3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use swayipc::{Connection, WindowChange, EventType};
use std::{env,fs::File, io::Read};
use regex::Regex;

struct WindowHider {
    term: String
}

impl WindowHider {
    fn get_parent_term_pid(&self, pid: i32) -> Option<i32> {
        let mut file = String::new();
        File::open(format!("/proc/{pid}/stat")).expect("procfs stat doesn't exist").read_to_string(&mut file).unwrap();
        let re = Regex::new(r"\d+ \((.*)\) (\w) (\d+) \d+").unwrap().captures(&file).unwrap();
        let name = re.get(1).unwrap().as_str();
        let status = re.get(2).unwrap().as_str();
        let ppid = re.get(3).unwrap().as_str().parse::<i32>().unwrap();

        println!("looking for {pid}. {name}, {status}, {ppid}");
        match name {
            _ if name == self.term => {
                Some(pid)
            },
            _ if name == "init" => {
                None
            }
            _ => {
                self.get_parent_term_pid(ppid)
            }
        }
    }

    fn hide(&self, conn: &mut Connection, pid: i32) -> Result<(), swayipc::Error> {
        let ppid = self.get_parent_term_pid(pid);
        if let Some(ppid) = ppid {
            println!("found parent pid of {pid} as {ppid}");
            conn.run_command(format!("[pid={ppid}] mark --add {pid}, move scratchpad"))?;
        }
        Ok(())
    }

    fn show(&self, conn: &mut Connection, pid: i32) -> Result<(), swayipc::Error> {
        conn.run_command(format!("[con_mark={pid}] move workspace current"))?;
        conn.run_command(format!("[con_mark={pid}] floating toggle"))?;
        Ok(())
    }
}

fn main() -> Result<(), swayipc::Error> {
    let mut conn = Connection::new().expect("couldn't connect to sway's socket");
    let evs = Connection::new()?.subscribe([EventType::Window])?; // one can't use the same
                                                                  // connection for events and for
                                                                  // running commands. :(

    let mut args: Vec<String> = env::args().collect();

    if args.len() < 2 {
        println!("usage: swhd <terminal>");
        return Ok(());
    }

    let wh = WindowHider {
        term: args.remove(1)
    };

    for item in evs {
        if let Ok(item) = item {
            match item {
                swayipc::Event::Window(win) => {
                    if win.change == WindowChange::New {
                        if let Some(pid) = win.container.pid {
                            match wh.hide(&mut conn, pid) {
                                Ok(_) => {},
                                Err(_) => println!("failed to hide terminal {pid}")
                            };
                        }
                    } else if win.change == WindowChange::Close {
                        if let Some(pid) = win.container.pid {
                            match wh.show(&mut conn, pid) {
                                Ok(_) => {},
                                Err(_) => println!("failed to show terminal {pid}")
                            };
                        }
                    }
                }
                _ => {}
            }
        }
    }

    Ok(())
}