Use xcb to get wm class
This commit is contained in:
parent
b9054a085a
commit
a5298f2d66
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -54,6 +54,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
|
"xcb",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -391,3 +392,13 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xcb"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
@ -13,5 +13,6 @@ i3ipc = "0.10.1"
|
|||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
simple_logger = "1.5.0"
|
|
||||||
signal-hook = "0.1.13"
|
signal-hook = "0.1.13"
|
||||||
|
simple_logger = "1.5.0"
|
||||||
|
xcb = "0.9.0"
|
||||||
|
65
src/main.rs
65
src/main.rs
@ -9,6 +9,7 @@ extern crate simple_logger;
|
|||||||
extern crate error_chain;
|
extern crate error_chain;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
extern crate xcb;
|
||||||
|
|
||||||
use counter::Counter;
|
use counter::Counter;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
@ -17,7 +18,6 @@ use log::{info, warn};
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use signal_hook::{iterator::Signals, SIGINT, SIGTERM};
|
use signal_hook::{iterator::Signals, SIGINT, SIGTERM};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
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>) {
|
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);
|
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 {
|
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 {
|
match classes {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
if c.len() > 0 {
|
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<Vec<String>> {
|
|
||||||
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::<Vec<String>>();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_icon_list(icons: Vec<String>) -> String {
|
fn format_icon_list(icons: Vec<String>) -> String {
|
||||||
let mut new_list: Vec<String> = Vec::new();
|
let mut new_list: Vec<String> = Vec::new();
|
||||||
let icon_count = icons.into_iter().collect::<Counter<_>>();
|
let icon_count = icons.into_iter().collect::<Counter<_>>();
|
||||||
@ -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])
|
.map(|c| symbols[c.to_digit(10).unwrap() as usize])
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_wm_classes(conn: &xcb::Connection, id: &i32) -> Vec<String> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user