From f05b8d87666da4f924eb414f02e69764ec434cc2 Mon Sep 17 00:00:00 2001 From: BitHeaven Date: Sat, 15 Mar 2025 22:03:13 +0500 Subject: [PATCH] First dwm --- .gitignore | 5 ++ Cargo.toml | 6 ++ src/main.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index ab951f8..620f8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,8 @@ Cargo.lock # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + + +# Added by cargo + +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..04d862f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rwm" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5e291db --- /dev/null +++ b/src/main.rs @@ -0,0 +1,183 @@ +use x11rb::connection::Connection; +use x11rb::protocol::xproto::*; +use x11rb::wrapper::ConnectionExt; +use x11rb::errors::ConnectionError; +use std::collections::HashMap; + +type Result = std::result::Result>; + +#[derive(Debug, Clone)] +struct Client { + win: Window, + name: String, + floating: bool, + tags: u32, + geometry: Rectangle, +} + +#[derive(Debug)] +struct Monitor { + id: usize, + clients: Vec, + layout: Layout, + // Add more monitor properties +} + +#[derive(Debug)] +enum Layout { + Tiled, + Floating, + Monocle, +} + +struct DwmState { + conn: XCBConnection, + screen_num: usize, + root: Window, + clients: HashMap, + monitors: Vec, + // Add more state properties +} + +impl DwmState { + fn new() -> Result { + let (conn, screen_num) = XCBConnection::connect(None)?; + let screen = &conn.setup().roots[screen_num]; + + Ok(Self { + conn, + screen_num, + root: screen.root, + clients: HashMap::new(), + monitors: vec![Monitor { + id: 0, + clients: vec![], + layout: Layout::Tiled, + }], + }) + } + + fn setup(&self) -> Result<()> { + // Set up window manager properties + self.conn.change_window_attributes( + self.root, + &ChangeWindowAttributesAux::default() + .event_mask(EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY), + )?; + + self.grab_keys()?; + Ok(()) + } + + fn grab_keys(&self) -> Result<()> { + // Example key grab (Alt+Return) + let keysym = x11rb::keysym::XK_Return; + let modifier = ModMask::MOD1; + + self.conn.grab_key( + true, + self.root, + modifier, + keysym, + GrabMode::ASYNC, + GrabMode::ASYNC, + )?; + + Ok(()) + } + + fn handle_event(&mut self, event: x11rb::protocol::Event) -> Result<()> { + match event { + Event::MapRequest(event) => self.handle_map_request(event.window), + Event::ConfigureRequest(event) => self.handle_configure_request(event), + Event::KeyPress(event) => self.handle_key_press(event.detail, event.state), + _ => Ok(()), + } + } + + fn handle_map_request(&mut self, window: Window) -> Result<()> { + // Create new client + let geometry = self.conn.get_geometry(window)?.reply()?; + let client = Client { + win: window, + name: String::new(), + floating: false, + tags: 1, + geometry: Rectangle { + x: 0, + y: 0, + width: geometry.width, + height: geometry.height, + }, + }; + + self.clients.insert(window, client.clone()); + self.monitors[0].clients.push(client); + self.conn.map_window(window)?; + self.arrange_windows() + } + + fn handle_configure_request(&mut self, event: ConfigureRequestEvent) -> Result<()> { + // Handle window configuration requests + let mut values = ConfigureWindowAux::new() + .x(event.x as i32) + .y(event.y as i32) + .width(event.width) + .height(event.height); + + self.conn.configure_window(event.window, &values)?; + Ok(()) + } + + fn handle_key_press(&mut self, keycode: u8, state: u16) -> Result<()> { + // Handle key bindings + if state == ModMask::MOD1.into() { + match keycode { + 36 => self.spawn_terminal(), // Enter key + _ => (), + } + } + Ok(()) + } + + fn arrange_windows(&self) -> Result<()> { + // Simple tiling layout + let monitor = &self.monitors[0]; + let num_clients = monitor.clients.len(); + let width = 800 / num_clients as u16; // Simplified screen size + + for (i, client) in monitor.clients.iter().enumerate() { + let x = (i as u16) * width; + self.conn.configure_window( + client.win, + &ConfigureWindowAux::new() + .x(x as i32) + .y(0) + .width(width) + .height(600), + )?; + } + Ok(()) + } + + fn spawn_terminal(&self) -> Result<()> { + // Spawn a terminal using std::process + std::process::Command::new("x-terminal-emulator") + .spawn() + .map_err(|e| Box::new(e) as Box)?; + Ok(()) + } + + fn run(&mut self) -> Result<()> { + self.setup()?; + loop { + let event = self.conn.wait_for_event()?; + self.handle_event(event)?; + } + } +} + +fn main() -> Result<()> { + let mut dwm = DwmState::new()?; + dwm.run() +}