oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git

Added layout names into bar, and in config files to be configurable. Updated test config and default config to include ExchangeClient, and SmartMoveWin

Commit
78580639c90d1c3ad8eccdbc3f1f938f57afcc72
Parent
8f52c5d
Author
tonybtw <tonybtw@tonybtw.com>
Date
2025-10-27 05:18:14

Diff

diff --git a/src/bar/bar.rs b/src/bar/bar.rs
index 9857406..f45e59c 100644
--- a/src/bar/bar.rs
+++ b/src/bar/bar.rs
@@ -171,6 +171,7 @@ impl Bar {
         current_tags: u32,
         occupied_tags: u32,
         draw_blocks: bool,
+        layout_symbol: &str,
     ) -> Result<(), X11Error> {
         if !self.needs_redraw {
             return Ok(());
@@ -246,6 +247,20 @@ impl Bar {
             x_position += tag_width as i16;
         }
 
+        x_position += 10;
+
+        let text_x = x_position;
+        let top_padding = 4;
+        let text_y = top_padding + font.ascent();
+
+        self.font_draw.draw_text(
+            font,
+            self.scheme_normal.foreground,
+            text_x,
+            text_y,
+            layout_symbol
+        );
+
         if draw_blocks && !self.status_text.is_empty() {
             let padding = 10;
             let mut x_position = self.width as i16 - padding;
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 070eec0..2fc4649 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -161,6 +161,12 @@ pub fn parse_config(input: &str) -> Result<crate::Config, ConfigError> {
     config_data_to_config(config_data)
 }
 
+#[derive(Debug, Deserialize)]
+struct LayoutSymbolOverrideData {
+    name: String,
+    symbol: String,
+}
+
 #[derive(Debug, Deserialize)]
 struct ConfigData {
     border_width: u32,
@@ -178,6 +184,8 @@ struct ConfigData {
     modkey: ModKey,
 
     tags: Vec<String>,
+    #[serde(default)]
+    layout_symbols: Vec<LayoutSymbolOverrideData>,
     keybindings: Vec<KeybindingData>,
     status_blocks: Vec<StatusBlockData>,
 
@@ -307,6 +315,15 @@ fn config_data_to_config(data: ConfigData) -> Result<crate::Config, ConfigError>
         });
     }
 
+    let layout_symbols = data
+        .layout_symbols
+        .into_iter()
+        .map(|l| crate::LayoutSymbolOverride {
+            name: l.name,
+            symbol: l.symbol,
+        })
+        .collect();
+
     Ok(crate::Config {
         border_width: data.border_width,
         border_focused: data.border_focused,
@@ -320,6 +337,7 @@ fn config_data_to_config(data: ConfigData) -> Result<crate::Config, ConfigError>
         terminal: data.terminal,
         modkey,
         tags: data.tags,
+        layout_symbols,
         keybindings,
         status_blocks,
         scheme_normal: crate::ColorScheme {
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index cf96dd2..90b9ff6 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -41,6 +41,7 @@ pub trait Layout {
         gaps: &GapConfig,
     ) -> Vec<WindowGeometry>;
     fn name(&self) -> &'static str;
+    fn symbol(&self) -> &'static str;
 }
 
 pub struct WindowGeometry {
diff --git a/src/layout/normie.rs b/src/layout/normie.rs
index 1dc3205..e189c10 100644
--- a/src/layout/normie.rs
+++ b/src/layout/normie.rs
@@ -9,6 +9,10 @@ impl Layout for NormieLayout {
         super::NORMIE
     }
 
+    fn symbol(&self) -> &'static str {
+        "><>"
+    }
+
     fn arrange(
         &self,
         windows: &[Window],
diff --git a/src/layout/tiling.rs b/src/layout/tiling.rs
index a31589e..f0e1464 100644
--- a/src/layout/tiling.rs
+++ b/src/layout/tiling.rs
@@ -8,6 +8,10 @@ impl Layout for TilingLayout {
         super::TILING
     }
 
+    fn symbol(&self) -> &'static str {
+        "[]="
+    }
+
     fn arrange(
         &self,
         windows: &[Window],
diff --git a/src/lib.rs b/src/lib.rs
index 293e3ce..147cdb6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,11 +8,18 @@ pub mod window_manager;
 
 pub mod prelude {
     pub use crate::ColorScheme;
+    pub use crate::LayoutSymbolOverride;
     pub use crate::bar::{BlockCommand, BlockConfig};
     pub use crate::keyboard::{Arg, KeyAction, handlers::Key, keycodes};
     pub use x11rb::protocol::xproto::KeyButMask;
 }
 
+#[derive(Clone)]
+pub struct LayoutSymbolOverride {
+    pub name: String,
+    pub symbol: String,
+}
+
 #[derive(Clone)]
 pub struct Config {
     // Appearance
@@ -35,6 +42,9 @@ pub struct Config {
     // Tags
     pub tags: Vec<String>,
 
+    // Layout symbol overrides
+    pub layout_symbols: Vec<LayoutSymbolOverride>,
+
     // Keybindings
     pub keybindings: Vec<crate::keyboard::handlers::Key>,
 
@@ -81,6 +91,7 @@ impl Default for Config {
                 .into_iter()
                 .map(String::from)
                 .collect(),
+            layout_symbols: vec![],
             keybindings: vec![
                 Key::new(
                     vec![MODKEY],
diff --git a/src/window_manager.rs b/src/window_manager.rs
index 03066dd..5ef536e 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -789,7 +789,19 @@ impl WindowManager {
         Ok(())
     }
 
+    fn get_layout_symbol(&self) -> String {
+        let layout_name = self.layout.name();
+        self.config
+            .layout_symbols
+            .iter()
+            .find(|l| l.name == layout_name)
+            .map(|l| l.symbol.clone())
+            .unwrap_or_else(|| self.layout.symbol().to_string())
+    }
+
     fn update_bar(&mut self) -> WmResult<()> {
+        let layout_symbol = self.get_layout_symbol();
+
         for (monitor_index, monitor) in self.monitors.iter().enumerate() {
             if let Some(bar) = self.bars.get_mut(monitor_index) {
                 let mut occupied_tags: TagMask = 0;
@@ -808,6 +820,7 @@ impl WindowManager {
                     monitor.selected_tags,
                     occupied_tags,
                     draw_blocks,
+                    &layout_symbol,
                 )?;
             }
         }
@@ -842,6 +855,7 @@ impl WindowManager {
                         Ok(layout) => {
                             self.layout = layout;
                             self.apply_layout()?;
+                            self.update_bar()?;
                         }
                         Err(e) => eprintln!("Failed to change layout: {}", e),
                     }
@@ -854,6 +868,7 @@ impl WindowManager {
                     Ok(layout) => {
                         self.layout = layout;
                         self.apply_layout()?;
+                        self.update_bar()?;
                     }
                     Err(e) => eprintln!("Failed to cycle layout: {}", e),
                 }
diff --git a/templates/config.ron b/templates/config.ron
index 18dcd89..69af9f1 100644
--- a/templates/config.ron
+++ b/templates/config.ron
@@ -18,6 +18,10 @@
     modkey: Mod4,
 
     tags: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
+    layout_symbols: [
+        (name: "tiling", symbol: "[T]"),
+        (name: "normie", symbol: "[F]"),
+    ],
 
     keybindings: [
         (modifiers: [Mod4], key: Return, action: Spawn, arg: "st"),
@@ -28,6 +32,7 @@
         (modifiers: [Mod4, Shift], key: Space, action: ToggleFloating),
         (modifiers: [Mod4], key: F, action: ChangeLayout, arg: "normie"),
         (modifiers: [Mod4], key: C, action: ChangeLayout, arg: "tiling"),
+        (modifiers: [Mod1], key: N, action: CycleLayout),
         (modifiers: [Mod4], key: A, action: ToggleGaps),
         (modifiers: [Mod4, Shift], key: Q, action: Quit),
         (modifiers: [Mod4, Shift], key: R, action: Restart),
@@ -53,6 +58,18 @@
         (modifiers: [Mod4, Shift], key: Key7, action: MoveToTag, arg: 6),
         (modifiers: [Mod4, Shift], key: Key8, action: MoveToTag, arg: 7),
         (modifiers: [Mod4, Shift], key: Key9, action: MoveToTag, arg: 8),
+
+        // Moving Windows
+        (modifiers: [Mod4, Control], key: K, action: SmartMoveWin, arg: 0), // UP
+        (modifiers: [Mod4, Control], key: J, action: SmartMoveWin, arg: 1), // DOWN
+        (modifiers: [Mod4, Control], key: H, action: SmartMoveWin, arg: 2), // LEFT
+        (modifiers: [Mod4, Control], key: L, action: SmartMoveWin, arg: 3), // RIGHT
+
+        // Exchanging Clients
+        (modifiers: [Mod4, Shift], key: K, action: ExchangeClient, arg: 0), // UP
+        (modifiers: [Mod4, Shift], key: J, action: ExchangeClient, arg: 1), // DOWN
+        (modifiers: [Mod4, Shift], key: H, action: ExchangeClient, arg: 2), // LEFT
+        (modifiers: [Mod4, Shift], key: L, action: ExchangeClient, arg: 3), // RIGHT
     ],
     
     status_blocks: [
diff --git a/test-config.ron b/test-config.ron
index b38fe05..ac3303a 100644
--- a/test-config.ron
+++ b/test-config.ron
@@ -16,7 +16,6 @@
     
     terminal: "st",
     modkey: Mod1,
-
     tags: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
 
     // Alternative icon tags (uncomment to use):
@@ -25,6 +24,11 @@
     // Alternative text tags (uncomment to use):
     // tags: ["DEV", "WWW", "SYS", "DOC", "VBOX", "CHAT", "MUS", "VID", "MISC"],
 
+    layout_symbols: [
+        (name: "tiling", symbol: "[T]"),
+        (name: "normie", symbol: "[F]"),
+    ],
+
     keybindings: [
         (modifiers: [Mod1], key: Return, action: Spawn, arg: "st"),
         (modifiers: [Mod1], key: D, action: Spawn, arg: ["sh", "-c", "dmenu_run -l 10"]),
@@ -41,6 +45,10 @@
         (modifiers: [Mod1], key: J, action: FocusStack, arg: -1),
         (modifiers: [Mod1], key: K, action: FocusStack, arg: 1),
         // Exchange client (vim-style with Mod+Shift)
+        (modifiers: [Mod1, Control], key: K, action: SmartMoveWin, arg: 0), // UP
+        (modifiers: [Mod1, Control], key: J, action: SmartMoveWin, arg: 1), // DOWN
+        (modifiers: [Mod1, Control], key: H, action: SmartMoveWin, arg: 2), // LEFT
+        (modifiers: [Mod1, Control], key: L, action: SmartMoveWin, arg: 3), // RIGHT
         (modifiers: [Mod1, Shift], key: K, action: ExchangeClient, arg: 0), // UP
         (modifiers: [Mod1, Shift], key: J, action: ExchangeClient, arg: 1), // DOWN
         (modifiers: [Mod1, Shift], key: H, action: ExchangeClient, arg: 2), // LEFT