diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-11-11 09:25:10 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-11-11 09:25:10 -0700 |
| commit | cc1bed1f1f3e26a6a00b292ace94b6991c181ff9 (patch) | |
| tree | d4a221e86b12e66f99e6355de7ac9e8aa0e9da3d /src/xtypes.rs | |
| parent | 4388695d7c14df7fbdb49ab235d38f7ba008921a (diff) | |
now it's in two files
Force-Push: yes Change-Id: I43fdbd0769fa61ef4e5d6ea053fa210175e47d6a
Diffstat (limited to 'src/xtypes.rs')
| -rw-r--r-- | src/xtypes.rs | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/xtypes.rs b/src/xtypes.rs new file mode 100644 index 0000000..3f67e58 --- /dev/null +++ b/src/xtypes.rs @@ -0,0 +1,269 @@ +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<Display>, + 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<Display> { + 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<Display>, create_window: &mut CreateWindow) + -> xcb::Result<Window> + { + 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<T: Deref<Target=Window>> 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<R: xcb::Request>(&self, request: &R) -> R::Cookie { + self.connection().0.send_request(request) + } + + fn wait_for_reply<C: xcb::CookieWithReplyChecked>(&self, cookie: C) + -> xcb::Result<C::Reply> + { + self.connection().0.wait_for_reply(cookie) + } + + fn send_request_checked<R: xcb::RequestWithoutReply>(&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<xcb::Event> { + self.connection().0.wait_for_event() + } +} + +impl HasConnection for Connection { + fn connection(&self) -> &Connection { self } +} + +impl<T: HasDisplay> 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<T: HasWindow> HasDisplay for T { + fn display(&self) -> &Display { self.window().display.borrow() } +} + + +pub trait ConnectionExt: HasConnection { + fn get_atom(&self, name: &[u8]) -> xcb::Result<Atom> { + 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<Atoms> { + 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<T: HasConnection> 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<T: HasDisplay + HasConnection> 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<T: HasWindow + HasDisplay + HasConnection> WindowExt for T { } + |