From aa1fadd6fd03bb7f4071624a2a3883f83e78b0b4 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Wed, 20 Jan 2021 22:42:50 +0100 Subject: [PATCH] Window switcher seems to work --- src/bin/swayr.rs | 20 ++------------------ src/client.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/ipc.rs | 2 +- src/lib.rs | 1 + src/util.rs | 21 ++++++++++++++++++--- src/window.rs | 20 +++++++++++++------- 6 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 src/client.rs diff --git a/src/bin/swayr.rs b/src/bin/swayr.rs index fb4e077..8bad2f7 100644 --- a/src/bin/swayr.rs +++ b/src/bin/swayr.rs @@ -1,21 +1,5 @@ -use std::collections::HashMap; -use std::os::unix::net::UnixStream; -use swayr::ipc; -use swayr::util; -use swayr::window; +use swayr::client; fn main() { - println!("sway here!"); - let root_node = ipc::get_tree(); - for win in window::get_windows(&root_node) { - println!(" {}", win); - } - - if let Ok(sock) = UnixStream::connect(util::get_swayr_socket_path()) { - let win_props: Result, serde_json::Error> = - serde_json::from_reader(sock); - println!("Here are the window properties:\n{:#?}", win_props) - } else { - panic!("Could not connect to socket!") - } + client::switch_window(); } diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..e8cb784 --- /dev/null +++ b/src/client.rs @@ -0,0 +1,44 @@ +use crate::ipc; +use crate::util; +use crate::window; +use std::collections::HashMap; +use std::os::unix::net::UnixStream; + +fn get_window_props() -> Result, serde_json::Error> { + if let Ok(sock) = UnixStream::connect(util::get_swayr_socket_path()) { + serde_json::from_reader(sock) + } else { + panic!("Could not connect to socket!") + } +} + +pub fn switch_window() { + let root_node = ipc::get_tree(); + let mut windows = window::get_windows(&root_node); + if let Ok(win_props) = get_window_props() { + windows.sort_unstable_by(|a, b| { + if a.node.focused { + std::cmp::Ordering::Greater + } else if b.node.focused { + std::cmp::Ordering::Less + } else { + let lru_a = win_props + .get(&a.node.id) + .map(|p| p.last_focus_time) + .unwrap_or(0); + let lru_b = win_props + .get(&b.node.id) + .map(|p| p.last_focus_time) + .unwrap_or(0); + lru_a.cmp(&lru_b).reverse() + } + }); + } + + if let Some(window) = util::select_window(&windows) { + util::swaymsg(vec![ + format!("[con_id={}]", window.node.id).as_str(), + "focus", + ]); + } +} diff --git a/src/ipc.rs b/src/ipc.rs index 8a1d8d1..36cefaa 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -7,7 +7,7 @@ use std::process as proc; pub type Id = u32; pub type Dim = u16; -pub type Pid = u16; +pub type Pid = u32; #[derive(Deserialize, Debug)] #[allow(dead_code)] diff --git a/src/lib.rs b/src/lib.rs index 896df33..26548ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod client; pub mod demon; pub mod ipc; pub mod util; diff --git a/src/util.rs b/src/util.rs index 1b332db..516b387 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,4 @@ +use crate::window; use std::io::Write; use std::process as proc; @@ -9,12 +10,26 @@ pub fn get_swayr_socket_path() -> String { format!("/run/user/{}/swayr-sock", users::get_current_uid()) } +pub fn swaymsg(args: Vec<&str>) -> String { + let mut cmd = proc::Command::new("swaymsg"); + for a in args { + cmd.arg(a); + } + + let output = cmd.output().expect("Error running swaymsg!"); + String::from_utf8(output.stdout).unwrap() +} + +pub fn select_window<'a>(windows: &'a Vec) -> Option<&'a window::Window<'a>> { + wofi_select("Select window", windows) +} + pub fn wofi_select<'a, 'b, TS>(prompt: &'a str, choices: &'b Vec) -> Option<&'b TS> where TS: std::fmt::Display + Sized, { let mut map: std::collections::HashMap = std::collections::HashMap::new(); - for c in choices.iter() { + for c in choices { map.insert(format!("{}", c), c); } @@ -29,9 +44,9 @@ where { let stdin = wofi.stdin.as_mut().expect("Failed to open wofi stdin"); - for k in map.keys() { + for c in choices { stdin - .write_all(format!("{}\n", k).as_bytes()) + .write_all(format!("{}\n", c).as_bytes()) .expect("Failed to write to wofi stdin"); } } diff --git a/src/window.rs b/src/window.rs index ae532d3..7cab1ce 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,15 +1,23 @@ use crate::ipc; -#[allow(dead_code)] +#[derive(Debug)] pub struct Window<'a> { + // TODO: Drop all fields except for node! + app_id: Option<&'a str>, name: &'a str, id: ipc::Id, - app_id: Option<&'a str>, + pub node: &'a ipc::Node, } impl<'a> std::fmt::Display for Window<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "{} — {}", self.app_id.unwrap_or(""), self.name) + write!( + f, + "{} — {} <{}>", + self.app_id.unwrap_or(""), + self.name, + self.id + ) } } @@ -21,16 +29,14 @@ pub fn get_windows(tree: &ipc::Node) -> Vec { && (n.r#type == ipc::NodeType::Con || n.r#type == ipc::NodeType::FloatingCon) { v.push(Window { - name: &n - .name - .as_ref() - .unwrap_or_else(|| panic!("Con without name. id = {}", n.id)), + name: &n.name.as_ref().unwrap(), id: n.id, app_id: match &n.app_id { Some(s) => Some(s.as_ref()), // TODO: Use n.window_properties.class instead! None => None, }, + node: &n, }) } }