Diff
diff --git a/readme.org b/readme.org
index 2b378cd..1f53c3d 100644
--- a/readme.org
+++ b/readme.org
@@ -1,7 +1,7 @@
#+AUTHOR: Tony
#+STARTUP: overview
-* OxWM β Oxidize Window Manager
+* OXWM β DWM but Better (and oxidized)
A dynamic window manager written in /Rustπ¦/, inspired by dwm but designed to evolve
on its own. Configuration is done in Rust source code, keeping with the suckless
philosophy of *"edit + recompile."*
@@ -24,7 +24,7 @@ nix develop
cargo build
#+end_src
-* π§ͺ Running Tests with just
+* Testing Xephyr with Justfile
The =justfile= includes a =test= recipe that starts Xephyr on =:1=, launches
test clients (xterm, xclock), and runs oxwm in the foreground.
@@ -36,24 +36,55 @@ just test
This should open a new Xephyr window. oxwm will attach to it and log X11
events in your host terminal. Clients like xterm/xclock will appear inside Xephyr.
-* πΊ Roadmap (High Level)
-| Step | Task | Status |
-|------+---------------------------------------------------------------------------------------+--------|
-| 1 | Connect to X, claim =SubstructureRedirect=, print events | DONE |
-| 2 | Handle =MapRequest= and =ConfigureRequest= so clients can map and appear in Xephyr | β³ |
-| 3 | Implement client tracking and a trivial tiling layout | β |
-| 4 | Add keybindings (Mod+j/k, Mod+Enter, etc.) | β |
-| 5 | Per-tag state, multiple layouts, borders, focus handling | β |
-| 6 | ICCCM/EWMH basics (WM_DELETE_WINDOW, fullscreen, etc) | β |
-| 7 | Split into =oxwm-core= library and =oxwm-user= config crate | β |
-| 8 | Polish developer workflow (Nix flake, just, docs) | β |
-
-* π Status
+* OXWM Todo List:
+** Reorganization Tasks
+- [ ] Move keyboard module to folder structure:
+ - [ ] Create =src/keyboard/mod.rs= with re-exports
+ - [ ] Move constants to =src/keyboard/keycodes.rs=
+ - [ ] Move key handlers to =src/keyboard/handlers.rs=
+ - [ ] Update imports in main.rs and window_manager.rs
+- [ ] Create =src/config.rs= in root directory for future configuration system
+
+** Core Window Management
+- [ ] Fix layout after program is closed (handle UnmapNotify events)
+ - [ ] Add UnmapNotify to event handling
+ - [ ] Remove closed windows from windows vector
+ - [ ] Re-apply layout after window removal
+- [ ] Add keybind to swap focus between windows
+ - [ ] Track focused window in WindowManager struct
+ - [ ] Implement focus cycling logic
+ - [ ] Add visual focus indication (borders/colors)
+
+** Key System Improvements
+- [ ] Connect config.rs to keyboard system for dynamic keybind generation
+- [ ] Add more dwm-like keybinds:
+ - [ ] Window focus switching (Alt+J/K)
+ - [ ] Master area resizing
+ - [ ] Layout switching
+ - [ ] Workspace/tag management
+- [ ] Better error handling for failed key grabs
+
+** Layout System
+- [ ] Add more layout types (monocle, floating)
+- [ ] Handle window resize requests properly
+- [ ] Add configurable gaps between windows
+- [ ] Implement layout switching keybinds
+
+** Polish & Features
+- [ ] Clean window destruction/cleanup
+- [ ] Handle edge cases (empty window list, invalid windows)
+- [ ] Add status bar integration
+- [ ] Better error messages and logging
+
+** Priority
+Reorganization and UnmapNotify handling should be immediate priorities.
+
+* Status
- Rust + x11rb skeleton running
- Nix flake devShell available
- =just test= launches Xephyr, clients, and oxwm
-* π License
+* License
[[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL]]
diff --git a/src/keyboard.rs b/src/keyboard.rs
new file mode 100644
index 0000000..f1508e2
--- /dev/null
+++ b/src/keyboard.rs
@@ -0,0 +1,28 @@
+// wip
+pub const RETURN: u8 = 36;
+pub const Q: u8 = 24;
+pub const ESCAPE: u8 = 9;
+pub const SPACE: u8 = 65;
+pub const TAB: u8 = 23;
+pub const BACKSPACE: u8 = 22;
+pub const DELETE: u8 = 119;
+
+// Function keys
+pub const F1: u8 = 67;
+pub const F2: u8 = 68;
+pub const F3: u8 = 69;
+pub const F4: u8 = 70;
+
+// Letters (assuming QWERTY)
+pub const A: u8 = 38;
+pub const S: u8 = 39;
+pub const D: u8 = 40;
+pub const F: u8 = 41;
+pub const J: u8 = 44;
+pub const K: u8 = 45;
+pub const L: u8 = 46;
+
+// Numbers
+pub const KEY_1: u8 = 10;
+pub const KEY_2: u8 = 11;
+pub const KEY_3: u8 = 12;
diff --git a/src/keys.rs b/src/keys.rs
new file mode 100644
index 0000000..af2a0bf
--- /dev/null
+++ b/src/keys.rs
@@ -0,0 +1,55 @@
+use crate::keyboard;
+use anyhow::Result;
+use x11rb::connection::Connection;
+use x11rb::protocol::xproto::*;
+
+pub fn setup_keybinds(connection: &impl Connection, root: Window) -> Result<()> {
+ connection.grab_key(
+ false,
+ root,
+ ModMask::M4.into(),
+ keyboard::RETURN,
+ GrabMode::ASYNC,
+ GrabMode::ASYNC,
+ )?;
+ connection.grab_key(
+ false,
+ root,
+ (ModMask::M1 | ModMask::SHIFT).into(),
+ keyboard::Q,
+ GrabMode::ASYNC,
+ GrabMode::ASYNC,
+ )?;
+
+ connection.grab_key(
+ false,
+ root,
+ ModMask::M4.into(),
+ keyboard::Q,
+ GrabMode::ASYNC,
+ GrabMode::ASYNC,
+ )?;
+
+ Ok(())
+}
+
+pub fn handle_key_press(connection: &impl Connection, event: KeyPressEvent) -> Result<()> {
+ println!("KeyPress: detail={}, state={:?}", event.detail, event.state);
+
+ match (event.detail, event.state) {
+ (keyboard::RETURN, state) if state.contains(KeyButMask::MOD1) => {
+ println!("Spawning terminal");
+ std::process::Command::new("xterm").spawn()?;
+ }
+ (keyboard::Q, state) if state.contains(KeyButMask::MOD1 | KeyButMask::SHIFT) => {
+ println!("Closing focused window");
+ let focus_reply = connection.get_input_focus()?.reply()?;
+ if focus_reply.focus != x11rb::NONE && focus_reply.focus != event.root {
+ connection.kill_client(focus_reply.focus)?;
+ connection.flush()?;
+ }
+ }
+ _ => {}
+ }
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index 938a384..96967ce 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,6 @@
use anyhow::Result;
+mod keyboard;
+mod keys;
mod layout;
mod window_manager;
diff --git a/src/window_manager.rs b/src/window_manager.rs
index dded7e3..f63758c 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -1,3 +1,4 @@
+use crate::keys;
use crate::layout::Layout;
use crate::layout::tiling::TilingLayout;
@@ -11,6 +12,7 @@ use x11rb::rust_connection::RustConnection;
pub struct WindowManager {
connection: RustConnection,
screen_number: usize,
+ root: Window,
screen: Screen,
windows: Vec<Window>,
layout: Box<dyn Layout>,
@@ -28,7 +30,8 @@ impl WindowManager {
&ChangeWindowAttributesAux::new().event_mask(
EventMask::SUBSTRUCTURE_REDIRECT
| EventMask::SUBSTRUCTURE_NOTIFY
- | EventMask::PROPERTY_CHANGE,
+ | EventMask::PROPERTY_CHANGE
+ | EventMask::KEY_PRESS,
),
)?
.check()?;
@@ -36,6 +39,7 @@ impl WindowManager {
return Ok(Self {
connection,
screen_number,
+ root,
screen,
windows: Vec::new(),
layout: Box::new(TilingLayout),
@@ -45,6 +49,8 @@ impl WindowManager {
pub fn run(&mut self) -> Result<()> {
println!("oxwm started on display {}", self.screen_number);
+ keys::setup_keybinds(&self.connection, self.root)?;
+
loop {
let event = self.connection.wait_for_event()?;
println!("event: {:?}", event);
@@ -65,6 +71,10 @@ impl WindowManager {
)?;
self.connection.flush()?;
}
+ Event::KeyPress(event) => {
+ println!("KeyPress event received!");
+ keys::handle_key_press(&self.connection, event)?;
+ }
_ => {}
}
return Ok(());