configure requests and unmap notifications

This commit is contained in:
missing 2022-06-24 16:12:28 -05:00
parent 5bedd4c8e1
commit 9ce7c2a757
2 changed files with 94 additions and 57 deletions

View file

@ -1,8 +1,12 @@
#![warn(clippy::pedantic)]
use std::collections::HashMap;
use breadx::{
prelude::{AsyncDisplayXprotoExt, SetMode},
traits::DisplayBase,
AsyncDisplayConnection, AsyncDisplayExt, BreadError, ConfigureWindowParameters, Event,
EventMask, WindowClass,
EventMask, Window, AsyncDisplay,
};
#[derive(Debug)] // TODO: actually print good errors on failure
@ -23,73 +27,104 @@ async fn main() -> Result<(), XcrabError> {
let root = conn.default_root();
let substructure_redirect = EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY;
// listen for substructure redirects to intercept events like window creation
root.set_event_mask_async(&mut conn, substructure_redirect)
root.set_event_mask_async(&mut conn, EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY)
.await?;
let mut clients = HashMap::new();
loop {
let ev = conn.wait_for_event_async().await?;
match ev {
Event::MapRequest(ev) => {
// the client wishes for their window to be displayed. we must create a new
// window with a titlebar and reparent the old window to this new window.
let win = ev.window;
let geometry = win.geometry_immediate_async(&mut conn).await?;
// TODO: tiling window manager logic
let new_x = geometry.x;
let new_y = geometry.y;
let new_width = geometry.width;
let new_height = geometry.height;
let parent = conn
.create_simple_window_async(
root,
new_x,
new_y,
new_width,
new_height,
3,
0xff0000,
0x000000,
)
.await?;
parent
.set_event_mask_async(&mut conn, substructure_redirect)
.await?;
win.change_save_set_async(&mut conn, SetMode::Insert)
.await?;
// tell the window what size we made it
win.configure_async(
&mut conn,
ConfigureWindowParameters {
width: Some(new_width.into()),
height: Some(new_height.into()),
..Default::default()
},
)
.await?;
win.reparent_async(&mut conn, parent, 0, 0).await?;
parent.map_async(&mut conn).await?;
win.map_async(&mut conn).await?;
clients.insert(ev.window, manage_window(&mut conn, ev.window).await?);
}
Event::ConfigureRequest(ev) => {
}
// cope from `ev` to `params`
let mut params = ConfigureWindowParameters {
x: Some(ev.x.into()),
y: Some(ev.y.into()),
width: Some(ev.width.into()),
height: Some(ev.height.into()),
border_width: Some(ev.border_width.into()),
sibling: Some(ev.sibling),
stack_mode: Some(ev.stack_mode),
};
// if this is a client, deny changing position or size (we are a tiling wm!)
if clients.contains_key(&ev.window) {
params.x = None;
params.y = None;
params.width = None;
params.height = None;
}
// forward the request
ev.window.configure_async(&mut conn, params).await?;
},
Event::UnmapNotify(ev) => {
if let Some(parent) = clients.get(&ev.window) {
parent.unmap_async(&mut conn).await?;
ev.window.reparent_async(&mut conn, root, 0, 0).await?;
// no longer related to us, remove from save set
ev.window.change_save_set_async(&mut conn, SetMode::Delete).await?;
parent.free_async(&mut conn).await?;
clients.remove(&ev.window);
}
},
_ => {}
}
}
Ok(())
}
async fn manage_window<Dpy: AsyncDisplay + ?Sized>(conn: &mut Dpy, win: Window) -> Result<Window, XcrabError> {
// the client wishes for their window to be displayed. we must create a new
// window with a titlebar and reparent the old window to this new window.
let root = conn.default_root();
let geometry = win.geometry_immediate_async(conn).await?;
// TODO: tiling window manager logic
let new_x = geometry.x;
let new_y = geometry.y;
let new_width = geometry.width;
let new_height = geometry.height;
let parent = conn
.create_simple_window_async(
root, new_x, new_y, new_width, new_height, 3, 0xff_00_00, 0x00_00_00,
)
.await?;
parent
.set_event_mask_async(conn, EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY)
.await?;
win.change_save_set_async(conn, SetMode::Insert)
.await?;
// tell the window what size we made it
win.configure_async(
conn,
ConfigureWindowParameters {
width: Some(new_width.into()),
height: Some(new_height.into()),
..Default::default()
},
)
.await?;
win.reparent_async(conn, parent, 0, 0).await?;
parent.map_async(conn).await?;
win.map_async(conn).await?;
Ok(parent)
}

View file

@ -1,3 +1,5 @@
#!/bin/sh
target/debug/xcrab &
sleep 0.15;