use crate::xtypes::*; use crate::xcolor::DisplayColorExt; use std::sync::Arc; use xcb::{ Xid }; use xcb::x::{ self, ClientMessageData, Cw, CreateWindow, EventMask, Screen, WindowClass }; mod xcolor; mod xtypes; #[derive(Clone, Copy, PartialEq, Eq)] enum ScreenSide { Top, Bottom, Left, Right } struct DockConfiguration { thickness: u16, side: ScreenSide, background_pixel: u32, } struct Dock { configuration: DockConfiguration, window: Window, } impl HasWindow for Dock { fn window(&self) -> &Window { &self.window } } #[derive(Debug)] struct Rectangle { left: T, top: T, width: T, height: T, } fn main() -> xcb::Result<()> { let display = Arc::new(Display::new()?); // #d4ffcc let background_pixel = display.allocate_color(54484, 65535, 52428)?; let _dock = Dock::new(Arc::clone(&display), DockConfiguration { thickness: 50, side: ScreenSide::Bottom, background_pixel, })?; loop { match display.wait_for_event()? { xcb::Event::X(x::Event::ButtonPress(event)) => { println!("click {:?}", event); } xcb::Event::X(x::Event::ClientMessage(event)) => { if let ClientMessageData::Data32([atom, ..]) = event.data() { if atom == display.atoms().wm_delete_window.resource_id() { break; } } } event => { println!("unknown event {:?}", event); } } } Ok(()) } impl Dock { fn new(display: Arc, configuration: DockConfiguration) -> xcb::Result { let screen = display.screen(); let dock_bounds = Dock::compute_bounds(&screen, &configuration); println!("back pixel {:?}", configuration.background_pixel); let window = Window::new(Arc::clone(&display), &mut CreateWindow { depth: x::COPY_FROM_PARENT as u8, wid: x::Window::none(), parent: screen.root(), x: dock_bounds.left as i16, y: dock_bounds.top as i16, width: dock_bounds.width, height: dock_bounds.height, border_width: 0, class: WindowClass::InputOutput, visual: screen.root_visual(), value_list: &[ Cw::BackPixel(configuration.background_pixel), Cw::EventMask(EventMask::EXPOSURE | EventMask::BUTTON_PRESS), ], })?; let dock = Dock { window, configuration }; dock.set_string_property(&x::ATOM_WM_NAME, b"grass bar")?; dock.set_atom_property(&display.atoms().wm_protocols, &[display.atoms().wm_delete_window])?; dock.set_atom_property(&display.atoms().wm_type, &[display.atoms().wm_type_dock])?; dock.set_strut_properties(&screen)?; dock.map_window()?; Ok(dock) } fn set_strut_properties(&self, screen: &Screen) -> xcb::Result<()> { let atoms = self.atoms(); let thickness = self.configuration.thickness as u32; let strut_values = match self.configuration.side { ScreenSide::Left => &[thickness, 0 as u32, 0 as u32, 0 as u32], ScreenSide::Right => &[0 as u32, thickness, 0 as u32, 0 as u32], ScreenSide::Top => &[0 as u32, 0 as u32, thickness, 0 as u32], ScreenSide::Bottom => &[0 as u32, 0 as u32, 0 as u32, thickness], }; self.set_cardinal_property(&atoms.wm_strut, strut_values)?; let strut_partial_values = &[ strut_values[0], strut_values[1], strut_values[2], strut_values[3], 0 as u32, if self.configuration.side == ScreenSide::Left { screen.height_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, if self.configuration.side == ScreenSide::Right { screen.height_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, if self.configuration.side == ScreenSide::Top { screen.width_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, if self.configuration.side == ScreenSide::Bottom { screen.width_in_pixels() as u32 } else { 0 as u32 }, ]; self.set_cardinal_property(&atoms.wm_strut_partial, strut_partial_values)?; Ok(()) } fn compute_bounds(screen: &Screen, configuration: &DockConfiguration) -> Rectangle { if configuration.side == ScreenSide::Top || configuration.side == ScreenSide::Bottom { let left = 0; let width = screen.width_in_pixels(); let height = configuration.thickness; let top = if configuration.side == ScreenSide::Bottom { screen.height_in_pixels() - height } else { 0 }; Rectangle { left, top, width, height } } else { let top = 0; let height = screen.height_in_pixels(); let width = configuration.thickness; let left = if configuration.side == ScreenSide::Right { screen.width_in_pixels() - width } else { 0 }; Rectangle { left, top, width, height } } } }