浏览代码

Restructure X11 support classes

Thomas Dy 8 年之前
父节点
当前提交
66f97f8a4c
共有 5 个文件被更改,包括 169 次插入134 次删除
  1. 3 0
      src/main.rs
  2. 64 0
      src/wm.rs
  3. 0 27
      src/wm/atom.rs
  4. 0 75
      src/wm/mod.rs
  5. 102 32
      src/x11.rs

+ 3 - 0
src/main.rs

@@ -1,3 +1,5 @@
+extern crate xcb;
+
 mod sensors;
 mod comm;
 mod config;
@@ -7,6 +9,7 @@ mod tray;
 mod store;
 mod music;
 mod wm;
+mod x11;
 
 use comm::{Channel, Message};
 use config::Config;

+ 64 - 0
src/wm.rs

@@ -0,0 +1,64 @@
+use xcb;
+use x11;
+use comm;
+use comm::Channel;
+use config::Config;
+use std::thread;
+use std::time::Duration;
+
+pub fn wait_for<F>(f: F) -> xcb::Window where F: Fn() -> xcb::Window {
+    loop {
+        let w = f();
+        if w == 0 {
+            thread::sleep(Duration::from_millis(100));
+        }
+        else {
+            return w;
+        }
+    }
+}
+
+pub fn wm(tx: &Channel, _config: &Config) {
+    if let Some(conn) = x11::Connection::new() {
+        let screen = conn.default_screen();
+        let mut last_win = screen.get_active_window();
+        comm::send(tx, "title", conn.get_window_name(last_win).as_ref());
+        conn.watch(screen.root, true);
+        conn.watch(last_win, true);
+        conn.flush();
+
+        let stalonetray = wait_for(|| screen.search_by_class("stalonetray"));
+        let panel = wait_for(|| screen.search_by_name("__panel_top"));
+
+        xcb::configure_window(&conn, stalonetray, &[(xcb::CONFIG_WINDOW_SIBLING as u16, panel), (xcb::CONFIG_WINDOW_STACK_MODE as u16, xcb::STACK_MODE_ABOVE)]);
+        xcb::change_window_attributes(&conn, stalonetray, &[(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_STRUCTURE_NOTIFY)]);
+
+        conn.event_loop(&mut |event: &xcb::GenericEvent| {
+            match event.response_type() {
+                xcb::PROPERTY_NOTIFY => {
+                    let prop_event: &xcb::PropertyNotifyEvent = xcb::cast_event(event);
+                    if prop_event.atom() == conn.atoms._NET_ACTIVE_WINDOW {
+                        let new_win = screen.get_active_window();
+                        conn.watch(last_win, false);
+                        conn.watch(new_win, true);
+                        conn.flush();
+                        last_win = new_win;
+                        comm::send(tx, "title", conn.get_window_name(last_win).as_ref());
+                    }
+                    else if prop_event.atom() == conn.atoms._NET_WM_NAME {
+                        comm::send(tx, "title", conn.get_window_name(last_win).as_ref());
+                    }
+                },
+                xcb::CONFIGURE_NOTIFY => {
+                    let event: &xcb::ConfigureNotifyEvent = xcb::cast_event(&event);
+                    let spacer = format!("%{{O{}}}", event.width()+5);
+                    comm::send(tx, "spacer", spacer.as_ref());
+                },
+                _ => ()
+            }
+        });
+    } else {
+        println!("Could not connect to X!");
+    }
+}
+

+ 0 - 27
src/wm/atom.rs

@@ -1,27 +0,0 @@
-extern crate xcb;
-
-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
-);

+ 0 - 75
src/wm/mod.rs

@@ -1,75 +0,0 @@
-extern crate xcb;
-
-mod atom;
-mod ewmh;
-
-use comm;
-use comm::Channel;
-use config::Config;
-use std::thread;
-use std::time::Duration;
-
-pub fn wait_for<F>(f: F) -> xcb::Window where F: Fn() -> xcb::Window {
-    loop {
-        let w = f();
-        if w == 0 {
-            thread::sleep(Duration::from_millis(100));
-        }
-        else {
-            return w;
-        }
-    }
-}
-
-pub fn wm(tx: &Channel, _config: &Config) {
-    if let Ok((conn, screen_num)) = xcb::Connection::connect(None) {
-        let ewmh = ewmh::connect(&conn, screen_num);
-
-        let mut last_win = ewmh.get_active_window();
-        comm::send(tx, "title", ewmh.get_window_name(last_win).as_ref());
-        ewmh.watch(ewmh.root, true);
-        ewmh.watch(last_win, true);
-
-        let stalonetray = wait_for(|| ewmh.search_by_class("stalonetray"));
-        let panel = wait_for(|| ewmh.search_by_name("__panel_top"));
-
-        xcb::configure_window(&conn, stalonetray, &[(xcb::CONFIG_WINDOW_SIBLING as u16, panel), (xcb::CONFIG_WINDOW_STACK_MODE as u16, xcb::STACK_MODE_ABOVE)]);
-        xcb::change_window_attributes(&conn, stalonetray, &[(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_STRUCTURE_NOTIFY)]);
-
-        conn.flush();
-
-        loop {
-            let event = conn.wait_for_event();
-            match event {
-                None => { break; }
-                Some(event) => {
-                    match event.response_type() {
-                        xcb::PROPERTY_NOTIFY => {
-                            let prop_event: &xcb::PropertyNotifyEvent = xcb::cast_event(&event);
-                            if prop_event.atom() == ewmh.atoms._NET_ACTIVE_WINDOW {
-                                let new_win = ewmh.get_active_window();
-                                ewmh.watch(last_win, false);
-                                ewmh.watch(new_win, true);
-                                conn.flush();
-                                last_win = new_win;
-                                comm::send(tx, "title", ewmh.get_window_name(last_win).as_ref());
-                            }
-                            else if prop_event.atom() == ewmh.atoms._NET_WM_NAME {
-                                comm::send(tx, "title", ewmh.get_window_name(last_win).as_ref());
-                            }
-                        },
-                        xcb::CONFIGURE_NOTIFY => {
-                            let event: &xcb::ConfigureNotifyEvent = xcb::cast_event(&event);
-                            let spacer = format!("%{{O{}}}", event.width()+5);
-                            comm::send(tx, "spacer", spacer.as_ref());
-                        },
-                        _ => ()
-                    }
-                }
-            }
-        }
-    } else {
-        println!("Could not connect to X!");
-    }
-}
-

+ 102 - 32
src/wm/ewmh.rs → src/x11.rs

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