From ece0eb7903cfc15d7fad48d1530bfab5d7e050f8 Mon Sep 17 00:00:00 2001 From: Janis Date: Sun, 28 Nov 2021 22:39:38 +0100 Subject: [PATCH] made border colors configurable in the config file --- Cargo.toml | 2 +- src/backends/traits.rs | 3 ++ src/backends/xlib/color.rs | 45 +++++++++++++++++++++ src/backends/xlib/mod.rs | 80 ++++++++++++++++++++++---------------- src/clients.rs | 2 +- src/state.rs | 47 ++++++++++++++++------ 6 files changed, 132 insertions(+), 47 deletions(-) create mode 100644 src/backends/xlib/color.rs diff --git a/Cargo.toml b/Cargo.toml index 6996d86..5e213ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -x11 = {version = "2.18.2", features = ["xlib"] } +x11 = {version = "2.18.2", features = ["xlib", "xft"] } log = "0.4.13" simple_logger = "1.11.0" dirs = "3.0.2" diff --git a/src/backends/traits.rs b/src/backends/traits.rs index c8e8494..603a3b8 100644 --- a/src/backends/traits.rs +++ b/src/backends/traits.rs @@ -40,6 +40,9 @@ pub trait WindowServerBackend { fn all_windows(&self) -> Option>; + fn set_active_window_border_color(&mut self, color_name: &str); + fn set_inactive_window_border_color(&mut self, color_name: &str); + fn resize_window(&self, window: Self::Window, new_size: Point) { self.configure_window(window, Some(new_size), None, None); } diff --git a/src/backends/xlib/color.rs b/src/backends/xlib/color.rs new file mode 100644 index 0000000..9e44477 --- /dev/null +++ b/src/backends/xlib/color.rs @@ -0,0 +1,45 @@ +use std::mem::MaybeUninit; + +use x11::{xft, xlib}; + +use super::Display; + +pub struct XftColor { + inner: xft::XftColor, +} + +impl XftColor { + pub fn pixel(&self) -> u64 { + self.inner.pixel + } + + pub fn color(&self) -> x11::xrender::XRenderColor { + self.inner.color + } + + pub fn new( + dpy: Display, + screen: i32, + mut color_name: String, + ) -> Result { + color_name.push('\0'); + let mut color = MaybeUninit::::zeroed(); + + unsafe { + xft::XftColorAllocName( + dpy.get(), + xlib::XDefaultVisual(dpy.get(), screen), + xlib::XDefaultColormap(dpy.get(), screen), + color_name.as_ptr() as *mut _, + color.as_mut_ptr(), + ) != 0 + } + .then(|| Self { + inner: unsafe { color.assume_init() }, + }) + .ok_or(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Unable to allocate color.", + )) + } +} diff --git a/src/backends/xlib/mod.rs b/src/backends/xlib/mod.rs index 2f50b6c..444c905 100644 --- a/src/backends/xlib/mod.rs +++ b/src/backends/xlib/mod.rs @@ -28,6 +28,7 @@ use super::{ WindowServerBackend, }; +pub mod color; pub mod keysym; pub type XLibWindowEvent = WindowEvent; @@ -100,31 +101,6 @@ impl From for XlibError { } } -// impl Into for XlibError { -// fn into(self) -> i32 { -// match self { -// XlibError::BadAccess => xlib::BadAccess.into(), -// XlibError::BadAlloc => xlib::BadAlloc.into(), -// XlibError::BadAtom => xlib::BadAtom.into(), -// XlibError::BadColor => xlib::BadColor.into(), -// XlibError::BadCursor => xlib::BadCursor.into(), -// XlibError::BadDrawable => xlib::BadDrawable.into(), -// XlibError::BadFont => xlib::BadFont.into(), -// XlibError::BadGC => xlib::BadGC.into(), -// XlibError::BadIDChoice => xlib::BadIDChoice.into(), -// XlibError::BadImplementation => xlib::BadImplementation.into(), -// XlibError::BadLength => xlib::BadLength.into(), -// XlibError::BadMatch => xlib::BadMatch.into(), -// XlibError::BadName => xlib::BadName.into(), -// XlibError::BadPixmap => xlib::BadPixmap.into(), -// XlibError::BadRequest => xlib::BadRequest.into(), -// XlibError::BadValue => xlib::BadValue.into(), -// XlibError::BadWindow => xlib::BadWindow.into(), -// XlibError::InvalidError(err) => err, -// } -// } -// } - impl Display { pub fn new(display: *mut x11::xlib::Display) -> Self { Self { @@ -144,6 +120,8 @@ pub struct XLib { screen: i32, atoms: XLibAtoms, keybinds: Vec, + active_border_color: Option, + inactive_border_color: Option, } impl Drop for XLib { @@ -174,6 +152,8 @@ impl XLib { modifier_state: ModifierState::empty(), atoms, keybinds: Vec::new(), + active_border_color: None, + inactive_border_color: None, } } @@ -684,12 +664,18 @@ impl WindowServerBackend for XLib { xlib::CurrentTime, ); - // TODO: make painting the window border a seperate function, and configurable - let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref(); + let border_color = self + .active_border_color + .as_ref() + .map(|color| color.pixel()) + .unwrap_or_else(|| { + xlib::XDefaultScreenOfDisplay(self.dpy()) + .as_ref() + .unwrap() + .white_pixel + }); - if let Some(screen) = screen { - xlib::XSetWindowBorder(self.dpy(), window, screen.white_pixel); - } + xlib::XSetWindowBorder(self.dpy(), window, border_color); xlib::XChangeProperty( self.dpy(), @@ -716,11 +702,19 @@ impl WindowServerBackend for XLib { ); // TODO: make painting the window border a seperate function, and configurable - let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref(); - if let Some(screen) = screen { - xlib::XSetWindowBorder(self.dpy(), window, screen.black_pixel); - } + let border_color = self + .inactive_border_color + .as_ref() + .map(|color| color.pixel()) + .unwrap_or_else(|| { + xlib::XDefaultScreenOfDisplay(self.dpy()) + .as_ref() + .unwrap() + .black_pixel + }); + + xlib::XSetWindowBorder(self.dpy(), window, border_color); xlib::XDeleteProperty( self.dpy(), @@ -885,6 +879,24 @@ impl WindowServerBackend for XLib { windows }) } + + fn set_active_window_border_color(&mut self, color_name: &str) { + self.active_border_color = color::XftColor::new( + self.display.clone(), + self.screen, + color_name.to_owned(), + ) + .ok(); + } + + fn set_inactive_window_border_color(&mut self, color_name: &str) { + self.inactive_border_color = color::XftColor::new( + self.display.clone(), + self.screen, + color_name.to_owned(), + ) + .ok(); + } } struct XLibAtoms { diff --git a/src/clients.rs b/src/clients.rs index ed85695..e641d8a 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -858,7 +858,7 @@ impl VirtualScreenStore { fn go_to_nth(&mut self, n: usize) -> usize { self.last_idx = Some(self.current_idx); - self.current_idx = n % self.screens.len(); + self.current_idx = n.min(self.screens.len() - 1); self.current_idx } diff --git a/src/state.rs b/src/state.rs index e706e6b..fd5ae0e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -34,6 +34,35 @@ pub struct WMConfig { mod_key: ModifierKey, gap: Option, kill_clients_on_exit: bool, + #[serde(default = "WMConfig::default_active_window_border_color")] + active_window_border_color: String, + #[serde(default = "WMConfig::default_inactive_window_border_color")] + inactive_window_border_color: String, +} + +impl WMConfig { + fn default_active_window_border_color() -> String { + "#ffffff".to_string() + } + + fn default_inactive_window_border_color() -> String { + "#444444".to_string() + } +} + +impl Default for WMConfig { + fn default() -> Self { + Self { + num_virtualscreens: 10, + mod_key: ModifierKey::Super, + gap: Some(2), + kill_clients_on_exit: false, + active_window_border_color: + Self::default_active_window_border_color(), + inactive_window_border_color: + Self::default_inactive_window_border_color(), + } + } } pub struct WindowManager @@ -256,6 +285,13 @@ where self.add_vs_switch_keybinds(); + self.backend.set_active_window_border_color( + &self.config.active_window_border_color, + ); + self.backend.set_inactive_window_border_color( + &self.config.inactive_window_border_color, + ); + // add all already existing windows to the WM if let Some(windows) = self.backend.all_windows() { windows @@ -869,17 +905,6 @@ where } } -impl Default for WMConfig { - fn default() -> Self { - Self { - num_virtualscreens: 10, - mod_key: ModifierKey::Super, - gap: Some(2), - kill_clients_on_exit: false, - } - } -} - impl Direction { fn west() -> Self { Direction::West(1)