ソースを参照

Implement taking ownership of tray selection

Thomas Dy 7 年 前
コミット
c5d84f5875
2 ファイル変更60 行追加24 行削除
  1. 12 24
      src/main.rs
  2. 48 0
      src/tray.rs

+ 12 - 24
src/main.rs

@@ -4,6 +4,7 @@ extern crate chan_signal;
 extern crate xcb;
 
 mod atom;
+mod tray;
 
 use std::thread;
 use std::sync::Arc;
@@ -15,41 +16,30 @@ fn main() {
         let conn = Arc::new(conn);
         let atoms = atom::Atoms::new(&conn);
 
-        let setup = conn.get_setup();
-        let screen = setup.roots().nth(preferred as usize).unwrap();
-
-        let owner = xcb::get_selection_owner(&conn, atoms.get(&atom::_NET_SYSTEM_TRAY_S0)).get_reply().unwrap().owner();
+        let owner = xcb::get_selection_owner(&conn, atoms.get(atom::_NET_SYSTEM_TRAY_S0)).get_reply().unwrap().owner();
         if owner != xcb::NONE {
             println!("Another system tray is already running");
             return
         }
 
-        let window = conn.generate_id();
-        xcb::create_window(
-            &conn,
-            xcb::COPY_FROM_PARENT as u8,
-            window,
-            screen.root(),
-            0, 0,
-            20, 20,
-            0,
-            xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
-            screen.root_visual(),
-            &[
-                (xcb::CW_BACK_PIXEL, screen.black_pixel()),
-                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)
-            ]
-        );
-        xcb::map_window(&conn, window);
-        conn.flush();
+        let tray = tray::Tray::new(&conn, &atoms, preferred as usize);
+        tray.create();
+        if !tray.take_selection() {
+            println!("Could not take ownership of tray selection. Maybe another tray is also running?");
+            return
+        }
 
         {
             let conn = conn.clone();
+            const CLIENT_MESSAGE: u8 = xcb::CLIENT_MESSAGE | 0x80;
             thread::spawn(move || {
                 loop {
                     match conn.wait_for_event() {
                         Some(event) => match event.response_type() {
                             xcb::EXPOSE => { println!("expose") },
+                            CLIENT_MESSAGE => {
+                                println!("client message");
+                            },
                             _ => {}
                         },
                         None => { break; }
@@ -67,8 +57,6 @@ fn main() {
         }
 
         // cleanup code
-        xcb::destroy_window(&conn, window);
-        conn.flush();
     }
     else {
         println!("Could not connect to X server!");

+ 48 - 0
src/tray.rs

@@ -0,0 +1,48 @@
+use atom;
+use xcb;
+
+pub struct Tray<'a> {
+    conn: &'a xcb::Connection,
+    atoms: &'a atom::Atoms<'a>,
+    screen: usize,
+    window: xcb::Window
+}
+
+impl<'a> Tray<'a> {
+    pub fn new<'b>(conn: &'b xcb::Connection, atoms: &'b atom::Atoms, screen: usize) -> Tray<'b> {
+        Tray::<'b> {
+            conn: conn,
+            atoms: atoms,
+            screen: screen,
+            window: conn.generate_id()
+        }
+    }
+
+    pub fn create(&self) {
+        let setup = self.conn.get_setup();
+        let screen = setup.roots().nth(self.screen).unwrap();
+
+        xcb::create_window(
+            &self.conn,
+            xcb::COPY_FROM_PARENT as u8,
+            self.window,
+            screen.root(),
+            0, 0,
+            20, 20,
+            0,
+            xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
+            screen.root_visual(),
+            &[
+                (xcb::CW_BACK_PIXEL, screen.black_pixel()),
+                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)
+            ]
+        );
+    }
+
+    pub fn take_selection(&self) -> bool {
+        let selection = self.atoms.get(atom::_NET_SYSTEM_TRAY_S0);
+        xcb::set_selection_owner(self.conn, self.window, selection, xcb::CURRENT_TIME);
+        let owner = xcb::get_selection_owner(self.conn, selection).get_reply().unwrap().owner();
+        owner == self.window
+    }
+}