diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..e90a964 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +max_width = 80 +newline_style = "Unix" +use_try_shorthand = true +use_field_init_shorthand = true +# format_code_in_doc_comments = true +# report_todo = "Always" +# report_fixme = "Always" diff --git a/src/bin/swayrd.rs b/src/bin/swayrd.rs index 3ae61fb..7a7d0e0 100644 --- a/src/bin/swayrd.rs +++ b/src/bin/swayrd.rs @@ -13,8 +13,9 @@ fn main() { Arc::new(RwLock::new(HashMap::new())); let win_props_for_ev_handler = win_props.clone(); - let subscriber_handle = - thread::spawn(move || demon::monitor_window_events(win_props_for_ev_handler)); + let subscriber_handle = thread::spawn(move || { + demon::monitor_window_events(win_props_for_ev_handler) + }); match demon::serve_client_requests(win_props) { Ok(()) => { diff --git a/src/client.rs b/src/client.rs index 66c67da..0279053 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,37 +1,15 @@ 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!") - } -} - -fn get_windows(root_node: &ipc::Node) -> std::vec::Vec { - let win_props = match get_window_props() { - Ok(win_props) => Some(win_props), - Err(e) => { - eprintln!("Got no win_props: {:?}", e); - None - } - }; - - window::get_windows(&root_node, win_props.unwrap_or(HashMap::new())) -} pub fn switch_window() { let root_node = get_tree(); - let mut windows = get_windows(&root_node); + let mut windows = window::get_windows(&root_node); windows.sort(); if let Some(window) = util::select_window("Switch to window", &windows) { util::swaymsg(vec![ - format!("[con_id={}]", window.node.id).as_str(), + format!("[con_id={}]", window.get_id()).as_str(), "focus", ]); } @@ -39,12 +17,12 @@ pub fn switch_window() { pub fn quit_window() { let root_node = get_tree(); - let mut windows = get_windows(&root_node); + let mut windows = window::get_windows(&root_node); windows.sort_by(|a, b| a.cmp(b).reverse()); if let Some(window) = util::select_window("Quit window", &windows) { util::swaymsg(vec![ - format!("[con_id={}]", window.node.id).as_str(), + format!("[con_id={}]", window.get_id()).as_str(), "kill", ]); } diff --git a/src/demon.rs b/src/demon.rs index c031229..0fc56c4 100644 --- a/src/demon.rs +++ b/src/demon.rs @@ -10,7 +10,9 @@ use std::sync::RwLock; use std::thread; use std::time::{SystemTime, UNIX_EPOCH}; -pub fn monitor_window_events(win_props: Arc>>) { +pub fn monitor_window_events( + win_props: Arc>>, +) { let child = proc::Command::new("swaymsg") .arg("--monitor") .arg("--raw") @@ -21,7 +23,8 @@ pub fn monitor_window_events(win_props: Arc(); + let stream = + Deserializer::from_reader(stdout).into_iter::(); for res in stream { match res { Ok(win_ev) => handle_window_event(win_ev, win_props.clone()), diff --git a/src/ipc.rs b/src/ipc.rs index 84c7f62..8df3dab 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -126,6 +126,27 @@ impl Node { pub fn iter(&self) -> NodeIter { NodeIter::new(self) } + + pub fn windows(&self) -> Vec<&Node> { + self.iter() + .filter(|n| { + (n.r#type == NodeType::Con || n.r#type == NodeType::FloatingCon) + && n.name.is_some() + }) + .collect() + } + + pub fn workspaces(&self) -> Vec<&Node> { + self.iter() + .filter(|n| n.r#type == NodeType::Workspace) + .collect() + } + + pub fn outputs(&self) -> Vec<&Node> { + self.iter() + .filter(|n| n.r#type == NodeType::Output) + .collect() + } } pub struct NodeIter<'a> { diff --git a/src/util.rs b/src/util.rs index c0eb924..1c574d1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,5 @@ use crate::window; +use std::collections::HashMap; use std::io::Write; use std::process as proc; @@ -34,11 +35,14 @@ pub fn select_window<'a>( wofi_select(prompt, windows) } -pub fn wofi_select<'a, 'b, TS>(prompt: &'a str, choices: &'b Vec) -> Option<&'b TS> +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(); + let mut map: HashMap = HashMap::new(); let mut strs: Vec = vec![]; for c in choices { let s = format!("{}", c); diff --git a/src/window.rs b/src/window.rs index 41a4dfa..8a4a28a 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,10 +1,14 @@ use crate::ipc; +use crate::util; use std::cmp; use std::collections::HashMap; +use std::fmt; +use std::os::unix::net::UnixStream; #[derive(Debug)] pub struct Window<'a> { - pub node: &'a ipc::Node, + node: &'a ipc::Node, + workspace: &'a ipc::Node, win_props: Option, } @@ -54,8 +58,10 @@ impl Ord for Window<'_> { } else if !self.node.focused && other.node.focused { std::cmp::Ordering::Less } else { - let lru_a = self.win_props.as_ref().map_or(0, |wp| wp.last_focus_time); - let lru_b = other.win_props.as_ref().map_or(0, |wp| wp.last_focus_time); + let lru_a = + self.win_props.as_ref().map_or(0, |wp| wp.last_focus_time); + let lru_b = + other.win_props.as_ref().map_or(0, |wp| wp.last_focus_time); lru_a.cmp(&lru_b).reverse() } } @@ -68,37 +74,61 @@ impl PartialOrd for Window<'_> { } impl<'a> std::fmt::Display for Window<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, - "{} — {} [{}]", + "“{}” \ + {} \ + on workspace {} \ + id {}", // Almost hide ID! if self.node.urgent { " background=\"darkred\" foreground=\"white\"" } else { "" }, - self.get_app_name(), self.get_title(), + self.get_app_name(), + self.workspace.name.as_ref().unwrap(), self.get_id() ) } } -/// Gets all application windows of the tree. -pub fn get_windows( +fn build_windows( tree: &ipc::Node, mut win_props: HashMap, ) -> Vec { let mut v = vec![]; - for n in tree.iter() { - if n.name.is_some() - && (n.r#type == ipc::NodeType::Con || n.r#type == ipc::NodeType::FloatingCon) - { + for workspace in tree.workspaces() { + for n in workspace.windows() { v.push(Window { node: &n, win_props: win_props.remove(&n.id), + workspace: &workspace, }) } } v } + +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!") + } +} + +/// Gets all application windows of the tree. +pub fn get_windows(root_node: &ipc::Node) -> Vec { + let win_props = match get_window_props() { + Ok(win_props) => Some(win_props), + Err(e) => { + eprintln!("Got no win_props: {:?}", e); + None + } + }; + + build_windows(&root_node, win_props.unwrap_or(HashMap::new())) +}