Migrate from x11 crate to x11rb crate

pull/142/head
Takashi Kokubun 2 years ago
parent 42d0842187
commit ea362b8663
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD

49
Cargo.lock generated

@ -404,6 +404,16 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "gethostname"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.1" version = "0.12.1"
@ -626,12 +636,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]] [[package]]
name = "polling" name = "polling"
version = "2.2.0" version = "2.2.0"
@ -1060,6 +1064,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "winapi-wsapoll"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@ -1076,13 +1089,25 @@ dependencies = [
] ]
[[package]] [[package]]
name = "x11" name = "x11rb"
version = "2.19.1" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507"
dependencies = [ dependencies = [
"libc", "gethostname",
"pkg-config", "nix 0.24.2",
"winapi",
"winapi-wsapoll",
"x11rb-protocol",
]
[[package]]
name = "x11rb-protocol"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67"
dependencies = [
"nix 0.24.2",
] ]
[[package]] [[package]]
@ -1105,7 +1130,7 @@ dependencies = [
"serde_with", "serde_with",
"serde_yaml", "serde_yaml",
"swayipc", "swayipc",
"x11", "x11rb",
"zbus", "zbus",
] ]

@ -23,10 +23,10 @@ serde_json = "1.0"
serde_with = { version = "2.0", features = ["chrono"] } serde_with = { version = "2.0", features = ["chrono"] }
serde_yaml = "0.9" serde_yaml = "0.9"
swayipc = { version = "3.0.0", optional = true } swayipc = { version = "3.0.0", optional = true }
x11_rs = { package = "x11", version = "2.19.1", features = ["xlib"], optional = true } x11rb = { version = "0.10.1", optional = true }
zbus = { version = "1.9.2", optional = true } zbus = { version = "1.9.2", optional = true }
[features] [features]
gnome = ["zbus"] gnome = ["zbus"]
sway = ["swayipc"] sway = ["swayipc"]
x11 = ["x11_rs"] x11 = ["x11rb"]

