use std::borrow::Borrow; use std::sync::Arc; use std::ops::Deref; use xcb::x::{ self, Atom, ChangeProperty, CreateWindow, InternAtom, MapWindow, PropMode, Screen }; pub struct Atoms { pub wm_protocols: Atom, pub wm_delete_window: Atom, pub wm_type: Atom, pub wm_type_dock: Atom, pub wm_strut: Atom, pub wm_strut_partial: Atom, } pub struct Connection(xcb::Connection); pub struct Display { connection: Connection, screen_index: i32, atoms: Atoms, } pub struct Window { display: Arc, window_id: x::Window, } impl Connection { pub fn connect(display_name: Option<&str>) -> xcb::ConnResult<(Connection, i32)> { let (connection, screen_index) = xcb::Connection::connect(display_name)?; Ok((Connection(connection), screen_index)) } } impl Display { pub fn new() -> xcb::Result { let (connection, screen_index) = Connection::connect(None)?; let atoms = connection.get_atoms()?; Ok(Display { connection, screen_index, atoms }) } pub fn screen_index(&self) -> i32 { self.screen_index } } impl Window { pub fn new(display: Arc, create_window: &mut CreateWindow) -> xcb::Result { let display_ref: &Display = display.borrow(); let connection: &Connection = &display_ref.connection; let window_id: x::Window = connection.0.generate_id(); create_window.wid = window_id; let cookie = connection.send_request_checked(create_window); connection.check_request(cookie)?; Ok(Window { display, window_id }) } } pub trait HasWindow { fn window(&self) -> &Window; fn window_id(&self) -> x::Window { self.window().window_id } } impl HasWindow for Window { fn window(&self) -> &Window { self } } impl> HasWindow for T { fn window(&self) -> &Window { &*self } } pub trait HasConnection { fn connection(&self) -> &Connection; fn get_setup(&self) -> &xcb::x::Setup { self.connection().0.get_setup() } fn send_request(&self, request: &R) -> R::Cookie { self.connection().0.send_request(request) } fn wait_for_reply(&self, cookie: C) -> xcb::Result { self.connection().0.wait_for_reply(cookie) } fn send_request_checked(&self, request: &R) -> xcb::VoidCookieChecked { self.connection().0.send_request_checked(request) } fn check_request(&self, cookie: xcb::VoidCookieChecked) -> xcb::ProtocolResult<()> { self.connection().0.check_request(cookie) } fn wait_for_event(&self) -> xcb::Result { self.connection().0.wait_for_event() } } impl HasConnection for Connection { fn connection(&self) -> &Connection { self } } impl HasConnection for T { fn connection(&self) -> &Connection { &self.display().connection } } pub trait HasDisplay { fn display(&self) -> &Display; fn atoms(&self) -> &Atoms { &self.display().atoms } } impl HasDisplay for Display { fn display(&self) -> &Display { self } } impl HasDisplay for T { fn display(&self) -> &Display { self.window().display.borrow() } } pub trait ConnectionExt: HasConnection { fn get_atom(&self, name: &[u8]) -> xcb::Result { let connection = self.connection(); let cookie = connection.send_request(&InternAtom { only_if_exists: true, name: name, }); Ok(connection.wait_for_reply(cookie)?.atom()) } fn get_atoms(&self) -> xcb::Result { let wm_protocols = self.get_atom(b"WM_PROTOCOLS")?; let wm_delete_window = self.get_atom(b"WM_DELETE_WINDOW")?; let wm_type = self.get_atom(b"_NET_WM_WINDOW_TYPE")?; let wm_type_dock = self.get_atom(b"_NET_WM_WINDOW_TYPE_DOCK")?; let wm_strut = self.get_atom(b"_NET_WM_STRUT")?; let wm_strut_partial = self.get_atom(b"_NET_WM_STRUT_PARTIAL")?; Ok(Atoms { wm_protocols, wm_delete_window, wm_type, wm_type_dock, wm_strut, wm_strut_partial, }) } } impl ConnectionExt for T { } pub trait DisplayExt: HasDisplay + HasConnection { fn screen(&self) -> &Screen { let setup = self.connection().get_setup(); let screen_index = self.display().screen_index() as usize; &setup.roots().nth(screen_index).unwrap() } } impl DisplayExt for T { } pub trait WindowExt: HasWindow + HasDisplay + HasConnection { fn map_window(&self) -> xcb::Result<()> { let cookie = self.send_request_checked(&MapWindow { window: self.window_id() }); self.check_request(cookie)?; Ok(()) } fn set_string_property(&self, property: &Atom, value: &[u8]) -> xcb::Result<()> { let connection = self.connection(); let cookie = connection.send_request_checked(&ChangeProperty { mode: PropMode::Replace, window: self.window_id(), property: *property, r#type: x::ATOM_STRING, data: value, }); connection.check_request(cookie)?; Ok(()) } fn set_atom_property(&self, property: &Atom, values: &[Atom]) -> xcb::Result<()> { let connection = self.connection(); let cookie = connection.send_request_checked(&ChangeProperty { mode: PropMode::Replace, window: self.window_id(), property: *property, r#type: x::ATOM_ATOM, data: values, }); connection.check_request(cookie)?; Ok(()) } fn set_cardinal_property(&self, property: &Atom, values: &[u32]) -> xcb::Result<()> { let connection = self.connection(); let cookie = connection.send_request_checked(&ChangeProperty { mode: PropMode::Replace, window: self.window_id(), property: *property, r#type: x::ATOM_CARDINAL, data: values, }); connection.check_request(cookie)?; Ok(()) } } impl WindowExt for T { }