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