@ -1,35 +1,34 @@
use crate::client::Client; use crate::client::Client;
use nix::libc;
use std::env; use std::env;
use x11_rs::xlib; use x11rb::protocol::xproto::{self};
use x11rb::protocol::xproto::{AtomEnum, Window};
use x11rb::{protocol::xproto::get_property, rust_connection::RustConnection};
pub struct X11Client { pub struct X11Client {
display: Option<*mut xlib::Display>, connection: Option<RustConnection>,
} }
impl X11Client { impl X11Client {
pub fn new() -> X11Client { pub fn new() -> X11Client {
X11Client { display: None } X11Client { connection: None }
} }
fn connect(&mut self) -> *mut xlib::Display { fn connect(&mut self) {
match self.display { if self.connection.is_some() {
Some(display) => display, return;
None => { }
if let Err(env::VarError::NotPresent) = env::var("DISPLAY") {
println!("$DISPLAY is not set. Defaulting to DISPLAY=:0");
env::set_var("DISPLAY", ":0");
}
let display = unsafe { xlib::XOpenDisplay(std::ptr::null()) }; if let Err(env::VarError::NotPresent) = env::var("DISPLAY") {
if display.is_null() { println!("$DISPLAY is not set. Defaulting to DISPLAY=:0");
let var = env::var("DISPLAY").unwrap(); env::set_var("DISPLAY", ":0");
println!("warning: Failed to connect to X11."); }
println!("If you saw \"No protocol specified\", try running `xhost +SI:localuser:root`."); match x11rb::connect(None) {
println!("If not, make sure `echo $DISPLAY` outputs xremap's $DISPLAY ({}).", var); Ok((connection, _)) => self.connection = Some(connection),
} Err(error) => {
self.display = Some(display); let var = env::var("DISPLAY").unwrap();
display println!("warning: Failed to connect to X11: {error}");
println!("If you saw \"No protocol specified\", try running `xhost +SI:localuser:root`.");
println!("If not, make sure `echo $DISPLAY` outputs xremap's $DISPLAY ({var}).");
} }
} }
} }
@ -37,74 +36,66 @@ impl X11Client {
impl Client for X11Client { impl Client for X11Client {
fn supported(&mut self) -> bool { fn supported(&mut self) -> bool {
let display = self.connect(); self.connect();
if display.is_null() { return self.connection.is_some();
false // TODO: Test XGetInputFocus and focused_window > 0?
} else {
let mut focused_window = 0;
let mut focus_state = 0;
unsafe { xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) };
focused_window > 0
}
} }
fn current_application(&mut self) -> Option<String> { fn current_application(&mut self) -> Option<String> {
if !self.supported() { self.connect();
return None; if let Some(conn) = &self.connection {
let mut window = get_focus_window(conn)?;
loop {
if let Some(wm_class) = get_wm_class(conn, window) {
// Workaround: https://github.com/JetBrains/jdk8u_jdk/blob/master/src/solaris/classes/sun/awt/X11/XFocusProxyWindow.java#L35
if &wm_class != "FocusProxy" {
return Some(wm_class);
}
}
window = get_parent_window(conn, window)?;
}
} }
return None;
}
}
let display = self.connect(); fn get_focus_window(conn: &RustConnection) -> Option<Window> {
let mut focused_window = 0; if let Ok(cookie) = xproto::get_input_focus(conn) {
let mut focus_state = 0; if let Ok(reply) = cookie.reply() {
unsafe { xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) }; return Some(reply.focus);
}
}
return None;
}
let mut x_class_hint = xlib::XClassHint { fn get_parent_window(conn: &RustConnection, window: Window) -> Option<Window> {
res_name: std::ptr::null_mut(), if let Ok(cookie) = xproto::query_tree(conn, window) {
res_class: std::ptr::null_mut(), if let Ok(reply) = cookie.reply() {
}; return Some(reply.parent);
let mut wm_class = String::new(); }
loop { }
unsafe { return None;
if xlib::XGetClassHint(display, focused_window, &mut x_class_hint) == 1 { }
if !x_class_hint.res_name.is_null() {
xlib::XFree(x_class_hint.res_name as *mut std::ffi::c_void);
}
if !x_class_hint.res_class.is_null() { fn get_wm_class(conn: &RustConnection, window: Window) -> Option<String> {
// Note: into_string() seems to free `x_class_hint.res_class`. So XFree isn't needed. if let Ok(cookie) = get_property(conn, false, window, AtomEnum::WM_CLASS, AtomEnum::STRING, 0, 1024) {
wm_class = std::ffi::CString::from_raw(x_class_hint.res_class as *mut libc::c_char) if let Ok(reply) = cookie.reply() {
.into_string() if reply.value.is_empty() {
.unwrap(); return None;
// Workaround: https://github.com/JetBrains/jdk8u_jdk/blob/master/src/solaris/classes/sun/awt/X11/XFocusProxyWindow.java#L35
if &wm_class != "FocusProxy" {
break;
}
}
}
} }
let mut nchildren: u32 = 0; if let Some(delimiter) = reply.value.iter().position(|byte| *byte == '\0' as u8) {
let mut root: xlib::Window = 0; let value = reply.value[(delimiter + 1)..].to_vec();
let mut parent: xlib::Window = 0; if let Some(end) = value.iter().position(|byte| *byte == '\0' as u8) {
let mut children: *mut xlib::Window = &mut 0; if end == value.len() - 1 {
unsafe { if let Ok(string) = String::from_utf8(value[..end].to_vec()) {
if xlib::XQueryTree(display, focused_window, &mut root, &mut parent, &mut children, &mut nchildren) == 0 return Some(string);
{ }
break; }
}
}
if !children.is_null() {
unsafe {
xlib::XFree(children as *mut std::ffi::c_void);
} }
} }
// The root client's parent is NULL. Avoid querying it to prevent SEGV on XGetClientHint.
if parent == 0 {
return None;
}
focused_window = parent;
} }
Some(wm_class)
} }
return None;
} }

Loading…
Cancel
Save