diff --git a/run.sh b/run.sh index ae9b608..6af8e00 100755 --- a/run.sh +++ b/run.sh @@ -9,4 +9,3 @@ xinit ./xinitrc -- \ -ac \ -screen 800x600 \ -host-cursor - diff --git a/src/main.rs b/src/main.rs index e0d87f5..654467d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![warn(clippy::pedantic)] use std::collections::HashMap; +//use std::sync::Rc; use breadx::{ prelude::{AsyncDisplayXprotoExt, MapState, SetMode}, @@ -9,8 +10,15 @@ use breadx::{ Event, EventMask, Window, }; +mod x11; + +use x11::client::XcrabClient; + +const BORDER_WIDTH: u16 = 5; +const GAP_WIDTH: u16 = 10; + #[derive(Debug)] // TODO: actually print good errors on failure -enum XcrabError { +pub enum XcrabError { Bread(BreadError), } @@ -43,8 +51,13 @@ async fn main() -> Result<(), XcrabError> { for &win in top_level_windows.iter() { let attrs = win.window_attributes_immediate_async(&mut conn).await?; + println!("a"); if !attrs.override_redirect && attrs.map_state == MapState::Viewable { - clients.insert(win, manage_window(&mut conn, win).await?); + clients.insert( + win, + XcrabClient::new(win, &mut conn, clients.len() + 1).await?, + ); + x11::client::calculate_geometry(&mut clients, &mut conn).await?; } } @@ -57,7 +70,11 @@ async fn main() -> Result<(), XcrabError> { Event::MapRequest(ev) => { let win = ev.window; - clients.insert(win, manage_window(&mut conn, win).await?); + clients.insert( + win, + XcrabClient::new(win, &mut conn, clients.len() + 1).await?, + ); + x11::client::calculate_geometry(&mut clients, &mut conn).await?; } Event::ConfigureRequest(ev) => { // cope from `ev` to `params` @@ -85,7 +102,7 @@ async fn main() -> Result<(), XcrabError> { Event::UnmapNotify(ev) => { if ev.event != root { if let Some(parent) = clients.get(&ev.window) { - parent.unmap_async(&mut conn).await?; + parent.parent.unmap_async(&mut conn).await?; ev.window.reparent_async(&mut conn, root, 0, 0).await?; @@ -94,7 +111,7 @@ async fn main() -> Result<(), XcrabError> { .change_save_set_async(&mut conn, SetMode::Delete) .await?; - parent.free_async(&mut conn).await?; + parent.parent.free_async(&mut conn).await?; clients.remove(&ev.window); } diff --git a/src/x11/client.rs b/src/x11/client.rs new file mode 100644 index 0000000..f0b3562 --- /dev/null +++ b/src/x11/client.rs @@ -0,0 +1,119 @@ +use breadx::prelude::{AsyncDisplayXprotoExt, Geometry, SetMode}; +use breadx::{AsyncDisplay, ConfigureWindowParameters, Window}; +use std::collections::HashMap; +use std::sync::Arc; + +pub struct XcrabClient { + geometry: XcrabGeometry, + position: usize, + pub parent: Window, +} + +#[derive(Debug)] +struct XcrabGeometry { + x: i16, + y: i16, + width: u16, + height: u16, +} + +impl XcrabClient { + pub async fn new( + window: Window, + dpy: &mut Dpy, + position: usize, + ) -> Result { + let geometry = window.geometry_immediate_async(dpy).await?; + + let root = dpy.default_root(); + let parent = dpy + .create_simple_window_async( + root, + geometry.x, + geometry.y, + geometry.width, + geometry.height, + crate::BORDER_WIDTH, + 0xff_00_00, + 0x00_00_00, + ) + .await?; + + Ok(XcrabClient { + geometry: XcrabGeometry { + x: geometry.x, + y: geometry.y, + width: geometry.width, + height: geometry.height, + }, + position, + parent, + }) + } + + pub fn update_geometry(&mut self, geometry: XcrabGeometry) { + self.geometry = geometry; + } +} + +pub async fn calculate_geometry( + windows: &mut HashMap, + dpy: &mut Dpy, +) -> Result<(), crate::XcrabError> { + let root = dpy.default_root(); + let root_geometry = root.geometry_immediate_async(dpy).await?; + let window_count = windows.len(); + + // let gap_width = crate::GAP_WIDTH as usize * (window_count + 1); + let width_per_window = root_geometry.width as usize / window_count; + let border_width = crate::BORDER_WIDTH as usize * 2; + + for (window, xcrab_client) in windows { + let xcrab_geometry = XcrabGeometry { + x: xcrab_client.position as i16 * width_per_window as i16, + y: xcrab_client.geometry.y, + width: (width_per_window - border_width) as u16, + height: xcrab_client.geometry.height, + }; + + xcrab_client.update_geometry(xcrab_geometry); + + window.change_save_set_async(dpy, SetMode::Insert).await?; + xcrab_client + .parent + .configure_async( + dpy, + ConfigureWindowParameters { + x: Some(xcrab_client.geometry.x.into()), + y: Some(xcrab_client.geometry.y.into()), + width: Some(xcrab_client.geometry.width.into()), + height: Some(xcrab_client.geometry.height.into()), + ..Default::default() + }, + ) + .await?; + + window + .configure_async( + dpy, + ConfigureWindowParameters { + width: Some(xcrab_client.geometry.width.into()), + height: Some(xcrab_client.geometry.height.into()), + ..Default::default() + }, + ) + .await?; + + window + .reparent_async(dpy, xcrab_client.parent, 0, 0) + .await?; + + xcrab_client.parent.map_async(dpy).await?; + + window.map_async(dpy).await?; + + println!("{:#?}", xcrab_client.geometry); + } + + Ok(()) +} diff --git a/src/x11/mod.rs b/src/x11/mod.rs new file mode 100644 index 0000000..b9babe5 --- /dev/null +++ b/src/x11/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/xinitrc b/xinitrc index f5fcefd..06e455c 100644 --- a/xinitrc +++ b/xinitrc @@ -5,4 +5,4 @@ xterm & sleep 2; -target/debug/xcrab \ No newline at end of file +target/debug/xcrab