First dwm
This commit is contained in:
parent
bf2d6651de
commit
f05b8d8766
5
.gitignore
vendored
5
.gitignore
vendored
@ -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
|
||||
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "rwm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
183
src/main.rs
Normal file
183
src/main.rs
Normal file
@ -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<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Client {
|
||||
win: Window,
|
||||
name: String,
|
||||
floating: bool,
|
||||
tags: u32,
|
||||
geometry: Rectangle,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Monitor {
|
||||
id: usize,
|
||||
clients: Vec<Client>,
|
||||
layout: Layout,
|
||||
// Add more monitor properties
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Layout {
|
||||
Tiled,
|
||||
Floating,
|
||||
Monocle,
|
||||
}
|
||||
|
||||
struct DwmState {
|
||||
conn: XCBConnection,
|
||||
screen_num: usize,
|
||||
root: Window,
|
||||
clients: HashMap<Window, Client>,
|
||||
monitors: Vec<Monitor>,
|
||||
// Add more state properties
|
||||
}
|
||||
|
||||
impl DwmState {
|
||||
fn new() -> Result<Self> {
|
||||
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<dyn std::error::Error>)?;
|
||||
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()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user