diff options
author | tcmal <me@aria.rip> | 2024-06-03 18:06:04 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-06-03 18:06:04 +0100 |
commit | c50e0ef424975e73d770ad5a4cc873abf2cb6a28 (patch) | |
tree | 2024c09efbae05f8b7c613ac67497b8c39ec7bbd | |
parent | dc8094726026c5b56b5600f95da8475561b1073d (diff) |
cursors & scaffolding event handling
-rw-r--r-- | src/cursors.rs | 53 | ||||
-rw-r--r-- | src/main.rs | 57 |
2 files changed, 102 insertions, 8 deletions
diff --git a/src/cursors.rs b/src/cursors.rs new file mode 100644 index 0000000..1e5fbd3 --- /dev/null +++ b/src/cursors.rs @@ -0,0 +1,53 @@ +use crate::Result; +use xcb::{ + x::{CreateGlyphCursor, Cursor, Font, OpenFont}, + Connection, +}; + +// https://tronche.com/gui/x/xlib/appendix/b/ +const XC_LEFT_PTR: u16 = 68; + +#[derive(Debug)] +pub struct Cursors { + font: Font, + + pub normal: Cursor, + // TODO: ... +} + +impl Cursors { + pub fn new_with(conn: &Connection) -> Result<Self> { + // Open cursor font + let font = conn.generate_id(); + conn.check_request(conn.send_request_checked(&OpenFont { + fid: font, + name: "cursor".as_bytes(), + }))?; + + Ok(Self { + normal: Self::load_cursor(conn, font, XC_LEFT_PTR)?, + font, + }) + } + + /// Load the cursor with the given id from `font` + fn load_cursor(conn: &Connection, font: Font, id: u16) -> Result<Cursor> { + let cid = conn.generate_id(); + // https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/Cursor.c#L34 + conn.check_request(conn.send_request_checked(&CreateGlyphCursor { + cid, + source_font: font, + mask_font: font, + source_char: id, + mask_char: id + 1, + fore_red: 0, + fore_green: 0, + fore_blue: 0, + back_red: u16::MAX, + back_green: u16::MAX, + back_blue: u16::MAX, + }))?; + + Ok(cid) + } +} diff --git a/src/main.rs b/src/main.rs index ea42009..adacdfd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,15 @@ use atoms::InternedAtoms; use clients::ClientList; +use cursors::Cursors; use thiserror::Error; use xcb::{ - x::{self, ChangeWindowAttributes, Screen, Window}, + x::{self, ChangeWindowAttributes, Window}, Connection, Extension, }; mod atoms; mod clients; +mod cursors; type Result<T, E = Error> = std::result::Result<T, E>; @@ -22,6 +24,9 @@ pub enum Error { #[error("connection error: {0}")] ConnectionError(#[from] xcb::ConnError), + #[error("protocol error: {0}")] + ProtocolError(#[from] xcb::ProtocolError), + #[error("generic xcb error: {0}")] XCBError(#[from] xcb::Error), } @@ -47,6 +52,8 @@ struct WM<'a> { root: Window, clients: ClientList, + + cursors: Cursors, atoms: InternedAtoms, } @@ -60,19 +67,18 @@ impl WM<'_> { .ok_or(Error::NoSuchScreen)?; // Check no other WM is running - let cookie = conn.send_request_checked(&ChangeWindowAttributes { + conn.check_request(conn.send_request_checked(&ChangeWindowAttributes { window: screen.root(), value_list: &[ x::Cw::BackPixel(screen.white_pixel()), x::Cw::EventMask(x::EventMask::SUBSTRUCTURE_REDIRECT), ], - }); - - conn.check_request(cookie) - .map_err(|_| Error::OtherWMRunning)?; + })) + .map_err(|_| Error::OtherWMRunning)?; Ok(WM { atoms: InternedAtoms::new_with(conn)?, + cursors: Cursors::new_with(conn)?, clients: Default::default(), conn, screen_num, @@ -80,11 +86,46 @@ impl WM<'_> { }) } - fn event_loop(&mut self) -> Result<()> { - self.update_geometry()?; + fn setup_root(&self) -> Result<()> { + // TODO: set wm properties + self.conn + .check_request(self.conn.send_request_checked(&ChangeWindowAttributes { + window: self.root, + value_list: &[ + x::Cw::EventMask( + x::EventMask::SUBSTRUCTURE_REDIRECT + | x::EventMask::SUBSTRUCTURE_NOTIFY + | x::EventMask::BUTTON_PRESS + | x::EventMask::POINTER_MOTION + | x::EventMask::ENTER_WINDOW + | x::EventMask::LEAVE_WINDOW + | x::EventMask::STRUCTURE_NOTIFY + | x::EventMask::PROPERTY_CHANGE, + ), + x::Cw::Cursor(self.cursors.normal), + ], + }))?; + + // TODO: grab keys + + // TODO: reset focus Ok(()) } + + fn event_loop(&mut self) -> Result<()> { + self.update_geometry()?; + self.setup_root()?; + + loop { + match self.conn.wait_for_event()? { + e => { + dbg!(e); + // TODO: actually deal with events + } + }; + } + } } fn cleanup_process_children() { // todo: dont transform children into zombies when they terminate |