oxwm

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

Restructured blocks to be more sane..

Commit
06c6741a6ff5edf0188ad33a9b5d8c6e819cc80f
Parent
d5b3499
Author
tonybtw <tonybtw@tonybtw.com>
Date
2025-10-04 05:47:42

Diff

diff --git a/src/bar/bar.rs b/src/bar/bar.rs
index 7c022c6..8a356a7 100644
--- a/src/bar/bar.rs
+++ b/src/bar/bar.rs
@@ -1,9 +1,6 @@
-use super::blocks::{Block, Clock, Sep, Uname};
+use super::blocks::Block;
 use super::font::{Font, FontDraw};
-use crate::config::{
-    CLOCK_COLOR, CLOCK_FORMAT, FONT, SCHEME_NORMAL, SCHEME_OCCUPIED, SCHEME_SELECTED, SEP_COLOR,
-    SEPARATOR, TAGS, UNAME_COLOR, UNAME_PREFIX,
-};
+use crate::config::{FONT, SCHEME_NORMAL, SCHEME_OCCUPIED, SCHEME_SELECTED, STATUS_BLOCKS, TAGS};
 use anyhow::Result;
 use std::time::Instant;
 use x11rb::COPY_DEPTH_FROM_PARENT;
@@ -42,7 +39,7 @@ impl Bar {
         }
         let font = Font::new(display, screen_num as i32, FONT)?;
 
-        let height = (font.height() as f32 * 1.25) as u16;
+        let height = (font.height() as f32 * 1.5) as u16;
 
         connection.create_window(
             COPY_DEPTH_FROM_PARENT,
@@ -87,13 +84,17 @@ impl Bar {
             })
             .collect();
 
-        let blocks: Vec<Box<dyn Block>> = vec![
-            Box::new(Uname::new(UNAME_PREFIX, UNAME_COLOR)),
-            Box::new(Sep::new(SEPARATOR, SEP_COLOR)),
-            Box::new(Clock::new(CLOCK_FORMAT, CLOCK_COLOR)),
-        ];
+        let blocks: Vec<Box<dyn Block>> = STATUS_BLOCKS
+            .iter()
+            .map(|config| config.to_block())
+            .collect();
 
         let block_last_updates = vec![Instant::now(); blocks.len()];
