From 4388695d7c14df7fbdb49ab235d38f7ba008921a Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Wed, 11 Nov 2026 08:39:19 -0700 Subject: many traits Force-Push: yes Change-Id: I311da368db44745f72897bf64b20bb92deba7033 --- src/main.rs | 394 ++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 267 insertions(+), 127 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index c8bb422..c80fdb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,194 @@ -use xcb::{ Connection, Xid }; +use std::borrow::Borrow; +use std::sync::Arc; +use std::ops::Deref; + +use xcb::{ Xid }; use xcb::x::{ self, Atom, ChangeProperty, - ClientMessageData, ClientMessageEvent, + ClientMessageData, Cw, CreateWindow, - Event, EventMask, InternAtom, MapWindow, PropMode, Screen, - SendEvent, SendEventDest, - Window, WindowClass + WindowClass }; +struct Connection(xcb::Connection); + +struct Display { + connection: Connection, + screen_index: i32, + atoms: Atoms, +} + +struct Window { + display: Arc, + window_id: x::Window, +} + + +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 } +} + + +trait HasConnection { + fn connection(&self) -> &Connection; +} + +impl HasConnection for Connection { + fn connection(&self) -> &Connection { self } +} + +impl HasConnection for T { + fn connection(&self) -> &Connection { &self.display().connection } +} + + +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() } +} + + +trait ConnectionExt: HasConnection { + fn get_atom(&self, name: &[u8]) -> xcb::Result { + let connection = self.connection(); + + let cookie = connection.0.send_request(&InternAtom { + only_if_exists: true, + name: name, + }); + + Ok(connection.0.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 { } + + +trait DisplayExt: HasDisplay + HasConnection { + fn screen(&self) -> &Screen { + let setup = self.connection().0.get_setup(); + let screen_index = self.display().screen_index as usize; + + &setup.roots().nth(screen_index).unwrap() + } +} + +impl DisplayExt for T { } + + +trait WindowExt: HasWindow + HasDisplay + HasConnection { + fn map_window(&self) -> xcb::Result<()> { + let display = self.display(); + + let cookie = display.connection.0.send_request_checked(&MapWindow { + window: self.window_id() + }); + display.connection.0.check_request(cookie)?; + + Ok(()) + } + + fn set_string_property(&self, property: &Atom, value: &[u8]) + -> xcb::Result<()> + { + let connection = self.connection(); + + let cookie = connection.0.send_request_checked(&ChangeProperty { + mode: PropMode::Replace, + window: self.window_id(), + property: *property, + r#type: x::ATOM_STRING, + data: value, + }); + connection.0.check_request(cookie)?; + + Ok(()) + } + + + fn set_atom_property(&self, property: &Atom, values: &[Atom]) + -> xcb::Result<()> + { + let connection = self.connection(); + + let cookie = connection.0.send_request_checked(&ChangeProperty { + mode: PropMode::Replace, + window: self.window_id(), + property: *property, + r#type: x::ATOM_ATOM, + data: values, + }); + connection.0.check_request(cookie)?; + + Ok(()) + } + + + fn set_cardinal_property(&self, property: &Atom, values: &[u32]) + -> xcb::Result<()> + { + let connection = self.connection(); + + let cookie = connection.0.send_request_checked(&ChangeProperty { + mode: PropMode::Replace, + window: self.window_id(), + property: *property, + r#type: x::ATOM_CARDINAL, + data: values, + }); + connection.0.check_request(cookie)?; + + Ok(()) + } +} + +impl WindowExt for T { } + + struct Atoms { wm_protocols: Atom, wm_delete_window: Atom, @@ -25,6 +198,7 @@ struct Atoms { wm_strut_partial: Atom, } + #[derive(Clone, Copy, PartialEq, Eq)] enum ScreenSide { Top, Bottom, Left, Right } @@ -33,6 +207,16 @@ struct DockConfiguration { side: ScreenSide, } +struct Dock { + configuration: DockConfiguration, + window: Window, +} + +impl HasWindow for Dock { + fn window(&self) -> &Window { &self.window } +} + + #[derive(Debug)] struct Rectangle { left: T, @@ -42,69 +226,56 @@ struct Rectangle { } -fn main() -> xcb::Result<()> { - let (connection, screen_index) = Connection::connect(None)?; - - let atoms = get_atoms(&connection)?; +impl Display { + fn new() -> xcb::Result { + let (connection, screen_index) = xcb::Connection::connect(None)?; + let connection = Connection(connection); - let setup = connection.get_setup(); - let screen = setup.roots().nth(screen_index as usize).unwrap(); + let atoms = connection.get_atoms()?; - let dock_configuration = DockConfiguration { - thickness: 50, - side: ScreenSide::Bottom, - }; + Ok(Display { connection, screen_index, atoms }) + } +} - let dock_bounds = compute_dock_bounds(&screen, &dock_configuration); - let window: Window = connection.generate_id(); +impl Window { + fn new(display: Arc, create_window: &mut CreateWindow) + -> xcb::Result + { + let display_ref: &Display = display.borrow(); + let connection: &Connection = &display_ref.connection; - println!("{}x{}", screen.width_in_pixels(), screen.height_in_pixels()); - println!("dock {:?}", dock_bounds); + let window_id: x::Window = connection.0.generate_id(); - let cookie = connection.send_request_checked(&CreateWindow { - depth: x::COPY_FROM_PARENT as u8, - wid: window, - 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(screen.black_pixel()), - Cw::EventMask(EventMask::EXPOSURE | EventMask::BUTTON_PRESS), - ], - }); - connection.check_request(cookie)?; + create_window.wid = window_id; + let cookie = connection.0.send_request_checked(create_window); + connection.0.check_request(cookie)?; - set_string_property(&connection, &window, &x::ATOM_WM_NAME, b"grass bar")?; + Ok(Window { display, window_id }) + } +} - set_atom_property(&connection, &window, - &atoms.wm_protocols, &[atoms.wm_delete_window])?; - set_atom_property(&connection, &window, - &atoms.wm_type, &[atoms.wm_type_dock])?; - set_dock_strut_properties(&connection, &window, &atoms, &screen, - &dock_configuration)?; +fn main() -> xcb::Result<()> { + let display = Arc::new(Display::new()?); - let cookie = connection.send_request_checked(&MapWindow { window }); - connection.check_request(cookie)?; + let _dock = Dock::new(Arc::clone(&display), DockConfiguration { + thickness: 50, + side: ScreenSide::Bottom, + })?; loop { - match connection.wait_for_event()? { + match display.connection.0.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 == atoms.wm_delete_window.resource_id() { - break; - } - } + if let ClientMessageData::Data32([atom, ..]) = event.data() { + if atom == display.atoms.wm_delete_window.resource_id() { + break; + } + } } event => { println!("unknown event {:?}", event); } @@ -115,76 +286,46 @@ fn main() -> xcb::Result<()> { } -fn get_atom(connection: &Connection, name: &[u8]) -> xcb::Result { - let cookie = connection.send_request(&InternAtom { - only_if_exists: true, - name: name, - }); - - Ok(connection.wait_for_reply(cookie)?.atom()) -} - - -fn set_string_property(connection: &Connection, window: &Window, - property: &Atom, value: &[u8]) - -> xcb::Result<()> -{ - let cookie = connection.send_request_checked(&ChangeProperty { - mode: PropMode::Replace, - window: *window, - property: *property, - r#type: x::ATOM_STRING, - data: value, - }); - connection.check_request(cookie)?; - - Ok(()) -} - - -fn set_atom_property(connection: &Connection, window: &Window, property: &Atom, values: &[Atom]) -> xcb::Result<()> { - let cookie = connection.send_request_checked(&ChangeProperty { - mode: PropMode::Replace, - window: *window, - property: *property, - r#type: x::ATOM_ATOM, - data: values, - }); - connection.check_request(cookie)?; - - Ok(()) -} +impl Dock { + fn new(display: Arc, configuration: DockConfiguration) + -> xcb::Result + { + let screen = display.screen(); + let dock_bounds = compute_dock_bounds(&screen, &configuration); -fn set_cardinal_property(connection: &Connection, window: &Window, property: &Atom, values: &[u32]) -> xcb::Result<()> { - let cookie = connection.send_request_checked(&ChangeProperty { - mode: PropMode::Replace, - window: *window, - property: *property, - r#type: x::ATOM_CARDINAL, - data: values, - }); - connection.check_request(cookie)?; + 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(screen.black_pixel()), + Cw::EventMask(EventMask::EXPOSURE | EventMask::BUTTON_PRESS), + ], + })?; + let dock = Dock { window, configuration }; - Ok(()) -} + dock.set_string_property(&x::ATOM_WM_NAME, b"grass bar")?; + dock.set_atom_property(&display.atoms.wm_protocols, + &[display.atoms.wm_delete_window])?; -fn get_atoms(connection: &Connection) -> xcb::Result { - let wm_protocols = get_atom(&connection, b"WM_PROTOCOLS")?; - let wm_delete_window = get_atom(&connection, b"WM_DELETE_WINDOW")?; + dock.set_atom_property(&display.atoms.wm_type, + &[display.atoms.wm_type_dock])?; - let wm_type = get_atom(&connection, b"_NET_WM_WINDOW_TYPE")?; - let wm_type_dock = get_atom(&connection, b"_NET_WM_WINDOW_TYPE_DOCK")?; + set_dock_strut_properties(&dock, &screen)?; - let wm_strut = get_atom(&connection, b"_NET_WM_STRUT")?; - let wm_strut_partial = get_atom(&connection, b"_NET_WM_STRUT_PARTIAL")?; + dock.map_window()?; - Ok(Atoms { - wm_protocols, wm_delete_window, - wm_type, wm_type_dock, - wm_strut, wm_strut_partial, - }) + Ok(dock) + } } @@ -217,21 +358,21 @@ fn compute_dock_bounds(screen: &Screen, configuration: &DockConfiguration) } -fn set_dock_strut_properties(connection: &Connection, window: &Window, - atoms: &Atoms, screen: &Screen, - configuration: &DockConfiguration) +fn set_dock_strut_properties(dock: &Dock, screen: &Screen) -> xcb::Result<()> { - let thickness = configuration.thickness as u32; + let window = dock.window(); + let atoms = dock.atoms(); + + let thickness = dock.configuration.thickness as u32; - let strut_values = match configuration.side { + let strut_values = match dock.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], }; - println!("struts {:?}", strut_values); - set_cardinal_property(&connection, &window, &atoms.wm_strut, strut_values)?; + window.set_cardinal_property(&atoms.wm_strut, strut_values)?; let strut_partial_values = &[ strut_values[0], @@ -240,29 +381,28 @@ fn set_dock_strut_properties(connection: &Connection, window: &Window, strut_values[3], 0 as u32, - if configuration.side == ScreenSide::Left { + if dock.configuration.side == ScreenSide::Left { screen.height_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, - if configuration.side == ScreenSide::Right { + if dock.configuration.side == ScreenSide::Right { screen.height_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, - if configuration.side == ScreenSide::Top { + if dock.configuration.side == ScreenSide::Top { screen.width_in_pixels() as u32 } else { 0 as u32 }, 0 as u32, - if configuration.side == ScreenSide::Bottom { + if dock.configuration.side == ScreenSide::Bottom { screen.width_in_pixels() as u32 } else { 0 as u32 }, ]; - println!("partial {:?}", strut_partial_values); - set_cardinal_property(&connection, &window, &atoms.wm_strut_partial, - strut_partial_values)?; + window.set_cardinal_property(&atoms.wm_strut_partial, + strut_partial_values)?; Ok(()) } -- cgit 1.4.1