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