浏览代码

Extract out widget trait

Thomas Dy 8 年之前
父节点
当前提交
cd595f9756
共有 4 个文件被更改,包括 95 次插入45 次删除
  1. 9 1
      src/ui/mod.rs
  2. 40 9
      src/ui/panel.rs
  3. 38 35
      src/ui/tray.rs
  4. 8 0
      src/ui/widget.rs

+ 9 - 1
src/ui/mod.rs

@@ -3,6 +3,7 @@ mod panel;
 mod ext;
 mod tray;
 mod util;
+mod widget;
 mod x11;
 
 use chan;
@@ -28,11 +29,18 @@ pub fn ui_main(signal: chan::Receiver<chan_signal::Signal>, cfg: &Config) -> i32
             });
         }
 
-        let mut panel = panel::Panel::new(conn, cfg);
+        let (mut panel, panel_rx) = panel::Panel::new(conn, cfg);
+
+        let tray = tray::Tray::new(panel.tx.clone(), panel.conn.clone(), panel.window);
+        panel.add_right_widget(Box::new(tray));
+
         panel.create();
 
         loop {
             chan_select!(
+                panel_rx.recv() => {
+                    panel.relayout();
+                },
                 rx.recv() -> event => {
                     if panel.handle_event(event.unwrap()) {
                         println!("Exiting");

+ 40 - 9
src/ui/panel.rs

@@ -1,9 +1,10 @@
+use chan;
 use config::Config;
 use xcb;
 use ui::ext;
 use ui::ext::ConnectionExt;
 use ui::font;
-use ui::tray;
+use ui::widget::Widget;
 use ui::x11;
 
 use std::sync::Arc;
@@ -12,14 +13,15 @@ pub struct Panel {
     pub conn: Arc<x11::Connection>,
     pub window: xcb::Window,
     pub width: u16,
-    tray: tray::Tray,
+    pub tx: chan::Sender<()>,
+    right_widgets: Vec<Box<Widget>>,
     fonts: font::FontLoader,
     picture: xcb::render::Picture,
     finishing: bool
 }
 
 impl Panel {
-    pub fn new(conn: x11::Connection, cfg: &Config) -> Panel {
+    pub fn new(conn: x11::Connection, cfg: &Config) -> (Panel, chan::Receiver<()>) {
         let conn = Arc::new(conn);
         let window = conn.generate_id();
         let picture = conn.generate_id();
@@ -32,18 +34,20 @@ impl Panel {
             font_loader.load(font);
         }
 
+        let (tx, rx) = chan::sync(10);
         let width = conn.default_screen().width;
-        let tray = tray::Tray::new(conn.clone(), window, width as u32);
 
-        Panel {
+        let panel = Panel {
             conn: conn,
             width: width,
+            tx: tx,
             window: window,
             fonts: font_loader,
-            tray: tray,
+            right_widgets: vec![],
             picture: picture,
             finishing: false
-        }
+        };
+        (panel, rx)
     }
 
     pub fn create(&self) {
@@ -92,8 +96,12 @@ impl Panel {
     }
 
     pub fn handle_event(&mut self, event: xcb::GenericEvent) -> bool {
-        let should_exit = self.tray.handle_event(&event, self.finishing);
+        let mut should_exit = false;
+        for widget in self.right_widgets.iter_mut() {
+            should_exit |= widget.handle_event(&event, self.finishing);
+        }
         if event.response_type() == xcb::EXPOSE {
+            self.relayout();
             self.draw_text("Hello 世界!");
         }
         if self.finishing && event.response_type() == xcb::DESTROY_NOTIFY {
@@ -105,6 +113,10 @@ impl Panel {
         should_exit
     }
 
+    pub fn add_right_widget(&mut self, widget: Box<Widget>) {
+        self.right_widgets.push(widget);
+    }
+
     pub fn create_pen(&self, r: u16, g: u16, b: u16, a: u16) -> xcb::render::Picture {
         let color = xcb::render::Color::new(r, g, b, a);
         let format = self.conn.get_pict_format(ext::PictFormat::ARGB32);
@@ -138,9 +150,28 @@ impl Panel {
         self.conn.flush();
     }
 
+    pub fn relayout(&self) {
+        let color = xcb::render::Color::new(0, 0, 0, 0xFFFF);
+        xcb::render::fill_rectangles(
+            &self.conn,
+            xcb::render::PICT_OP_SRC as u8,
+            self.picture,
+            color,
+            &[xcb::Rectangle::new(0, 0, self.width, 20)]
+        );
+        let mut right_pos = self.width;
+        for widget in self.right_widgets.iter() {
+            right_pos -= widget.width();
+            widget.render(right_pos);
+        }
+        self.conn.flush();
+    }
+
     pub fn finish(&mut self) {
         self.finishing = true;
-        self.tray.finish();
+        for widget in self.right_widgets.iter_mut() {
+            widget.finish();
+        }
         xcb::destroy_window(&self.conn, self.window);
         self.conn.flush();
     }

+ 38 - 35
src/ui/tray.rs

@@ -1,4 +1,6 @@
+use chan;
 use ui;
+use ui::widget;
 use ui::x11;
 use xcb;
 
@@ -7,19 +9,19 @@ use std::sync::Arc;
 const CLIENT_MESSAGE: u8 = xcb::CLIENT_MESSAGE | 0x80; // 0x80 flag for client messages
 
 pub struct Tray {
+    tx: chan::Sender<()>,
     conn: Arc<x11::Connection>,
     window: xcb::Window,
-    panel_width: u32,
     children: Vec<xcb::Window>,
     timestamp: xcb::Timestamp,
 }
 
 impl Tray {
-    pub fn new(conn: Arc<x11::Connection>, window: xcb::Window, width: u32) -> Tray {
+    pub fn new(tx: chan::Sender<()>, conn: Arc<x11::Connection>, window: xcb::Window) -> Tray {
         Tray {
             conn: conn,
+            tx: tx,
             window: window,
-            panel_width: width,
             children: vec![],
             timestamp: 0
         }
@@ -46,27 +48,22 @@ impl Tray {
         ok
     }
 
-    fn x_pos(&self, index: usize) -> u32 {
-        let tray_width = (index + 1) as u32 * ui::SIZE as u32;
-        self.panel_width - tray_width
-    }
-
     pub fn adopt(&mut self, window: xcb::Window) {
         let conn = &self.conn;
         xcb::change_window_attributes(conn, window, &[
             (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_STRUCTURE_NOTIFY)
         ]);
-        xcb::reparent_window(conn, window, self.window, self.x_pos(self.children.len()) as i16, 0);
+        xcb::reparent_window(conn, window, self.window, 0, 0);
         xcb::map_window(conn, window);
         self.force_size(window, None);
         conn.flush();
         self.children.push(window);
-        self.reposition();
+        self.tx.send(());
     }
 
     pub fn forget(&mut self, window: xcb::Window) {
         self.children.retain(|child| *child != window);
-        self.reposition();
+        self.tx.send(());
     }
 
     pub fn force_size(&self, window: xcb::Window, dimensions: Option<(u16, u16)>) {
@@ -83,38 +80,25 @@ impl Tray {
             conn.flush();
         }
     }
+}
 
-    pub fn reposition(&self) {
-        let conn = &self.conn;
-        for (index, child) in self.children.iter().enumerate() {
-            let window = *child;
-            xcb::configure_window(conn, window, &[
-                (xcb::CONFIG_WINDOW_X as u16, self.x_pos(index))
-            ]);
-        }
-        conn.flush();
+impl widget::Widget for Tray {
+    fn width(&self) -> u16 {
+        (self.children.len() * 20) as u16
     }
 
-    pub fn finish(&mut self) {
-        let conn = &self.conn;
-        let screen = conn.default_screen();
-
-        for child in self.children.iter() {
+    fn render(&self, x: u16) {
+        for (index, child) in self.children.iter().enumerate() {
             let window = *child;
-            xcb::change_window_attributes(conn, window, &[
-                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)
+            let xpos = x as u32 + index as u32 * 20;
+            xcb::configure_window(&self.conn, window, &[
+                (xcb::CONFIG_WINDOW_X as u16, xpos)
             ]);
-            xcb::unmap_window(conn, window);
-            xcb::reparent_window(conn, window, screen.root, 0, 0);
         }
-        xcb::change_window_attributes(conn, self.window, &[
-            (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_STRUCTURE_NOTIFY)
-        ]);
-        xcb::set_selection_owner(conn, xcb::NONE, conn.atom(x11::_NET_SYSTEM_TRAY_S0), self.timestamp);
-        conn.flush();
+        self.conn.flush();
     }
 
-    pub fn handle_event(&mut self, event: &xcb::GenericEvent, is_finishing: bool) -> bool {
+    fn handle_event(&mut self, event: &xcb::GenericEvent, is_finishing: bool) -> bool {
         if is_finishing {
             return false
         }
@@ -161,4 +145,23 @@ impl Tray {
         }
         false
     }
+
+    fn finish(&mut self) {
+        let conn = &self.conn;
+        let screen = conn.default_screen();
+
+        for child in self.children.iter() {
+            let window = *child;
+            xcb::change_window_attributes(conn, window, &[
+                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)
+            ]);
+            xcb::unmap_window(conn, window);
+            xcb::reparent_window(conn, window, screen.root, 0, 0);
+        }
+        xcb::change_window_attributes(conn, self.window, &[
+            (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_STRUCTURE_NOTIFY)
+        ]);
+        xcb::set_selection_owner(conn, xcb::NONE, conn.atom(x11::_NET_SYSTEM_TRAY_S0), self.timestamp);
+        conn.flush();
+    }
 }

+ 8 - 0
src/ui/widget.rs

@@ -0,0 +1,8 @@
+use xcb;
+
+pub trait Widget {
+    fn render(&self, x: u16);
+    fn width(&self) -> u16;
+    fn handle_event(&mut self, event: &xcb::GenericEvent, is_finishing: bool) -> bool;
+    fn finish(&mut self);
+}