Skip to content

Commit e7d928a

Browse files
committed
feat(config): allow colours in both rgb and hex
This commit introduces the ability for users to specify colours in the static config file in either RGB or Hex format. This is done by introducing a new enum, Colour, which provides variants wrapping the internal Rgb type, and the HexColour type from the hex_colour crate. HexColour itself is wrapped in a new struct, Hex, in order to allow the implementation of the JsonSchema trait. A number of From<T> implementations have been done in order to make working with the Colour enum more ergonomic. Ultimately, the core representation for colours in komorebi remains the Rgb struct, any and Hex-specified colours will be converted to this Rgb type before being converted to u32 to pass them on to various Win32 API calls.
1 parent 608ec03 commit e7d928a

File tree

7 files changed

+245
-124
lines changed

7 files changed

+245
-124
lines changed

Cargo.lock

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

komorebi/Cargo.toml

+7-6
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ komorebi-core = { path = "../komorebi-core" }
1515

1616
bitflags = "2"
1717
clap = { version = "4", features = ["derive"] }
18+
color-eyre = { workspace = true }
1819
crossbeam-channel = "0.5"
1920
crossbeam-utils = "0.8"
2021
ctrlc = "3"
22+
dirs = { workspace = true }
2123
getset = "0.1"
24+
hex_color = { version = "3", features = ["serde"] }
2225
hotwatch = "0.4"
2326
lazy_static = "1"
2427
miow = "0.5"
@@ -38,14 +41,12 @@ tracing-appender = "0.2"
3841
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
3942
uds_windows = "1"
4043
which = "5"
44+
widestring = "1"
45+
windows = { workspace = true }
46+
windows-implement = { workspace = true }
47+
windows-interface = { workspace = true }
4148
winput = "0.2"
4249
winreg = "0.52"
43-
windows-interface = { workspace = true }
44-
windows-implement = { workspace = true }
45-
windows = { workspace = true }
46-
color-eyre = { workspace = true }
47-
dirs = { workspace = true }
48-
widestring = "1"
4950

5051
[features]
5152
deadlock_detection = []

komorebi/src/colour.rs

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use hex_color::HexColor;
2+
use schemars::gen::SchemaGenerator;
3+
use schemars::schema::InstanceType;
4+
use schemars::schema::Schema;
5+
use schemars::schema::SchemaObject;
6+
use schemars::JsonSchema;
7+
use serde::Deserialize;
8+
use serde::Serialize;
9+
10+
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
11+
#[serde(untagged)]
12+
pub enum Colour {
13+
/// Colour represented as RGB
14+
Rgb(Rgb),
15+
/// Colour represented as Hex
16+
Hex(Hex),
17+
}
18+
19+
impl From<Rgb> for Colour {
20+
fn from(value: Rgb) -> Self {
21+
Self::Rgb(value)
22+
}
23+
}
24+
25+
impl From<u32> for Colour {
26+
fn from(value: u32) -> Self {
27+
Self::Rgb(Rgb::from(value))
28+
}
29+
}
30+
31+
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
32+
pub struct Hex(HexColor);
33+
34+
impl JsonSchema for Hex {
35+
fn schema_name() -> String {
36+
String::from("Hex")
37+
}
38+
39+
fn json_schema(_: &mut SchemaGenerator) -> Schema {
40+
SchemaObject {
41+
instance_type: Some(InstanceType::String.into()),
42+
..Default::default()
43+
}
44+
.into()
45+
}
46+
}
47+
48+
impl From<Colour> for u32 {
49+
fn from(value: Colour) -> Self {
50+
match value {
51+
Colour::Rgb(val) => val.into(),
52+
Colour::Hex(val) => (Rgb::from(val)).into(),
53+
}
54+
}
55+
}
56+
57+
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
58+
pub struct Rgb {
59+
/// Red
60+
pub r: u32,
61+
/// Green
62+
pub g: u32,
63+
/// Blue
64+
pub b: u32,
65+
}
66+
67+
impl Rgb {
68+
pub fn new(r: u32, g: u32, b: u32) -> Self {
69+
Self { r, g, b }
70+
}
71+
}
72+
73+
impl From<Hex> for Rgb {
74+
fn from(value: Hex) -> Self {
75+
value.0.into()
76+
}
77+
}
78+
79+
impl From<HexColor> for Rgb {
80+
fn from(value: HexColor) -> Self {
81+
Self {
82+
r: value.r as u32,
83+
g: value.g as u32,
84+
b: value.b as u32,
85+
}
86+
}
87+
}
88+
89+
impl From<Rgb> for u32 {
90+
fn from(value: Rgb) -> Self {
91+
value.r | (value.g << 8) | (value.b << 16)
92+
}
93+
}
94+
95+
impl From<u32> for Rgb {
96+
fn from(value: u32) -> Self {
97+
Self {
98+
r: value & 0xff,
99+
g: value >> 8 & 0xff,
100+
b: value >> 16 & 0xff,
101+
}
102+
}
103+
}

komorebi/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod border;
22
pub mod com;
33
#[macro_use]
44
pub mod ring;
5+
pub mod colour;
56
pub mod container;
67
pub mod hidden;
78
pub mod monitor;

