extern crate xcb; use std::mem; const ATOMS: [&'static str; 3] = [ "_NET_ACTIVE_WINDOW", "_NET_WM_NAME", "UTF8_STRING" ]; #[allow(non_snake_case)] pub struct EWMH<'a> { pub conn: &'a xcb::Connection, pub root: xcb::Window, pub _NET_ACTIVE_WINDOW: xcb::Atom, pub _NET_WM_NAME: xcb::Atom, pub UTF8_STRING: xcb::Atom } pub struct WinClass { pub instance: String, pub class: String } pub fn connect<'a>(conn: &'a xcb::Connection, screen_num: i32) -> EWMH { let setup = conn.get_setup(); let screen = setup.roots().nth(screen_num as usize).unwrap(); let atoms: Vec = ATOMS .iter() .map(|name| xcb::intern_atom(&conn, false, name)) .map(|cookie| cookie.get_reply().unwrap().atom()) .collect(); EWMH { conn: conn, root: screen.root(), _NET_ACTIVE_WINDOW: atoms[0], _NET_WM_NAME: atoms[1], UTF8_STRING: atoms[2] } } impl<'a> EWMH<'a> { pub fn get_active_window(&self) -> xcb::Window { let cookie = xcb::get_property(&self.conn, false, self.root, self._NET_ACTIVE_WINDOW, xcb::ATOM_WINDOW, 0, 4); let reply = cookie.get_reply().unwrap(); let value: &xcb::Window = unsafe { mem::transmute(&(reply.value()[0])) }; *value } pub fn get_window_name(&self, win: xcb::Window) -> String { let cookie = xcb::get_property(&self.conn, false, win, self._NET_WM_NAME, self.UTF8_STRING, 0, 100); let reply = cookie.get_reply(); let value: &str = match reply { Ok(reply) => unsafe { mem::transmute(reply.value()) }, _ => "" }; if value == "" { let cookie = xcb::get_property(&self.conn, false, win, xcb::ATOM_WM_NAME, xcb::ATOM_STRING, 0, 100); let reply = cookie.get_reply(); let value: &str = match reply { Ok(reply) => unsafe { mem::transmute(reply.value()) }, _ => "" }; value.to_string() } else { value.to_string() } } pub fn get_window_class(&self, win: xcb::Window) -> WinClass { let cookie = xcb::get_property(&self.conn, false, win, xcb::ATOM_WM_CLASS, xcb::ATOM_STRING, 0, 100); let reply = cookie.get_reply(); let value: &str = match reply { Ok(reply) => unsafe { mem::transmute(reply.value()) }, _ => "" }; let parts: Vec<&str> = value.split_terminator('\0').collect(); if parts.len() == 2 { WinClass { instance: parts[0].to_string(), class: parts[1].to_string() } } else { WinClass { instance: "".to_string(), class: "".to_string() } } } pub fn watch(&self, win: xcb::Window, enabled: bool) { let value = if enabled { xcb::EVENT_MASK_PROPERTY_CHANGE } else { xcb::EVENT_MASK_NO_EVENT }; xcb::change_window_attributes(&self.conn, win, &[(xcb::CW_EVENT_MASK, value)]); } pub fn search_by_name(&self, name: &str) -> xcb::Window { let cookie = xcb::query_tree(&self.conn, self.root); let reply = cookie.get_reply().unwrap(); for w in reply.children() { if self.get_window_name(*w) == name { return *w; } } return 0; } pub fn search_by_class(&self, class_name: &str) -> xcb::Window { let cookie = xcb::query_tree(&self.conn, self.root); let reply = cookie.get_reply().unwrap(); for w in reply.children() { if self.get_window_class(*w).class == class_name { return *w; } } return 0; } }