From a5298f2d665d0dff5c53e522e095c4d154985f7d Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Mon, 10 Feb 2020 23:59:55 +0100 Subject: [PATCH] Use xcb to get wm class --- Cargo.lock | 11 +++++++++ Cargo.toml | 3 ++- src/main.rs | 65 ++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9de121..09f5668 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,7 @@ dependencies = [ "regex", "signal-hook", "simple_logger", + "xcb", ] [[package]] @@ -391,3 +392,13 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xcb" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6" +dependencies = [ + "libc", + "log", +] diff --git a/Cargo.toml b/Cargo.toml index 5f86145..cac1b1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,5 +13,6 @@ i3ipc = "0.10.1" lazy_static = "1.4" log = "0.4" regex = "1" -simple_logger = "1.5.0" signal-hook = "0.1.13" +simple_logger = "1.5.0" +xcb = "0.9.0" diff --git a/src/main.rs b/src/main.rs index 4476f2e..e5a21bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate simple_logger; extern crate error_chain; #[macro_use] extern crate clap; +extern crate xcb; use counter::Counter; use errors::*; @@ -17,7 +18,6 @@ use log::{info, warn}; use regex::Regex; use signal_hook::{iterator::Signals, SIGINT, SIGTERM}; use std::collections::HashMap; -use std::process::Command; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::thread; @@ -455,7 +455,9 @@ fn find_workspaces(node: &i3ipc::reply::Node) -> Vec<&i3ipc::reply::Node> { } fn find_workspaces_rec<'a>(node: &'a i3ipc::reply::Node, ws: &mut Vec<&'a i3ipc::reply::Node>) { - if node.nodetype == i3ipc::reply::NodeType::Workspace && node.name != Some("__i3_scratch".to_string()) { + if node.nodetype == i3ipc::reply::NodeType::Workspace + && node.name != Some("__i3_scratch".to_string()) + { ws.push(node); } @@ -479,7 +481,8 @@ fn leaves(node: &i3ipc::reply::Node) -> Vec<&i3ipc::reply::Node> { } fn icon_for_window(node: &i3ipc::reply::Node) -> String { - let classes = node.window.and_then(|w| xprop(w, "WM_CLASS")); + let (conn, _) = xcb::Connection::connect(None).unwrap(); + let classes = node.window.and_then(|w| Some(get_wm_classes(&conn, &w))); match classes { Some(c) => { if c.len() > 0 { @@ -496,23 +499,6 @@ fn icon_for_window(node: &i3ipc::reply::Node) -> String { } } -fn xprop(win_id: i32, property: &str) -> Option> { - return Command::new("xprop") - .arg("-id") - .arg(win_id.to_string()) - .arg(property) - .output() - .ok() - .and_then(|r| String::from_utf8(r.stdout).ok()) - .map(|prop| { - let re = Regex::new(r#"([^"]*)"#).unwrap(); - return re - .find_iter(prop.as_str()) - .map(|m| String::from(m.as_str())) - .collect::>(); - }); -} - fn format_icon_list(icons: Vec) -> String { let mut new_list: Vec = Vec::new(); let icon_count = icons.into_iter().collect::>(); @@ -539,3 +525,42 @@ fn encode_base_10_number(n: usize, symbols: &[&str; 10]) -> String { .map(|c| symbols[c.to_digit(10).unwrap() as usize]) .collect() } + +fn get_wm_classes(conn: &xcb::Connection, id: &i32) -> Vec { + let window: xcb::xproto::Window = *id as u32; + let long_length: u32 = 8; + let mut long_offset: u32 = 0; + let mut buf = Vec::new(); + loop { + let cookie = xcb::xproto::get_property( + &conn, + false, + window, + xcb::xproto::ATOM_WM_CLASS, + xcb::xproto::ATOM_STRING, + long_offset, + long_length, + ); + match cookie.get_reply() { + Ok(reply) => { + let value: &[u8] = reply.value(); + buf.extend_from_slice(value); + match reply.bytes_after() { + 0 => break, + _ => { + let len = reply.value_len(); + long_offset += len / 4; + } + } + } + Err(err) => { + println!("{:?}", err); + break; + } + } + } + let result = String::from_utf8(buf).unwrap(); + let results: Vec<&str> = result.split('\0').collect(); + + return results.iter().map(|r| r.to_string()).collect(); +}