|  | @@ -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;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 |