mirror of https://github.com/k0kubun/xremap
Support wm_class for X11
parent
63ec6948e6
commit
39dbc8a1fe
@ -0,0 +1 @@
|
|||||||
|
pub mod x11_client;
|
@ -0,0 +1,116 @@
|
|||||||
|
pub struct X11Client {
|
||||||
|
// Both of them are lazily initialized
|
||||||
|
display: Option<*mut x11::xlib::Display>,
|
||||||
|
supported: Option<bool>,
|
||||||
|
last_wm_class: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X11Client {
|
||||||
|
pub fn new() -> X11Client {
|
||||||
|
X11Client {
|
||||||
|
display: None,
|
||||||
|
supported: None,
|
||||||
|
last_wm_class: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported(&mut self) -> bool {
|
||||||
|
match self.supported {
|
||||||
|
Some(supported) => supported,
|
||||||
|
None => {
|
||||||
|
let display = self.display();
|
||||||
|
let mut focused_window = 0;
|
||||||
|
let mut focus_state = 0;
|
||||||
|
unsafe { x11::xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) };
|
||||||
|
let supported = focused_window > 0;
|
||||||
|
self.supported = Some(supported);
|
||||||
|
supported
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_wm_class(&mut self) -> Option<String> {
|
||||||
|
if !self.supported() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let display = self.display();
|
||||||
|
let mut focused_window = 0;
|
||||||
|
let mut focus_state = 0;
|
||||||
|
unsafe { x11::xlib::XGetInputFocus(display, &mut focused_window, &mut focus_state) };
|
||||||
|
|
||||||
|
let mut x_class_hint = x11::xlib::XClassHint {
|
||||||
|
res_name: std::ptr::null_mut(),
|
||||||
|
res_class: std::ptr::null_mut(),
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
unsafe {
|
||||||
|
if x11::xlib::XGetClassHint(display, focused_window, &mut x_class_hint) == 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut nchildren: u32 = 0;
|
||||||
|
let mut root: x11::xlib::Window = 0;
|
||||||
|
let mut parent: x11::xlib::Window = 0;
|
||||||
|
let mut children: *mut x11::xlib::Window = &mut 0;
|
||||||
|
unsafe {
|
||||||
|
if x11::xlib::XQueryTree(
|
||||||
|
display,
|
||||||
|
focused_window,
|
||||||
|
&mut root,
|
||||||
|
&mut parent,
|
||||||
|
&mut children,
|
||||||
|
&mut nchildren,
|
||||||
|
) == 0
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !children.is_null() {
|
||||||
|
unsafe {
|
||||||
|
x11::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !x_class_hint.res_name.is_null() {
|
||||||
|
unsafe {
|
||||||
|
x11::xlib::XFree(x_class_hint.res_name as *mut std::ffi::c_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !x_class_hint.res_class.is_null() {
|
||||||
|
let wm_class = unsafe {
|
||||||
|
// Note: This seems to free `x_class_hint.res_class`. So XFree on it would double-free it.
|
||||||
|
std::ffi::CString::from_raw(x_class_hint.res_class as *mut i8)
|
||||||
|
.into_string()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
if &self.last_wm_class != &wm_class {
|
||||||
|
self.last_wm_class = wm_class.clone();
|
||||||
|
println!("wm_class: {}", &wm_class);
|
||||||
|
}
|
||||||
|
Some(wm_class)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(&mut self) -> *mut x11::xlib::Display {
|
||||||
|
match self.display {
|
||||||
|
Some(display) => display,
|
||||||
|
None => {
|
||||||
|
let display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
|
||||||
|
self.display = Some(display);
|
||||||
|
display
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue