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, is_root: bool) -> Option { 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::().unwrap(); println!("looking for {pid}. {name}, {status}, {ppid}"); match name { _ if name == self.term && !is_root => { Some(pid) }, _ if name == "init" => { None } _ => { self.get_parent_term_pid(ppid, false) } } } fn hide(&self, conn: &mut Connection, pid: i32) -> Result<(), swayipc::Error> { let ppid = self.get_parent_term_pid(pid, true); 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 = env::args().collect(); if args.len() < 2 { println!("usage: swhd "); 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(()) }