summary refs log tree commit diff
path: root/src/xtypes.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-11-11 09:25:10 -0700
committerIrene Knapp <ireneista@irenes.space>2026-11-11 09:25:10 -0700
commitcc1bed1f1f3e26a6a00b292ace94b6991c181ff9 (patch)
treed4a221e86b12e66f99e6355de7ac9e8aa0e9da3d /src/xtypes.rs
parent4388695d7c14df7fbdb49ab235d38f7ba008921a (diff)
now it's in two files
Force-Push: yes
Change-Id: I43fdbd0769fa61ef4e5d6ea053fa210175e47d6a
Diffstat (limited to 'src/xtypes.rs')
-rw-r--r--src/xtypes.rs269
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 { }
+