+        // let blocks: Vec<Box<dyn Block>> = vec![
+        //     Box::new(Uname::new(UNAME_PREFIX, UNAME_COLOR)),
+        //     Box::new(Sep::new(SEPARATOR, SEP_COLOR)),
+        //     Box::new(Clock::new(CLOCK_FORMAT, CLOCK_COLOR)),
+        // ];
 
         Ok(Bar {
             window,
diff --git a/src/bar/blocks/battery.rs b/src/bar/blocks/battery.rs
new file mode 100644
index 0000000..736fc47
--- /dev/null
+++ b/src/bar/blocks/battery.rs
@@ -0,0 +1,68 @@
+use super::Block;
+use anyhow::Result;
+use std::fs;
+use std::time::Duration;
+
+pub struct Battery {
+    format_charging: String,
+    format_discharging: String,
+    format_full: String,
+    interval: Duration,
+    color: u32,
+    battery_path: String,
+}
+
+impl Battery {
+    pub fn new(
+        format_charging: &str,
+        format_discharging: &str,
+        format_full: &str,
+        interval_secs: u64,
+        color: u32,
+    ) -> Self {
+        Self {
+            format_charging: format_charging.to_string(),
+            format_discharging: format_discharging.to_string(),
+            format_full: format_full.to_string(),
+            interval: Duration::from_secs(interval_secs),
+            color,
+            battery_path: "/sys/class/power_supply/BAT0".to_string(),
+        }
+    }
+
+    fn read_file(&self, filename: &str) -> Result<String> {
+        let path = format!("{}/{}", self.battery_path, filename);
+        Ok(fs::read_to_string(path)?.trim().to_string())
+    }
+
+    fn get_capacity(&self) -> Result<u32> {
+        Ok(self.read_file("capacity")?.parse()?)
+    }
+
+    fn get_status(&self) -> Result<String> {
+        self.read_file("status")
+    }
+}
+
+impl Block for Battery {
+    fn content(&mut self) -> Result<String> {
+        let capacity = self.get_capacity()?;
+        let status = self.get_status()?;
+
+        let format = match status.as_str() {
+            "Charging" => &self.format_charging,
+            "Full" => &self.format_full,
+            _ => &self.format_discharging,
+        };
+
+        Ok(format.replace("{}", &capacity.to_string()))
+    }
+
+    fn interval(&self) -> Duration {
+        self.interval
+    }
+
+    fn color(&self) -> u32 {
+        self.color
+    }
+}
diff --git a/src/bar/blocks/clock.rs b/src/bar/blocks/clock.rs
deleted file mode 100644
index 0a7f666..0000000
--- a/src/bar/blocks/clock.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use super::Block;
-use anyhow::Result;
-use chrono::Local;
-use std::time::Duration;
-
-pub struct Clock {
-    format: &'static str,
-    color: u32,
-}
-
-impl Clock {
-    pub fn new(format: &'static str, color: u32) -> Self {
-        Self { format, color }
-    }
-}
-
-impl Block for Clock {
-    fn content(&mut self) -> Result<String> {
-        let now = Local::now();
-        Ok(now.format(self.format).to_string())
-    }
-
-    fn interval(&self) -> Duration {
-        Duration::from_secs(1)
-    }
-
-    fn color(&self) -> u32 {
-        self.color
-    }
-}
diff --git a/src/bar/blocks/datetime.rs b/src/bar/blocks/datetime.rs
new file mode 100644
index 0000000..6ce6b3d
--- /dev/null
+++ b/src/bar/blocks/datetime.rs
@@ -0,0 +1,38 @@
+use super::Block;
+use anyhow::Result;
+use chrono::Local;
+use std::time::Duration;
+
+pub struct DateTime {
+    format_template: String,
+    time_format: String,
+    interval: Duration,
+    color: u32,
+}
+
+impl DateTime {
+    pub fn new(format_template: &str, time_format: &str, interval_secs: u64, color: u32) -> Self {
+        Self {
+            format_template: format_template.to_string(),
+            time_format: time_format.to_string(),
+            interval: Duration::from_secs(interval_secs),
+            color,
+        }
+    }
+}
+
+impl Block for DateTime {
+    fn content(&mut self) -> Result<String> {
+        let now = Local::now();
+        let time_str = now.format(&self.time_format).to_string();
+        Ok(self.format_template.replace("{}", &time_str))
+    }
+
+    fn interval(&self) -> Duration {
+        self.interval
+    }
+
+    fn color(&self) -> u32 {
+        self.color
+    }
+}
diff --git a/src/bar/blocks/mod.rs b/src/bar/blocks/mod.rs
index a36c343..6c9ccc3 100644
--- a/src/bar/blocks/mod.rs
+++ b/src/bar/blocks/mod.rs
@@ -1,20 +1,96 @@
 use anyhow::Result;
 use std::time::Duration;
 
-pub mod clock;
-pub mod sep;
-pub mod uname;
+mod battery;
+mod datetime;
+mod shell;
 
-pub use clock::Clock;
-pub use sep::Sep;
-pub use uname::Uname;
+use battery::Battery;
+use datetime::DateTime;
+use shell::ShellBlock;
 
 pub trait Block {
     fn content(&mut self) -> Result<String>;
     fn interval(&self) -> Duration;
     fn color(&self) -> u32;
+}
+
+pub struct BlockConfig {
+    pub format: &'static str,
+    pub command: BlockCommand,
+    pub interval_secs: u64,
+    pub color: u32,
+}
+
+pub enum BlockCommand {
+    Shell(&'static str),
+    DateTime(&'static str),
+    Battery {
+        format_charging: &'static str,
+        format_discharging: &'static str,
+        format_full: &'static str,
+    },
+    Static(&'static str),
+}
+
+impl BlockConfig {
+    pub fn to_block(&self) -> Box<dyn Block> {
+        match self.command {
+            BlockCommand::Shell(cmd) => Box::new(ShellBlock::new(
+                self.format,
+                cmd,
+                self.interval_secs,
+                self.color,
+            )),
+            BlockCommand::DateTime(fmt) => Box::new(DateTime::new(
+                self.format,
+                fmt,
+                self.interval_secs,
+                self.color,
+            )),
+            BlockCommand::Battery {
+                format_charging,
+                format_discharging,
+                format_full,
+            } => Box::new(Battery::new(
+                format_charging,
+                format_discharging,
+                format_full,
+                self.interval_secs,
+                self.color,
+            )),
+            BlockCommand::Static(text) => Box::new(StaticBlock::new(
+                &format!("{}{}", self.format, text),
+                self.color,
+            )),
+        }
+    }
+}
+
+struct StaticBlock {
+    text: String,
+    color: u32,
+}
+
+impl StaticBlock {
+    fn new(text: &str, color: u32) -> Self {
+        Self {
+            text: text.to_string(),
+            color,
+        }
+    }
+}
+
+impl Block for StaticBlock {
+    fn content(&mut self) -> Result<String> {
+        Ok(self.text.clone())
+    }
+
+    fn interval(&self) -> Duration {
+        Duration::from_secs(u64::MAX)
+    }
 
-    fn on_click(&mut self) -> Result<()> {
-        Ok(())
+    fn color(&self) -> u32 {
+        self.color
     }
 }
diff --git a/src/bar/blocks/sep.rs b/src/bar/blocks/sep.rs
deleted file mode 100644
index 07f1c7a..0000000
--- a/src/bar/blocks/sep.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use super::Block;
-use anyhow::Result;
-use std::time::Duration;
-
-pub struct Sep {
-    text: &'static str,
-    color: u32,
-}
-
-impl Sep {
-    pub fn new(text: &'static str, color: u32) -> Self {
-        Self { text, color }
-    }
-}
-
-impl Block for Sep {
-    fn content(&mut self) -> Result<String> {
-        Ok(self.text.to_string())
-    }
-
-    fn interval(&self) -> Duration {
-        Duration::from_secs(u64::MAX)
-    }
-
-    fn color(&self) -> u32 {
-        self.color
-    }
-}
diff --git a/src/bar/blocks/shell.rs b/src/bar/blocks/shell.rs
new file mode 100644
index 0000000..51a20df
--- /dev/null
+++ b/src/bar/blocks/shell.rs
@@ -0,0 +1,39 @@
+use super::Block;
+use anyhow::Result;
+use std::process::Command;
+use std::time::Duration;
+
+pub struct ShellBlock {
+    format: String,
+    command: String,
+    interval: Duration,
+    color: u32,
+}
+
+impl ShellBlock {
+    pub fn new(format: &str, command: &str, interval_secs: u64, color: u32) -> Self {
+        Self {
+            format: format.to_string(),
+            command: command.to_string(),
+            interval: Duration::from_secs(interval_secs),
+            color,
+        }
+    }
+}
+
+impl Block for ShellBlock {
+    fn content(&mut self) -> Result<String> {
+        let output = Command::new("sh").arg("-c").arg(&self.command).output()?;
+
+        let result = String::from_utf8_lossy(&output.stdout).trim().to_string();
+        Ok(self.format.replace("{}", &result))
+    }
+
+    fn interval(&self) -> Duration {
+        self.interval
+    }
+
+    fn color(&self) -> u32 {
+        self.color
+    }
+}
diff --git a/src/bar/blocks/uname.rs b/src/bar/blocks/uname.rs
deleted file mode 100644
index 5a0bc7e..0000000
--- a/src/bar/blocks/uname.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use super::Block;
-use anyhow::Result;
-use std::process::Command;
-use std::time::Duration;
-
-pub struct Uname {
-    cached_version: String,
-    prefix: &'static str,
-    color: u32,
-}
-
-impl Uname {
-    pub fn new(prefix: &'static str, color: u32) -> Self {
-        Self {
-            cached_version: String::new(),
-            prefix,
-            color,
-        }
-    }
-}
-
-impl Block for Uname {
-    fn content(&mut self) -> Result<String> {
-        if self.cached_version.is_empty() {
-            let output = Command::new("uname").arg("-r").output()?;
-            self.cached_version = String::from_utf8_lossy(&output.stdout).trim().to_string();
-        }
-        Ok(format!("{}{}", self.prefix, self.cached_version))
-    }
-
-    fn interval(&self) -> Duration {
-        Duration::from_secs(u64::MAX)
-    }
-
-    fn color(&self) -> u32 {
-        self.color
-    }
-}
diff --git a/src/bar/mod.rs b/src/bar/mod.rs
index c3f1d80..3009746 100644
--- a/src/bar/mod.rs
+++ b/src/bar/mod.rs
@@ -1,9 +1,9 @@
 mod bar;
 mod blocks;
 mod font;
-// mod widgets;  // TODO: implement later
 
 pub use bar::Bar;
+pub use blocks::{BlockCommand, BlockConfig};
 
 // Bar position (for future use)
 #[derive(Debug, Clone, Copy)]
diff --git a/src/config.rs b/src/config.rs
index e22ec98..90905fa 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,3 +1,4 @@
+use crate::bar::{BlockCommand, BlockConfig};
 use crate::keyboard::handlers::Key;
 use crate::keyboard::{Arg, KeyAction, keycodes};
 use x11rb::protocol::xproto::KeyButMask;
@@ -8,7 +9,7 @@ use x11rb::protocol::xproto::KeyButMask;
 pub const BORDER_WIDTH: u32 = 1;
 pub const BORDER_FOCUSED: u32 = 0x6dade3;
 pub const BORDER_UNFOCUSED: u32 = 0xbbbbbb;
-pub const FONT: &str = "JetBrainsMono Nerd Font:style=Bold:size=12";
+pub const FONT: &str = "JetBrainsMono Nerd Font:style=Bold:size=14";
 
 // ========================================
 // DEFAULTS
@@ -110,11 +111,41 @@ pub const KEYBINDINGS: &[Key] = &[
 // ========================================
 // STATUS BAR BLOCKS
 // ========================================
-pub const CLOCK_FORMAT: &str = " 󰸘 %a, %b %d - %-I:%M %P"; // "Fri, Oct 03 - 7:58 pm"
-pub const SEPARATOR: &str = " | ";
-pub const UNAME_COLOR: u32 = RED;
-pub const UNAME_PREFIX: &str = "  ";
-pub const SEP_COLOR: u32 = GRAY_LIGHT;
-pub const CLOCK_COLOR: u32 = CYAN;
+pub const STATUS_BLOCKS: &[BlockConfig] = &[
+    BlockConfig {
+        format: "",
+        command: BlockCommand::Battery {
+            format_charging: " 󰂄 Bat: {}%",
+            format_discharging: " 󰁹 Bat:{}%",
+            format_full: " 󰁹 Bat: {}%",
+        },
+        interval_secs: 30,
+        color: BLUE,
+    },
+    BlockConfig {
+        format: " | ",
+        command: BlockCommand::Static(""),
+        interval_secs: u64::MAX,
+        color: GRAY_LIGHT,
+    },
+    BlockConfig {
+        format: "  {}",
+        command: BlockCommand::Shell("uname -r"),
+        interval_secs: u64::MAX,
+        color: RED,
+    },
+    BlockConfig {
+        format: " | ",
+        command: BlockCommand::Static(""),
+        interval_secs: u64::MAX,
+        color: GRAY_LIGHT,
+    },
+    BlockConfig {
+        format: " 󰸘 {}",
+        command: BlockCommand::DateTime("%a, %b %d - %-I:%M %P"),
+        interval_secs: 1,
+        color: CYAN,
+    },
+];
 
 const SHIFT: KeyButMask = KeyButMask::SHIFT;