|
@@ -1,42 +1,83 @@
|
|
|
-extern crate xcb;
|
|
|
-
|
|
|
-use wm::atom;
|
|
|
+use xcb;
|
|
|
use std::mem;
|
|
|
+use std::ops::Deref;
|
|
|
|
|
|
-pub struct EWMH<'a> {
|
|
|
- pub conn: &'a xcb::Connection,
|
|
|
- pub root: xcb::Window,
|
|
|
- pub atoms: atom::Atoms
|
|
|
+fn load_atom(conn: &xcb::Connection, name: &str) -> xcb::Atom {
|
|
|
+ let cookie = xcb::intern_atom(conn, true, name);
|
|
|
+ cookie.get_reply().unwrap().atom()
|
|
|
}
|
|
|
|
|
|
+macro_rules! atoms {
|
|
|
+ ( $( $x:ident ),* ) => {
|
|
|
+ #[allow(non_snake_case)]
|
|
|
+ pub struct Atoms {
|
|
|
+ $(pub $x: xcb::Atom),*
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn load_atoms(conn: &xcb::Connection) -> Atoms {
|
|
|
+ Atoms {
|
|
|
+ $($x: load_atom(conn, stringify!($x))),*
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+atoms!(
|
|
|
+ _NET_ACTIVE_WINDOW,
|
|
|
+ _NET_WM_NAME,
|
|
|
+ UTF8_STRING
|
|
|
+);
|
|
|
+
|
|
|
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();
|
|
|
- EWMH {
|
|
|
- conn: conn,
|
|
|
- root: screen.root(),
|
|
|
- atoms: atom::load_atoms(conn)
|
|
|
- }
|
|
|
+pub struct Connection {
|
|
|
+ conn: xcb::Connection,
|
|
|
+ default_screen: i32,
|
|
|
+ pub atoms: Atoms
|
|
|
}
|
|
|
|
|
|
-impl<'a> EWMH<'a> {
|
|
|
- pub fn get_active_window(&self) -> xcb::Window {
|
|
|
- let cookie = xcb::get_property(&self.conn, false, self.root, self.atoms._NET_ACTIVE_WINDOW, xcb::ATOM_WINDOW, 0, 4);
|
|
|
- let reply = cookie.get_reply().unwrap();
|
|
|
- if reply.value_len() == 0 {
|
|
|
- 0
|
|
|
+impl Connection {
|
|
|
+ pub fn new() -> Option<Connection> {
|
|
|
+ if let Ok((conn, default_screen)) = xcb::Connection::connect(None) {
|
|
|
+ Some(Connection {
|
|
|
+ atoms: load_atoms(&conn),
|
|
|
+ default_screen: default_screen,
|
|
|
+ conn: conn
|
|
|
+ })
|
|
|
}
|
|
|
else {
|
|
|
- let value: &xcb::Window = unsafe { mem::transmute(&(reply.value()[0])) };
|
|
|
- *value
|
|
|
+ None
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn default_screen<'a>(&'a self) -> Screen<'a> {
|
|
|
+ self.screen(self.default_screen as usize)
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn screen<'a>(&'a self, index: usize) -> Screen<'a> {
|
|
|
+ let setup = self.conn.get_setup();
|
|
|
+ let screen = setup.roots().nth(index).unwrap();
|
|
|
+ Screen {
|
|
|
+ conn: &self,
|
|
|
+ atoms: &self.atoms,
|
|
|
+ root: screen.root(),
|
|
|
+ index: index
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ 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 get_window_name(&self, win: xcb::Window) -> String {
|
|
|
let cookie = xcb::get_property(&self.conn, false, win, self.atoms._NET_WM_NAME, self.atoms.UTF8_STRING, 0, 100);
|
|
|
let reply = cookie.get_reply();
|
|
@@ -80,21 +121,51 @@ impl<'a> EWMH<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub fn watch(&self, win: xcb::Window, enabled: bool) {
|
|
|
- let value = if enabled {
|
|
|
- xcb::EVENT_MASK_PROPERTY_CHANGE
|
|
|
+ pub fn event_loop(&self, handler: &mut FnMut(&xcb::GenericEvent)) {
|
|
|
+ loop {
|
|
|
+ match self.conn.wait_for_event() {
|
|
|
+ None => { break; }
|
|
|
+ Some(event) => {
|
|
|
+ handler(&event)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Deref for Connection {
|
|
|
+ type Target = xcb::Connection;
|
|
|
+
|
|
|
+ fn deref(&self) -> &xcb::Connection {
|
|
|
+ &self.conn
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct Screen<'a> {
|
|
|
+ conn: &'a Connection,
|
|
|
+ pub atoms: &'a Atoms,
|
|
|
+ pub root: xcb::Window,
|
|
|
+ pub index: usize
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> Screen<'a> {
|
|
|
+ pub fn get_active_window(&self) -> xcb::Window {
|
|
|
+ let cookie = xcb::get_property(self.conn, false, self.root, self.atoms._NET_ACTIVE_WINDOW, xcb::ATOM_WINDOW, 0, 4);
|
|
|
+ let reply = cookie.get_reply().unwrap();
|
|
|
+ if reply.value_len() == 0 {
|
|
|
+ 0
|
|
|
}
|
|
|
else {
|
|
|
- xcb::EVENT_MASK_NO_EVENT
|
|
|
- };
|
|
|
- xcb::change_window_attributes(&self.conn, win, &[(xcb::CW_EVENT_MASK, value)]);
|
|
|
+ let value: &xcb::Window = unsafe { mem::transmute(&(reply.value()[0])) };
|
|
|
+ *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 {
|
|
|
+ if self.conn.get_window_name(*w) == name {
|
|
|
return *w;
|
|
|
}
|
|
|
}
|
|
@@ -105,11 +176,10 @@ impl<'a> EWMH<'a> {
|
|
|
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 {
|
|
|
+ if self.conn.get_window_class(*w).class == class_name {
|
|
|
return *w;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
-
|