summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-06-03 18:06:04 +0100
committertcmal <me@aria.rip>2024-06-03 18:06:04 +0100
commitc50e0ef424975e73d770ad5a4cc873abf2cb6a28 (patch)
tree2024c09efbae05f8b7c613ac67497b8c39ec7bbd
parentdc8094726026c5b56b5600f95da8475561b1073d (diff)
cursors & scaffolding event handling
-rw-r--r--src/cursors.rs53
-rw-r--r--src/main.rs57
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