From f74d622c35df3153e9741d0aa8fa9e4da09334d6 Mon Sep 17 00:00:00 2001 From: Daniel Berg Date: Fri, 13 Dec 2024 23:27:28 +0100 Subject: [PATCH] feat: convert to using swayipc It is compatible with i3, so it can work for both sway and i3 --- Cargo.lock | 47 +++++++++++++++++++++--------------------- Cargo.toml | 6 +++--- src/lib.rs | 59 +++++++++++++++++++++++++++-------------------------- src/main.rs | 29 +++++++++++++------------- 4 files changed, 70 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6dc718a..23d7284 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,12 +66,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cfg-if" version = "1.0.0" @@ -180,27 +174,16 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "i3ipc" -version = "0.10.1" -source = "git+https://github.com/roosta/i3ipc-rs#8836d4144e095b117b83cf8720ff6f0cee310164" -dependencies = [ - "byteorder", - "log", - "serde", - "serde_json", -] - [[package]] name = "i3wsr" version = "3.0.0" dependencies = [ "clap", "dirs", - "i3ipc", "itertools", "regex", "serde", + "swayipc", "thiserror", "toml", ] @@ -252,12 +235,6 @@ dependencies = [ "libc", ] -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - [[package]] name = "memchr" version = "2.7.4" @@ -381,6 +358,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "swayipc" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c50cb2e98e88b52066a35ef791fffd8f6fa631c3a4983de18ba41f718c736" +dependencies = [ + "serde", + "serde_json", + "swayipc-types", +] + +[[package]] +name = "swayipc-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551233c60323e87cfb8194c21cc44577ab848d00bb7fa2d324a2c7f52609eaff" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "syn" version = "2.0.90" diff --git a/Cargo.toml b/Cargo.toml index bc51331..9853903 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,10 @@ itertools = "0.13" regex = "1.11" dirs = "5.0" thiserror = "1.0" -# swayipc = "3.0" +swayipc = "3.0" # log = "0.4" -[dependencies.i3ipc] -git = 'https://github.com/roosta/i3ipc-rs' +# [dependencies.i3ipc] +# git = 'https://github.com/roosta/i3ipc-rs' # path = "../i3ipc-rs" diff --git a/src/lib.rs b/src/lib.rs index 90ca6f2..901130f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,14 @@ -use i3ipc::{ - event::{ - inner::{WindowChange, WorkspaceChange}, - WindowEventInfo, WorkspaceEventInfo, - }, - reply::{Node, NodeType, WindowProperty}, - I3Connection, +use swayipc::{ + Connection, + Node, + NodeType, + WindowChange, + WindowEvent, + WindowProperties, + WorkspaceChange, + WorkspaceEvent, }; use itertools::Itertools; -use std::collections::HashMap; pub mod config; pub mod regex; @@ -36,21 +37,21 @@ fn format_with_icon(icon: &char, title: &str, no_names: bool, no_icon_names: boo } fn get_title( - props: &HashMap, + props: &WindowProperties, config: &Config, res: ®ex::Compiled, ) -> Result> { let display_prop = config.get_general("display_property").unwrap_or_else(|| "class".to_string()); // Try to find an alias first - let title = find_alias(props.get(&WindowProperty::Title), &res.name) - .or_else(|| find_alias(props.get(&WindowProperty::Instance), &res.instance)) - .or_else(|| find_alias(props.get(&WindowProperty::Class), &res.class)) - // If no alias found, fall back to the configured display property - .or_else(|| match display_prop.as_str() { - "name" => props.get(&WindowProperty::Title).map(|s| s.to_string()), - "instance" => props.get(&WindowProperty::Instance).map(|s| s.to_string()), - _ => props.get(&WindowProperty::Class).map(|s| s.to_string()), + let title = find_alias(props.title.as_ref(), &res.name) + .or_else(|| find_alias(props.instance.as_ref(), &res.instance)) + .or_else(|| find_alias(props.class.as_ref(), &res.class)) + // If no alias found, fall back to the configured display property + .or_else(|| match display_prop.as_str() { + "name" => props.title.clone(), + "instance" => props.instance.clone(), + _ => props.class.clone(), }) .ok_or_else(|| format!("failed to get alias, display_prop {}, or class", display_prop))?; @@ -75,7 +76,7 @@ fn get_workspaces(tree: Node) -> Vec { for output in tree.nodes { for container in output.nodes { for workspace in container.nodes { - if let NodeType::Workspace = workspace.nodetype { + if let NodeType::Workspace = workspace.node_type { match &workspace.name { Some(name) => { if !name.eq("__i3_scratch") { @@ -93,14 +94,14 @@ fn get_workspaces(tree: Node) -> Vec { } /// get window ids for any depth collection of nodes -fn get_properties(mut nodes: Vec>) -> Vec> { +fn get_properties(mut nodes: Vec>) -> Vec { let mut window_props = Vec::new(); while let Some(next) = nodes.pop() { for n in next { nodes.push(n.nodes.iter().collect()); if let Some(w) = &n.window_properties { - window_props.push(w.to_owned()); + window_props.push(w.clone()); } } } @@ -180,11 +181,11 @@ fn format_workspace_name( /// Update all workspace names in tree pub fn update_tree( - i3_conn: &mut I3Connection, + conn: &mut Connection, config: &Config, res: ®ex::Compiled, ) -> Result<(), Box> { - let tree = i3_conn.get_tree()?; + let tree = conn.get_tree()?; let separator = config.get_general("separator").unwrap_or_else(|| " | ".to_string()); let split_at = get_split_char(config); @@ -212,7 +213,7 @@ pub fn update_tree( // Only send command if name changed if old != &new { let command = format!("rename workspace \"{}\" to \"{}\"", old, new); - i3_conn.run_command(&command)?; + conn.run_command(command)?; } } Ok(()) @@ -220,14 +221,14 @@ pub fn update_tree( /// handles new and close window events, to set the workspace name based on content pub fn handle_window_event( - e: &WindowEventInfo, - i3_conn: &mut I3Connection, + e: &WindowEvent, + conn: &mut Connection, config: &Config, res: ®ex::Compiled, ) -> Result<(), Box> { match e.change { WindowChange::New | WindowChange::Close | WindowChange::Move | WindowChange::Title => { - update_tree(i3_conn, config, res)?; + update_tree(conn, config, res)?; } _ => (), } @@ -236,14 +237,14 @@ pub fn handle_window_event( /// handles ws events, pub fn handle_ws_event( - e: &WorkspaceEventInfo, - i3_conn: &mut I3Connection, + e: &WorkspaceEvent, + conn: &mut Connection, config: &Config, res: ®ex::Compiled, ) -> Result<(), Box> { match e.change { WorkspaceChange::Empty | WorkspaceChange::Focus => { - update_tree(i3_conn, config, res)?; + update_tree(conn, config, res)?; } _ => (), } diff --git a/src/main.rs b/src/main.rs index e1079f8..146fd84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use clap::{Parser, ValueEnum}; use dirs::config_dir; -use i3ipc::{event::Event, MessageError, I3Connection, I3EventListener, Subscription}; +use swayipc::{Connection, Event, EventType, Fallible}; use i3wsr::config::{Config, ConfigError}; use std::error::Error; use std::io; @@ -117,21 +117,21 @@ fn setup() -> Result> { Ok(config) } -/// Handles i3 events and updates workspace names +/// Handles sway events and updates workspace names fn handle_event( - event: Result, - i3_conn: &mut I3Connection, + event: Fallible, + conn: &mut Connection, config: &Config, res: &i3wsr::regex::Compiled, ) { match event { - Ok(Event::WindowEvent(e)) => { - if let Err(error) = i3wsr::handle_window_event(&e, i3_conn, config, res) { + Ok(Event::Window(e)) => { + if let Err(error) = i3wsr::handle_window_event(&e, conn, config, res) { eprintln!("Window event error: {}", error); } } - Ok(Event::WorkspaceEvent(e)) => { - if let Err(error) = i3wsr::handle_ws_event(&e, i3_conn, config, res) { + Ok(Event::Workspace(e)) => { + if let Err(error) = i3wsr::handle_ws_event(&e, conn, config, res) { eprintln!("Workspace event error: {}", error); } } @@ -140,19 +140,18 @@ fn handle_event( } } -/// Entry main loop: continuously listen to i3 window events and workspace events +/// Entry main loop: continuously listen to sway window events and workspace events fn main() -> Result<(), Box> { let config = setup()?; let res = i3wsr::regex::parse_config(&config)?; - let mut listener = I3EventListener::connect()?; - listener.subscribe(&[Subscription::Window, Subscription::Workspace])?; + let mut conn = Connection::new()?; + let subscriptions = [EventType::Window, EventType::Workspace]; - let mut i3_conn = I3Connection::connect()?; - i3wsr::update_tree(&mut i3_conn, &config, &res)?; + i3wsr::update_tree(&mut conn, &config, &res)?; - for event in listener.listen() { - handle_event(event, &mut i3_conn, &config, &res); + for event in Connection::new()?.subscribe(&subscriptions)? { + handle_event(event, &mut conn, &config, &res); } Ok(())