From 204518016bbf3552116f52ed416199aea0adfc86 Mon Sep 17 00:00:00 2001 From: missing <4a656666official@gmail.com> Date: Sun, 26 Jun 2022 13:40:34 -0500 Subject: [PATCH] config stuff --- run.sh | 2 +- src/config.rs | 20 +++-- src/x11/client.rs | 186 ++++++++++++++++++++++++++++++---------------- xinitrc | 2 +- 4 files changed, 137 insertions(+), 73 deletions(-) diff --git a/run.sh b/run.sh index 6af8e00..34f2c46 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,6 @@ #!/bin/sh -cargo build; +cargo build || exit; XEPHYR=$(which Xephyr | cut -f2 -d' ') xinit ./xinitrc -- \ diff --git a/src/config.rs b/src/config.rs index fbbac13..c90e925 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,30 +7,34 @@ use serde::{Deserialize, Serialize}; pub struct XcrabConfig { border_color: Option, border_size: Option, - gap_width: Option, + gap_size: Option, } +const DEFAULT_BORDER_COLOR: u32 = 0xff_00_00; // red +const DEFAULT_BORDER_SIZE: u16 = 5; +const DEFAULT_GAP_SIZE: u16 = 10; + impl Default for XcrabConfig { fn default() -> Self { Self { - border_color: Some(0xff_00_00), // red - border_size: Some(5), - gap_width: Some(10), + border_color: Some(DEFAULT_BORDER_COLOR), + border_size: Some(DEFAULT_BORDER_SIZE), + gap_size: Some(DEFAULT_GAP_SIZE), } } } impl XcrabConfig { pub fn border_color(&self) -> u32 { - self.border_color.unwrap_or(0xff_00_00) + self.border_color.unwrap_or(DEFAULT_BORDER_COLOR) } pub fn border_size(&self) -> u16 { - self.border_size.unwrap_or(5) + self.border_size.unwrap_or(DEFAULT_BORDER_SIZE) } - pub fn gap_width(&self) -> u16 { - self.gap_width.unwrap_or(10) + pub fn gap_size(&self) -> u16 { + self.gap_size.unwrap_or(DEFAULT_GAP_SIZE) } } diff --git a/src/x11/client.rs b/src/x11/client.rs index 56ee72c..9895af6 100644 --- a/src/x11/client.rs +++ b/src/x11/client.rs @@ -2,7 +2,7 @@ use breadx::prelude::{AsyncDisplayXprotoExt, SetMode}; use breadx::{AsyncDisplay, ConfigureWindowParameters, EventMask, Window}; use std::collections::HashMap; -use crate::{Result, XcrabError}; +use crate::{Result, XcrabError, CONFIG}; #[derive(Debug, Clone, Copy)] pub enum Direction { @@ -23,6 +23,12 @@ pub struct XcrabWindowManager { #[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, Copy)] struct XcrabClient { + frame: FramedWindow, + geo: XcrabGeometry, +} + +#[derive(Debug, Clone, Copy)] +struct XcrabGeometry { x: u32, y: u32, width: u32, @@ -51,6 +57,7 @@ impl XcrabWindowManager { let frame = frame(conn, win).await?; if let Some(focused) = self.focused { + #[allow(clippy::enum_glob_use)] use Direction::*; let focused_client = *self @@ -60,10 +67,10 @@ impl XcrabWindowManager { let new_client = match direction { Up | Down => { - if focused_client.height % 2 == 1 { + if focused_client.geo.height % 2 == 1 { for client in self.clients.values_mut() { - client.y *= 2; - client.height *= 2; + client.geo.y *= 2; + client.geo.height *= 2; } self.grid_height *= 2; @@ -71,24 +78,24 @@ impl XcrabWindowManager { let focused_client = self.clients.get_mut(&focused).unwrap(); - focused_client.height /= 2; - let height = focused_client.height; + focused_client.geo.height /= 2; + let height = focused_client.geo.height; - let mut new_client = *focused_client; + let mut new_client = XcrabClient { frame, geo: focused_client.geo }; if let Up = direction { - focused_client.y += height; + focused_client.geo.y += height; } else { - new_client.y += height; + new_client.geo.y += height; } new_client } Left | Right => { - if focused_client.width % 2 == 1 { + if focused_client.geo.width % 2 == 1 { for client in self.clients.values_mut() { - client.x *= 2; - client.width *= 2; + client.geo.x *= 2; + client.geo.width *= 2; } self.grid_width *= 2; @@ -96,15 +103,15 @@ impl XcrabWindowManager { let focused_client = self.clients.get_mut(&focused).unwrap(); - focused_client.width /= 2; - let width = focused_client.width; + focused_client.geo.width /= 2; + let width = focused_client.geo.width; - let mut new_client = *focused_client; + let mut new_client = XcrabClient { frame, geo: focused_client.geo }; if let Left = direction { - focused_client.x += width; + focused_client.geo.x += width; } else { - new_client.x += width; + new_client.geo.x += width; } new_client @@ -121,13 +128,15 @@ impl XcrabWindowManager { self.grid_width = 1; self.grid_height = 1; - let client = XcrabClient { + let geo = XcrabGeometry { x: 0, y: 0, width: 1, height: 1, }; + let client = XcrabClient { frame, geo }; + self.clients.insert(win, client); self.update_client(conn, win).await?; @@ -135,8 +144,7 @@ impl XcrabWindowManager { self.focused = Some(win); } - win.map_async(conn).await?; - frame.map_async(conn).await?; + frame.map(conn).await?; Ok(()) } @@ -156,15 +164,14 @@ impl XcrabWindowManager { let root_width: u32 = root_geo.width.into(); let root_height: u32 = root_geo.height.into(); - let x = (client.x * root_width) / self.grid_width; - let y = (client.y * root_height) / self.grid_height; - let width = (client.width * root_width) / self.grid_width; - let height = (client.height * root_height) / self.grid_height; + let x = (client.geo.x * root_width) / self.grid_width; + let y = (client.geo.y * root_height) / self.grid_height; + let width = (client.geo.width * root_width) / self.grid_width; + let height = (client.geo.height * root_height) / self.grid_height; - let parent = win.query_tree_immediate_async(conn).await?.parent; - - parent - .configure_async( + client + .frame + .configure( conn, ConfigureWindowParameters { x: Some(x.try_into().unwrap()), @@ -176,18 +183,6 @@ impl XcrabWindowManager { ) .await?; - win.configure_async( - conn, - ConfigureWindowParameters { - x: Some(0), - y: Some(0), - width: Some(width), - height: Some(height), - ..Default::default() - }, - ) - .await?; - Ok(()) } @@ -200,47 +195,112 @@ impl XcrabWindowManager { conn: &mut Dpy, win: Window, ) -> Result<()> { - // TODO: maybe an `unframe` method? - let root = conn.default_root(); - - let parent = win.query_tree_immediate_async(conn).await?.parent; - - parent.unmap_async(conn).await?; - - win.reparent_async(conn, root, 0, 0).await?; - - // no longer related to us, remove from save set - win.change_save_set_async(conn, SetMode::Delete).await?; - - parent.free_async(conn).await?; - - self.clients.remove(&win); + self.clients + .remove(&win) + .ok_or(XcrabError::ClientDoesntExist)? + .frame + .unframe(conn) + .await?; Ok(()) } } -async fn frame(conn: &mut Dpy, win: Window) -> Result { - const GAP_WIDTH: u16 = 10; +#[derive(Debug, Clone, Copy)] +struct FramedWindow { + frame: Window, + win: Window, +} +impl FramedWindow { + async fn configure( + self, + conn: &mut Dpy, + props: ConfigureWindowParameters, + ) -> Result<()> { + let border_size = CONFIG.border_size(); + let gap_size = CONFIG.gap_size(); + + let coordinate_inset = i32::from(gap_size); + let dimension_inset = 2 * (u32::from(gap_size) + u32::from(border_size)); + + let width = props.width.map(|v| v - dimension_inset); + let height = props.height.map(|v| v - dimension_inset); + + self.frame + .configure_async( + conn, + ConfigureWindowParameters { + x: props.x.map(|v| v + coordinate_inset), + y: props.y.map(|v| v + coordinate_inset), + width, + height, + border_width: Some(border_size.into()), + ..Default::default() + }, + ) + .await?; + + self.win + .configure_async( + conn, + ConfigureWindowParameters { + x: Some(-1), + y: Some(-1), + width, + height, + ..Default::default() + }, + ) + .await?; + + Ok(()) + } + + async fn map(self, conn: &mut Dpy) -> Result<()> { + self.win.map_async(conn).await?; + self.frame.map_async(conn).await?; + + Ok(()) + } + + async fn unframe(self, conn: &mut Dpy) -> Result<()> { + let root = conn.default_root(); + + self.frame.unmap_async(conn).await?; + + self.win.reparent_async(conn, root, 0, 0).await?; + + // no longer related to us, remove from save set + self.win + .change_save_set_async(conn, SetMode::Delete) + .await?; + + self.frame.free_async(conn).await?; + + Ok(()) + } +} + +async fn frame(conn: &mut Dpy, win: Window) -> Result { let root = conn.default_root(); let geometry = win.geometry_immediate_async(conn).await?; - let parent = conn + let frame = conn .create_simple_window_async( root, geometry.x, geometry.y, geometry.width, geometry.height, - crate::CONFIG.border_size(), - crate::CONFIG.border_color(), + CONFIG.border_size(), + CONFIG.border_color(), 0x00_00_00, ) .await?; - parent + frame .set_event_mask_async( conn, EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY, @@ -249,7 +309,7 @@ async fn frame(conn: &mut Dpy, win: Window) -> Resul win.change_save_set_async(conn, SetMode::Insert).await?; - win.reparent_async(conn, parent, 0, 0).await?; + win.reparent_async(conn, frame, 0, 0).await?; - Ok(parent) + Ok(FramedWindow { frame, win }) } diff --git a/xinitrc b/xinitrc index 06e455c..3784a2e 100644 --- a/xinitrc +++ b/xinitrc @@ -3,6 +3,6 @@ xclock & xterm & -sleep 2; +sleep 0.5; target/debug/xcrab