From 0309522e25c762bdc5cccfcde9eea90c9f8cf9da Mon Sep 17 00:00:00 2001 From: Jory Severijnse Date: Mon, 16 Mar 2026 17:32:54 +0100 Subject: [PATCH] Add caps lock indicator and keyboard layout support - Add caps lock ring color change when caps lock is enabled (matching swaylock-effects) - Add configurable caps lock colors: ring, text, key highlight, backspace highlight - Add show_caps_lock_text config option (enabled by default) - Add keyboard layout display with show_keyboard_layout option (disabled by default) - Change keyboard_layout from u32 to String for proper display - Add rust-cache to CI and dbus-1-dev dependency --- .github/workflows/ci.yml | 15 ++++++---- src/config.rs | 26 +++++++++++++---- src/lock.rs | 1 - src/main.rs | 2 +- src/render.rs | 61 +++++++++++++++++++++++++--------------- src/system.rs | 2 +- 6 files changed, 71 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa8302a..0f8bcd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,7 @@ jobs: args: "--no-default-features" steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: | sudo apt-get update @@ -31,7 +32,7 @@ jobs: llvm clang libclang-dev \ pkg-config \ libglib2.0-dev libcairo2-dev libpango1.0-dev libatk1.0-dev \ - libpam0g-dev \ + libpam0g-dev libdbus-1-dev \ libwayland-dev libxkbcommon-dev - name: Build (${{ matrix.features }}) run: cargo build --verbose ${{ matrix.args }} @@ -43,6 +44,7 @@ jobs: container: debian:stable-slim steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: | apt-get update @@ -50,7 +52,7 @@ jobs: llvm clang libclang-dev \ pkg-config \ libglib2.0-dev libcairo2-dev libpango1.0-dev libatk1.0-dev \ - libpam0g-dev \ + libpam0g-dev libdbus-1-dev \ libwayland-dev libxkbcommon-dev \ cargo rustc - name: Build @@ -61,13 +63,14 @@ jobs: container: fedora:latest steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: | dnf install -y \ llvm clang libclang-devel \ pkg-config \ glib2-devel cairo-devel pango-devel atk-devel \ - pam-devel \ + pam-devel dbus-devel \ wayland-devel libxkbcommon-devel \ cargo rust - name: Build @@ -78,12 +81,13 @@ jobs: container: archlinux:latest steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: | pacman -Sy --noconfirm \ llvm clang pkgconf \ glib2 cairo pango atk \ - pam \ + pam dbus \ wayland libxkbcommon \ rust cargo - name: Build @@ -94,13 +98,14 @@ jobs: container: opensuse/tumbleweed:latest steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: | zypper install -y \ llvm clang \ pkg-config \ glib2-devel cairo-devel pango-devel atk-devel \ - pam-devel \ + pam-devel dbus-1-devel \ wayland-devel libxkbcommon-devel \ rust cargo - name: Build diff --git a/src/config.rs b/src/config.rs index 9a68072..5778ee3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -42,6 +42,21 @@ pub struct Config { #[arg(long, default_value = "4EAC41", value_parser = util::parse_hex_color)] pub key_hl_color: (f64, f64, f64, f64), + #[arg(long, default_value = "4EAC41", value_parser = util::parse_hex_color)] + pub caps_lock_key_hl_color: (f64, f64, f64, f64), + + #[arg(long, default_value = "DB3300", value_parser = util::parse_hex_color)] + pub caps_lock_bs_hl_color: (f64, f64, f64, f64), + + #[arg(long, default_value = "E5A445", value_parser = util::parse_hex_color)] + pub caps_lock_color: (f64, f64, f64, f64), + + #[arg(long, default_value = "E5A445", value_parser = util::parse_hex_color)] + pub caps_lock_text_color: (f64, f64, f64, f64), + + #[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")] + pub show_caps_lock_text: bool, + #[arg(long, default_value = "00000000", value_parser = util::parse_hex_color)] pub line_color: (f64, f64, f64, f64), @@ -184,11 +199,12 @@ impl Config { merge_f32(&mut config.grace, "grace"); merge_f32(&mut config.fade_in, "fade_in"); merge_string(&mut config.pam_service, "pam_service"); - merge_bool(&mut config.show_media, "show_media"); - merge_bool(&mut config.show_battery, "show_battery"); - merge_bool(&mut config.show_network, "show_network"); - merge_bool(&mut config.show_bluetooth, "show_bluetooth"); - merge_bool(&mut config.show_album_art, "show_album_art"); + merge_bool(&mut config.show_media, "show_media"); + merge_bool(&mut config.show_battery, "show_battery"); + merge_bool(&mut config.show_network, "show_network"); + merge_bool(&mut config.show_bluetooth, "show_bluetooth"); + merge_bool(&mut config.show_album_art, "show_album_art"); + merge_bool(&mut config.show_keyboard_layout, "show_keyboard_layout"); if !is_cli("image") { if let Some(toml::Value::String(s)) = table.get("image") { diff --git a/src/lock.rs b/src/lock.rs index 68a83ca..7535a3d 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -109,7 +109,6 @@ impl LockedSurface { // Update caps lock state in renderer self.renderer.caps_lock = self.input_handler.caps_lock(); - log::debug!("Caps lock state: {}", self.input_handler.caps_lock()); // Set background if available and not already applied if !self.background_applied { diff --git a/src/main.rs b/src/main.rs index a692275..4a4a288 100644 --- a/src/main.rs +++ b/src/main.rs @@ -724,7 +724,7 @@ fn main() -> Result<(), Box> { } let mut status = state.system_manager.get_status(); - status.keyboard_layout = Some(state.current_layout); + status.keyboard_layout = Some(state.current_layout.to_string()); if let Ok(mut lm) = state.lock_manager.lock() { lm.set_system_status(status); diff --git a/src/render.rs b/src/render.rs index 47b0d53..6c84267 100644 --- a/src/render.rs +++ b/src/render.rs @@ -238,7 +238,7 @@ impl Renderer { self.draw_password_display(); } - if self.caps_lock { + if self.caps_lock && self.config.show_caps_lock_text { self.draw_caps_lock_indicator(); } @@ -351,13 +351,18 @@ impl Renderer { self.context.stroke().unwrap(); } - self.context.new_path(); - let (r, g, b, a) = self.config.ring_color; - self.context.set_source_rgba(r, g, b, a * self.fade_alpha); - self.context.set_line_width(thickness); - self.context - .arc(center_x, center_y, radius, 0.0, 2.0 * std::f64::consts::PI); - self.context.stroke().unwrap(); + // Use caps lock color when caps lock is on and indicator is enabled, otherwise ring color + let (r, g, b, a) = if self.caps_lock { + self.config.caps_lock_color + } else { + self.config.ring_color + }; + self.context.new_path(); + self.context.set_source_rgba(r, g, b, a * self.fade_alpha); + self.context.set_line_width(thickness); + self.context + .arc(center_x, center_y, radius, 0.0, 2.0 * std::f64::consts::PI); + self.context.stroke().unwrap(); let (r, g, b, a) = self.config.separator_color; if a > 0.0 { @@ -388,12 +393,16 @@ impl Renderer { let center_y = self.height as f64 / 2.0; let radius = self.config.indicator_radius as f64; self.context.new_path(); - self.context.set_font_size(12.0); - self.context.set_source_rgba(1.0, 0.5, 0.0, self.fade_alpha); - let text = "CAPS LOCK"; + // Use configurable caps lock text color + let (r, g, b, a) = self.config.caps_lock_text_color; + self.context.set_source_rgba(r, g, b, a * self.fade_alpha); + // Increase font size for bigger letters + self.context.set_font_size(24.0); + let text = "Caps Lock"; let te = self.context.text_extents(text).unwrap(); + // Position above the ring self.context - .move_to(center_x - te.width() / 2.0, center_y + radius / 1.1 + 20.0); + .move_to(center_x - te.width() / 2.0, center_y - radius - 10.0); self.context.show_text(text).unwrap(); } @@ -443,7 +452,11 @@ impl Renderer { }; if intensity > 0.0 { - let (r, g, b, a) = self.config.key_hl_color; + let (r, g, b, a) = if self.caps_lock { + self.config.caps_lock_key_hl_color + } else { + self.config.key_hl_color + }; self.context .set_source_rgba(r, g, b, a * intensity * self.fade_alpha); self.context.set_line_width(thickness + 1.5); @@ -708,17 +721,19 @@ impl Renderer { } fn draw_keyboard_layout(&self) { - if let Some(layout) = self.system_status.keyboard_layout { - let margin = 20.0; - let x = margin; - let y = margin + 80.0; + if self.config.show_keyboard_layout { + if let Some(ref layout) = self.system_status.keyboard_layout { + let margin = 20.0; + let x = margin; + let y = margin + 80.0; - self.context.new_path(); - self.context.set_source_rgba(1.0, 1.0, 1.0, self.fade_alpha); - self.context.set_font_size(16.0); - let text = format!("Layout: {}", layout); - self.context.move_to(x, y); - self.context.show_text(&text).unwrap(); + self.context.new_path(); + self.context.set_source_rgba(1.0, 1.0, 1.0, self.fade_alpha); + self.context.set_font_size(16.0); + let text = format!("Layout: {}", layout); + self.context.move_to(x, y); + self.context.show_text(&text).unwrap(); + } } } diff --git a/src/system.rs b/src/system.rs index 8ce0661..4cdc33a 100644 --- a/src/system.rs +++ b/src/system.rs @@ -17,7 +17,7 @@ pub struct SystemStatus { pub wifi_strength: Option, pub bluetooth_connected: bool, pub bluetooth_devices: Vec, - pub keyboard_layout: Option, + pub keyboard_layout: Option, } #[derive(Debug, Clone, Copy)]