Diff
diff --git a/src/config.rs b/src/config.rs
index be28ee9..ccb40fd 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -6,11 +6,20 @@ use x11rb::protocol::xproto::KeyButMask;
// ========================================
// APPEARANCE
// ========================================
-pub const BORDER_WIDTH: u32 = 1;
+pub const BORDER_WIDTH: u32 = 0;
pub const BORDER_FOCUSED: u32 = 0x6dade3;
pub const BORDER_UNFOCUSED: u32 = 0xbbbbbb;
pub const FONT: &str = "JetBrainsMono Nerd Font:style=Bold:size=14";
+// ========================================
+// GAPS (Vanity Gaps)
+// ========================================
+pub const GAPS_ENABLED: bool = true;
+pub const GAP_INNER_HORIZONTAL: u32 = 3;
+pub const GAP_INNER_VERTICAL: u32 = 3;
+pub const GAP_OUTER_HORIZONTAL: u32 = 3;
+pub const GAP_OUTER_VERTICAL: u32 = 3;
+//
// ========================================
// DEFAULTS
// ========================================
@@ -89,6 +98,7 @@ pub const KEYBINDINGS: &[Key] = &[
Key::new(&[MODKEY], keycodes::S, KeyAction::Spawn, Arg::Array(SCREENSHOT_CMD)),
Key::new(&[MODKEY], keycodes::D, KeyAction::Spawn, Arg::Array(DMENU_CMD)),
Key::new(&[MODKEY], keycodes::Q, KeyAction::KillClient, Arg::None),
+ Key::new(&[MODKEY], keycodes::A, KeyAction::ToggleGaps, Arg::None),
Key::new(&[MODKEY, SHIFT], keycodes::Q, KeyAction::Quit, Arg::None),
Key::new(&[MODKEY, SHIFT], keycodes::R, KeyAction::Restart, Arg::None),
Key::new(&[MODKEY], keycodes::J, KeyAction::FocusStack, Arg::Int(-1)),
diff --git a/src/keyboard/handlers.rs b/src/keyboard/handlers.rs
index e13a690..6288bde 100644
--- a/src/keyboard/handlers.rs
+++ b/src/keyboard/handlers.rs
@@ -11,6 +11,7 @@ pub enum KeyAction {
Quit,
Restart,
ViewTag,
+ ToggleGaps,
MoveToTag,
None,
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index df0e970..f8a9918 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -2,12 +2,20 @@ pub mod tiling;
use x11rb::protocol::xproto::Window;
+pub struct GapConfig {
+ pub inner_horizontal: u32,
+ pub inner_vertical: u32,
+ pub outer_horizontal: u32,
+ pub outer_vertical: u32,
+}
+
pub trait Layout {
fn arrange(
&self,
windows: &[Window],
screen_width: u32,
screen_height: u32,
+ gaps: &GapConfig,
) -> Vec<WindowGeometry>;
}
diff --git a/src/layout/tiling.rs b/src/layout/tiling.rs
index 14d7ac9..6bfef1f 100644
--- a/src/layout/tiling.rs
+++ b/src/layout/tiling.rs
@@ -1,4 +1,4 @@
-use super::{Layout, WindowGeometry};
+use super::{GapConfig, Layout, WindowGeometry};
use x11rb::protocol::xproto::Window;
pub struct TilingLayout;
@@ -9,6 +9,7 @@ impl Layout for TilingLayout {
windows: &[Window],
screen_width: u32,
screen_height: u32,
+ gaps: &GapConfig,
) -> Vec<WindowGeometry> {
let window_count = windows.len();
if window_count == 0 {
@@ -16,31 +17,60 @@ impl Layout for TilingLayout {
}
if window_count == 1 {
+ let x = gaps.outer_horizontal as i32;
+ let y = gaps.outer_vertical as i32;
+ let width = screen_width.saturating_sub(2 * gaps.outer_horizontal);
+ let height = screen_height.saturating_sub(2 * gaps.outer_vertical);
+
vec![WindowGeometry {
- x_coordinate: 0,
- y_coordinate: 0,
- width: screen_width,
- height: screen_height,
+ x_coordinate: x,
+ y_coordinate: y,
+ width,
+ height,
}]
} else {
- let master_width = screen_width / 2;
- let mut geometries = vec![WindowGeometry {
- x_coordinate: 0,
- y_coordinate: 0,
+ let mut geometries = Vec::new();
+
+ let master_width = (screen_width / 2)
+ .saturating_sub(gaps.outer_horizontal)
+ .saturating_sub(gaps.inner_horizontal / 2);
+
+ let master_x = gaps.outer_horizontal as i32;
+ let master_y = gaps.outer_vertical as i32;
+ let master_height = screen_height.saturating_sub(2 * gaps.outer_vertical);
+
+ geometries.push(WindowGeometry {
+ x_coordinate: master_x,
+ y_coordinate: master_y,
width: master_width,
- height: screen_height,
- }];
+ height: master_height,
+ });
+
+ let stack_count = window_count - 1;
+ let stack_x = (screen_width / 2 + gaps.inner_horizontal / 2) as i32;
+ let stack_width = (screen_width / 2)
+ .saturating_sub(gaps.outer_horizontal)
+ .saturating_sub(gaps.inner_horizontal / 2);
+
+ let total_stack_height = screen_height.saturating_sub(2 * gaps.outer_vertical);
+
+ let total_inner_gaps = gaps.inner_vertical * (stack_count as u32 - 1);
+ let stack_height =
+ total_stack_height.saturating_sub(total_inner_gaps) / stack_count as u32;
- let stack_height = screen_height / (window_count - 1) as u32;
for i in 1..window_count {
- let y_offset = ((i - 1) as u32) * stack_height;
+ let stack_index = i - 1;
+ let y_offset = gaps.outer_vertical
+ + (stack_index as u32) * (stack_height + gaps.inner_vertical);
+
geometries.push(WindowGeometry {
- x_coordinate: master_width as i32,
+ x_coordinate: stack_x,
y_coordinate: y_offset as i32,
- width: master_width,
+ width: stack_width,
height: stack_height,
});
}
+
return geometries;
}
}
diff --git a/src/window_manager.rs b/src/window_manager.rs
index 8148e70..bf7f0a4 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -1,6 +1,10 @@
use crate::bar::Bar;
-use crate::config::{BORDER_FOCUSED, BORDER_UNFOCUSED, BORDER_WIDTH, TAG_COUNT};
+use crate::config::{
+ BORDER_FOCUSED, BORDER_UNFOCUSED, BORDER_WIDTH, GAP_INNER_HORIZONTAL, GAP_INNER_VERTICAL,
+ GAP_OUTER_HORIZONTAL, GAP_OUTER_VERTICAL, GAPS_ENABLED, TAG_COUNT,
+};
use crate::keyboard::{self, Arg, KeyAction};
+use crate::layout::GapConfig;
use crate::layout::Layout;
use crate::layout::tiling::TilingLayout;
use anyhow::Result;
@@ -25,6 +29,7 @@ pub struct WindowManager {
layout: Box<dyn Layout>,
window_tags: std::collections::HashMap<Window, TagMask>,
selected_tags: TagMask,
+ gaps_enabled: bool,
bar: Bar,
}
@@ -49,6 +54,7 @@ impl WindowManager {
let bar = Bar::new(&connection, &screen, screen_number)?;
let selected_tags = Self::get_saved_selected_tags(&connection, root)?;
+ let gaps_enabled = GAPS_ENABLED;
let mut window_manger = Self {
connection,
@@ -60,6 +66,7 @@ impl WindowManager {
layout: Box::new(TilingLayout),
window_tags: std::collections::HashMap::new(),
selected_tags,
+ gaps_enabled,
bar,
};
@@ -287,6 +294,10 @@ impl WindowManager {
self.move_to_tag(*tag_index as usize)?;
}
}
+ KeyAction::ToggleGaps => {
+ self.gaps_enabled = !self.gaps_enabled;
+ self.apply_layout()?;
+ }
KeyAction::None => {
//no-op
}
@@ -520,8 +531,26 @@ impl WindowManager {
let bar_height = self.bar.height() as u32;
let usable_height = screen_height.saturating_sub(bar_height);
+ let gaps = if self.gaps_enabled {
+ GapConfig {
+ inner_horizontal: GAP_INNER_HORIZONTAL,
+ inner_vertical: GAP_INNER_VERTICAL,
+ outer_horizontal: GAP_OUTER_HORIZONTAL,
+ outer_vertical: GAP_OUTER_VERTICAL,
+ }
+ } else {
+ GapConfig {
+ inner_horizontal: 0,
+ inner_vertical: 0,
+ outer_horizontal: 0,
+ outer_vertical: 0,
+ }
+ };
+
let visible = self.visible_windows();
- let geometries = self.layout.arrange(&visible, screen_width, usable_height);
+ let geometries = self
+ .layout
+ .arrange(&visible, screen_width, usable_height, &gaps);
for (window, geometry) in visible.iter().zip(geometries.iter()) {
let adjusted_width = geometry.width.saturating_sub(2 * border_width);