New quit-window command

timeout_old
Tassilo Horn 4 years ago
parent 3bf88f2782
commit f9029af82d
  1. 5
      src/bin/swayr.rs
  2. 36
      src/client.rs
  3. 13
      src/demon.rs
  4. 11
      src/util.rs
  5. 73
      src/window.rs

@ -18,13 +18,16 @@ struct Opts {
#[derive(Clap)] #[derive(Clap)]
enum SwayrCommand { enum SwayrCommand {
/// Switch window using wofi (urgent first, then LRU order, focused last) /// Switch window with display order urgent first, then LRU order, focused last
SwitchWindow, SwitchWindow,
/// Quit a window with display order focused first, then reverse-LRU order, urgent last
QuitWindow,
} }
fn main() { fn main() {
let opts: Opts = Opts::parse(); let opts: Opts = Opts::parse();
match opts.command { match opts.command {
SwayrCommand::SwitchWindow => client::switch_window(), SwayrCommand::SwitchWindow => client::switch_window(),
SwayrCommand::QuitWindow => client::quit_window(),
} }
} }

@ -12,15 +12,24 @@ fn get_window_props() -> Result<HashMap<ipc::Id, ipc::WindowProps>, serde_json::
} }
} }
fn get_windows(root_node: &ipc::Node) -> std::vec::Vec<window::Window> {
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() { pub fn switch_window() {
let root_node = get_tree(); let root_node = get_tree();
let mut windows = window::get_windows(&root_node); let mut windows = get_windows(&root_node);
match get_window_props() { windows.sort();
Ok(win_props) => window::sort_windows(&mut windows, win_props),
Err(e) => eprintln!("Got no win_props: {:?}", e),
}
if let Some(window) = util::select_window(&windows) { if let Some(window) = util::select_window("Switch to window", &windows) {
util::swaymsg(vec![ util::swaymsg(vec![
format!("[con_id={}]", window.node.id).as_str(), format!("[con_id={}]", window.node.id).as_str(),
"focus", "focus",
@ -28,7 +37,20 @@ pub fn switch_window() {
} }
} }
pub fn get_tree() -> ipc::Node { pub fn quit_window() {
let root_node = get_tree();
let mut windows = 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(),
"kill",
]);
}
}
fn get_tree() -> ipc::Node {
let output = util::swaymsg(vec!["-t", "get_tree"]); let output = util::swaymsg(vec!["-t", "get_tree"]);
let result = serde_json::from_str(output.as_str()); let result = serde_json::from_str(output.as_str());

@ -34,12 +34,6 @@ fn handle_window_event(
ev: ipc::WindowEvent, ev: ipc::WindowEvent,
win_props: Arc<RwLock<HashMap<ipc::Id, ipc::WindowProps>>>, win_props: Arc<RwLock<HashMap<ipc::Id, ipc::WindowProps>>>,
) { ) {
if util::is_debug() {
println!(
"Handling {:?} event for container {}",
ev.change, ev.container.id
);
}
match ev.change { match ev.change {
ipc::WindowEventType::Focus => { ipc::WindowEventType::Focus => {
let mut write_lock = win_props.write().unwrap(); let mut write_lock = win_props.write().unwrap();
@ -59,13 +53,6 @@ fn handle_window_event(
} }
_ => (), _ => (),
} }
if util::is_debug() {
println!(
"New window properties state:\n{:#?}",
win_props.read().unwrap()
);
}
} }
fn get_epoch_time_as_millis() -> u128 { fn get_epoch_time_as_millis() -> u128 {

@ -2,10 +2,6 @@ use crate::window;
use std::io::Write; use std::io::Write;
use std::process as proc; use std::process as proc;
pub fn is_debug() -> bool {
true
}
pub fn get_swayr_socket_path() -> String { pub fn get_swayr_socket_path() -> String {
let wayland_display = std::env::var("WAYLAND_DISPLAY"); let wayland_display = std::env::var("WAYLAND_DISPLAY");
format!( format!(
@ -31,8 +27,11 @@ pub fn swaymsg(args: Vec<&str>) -> String {
String::from_utf8(output.stdout).unwrap() String::from_utf8(output.stdout).unwrap()
} }
pub fn select_window<'a>(windows: &'a Vec<window::Window>) -> Option<&'a window::Window<'a>> { pub fn select_window<'a>(
wofi_select("Select window", windows) prompt: &'a str,
windows: &'a Vec<window::Window>,
) -> Option<&'a window::Window<'a>> {
wofi_select(prompt, windows)
} }
pub fn wofi_select<'a, 'b, TS>(prompt: &'a str, choices: &'b Vec<TS>) -> Option<&'b TS> pub fn wofi_select<'a, 'b, TS>(prompt: &'a str, choices: &'b Vec<TS>) -> Option<&'b TS>

@ -1,9 +1,11 @@
use crate::ipc; use crate::ipc;
use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct Window<'a> { pub struct Window<'a> {
pub node: &'a ipc::Node, pub node: &'a ipc::Node,
win_props: Option<ipc::WindowProps>,
} }
impl Window<'_> { impl Window<'_> {
@ -31,6 +33,40 @@ impl Window<'_> {
} }
} }
impl PartialEq for Window<'_> {
fn eq(&self, other: &Window) -> bool {
self.get_id() == other.get_id()
}
}
impl Eq for Window<'_> {}
impl Ord for Window<'_> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
if self == other {
cmp::Ordering::Equal
} else if self.node.urgent && !other.node.urgent {
cmp::Ordering::Less
} else if !self.node.urgent && other.node.urgent {
std::cmp::Ordering::Greater
} else if self.node.focused && !other.node.focused {
std::cmp::Ordering::Greater
} 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);
lru_a.cmp(&lru_b).reverse()
}
}
}
impl PartialOrd for Window<'_> {
fn partial_cmp(&self, other: &Window) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'a> std::fmt::Display for Window<'a> { 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 std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!( write!(
@ -49,41 +85,20 @@ impl<'a> std::fmt::Display for Window<'a> {
} }
/// Gets all application windows of the tree. /// Gets all application windows of the tree.
pub fn get_windows(tree: &ipc::Node) -> Vec<Window> { pub fn get_windows(
tree: &ipc::Node,
mut win_props: HashMap<ipc::Id, ipc::WindowProps>,
) -> Vec<Window> {
let mut v = vec![]; let mut v = vec![];
for n in tree.iter() { for n in tree.iter() {
if n.name.is_some() if n.name.is_some()
&& (n.r#type == ipc::NodeType::Con || n.r#type == ipc::NodeType::FloatingCon) && (n.r#type == ipc::NodeType::Con || n.r#type == ipc::NodeType::FloatingCon)
{ {
v.push(Window { node: &n }) v.push(Window {
node: &n,
win_props: win_props.remove(&n.id),
})
} }
} }
v v
} }
/// 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<Window>, win_props: HashMap<ipc::Id, ipc::WindowProps>) {
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 && !b.node.focused {
std::cmp::Ordering::Greater
} else if !a.node.focused && 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()
}
});
}

Loading…
Cancel
Save