komorebi/src/process_command.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use komorebi_core::WindowContainerBehaviour;
3838
use komorebi_core::WindowKind;
3939

4040
use crate::border::Border;
41+
use crate::colour::Rgb;
4142
use crate::current_virtual_desktop;
4243
use crate::notify_subscribers;
4344
use crate::static_config::StaticConfig;
@@ -1234,14 +1235,14 @@ impl WindowManager {
12341235
SocketMessage::ActiveWindowBorderColour(kind, r, g, b) => {
12351236
match kind {
12361237
WindowKind::Single => {
1237-
BORDER_COLOUR_SINGLE.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
1238-
BORDER_COLOUR_CURRENT.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
1238+
BORDER_COLOUR_SINGLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
1239+
BORDER_COLOUR_CURRENT.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
12391240
}
12401241
WindowKind::Stack => {
1241-
BORDER_COLOUR_STACK.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
1242+
BORDER_COLOUR_STACK.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
12421243
}
12431244
WindowKind::Monocle => {
1244-
BORDER_COLOUR_MONOCLE.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
1245+
BORDER_COLOUR_MONOCLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
12451246
}
12461247
}
12471248

komorebi/src/static_config.rs

+12-42
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::border::Border;
2+
use crate::colour::Colour;
23
use crate::current_virtual_desktop;
34
use crate::monitor::Monitor;
45
use crate::ring::Ring;
@@ -28,6 +29,7 @@ use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
2829
use crate::REGEX_IDENTIFIERS;
2930
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
3031
use crate::WORKSPACE_RULES;
32+
3133
use color_eyre::Result;
3234
use crossbeam_channel::Receiver;
3335
use hotwatch::notify::DebouncedEvent;
@@ -62,34 +64,14 @@ use std::sync::Arc;
6264
use uds_windows::UnixListener;
6365
use uds_windows::UnixStream;
6466

65-
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
66-
pub struct Rgb {
67-
/// Red
68-
pub r: u32,
69-
/// Green
70-
pub g: u32,
71-
/// Blue
72-
pub b: u32,
73-
}
74-
75-
impl From<u32> for Rgb {
76-
fn from(value: u32) -> Self {
77-
Self {
78-
r: value & 0xff,
79-
g: value >> 8 & 0xff,
80-
b: value >> 16 & 0xff,
81-
}
82-
}
83-
}
84-
8567
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
8668
pub struct ActiveWindowBorderColours {
8769
/// Border colour when the container contains a single window
88-
pub single: Rgb,
70+
pub single: Colour,
8971
/// Border colour when the container contains multiple windows
90-
pub stack: Rgb,
72+
pub stack: Colour,
9173
/// Border colour when the container is in monocle mode
92-
pub monocle: Rgb,
74+
pub monocle: Colour,
9375
}
9476

9577
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
@@ -377,13 +359,13 @@ impl From<&WindowManager> for StaticConfig {
377359
None
378360
} else {
379361
Option::from(ActiveWindowBorderColours {
380-
single: Rgb::from(BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)),
381-
stack: Rgb::from(if BORDER_COLOUR_STACK.load(Ordering::SeqCst) == 0 {
362+
single: Colour::from(BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)),
363+
stack: Colour::from(if BORDER_COLOUR_STACK.load(Ordering::SeqCst) == 0 {
382364
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)
383365
} else {
384366
BORDER_COLOUR_STACK.load(Ordering::SeqCst)
385367
}),
386-
monocle: Rgb::from(if BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst) == 0 {
368+
monocle: Colour::from(if BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst) == 0 {
387369
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)
388370
} else {
389371
BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst)
@@ -487,22 +469,10 @@ impl StaticConfig {
487469
);
488470

489471
if let Some(colours) = &self.active_window_border_colours {
490-
BORDER_COLOUR_SINGLE.store(
491-
colours.single.r | (colours.single.g << 8) | (colours.single.b << 16),
492-
Ordering::SeqCst,
493-
);
494-
BORDER_COLOUR_CURRENT.store(
495-
colours.single.r | (colours.single.g << 8) | (colours.single.b << 16),
496-
Ordering::SeqCst,
497-
);
498-
BORDER_COLOUR_STACK.store(
499-
colours.stack.r | (colours.stack.g << 8) | (colours.stack.b << 16),
500-
Ordering::SeqCst,
501-
);
502-
BORDER_COLOUR_MONOCLE.store(
503-
colours.monocle.r | (colours.monocle.g << 8) | (colours.monocle.b << 16),
504-
Ordering::SeqCst,
505-
);
472+
BORDER_COLOUR_SINGLE.store(u32::from(colours.single), Ordering::SeqCst);
473+
BORDER_COLOUR_CURRENT.store(u32::from(colours.single), Ordering::SeqCst);
474+
BORDER_COLOUR_STACK.store(u32::from(colours.stack), Ordering::SeqCst);
475+
BORDER_COLOUR_MONOCLE.store(u32::from(colours.monocle), Ordering::SeqCst);
506476
}
507477

508478
let mut float_identifiers = FLOAT_IDENTIFIERS.lock();

0 commit comments

Comments
 (0)