forked from InfoshockTech/xcrab
config stuff
This commit is contained in:
parent
c9d07378c0
commit
204518016b
2
run.sh
2
run.sh
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
cargo build;
|
||||
cargo build || exit;
|
||||
|
||||
XEPHYR=$(which Xephyr | cut -f2 -d' ')
|
||||
xinit ./xinitrc -- \
|
||||
|
|
|
@ -7,30 +7,34 @@ use serde::{Deserialize, Serialize};
|
|||
pub struct XcrabConfig {
|
||||
border_color: Option<u32>,
|
||||
border_size: Option<u16>,
|
||||
gap_width: Option<u16>,
|
||||
gap_size: Option<u16>,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Dpy: AsyncDisplay + ?Sized>(conn: &mut Dpy, win: Window) -> Result<Window> {
|
||||
const GAP_WIDTH: u16 = 10;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct FramedWindow {
|
||||
frame: Window,
|
||||
win: Window,
|
||||
}
|
||||
|
||||
impl FramedWindow {
|
||||
async fn configure<Dpy: AsyncDisplay + ?Sized>(
|
||||
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<Dpy: AsyncDisplay + ?Sized>(self, conn: &mut Dpy) -> Result<()> {
|
||||
self.win.map_async(conn).await?;
|
||||
self.frame.map_async(conn).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn unframe<Dpy: AsyncDisplay + ?Sized>(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<Dpy: AsyncDisplay + ?Sized>(conn: &mut Dpy, win: Window) -> Result<FramedWindow> {
|
||||
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<Dpy: AsyncDisplay + ?Sized>(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 })
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue