Diff
diff --git a/Cargo.lock b/Cargo.lock
index c241f04..29e52c0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,18 +2,74 @@
# It is not intended for manual editing.
version = 4
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "anyhow"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
[[package]]
name = "bitflags"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "cc"
+version = "1.2.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
+
+[[package]]
+name = "chrono"
+version = "0.4.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
[[package]]
name = "errno"
version = "0.3.14"
@@ -24,6 +80,12 @@ dependencies = [
"windows-sys",
]
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3"
+
[[package]]
name = "gethostname"
version = "1.0.2"
@@ -34,6 +96,40 @@ dependencies = [
"windows-targets",
]
+[[package]]
+name = "iana-time-zone"
+version = "0.1.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
[[package]]
name = "libc"
version = "0.2.175"
@@ -46,11 +142,33 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
+[[package]]
+name = "log"
+version = "0.4.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
[[package]]
name = "oxwm"
version = "0.1.0"
dependencies = [
"anyhow",
+ "chrono",
"x11",
"x11rb",
]
@@ -61,6 +179,24 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
+dependencies = [
+ "proc-macro2",
+]
+
[[package]]
name = "rustix"
version = "1.1.2"
@@ -74,12 +210,153 @@ dependencies = [
"windows-sys",
]
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "syn"
+version = "2.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
+[[package]]
+name = "windows-result"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
+dependencies = [
+ "windows-link",
+]
+
[[package]]
name = "windows-sys"
version = "0.61.0"
diff --git a/Cargo.toml b/Cargo.toml
index 7d6e1be..9bcfaaf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2024"
x11 = { version = "2.21", features = ["xlib", "xft"] }
x11rb = "0.13"
anyhow = "1"
-
+chrono = "0.4"
diff --git a/src/bar/bar.rs b/src/bar/bar.rs
index 4de417b..7c022c6 100644
--- a/src/bar/bar.rs
+++ b/src/bar/bar.rs
@@ -1,6 +1,11 @@
+use super::blocks::{Block, Clock, Sep, Uname};
use super::font::{Font, FontDraw};
-use crate::config::{FONT, SCHEME_NORMAL, SCHEME_OCCUPIED, SCHEME_SELECTED, TAGS};
+use crate::config::{
+ CLOCK_COLOR, CLOCK_FORMAT, FONT, SCHEME_NORMAL, SCHEME_OCCUPIED, SCHEME_SELECTED, SEP_COLOR,
+ SEPARATOR, TAGS, UNAME_COLOR, UNAME_PREFIX,
+};
use anyhow::Result;
+use std::time::Instant;
use x11rb::COPY_DEPTH_FROM_PARENT;
use x11rb::connection::Connection;
use x11rb::protocol::xproto::*;
@@ -18,6 +23,10 @@ pub struct Bar {
tag_widths: Vec<u16>,
needs_redraw: bool,
+
+ blocks: Vec<Box<dyn Block>>,
+ block_last_updates: Vec<Instant>,
+ status_text: String,
}
impl Bar {
@@ -78,6 +87,14 @@ 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 block_last_updates = vec![Instant::now(); blocks.len()];
+
Ok(Bar {
window,
width,
@@ -88,6 +105,9 @@ impl Bar {
display,
tag_widths,
needs_redraw: true,
+ blocks,
+ block_last_updates,
+ status_text: String::new(),
})
}
@@ -103,6 +123,35 @@ impl Bar {
self.needs_redraw = true;
}
+ pub fn update_blocks(&mut self) -> Result<()> {
+ let now = Instant::now();
+ let mut changed = false;
+
+ for (i, block) in self.blocks.iter_mut().enumerate() {
+ let elapsed = now.duration_since(self.block_last_updates[i]);
+
+ if elapsed >= block.interval() {
+ if let Ok(_) = block.content() {
+ self.block_last_updates[i] = now;
+ changed = true;
+ }
+ }
+ }
+
+ if changed {
+ let mut parts = Vec::new();
+ for block in &mut self.blocks {
+ if let Ok(text) = block.content() {
+ parts.push(text);
+ }
+ }
+ self.status_text = parts.join("");
+ self.needs_redraw = true;
+ }
+
+ Ok(())
+ }
+
pub fn draw(
&mut self,
connection: &RustConnection,
@@ -182,6 +231,25 @@ impl Bar {
x_position += tag_width as i16;
}
+
+ if !self.status_text.is_empty() {
+ let padding = 10;
+ let mut x_position = self.width as i16 - padding;
+
+ for block in self.blocks.iter_mut().rev() {
+ if let Ok(text) = block.content() {
+ let text_width = self.font.text_width(&text);
+ x_position -= text_width as i16;
+
+ let top_padding = 4;
+ let text_y = top_padding + self.font.ascent();
+
+ self.font_draw
+ .draw_text(&self.font, block.color(), x_position, text_y, &text);
+ }
+ }
+ }
+
connection.flush()?;
unsafe {
@@ -204,4 +272,7 @@ impl Bar {
}
None
}
+ pub fn needs_redraw(&self) -> bool {
+ self.needs_redraw
+ }
}
diff --git a/src/bar/blocks/clock.rs b/src/bar/blocks/clock.rs
new file mode 100644
index 0000000..0a7f666
--- /dev/null
+++ b/src/bar/blocks/clock.rs
@@ -0,0 +1,30 @@
+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/mod.rs b/src/bar/blocks/mod.rs
new file mode 100644
index 0000000..a36c343
--- /dev/null
+++ b/src/bar/blocks/mod.rs
@@ -0,0 +1,20 @@
+use anyhow::Result;
+use std::time::Duration;
+
+pub mod clock;
+pub mod sep;
+pub mod uname;
+
+pub use clock::Clock;
+pub use sep::Sep;
+pub use uname::Uname;
+
+pub trait Block {
+ fn content(&mut self) -> Result<String>;
+ fn interval(&self) -> Duration;
+ fn color(&self) -> u32;
+
+ fn on_click(&mut self) -> Result<()> {
+ Ok(())
+ }
+}
diff --git a/src/bar/blocks/sep.rs b/src/bar/blocks/sep.rs
new file mode 100644
index 0000000..07f1c7a
--- /dev/null
+++ b/src/bar/blocks/sep.rs
@@ -0,0 +1,28 @@
+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/uname.rs b/src/bar/blocks/uname.rs
new file mode 100644
index 0000000..5a0bc7e
--- /dev/null
+++ b/src/bar/blocks/uname.rs
@@ -0,0 +1,38 @@
+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 a41bd9b..c3f1d80 100644
--- a/src/bar/mod.rs
+++ b/src/bar/mod.rs
@@ -1,4 +1,5 @@
mod bar;
+mod blocks;
mod font;
// mod widgets; // TODO: implement later
diff --git a/src/config.rs b/src/config.rs
index 38ad5d9..e22ec98 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -24,8 +24,12 @@ pub const MODKEY: KeyButMask = KeyButMask::MOD1;
const GRAY_DARK: u32 = 0x222222;
const GRAY_MID: u32 = 0x444444;
const GRAY_LIGHT: u32 = 0xbbbbbb;
-const CYAN: u32 = 0x6dade3;
+const CYAN: u32 = 0x0db9d7;
const MAGENTA: u32 = 0xad8ee6;
+const RED: u32 = 0xf7768e;
+const GREEN: u32 = 0x9ece6a;
+const BLUE: u32 = 0x7aa2f7;
+const YELLOW: u32 = 0xe0af68;
pub struct ColorScheme {
pub foreground: u32,
@@ -103,4 +107,14 @@ pub const KEYBINDINGS: &[Key] = &[
Key::new(&[MODKEY, SHIFT], keycodes::KEY_9, KeyAction::MoveToTag, Arg::Int(8)),
];
+// ========================================
+// 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;
+
const SHIFT: KeyButMask = KeyButMask::SHIFT;
diff --git a/src/window_manager.rs b/src/window_manager.rs
index 7a59360..672dace 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -1,13 +1,13 @@
use crate::bar::Bar;
use crate::config::{BORDER_FOCUSED, BORDER_UNFOCUSED, BORDER_WIDTH, TAG_COUNT};
use crate::keyboard::{self, Arg, KeyAction};
-use crate::layout::Layout;
use crate::layout::tiling::TilingLayout;
+use crate::layout::Layout;
use anyhow::Result;
use x11rb::connection::Connection;
-use x11rb::protocol::Event;
use x11rb::protocol::xproto::*;
+use x11rb::protocol::Event;
use x11rb::rust_connection::RustConnection;
pub type TagMask = u32;
@@ -70,11 +70,33 @@ impl WindowManager {
self.update_bar()?;
loop {
- let event = self.connection.wait_for_event()?;
- self.handle_event(event)?;
+ self.bar.update_blocks()?;
+
+ if let Ok(Some(event)) = self.connection.poll_for_event() {
+ self.handle_event(event)?;
+ }
+
+ if self.bar.needs_redraw() {
+ self.update_bar()?;
+ }
+
+ std::thread::sleep(std::time::Duration::from_millis(10));
}
}
+ // pub fn run(&mut self) -> Result<()> {
+ // println!("oxwm started on display {}", self.screen_number);
+ //
+ // keyboard::setup_keybinds(&self.connection, self.root)?;
+ //
+ // self.update_bar()?;
+ //
+ // loop {
+ // let event = self.connection.wait_for_event()?;
+ // self.handle_event(event)?;
+ // }
+ // }
+
fn update_bar(&mut self) -> Result<()> {
let mut occupied_tags: TagMask = 0;
for &tags in self.window_tags.values() {