From 7184747a5fb923a1f170438b22d48901e62fd256 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Thu, 21 Jan 2021 16:30:26 +0100 Subject: [PATCH] More, more, more... --- src/client.rs | 55 ++++++++++++++++++++++----------- src/ipc.rs | 32 -------------------- src/util.rs | 16 +++++++++- src/window.rs | 84 ++++++++++++++++++++++++++++++++++----------------- 4 files changed, 108 insertions(+), 79 deletions(-) diff --git a/src/client.rs b/src/client.rs index e8cb784..ac3f0b0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -13,26 +13,10 @@ fn get_window_props() -> Result, serde_json:: } pub fn switch_window() { - let root_node = ipc::get_tree(); + let root_node = 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() - } - }); + window::sort_windows(&mut windows, win_props); } if let Some(window) = util::select_window(&windows) { @@ -42,3 +26,38 @@ pub fn switch_window() { ]); } } + +pub fn get_tree() -> ipc::Node { + let output = util::swaymsg(vec!["-t", "get_tree"]); + let result = serde_json::from_str(output.as_str()); + + match result { + Ok(node) => node, + Err(e) => { + eprintln!("Error: {}", e); + panic!() + } + } +} + +#[test] +fn test_get_tree() { + let tree = get_tree(); + + println!("Those IDs are in get_tree():"); + for n in tree.iter() { + println!(" id: {}, type: {:?}", n.id, n.r#type); + } +} + +#[test] +fn test_get_windows() { + let tree = get_tree(); + let cons = window::get_windows(&tree); + + println!("There are {} cons.", cons.len()); + + for c in cons { + println!(" {}", c); + } +} diff --git a/src/ipc.rs b/src/ipc.rs index 36cefaa..1fa2cd8 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -3,7 +3,6 @@ extern crate serde_json; extern crate users; use serde::{Deserialize, Serialize}; -use std::process as proc; pub type Id = u32; pub type Dim = u16; @@ -154,37 +153,6 @@ impl<'a> Iterator for NodeIter<'a> { } } -pub fn get_tree() -> Node { - let output = proc::Command::new("swaymsg") - .arg("-t") - .arg("get_tree") - .output() - .expect("Error running swaymsg!"); - let result = serde_json::from_str( - String::from_utf8(output.stdout) - .expect("Wrong string data!") - .as_str(), - ); - - match result { - Ok(node) => node, - Err(e) => { - eprintln!("Error: {}", e); - panic!() - } - } -} - -#[test] -fn test_get_tree() { - let tree = get_tree(); - - println!("Those IDs are in get_tree():"); - for n in tree.iter() { - println!(" id: {}, type: {:?}", n.id, n.r#type); - } -} - #[derive(Deserialize, Debug)] #[allow(dead_code)] pub enum WindowEventType { diff --git a/src/util.rs b/src/util.rs index 516b387..8ed9d7e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,7 +7,18 @@ pub fn is_debug() -> bool { } pub fn get_swayr_socket_path() -> String { - format!("/run/user/{}/swayr-sock", users::get_current_uid()) + let wayland_display = std::env::var("WAYLAND_DISPLAY"); + format!( + "/run/user/{}/swayr-{}.sock", + users::get_current_uid(), + match wayland_display { + Ok(val) => val, + Err(_e) => { + eprintln!("Couldn't get WAYLAND_DISPLAY!"); + String::from("unknown") + } + } + ) } pub fn swaymsg(args: Vec<&str>) -> String { @@ -35,6 +46,9 @@ where let mut wofi = proc::Command::new("wofi") .arg("--show=dmenu") + .arg("--allow-markup") + .arg("--allow-images") + .arg("--insensitive") .arg("--prompt") .arg(prompt) .stdin(proc::Stdio::piped()) diff --git a/src/window.rs b/src/window.rs index 7cab1ce..f58700c 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,22 +1,44 @@ use crate::ipc; +use std::collections::HashMap; #[derive(Debug)] pub struct Window<'a> { - // TODO: Drop all fields except for node! - app_id: Option<&'a str>, - name: &'a str, - id: ipc::Id, pub node: &'a ipc::Node, } +impl Window<'_> { + pub fn get_id(&self) -> ipc::Id { + self.node.id + } + + pub fn get_app_name(&self) -> &str { + if let Some(app_id) = &self.node.app_id { + app_id + } else if let Some(wp_class) = self + .node + .window_properties + .as_ref() + .and_then(|wp| wp.class.as_ref()) + { + wp_class + } else { + "" + } + } + + pub fn get_title(&self) -> &str { + self.node.name.as_ref().unwrap() + } +} + 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, - self.id + "{} — {} [{}]", + self.get_app_name(), + self.get_title(), + self.get_id() ) } } @@ -28,29 +50,35 @@ pub fn get_windows(tree: &ipc::Node) -> Vec { if n.name.is_some() && (n.r#type == ipc::NodeType::Con || n.r#type == ipc::NodeType::FloatingCon) { - v.push(Window { - 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, - }) + v.push(Window { node: &n }) } } v } -#[test] -fn test_get_windows() { - let tree = ipc::get_tree(); - let cons = get_windows(&tree); - - println!("There are {} cons.", cons.len()); - - for c in cons { - println!(" {}", c); - } +/// Sorts windows so that urgent windows come first, the currently focused +/// window comes last, and otherwise windows are sorted in last-recently-used +/// order. +pub fn sort_windows(windows: &mut Vec, win_props: HashMap) { + windows.sort_unstable_by(|a, b| { + if a.node.urgent && !b.node.urgent { + std::cmp::Ordering::Less + } else if !a.node.urgent && b.node.urgent { + std::cmp::Ordering::Greater + } else 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() + } + }); }