Browse Source

Split window and panel logic

Thomas Dy 7 years ago
parent
commit
71dd21f5f2
10 changed files with 168 additions and 135 deletions
  1. 2 3
      src/main.rs
  2. 2 2
      src/ui/context.rs
  3. 5 4
      src/ui/font.rs
  4. 1 0
      src/ui/mod.rs
  5. 50 114
      src/ui/panel.rs
  6. 104 0
      src/ui/window.rs
  7. 1 4
      src/ui/x11.rs
  8. 1 2
      src/widgets/mod.rs
  9. 1 3
      src/widgets/title.rs
  10. 1 3
      src/widgets/tray.rs

+ 2 - 3
src/main.rs

@@ -35,7 +35,7 @@ fn main() {
         }
         {
             let tx = tx.clone();
-            let conn = conn.clone_connection();
+            let conn = conn.clone();
             thread::spawn(move || {
                 loop {
                     match conn.wait_for_event() {
@@ -63,12 +63,11 @@ fn main() {
             widgets::title
         ];
 
-        let mut right_widgets: Vec<widgets::WidgetConstructor> = vec![
+        let right_widgets: Vec<widgets::WidgetConstructor> = vec![
             widgets::mpd,
             widgets::sensors,
             widgets::tray
         ];
-        right_widgets.reverse();
 
         for cons in left_widgets {
             let widget = cons(params.clone());

+ 2 - 2
src/ui/context.rs

@@ -9,7 +9,7 @@ use xcb;
 
 #[derive(Clone)]
 pub struct Context {
-    pub conn: Rc<x11::Connection>,
+    pub conn: x11::Connection,
     pub window: xcb::Window,
     picture: xcb::render::Picture,
     pen: xcb::render::Picture,
@@ -19,7 +19,7 @@ pub struct Context {
 
 impl Context {
     pub fn new(
-        conn: Rc<x11::Connection>,
+        conn: x11::Connection,
         window: xcb::Window,
         picture: xcb::render::Picture,
         fonts: Rc<font::FontLoader>

+ 5 - 4
src/ui/font.rs

@@ -4,6 +4,7 @@ use fontconfig_sys::*;
 use ui::ext;
 use ui::ext::ConnectionExt;
 use ui::util;
+use ui::x11;
 use xcb;
 
 use std::cell::RefCell;
@@ -11,7 +12,7 @@ use std::collections::HashMap;
 use std::ffi::{CString, CStr};
 use std::mem;
 use std::ptr;
-use std::sync::{Arc, Once, ONCE_INIT};
+use std::sync::{Once, ONCE_INIT};
 
 static FC_INIT: Once = ONCE_INIT;
 
@@ -123,13 +124,13 @@ impl<'a> RenderableText<'a> {
 }
 
 pub struct FontLoader {
-    conn: Arc<xcb::Connection>,
+    conn: x11::Connection,
     library: ft::Library,
     fonts: Vec<Font>
 }
 
 impl FontLoader {
-    pub fn new(conn: Arc<xcb::Connection>) -> Self {
+    pub fn new(conn: x11::Connection) -> Self {
         FC_INIT.call_once(|| unsafe {
             assert_eq!(FcInit(), 1);
         });
@@ -145,7 +146,7 @@ impl FontLoader {
         }
     }
 
-    pub fn from_config(conn: Arc<xcb::Connection>, cfg: &Config) -> Self {
+    pub fn from_config(conn: x11::Connection, cfg: &Config) -> Self {
         let val = cfg.lookup("bar.fonts").unwrap();
         let fonts = val.as_slice().unwrap();
         let fonts = fonts.iter().flat_map(|elem| elem.as_str());

+ 1 - 0
src/ui/mod.rs

@@ -4,6 +4,7 @@ pub mod panel;
 pub mod ext;
 pub mod util;
 pub mod context;
+pub mod window;
 pub mod x11;
 
 pub const SIZE: u16 = 20;

+ 50 - 114
src/ui/panel.rs

@@ -1,17 +1,15 @@
-use config::Config;
 use xcb;
-use ui;
-use ui::color;
+
+use config::Config;
 use ui::context::Context;
-use ui::ext;
-use ui::ext::ConnectionExt;
-use ui::font;
+use ui::window::Window;
 use ui::x11;
 use widgets::{Message, Update, Widget};
 
-use std::rc::Rc;
-use std::iter;
-use std::slice;
+enum WidgetAlign {
+    Left,
+    Right
+}
 
 #[derive(PartialEq)]
 enum WidgetStatus {
@@ -23,15 +21,17 @@ enum WidgetStatus {
 
 struct WidgetState {
     widget: Box<Widget>,
+    align: WidgetAlign,
     position: u16,
     width: u16,
     status: WidgetStatus
 }
 
 impl WidgetState {
-    fn new(widget: Box<Widget>) -> Self {
+    fn new(widget: Box<Widget>, align: WidgetAlign) -> Self {
         WidgetState {
             widget: widget,
+            align: align,
             position: 0,
             width: 0,
             status: WidgetStatus::PendingMeasure
@@ -72,94 +72,37 @@ impl WidgetState {
 }
 
 pub struct Panel {
-    pub conn: Rc<x11::Connection>,
-    pub window: xcb::Window,
-    pub width: u16,
-    left_widgets: Vec<WidgetState>,
-    right_widgets: Vec<WidgetState>,
-    fonts: Rc<font::FontLoader>,
-    picture: xcb::render::Picture,
+    window: Window,
+    conn: x11::Connection,
+    context: Context,
+    widgets: Vec<WidgetState>,
     finishing: bool
 }
 
 impl Panel {
     pub fn new(conn: x11::Connection, cfg: &Config) -> Panel {
-        let conn = Rc::new(conn);
-        let window = conn.generate_id();
-        let picture = conn.generate_id();
-
-        let width = conn.default_screen().width;
-        let font_loader = Rc::new(font::FontLoader::from_config(conn.clone_connection(), cfg));
+        let window = Window::new(conn.clone(), cfg);
+        let context = window.make_context();
 
         Panel {
-            conn: conn,
-            width: width,
             window: window,
-            left_widgets: vec![],
-            right_widgets: vec![],
-            fonts: font_loader,
-            picture: picture,
+            conn: conn,
+            context: context,
+            widgets: vec![],
             finishing: false
         }
     }
 
     pub fn create(&mut self) {
-        let (root, width) = {
-            let screen = self.conn.default_screen();
-            (screen.root, screen.width)
-        };
-
-        xcb::create_window(
-            &self.conn,
-            xcb::COPY_FROM_PARENT as u8,
-            self.window,
-            root,
-            0, 0,
-            width, ui::SIZE,
-            0,
-            xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
-            xcb::COPY_FROM_PARENT,
-            &[
-                (xcb::CW_BACK_PIXEL, 0xFF000000),
-                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_PROPERTY_CHANGE | xcb::EVENT_MASK_STRUCTURE_NOTIFY | xcb::EVENT_MASK_BUTTON_PRESS)
-            ]
-        );
-        self.set_property(
-            self.conn.atom(x11::_NET_WM_WINDOW_TYPE),
-            xcb::ATOM_ATOM,
-            32,
-            &[self.conn.atom(x11::_NET_WM_WINDOW_TYPE_DOCK)]
-        );
-        xcb::map_window(&self.conn, self.window);
-        xcb::render::create_picture(&self.conn, self.picture, self.window, self.conn.get_pict_format(ext::PictFormat::RGB24), &[
-            (xcb::render::CP_POLY_EDGE, xcb::render::POLY_EDGE_SMOOTH),
-            (xcb::render::CP_POLY_MODE, xcb::render::POLY_MODE_IMPRECISE)
-        ]);
-        self.conn.flush();
-        for state in self.widgets_iter() {
+        self.window.create();
+        for state in self.widgets.iter_mut() {
             state.widget.init();
         }
         self.conn.flush();
     }
 
     pub fn make_context(&self) -> Context {
-        Context::new(self.conn.clone(), self.window, self.picture, self.fonts.clone())
-    }
-
-    fn widgets_iter(&mut self) -> iter::Chain<slice::IterMut<WidgetState>, slice::IterMut<WidgetState>>{
-        self.left_widgets.iter_mut().chain(self.right_widgets.iter_mut())
-    }
-
-    pub fn set_property<T>(&self, name: xcb::Atom, type_: xcb::Atom, format: u8, data: &[T]) {
-        xcb::change_property(
-            &self.conn,
-            xcb::PROP_MODE_REPLACE as u8,
-            self.window,
-            name,
-            type_,
-            format,
-            data
-        );
+        self.context.clone()
     }
 
     pub fn handle_event(&mut self, event: Message) -> bool {
@@ -169,11 +112,8 @@ impl Panel {
         let mut press_location = None;
 
         if let Message::XcbEvent(ref event) = event {
-            if finishing && event.response_type() == xcb::DESTROY_NOTIFY {
-                let event: &xcb::DestroyNotifyEvent = unsafe { xcb::cast_event(event) };
-                if event.window() == self.window {
-                    return true
-                }
+            if finishing && self.window.handle_event(event) {
+                return true
             }
             if event.response_type() == xcb::EXPOSE {
                 should_relayout = true;
@@ -201,7 +141,7 @@ impl Panel {
                 };
             };
             if let Some(x) = press_location {
-                for mut state in self.widgets_iter() {
+                for mut state in self.widgets.iter_mut() {
                     if state.contains(x) {
                         let offset_x = x - state.position;
                         let event = Message::MousePress(offset_x);
@@ -209,13 +149,13 @@ impl Panel {
                     }
                 }
             }
-            for mut state in self.widgets_iter() {
+            for mut state in self.widgets.iter_mut() {
                 delegate_event(&mut state, &event);
             }
         }
 
         // check widgets that requested relayout if widths have changed
-        if self.widgets_iter().any(|state| state.measure()) {
+        if self.widgets.iter_mut().any(|state| state.measure()) {
             should_relayout = true;
         }
 
@@ -229,32 +169,26 @@ impl Panel {
     }
 
     pub fn add_left_widget(&mut self, widget: Box<Widget>) {
-        self.left_widgets.push(WidgetState::new(widget));
+        self.widgets.push(WidgetState::new(widget, WidgetAlign::Left));
     }
 
     pub fn add_right_widget(&mut self, widget: Box<Widget>) {
-        self.right_widgets.push(WidgetState::new(widget));
+        self.widgets.insert(0, WidgetState::new(widget, WidgetAlign::Right));
     }
 
     pub fn relayout(&mut self) {
-        xcb::render::fill_rectangles(
-            &self.conn,
-            xcb::render::PICT_OP_SRC as u8,
-            self.picture,
-            color::BLACK,
-            &[xcb::Rectangle::new(0, 0, self.width, ui::SIZE)]
-        );
+        self.context.draw_bg(0, self.window.width);
 
         // measure
         let mut total_width = 0;
-        for state in self.widgets_iter() {
+        for state in self.widgets.iter_mut() {
             state.measure();
             if !state.widget.fit_width() {
                 total_width += state.width;
             }
         }
-        let margin = self.width.saturating_sub(total_width);
-        for state in self.widgets_iter() {
+        let margin = self.window.width.saturating_sub(total_width);
+        for state in self.widgets.iter_mut() {
             if state.widget.fit_width() {
                 state.width = margin;
             }
@@ -262,18 +196,22 @@ impl Panel {
 
         // position
         let mut left_pos = 0;
-        for state in self.left_widgets.iter_mut() {
-            state.position = left_pos;
-            left_pos += state.width;
-        }
-        let mut right_pos = self.width;
-        for state in self.right_widgets.iter_mut() {
-            right_pos -= state.width;
-            state.position = right_pos;
+        let mut right_pos = self.window.width;
+        for state in self.widgets.iter_mut() {
+            match state.align {
+                WidgetAlign::Left => {
+                    state.position = left_pos;
+                    left_pos += state.width;
+                },
+                WidgetAlign::Right => {
+                    right_pos -= state.width;
+                    state.position = right_pos;
+                }
+            }
         }
 
         // render
-        for state in self.widgets_iter() {
+        for state in self.widgets.iter_mut() {
             state.widget.render(state.position, state.width);
             state.update(WidgetStatus::Okay);
         }
@@ -281,10 +219,9 @@ impl Panel {
     }
 
     pub fn rerender(&mut self) {
-        let context = self.make_context();
-        for state in self.widgets_iter() {
+        for state in self.widgets.iter_mut() {
             if state.should_render() {
-                context.draw_bg(state.position, state.width);
+                self.context.draw_bg(state.position, state.width);
                 state.widget.render(state.position, state.width);
                 state.update(WidgetStatus::Okay);
             }
@@ -294,10 +231,9 @@ impl Panel {
 
     pub fn finish(&mut self) {
         self.finishing = true;
-        for state in self.widgets_iter() {
+        for state in self.widgets.iter_mut() {
             state.widget.finish();
         }
-        xcb::destroy_window(&self.conn, self.window);
-        self.conn.flush();
+        self.window.finish();
     }
 }

+ 104 - 0
src/ui/window.rs

@@ -0,0 +1,104 @@
+use std::rc::Rc;
+
+use xcb;
+
+use config::Config;
+use ui;
+use ui::context::Context;
+use ui::ext;
+use ui::ext::ConnectionExt;
+use ui::x11;
+use ui::font;
+
+pub struct Window {
+    conn: x11::Connection,
+    pub window: xcb::Window,
+    pub width: u16,
+    fonts: Rc<font::FontLoader>,
+    picture: xcb::render::Picture
+}
+
+impl Window {
+    pub fn new(conn: x11::Connection, cfg: &Config) -> Self {
+        let conn = conn;
+        let window = conn.generate_id();
+        let picture = conn.generate_id();
+
+        let width = conn.default_screen().width;
+        let font_loader = Rc::new(font::FontLoader::from_config(conn.clone(), cfg));
+
+        Window {
+            conn: conn,
+            width: width,
+            window: window,
+            fonts: font_loader,
+            picture: picture
+        }
+    }
+
+    pub fn create(&mut self) {
+        let (root, width) = {
+            let screen = self.conn.default_screen();
+            (screen.root, screen.width)
+        };
+
+        xcb::create_window(
+            &self.conn,
+            xcb::COPY_FROM_PARENT as u8,
+            self.window,
+            root,
+            0, 0,
+            width, ui::SIZE,
+            0,
+            xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
+            xcb::COPY_FROM_PARENT,
+            &[
+                (xcb::CW_BACK_PIXEL, 0xFF000000),
+                (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_PROPERTY_CHANGE | xcb::EVENT_MASK_STRUCTURE_NOTIFY | xcb::EVENT_MASK_BUTTON_PRESS)
+            ]
+        );
+        self.set_property(
+            self.conn.atom(x11::_NET_WM_WINDOW_TYPE),
+            xcb::ATOM_ATOM,
+            32,
+            &[self.conn.atom(x11::_NET_WM_WINDOW_TYPE_DOCK)]
+        );
+        xcb::map_window(&self.conn, self.window);
+        xcb::render::create_picture(&self.conn, self.picture, self.window, self.conn.get_pict_format(ext::PictFormat::RGB24), &[
+            (xcb::render::CP_POLY_EDGE, xcb::render::POLY_EDGE_SMOOTH),
+            (xcb::render::CP_POLY_MODE, xcb::render::POLY_MODE_IMPRECISE)
+        ]);
+        self.conn.flush();
+    }
+
+    pub fn make_context(&self) -> Context {
+        Context::new(self.conn.clone(), self.window, self.picture, self.fonts.clone())
+    }
+
+    pub fn set_property<T>(&self, name: xcb::Atom, type_: xcb::Atom, format: u8, data: &[T]) {
+        xcb::change_property(
+            &self.conn,
+            xcb::PROP_MODE_REPLACE as u8,
+            self.window,
+            name,
+            type_,
+            format,
+            data
+        );
+    }
+
+    pub fn handle_event(&mut self, event: &xcb::GenericEvent) -> bool {
+        if event.response_type() == xcb::DESTROY_NOTIFY {
+            let event: &xcb::DestroyNotifyEvent = unsafe { xcb::cast_event(event) };
+            if event.window() == self.window {
+                return true
+            }
+        }
+        false
+    }
+
+    pub fn finish(&mut self) {
+        xcb::destroy_window(&self.conn, self.window);
+        self.conn.flush();
+    }
+}

+ 1 - 4
src/ui/x11.rs

@@ -30,6 +30,7 @@ pub struct WinClass {
     pub class: String
 }
 
+#[derive(Clone)]
 pub struct Connection {
     conn: Arc<xcb::Connection>,
     default_screen: i32,
@@ -50,10 +51,6 @@ impl Connection {
         }
     }
 
-    pub fn clone_connection(&self) -> Arc<xcb::Connection> {
-        self.conn.clone()
-    }
-
     pub fn atom(&self, name: &str) -> xcb::Atom {
         let mut cache = self.cache.borrow_mut();
         if cache.contains_key(name) {

+ 1 - 2
src/widgets/mod.rs

@@ -1,4 +1,3 @@
-use std::rc::Rc;
 use std::sync::mpsc;
 
 use xcb;
@@ -62,7 +61,7 @@ pub struct WidgetParams {
 }
 
 impl WidgetParams {
-    fn conn(&self) -> Rc<x11::Connection> {
+    fn conn(&self) -> x11::Connection {
         self.context.conn.clone()
     }
 

+ 1 - 3
src/widgets/title.rs

@@ -1,5 +1,3 @@
-use std::rc::Rc;
-
 use xcb;
 
 use ui::context::Context;
@@ -9,7 +7,7 @@ use widgets::{Message, Update, Widget, WidgetParams};
 const MARGIN: u16 = 7;
 
 pub struct Title {
-    conn: Rc<x11::Connection>,
+    conn: x11::Connection,
     context: Context,
     title: String,
     last_win: xcb::Window

+ 1 - 3
src/widgets/tray.rs

@@ -1,5 +1,3 @@
-use std::rc::Rc;
-
 use xcb;
 
 use ui;
@@ -9,7 +7,7 @@ use widgets::{Message, Update, Widget, WidgetParams};
 const CLIENT_MESSAGE: u8 = xcb::CLIENT_MESSAGE | 0x80; // 0x80 flag for client messages
 
 pub struct Tray {
-    conn: Rc<x11::Connection>,
+    conn: x11::Connection,
     window: xcb::Window,
     children: Vec<xcb::Window>,
     timestamp: xcb::Timestamp,