Compare commits

..

1 Commits

Author SHA1 Message Date
LGUG2Z 7fed31bc54 wip use cached monitor idx when handling newly spawned windows 2025-03-31 15:40:59 -07:00
54 changed files with 1266 additions and 6521 deletions
Generated
+214 -852
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -394,7 +394,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
Below is a simple example of how to use `komorebi-client` in a basic Rust application. Below is a simple example of how to use `komorebi-client` in a basic Rust application.
```rust ```rust
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.36"} // komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.35"}
use anyhow::Result; use anyhow::Result;
use komorebi_client::Notification; use komorebi_client::Notification;
+1 -4
View File
@@ -13,8 +13,7 @@ feature-depth = 1
[advisories] [advisories]
ignore = [ ignore = [
{ id = "RUSTSEC-2020-0016", reason = "local tcp connectivity is an opt-in feature, and there is no upgrade path for TcpStreamExt" }, { id = "RUSTSEC-2020-0016", reason = "local tcp connectivity is an opt-in feature, and there is no upgrade path for TcpStreamExt" },
{ id = "RUSTSEC-2024-0436", reason = "paste being unmaintained is not an issue in our use" }, { id = "RUSTSEC-2024-0436", reason = "paste being unmaintained is not an issue in our use" }
{ id = "RUSTSEC-2024-0320", reason = "not using any yaml features from this library" }
] ]
[licenses] [licenses]
@@ -94,6 +93,4 @@ allow-git = [
"https://github.com/LGUG2Z/catppuccin-egui", "https://github.com/LGUG2Z/catppuccin-egui",
"https://github.com/LGUG2Z/windows-icons", "https://github.com/LGUG2Z/windows-icons",
"https://github.com/LGUG2Z/win32-display-data", "https://github.com/LGUG2Z/win32-display-data",
"https://github.com/LGUG2Z/flavours",
"https://github.com/LGUG2Z/base16_color_scheme",
] ]
+132 -260
View File
@@ -3,9 +3,8 @@
[ [
"0BSD", "0BSD",
[ [
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"win32-display-data 0.1.0 git+https://github.com/LGUG2Z/win32-display-data?rev=a28c6559a9de2f92c142a714947a9b081776caca" "win32-display-data 0.1.0 git+https://github.com/LGUG2Z/win32-display-data?rev=55cebdebfbd68dbd14945a1ba90f6b05b7be2893"
] ]
], ],
[ [
@@ -17,7 +16,6 @@
"accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index", "accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index", "accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index", "accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index",
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index", "ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
"anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index", "anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index",
@@ -26,75 +24,66 @@
"anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index", "anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index", "anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index", "anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index",
"approx 0.3.2 registry+https://github.com/rust-lang/crates.io-index", "arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index", "arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index", "atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index", "autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index", "backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index", "base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index", "bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index", "bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index", "bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index", "bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index", "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index", "cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index", "cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index", "cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index", "chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index", "clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.36 registry+https://github.com/rust-lang/crates.io-index", "clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.36 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index", "clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index", "color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index", "colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index", "crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index", "ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index", "deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"dirs 4.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index", "dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index", "displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index", "document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
"dpi 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "dpi 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index", "dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index", "dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index", "egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"either 1.15.0 registry+https://github.com/rust-lang/crates.io-index", "either 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index", "encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
"enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index", "enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index",
"enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index", "enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index",
"env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index", "equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index", "eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index",
"fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index", "fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
"fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index", "fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index", "filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.1 registry+https://github.com/rust-lang/crates.io-index", "flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index", "fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index",
"form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index", "form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
"futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
@@ -106,66 +95,53 @@
"futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index", "getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index", "getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index", "gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index", "git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index", "gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"glutin 0.32.2 registry+https://github.com/rust-lang/crates.io-index", "glutin 0.32.2 registry+https://github.com/rust-lang/crates.io-index",
"glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index", "glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index", "glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index", "half 2.4.1 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index", "hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index", "hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.3.1 registry+https://github.com/rust-lang/crates.io-index", "http 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index", "httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
"hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index", "hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index", "iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index",
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index", "idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index", "image 0.25.5 registry+https://github.com/rust-lang/crates.io-index",
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index", "imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
"immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index", "immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index",
"indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index", "indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index", "indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index", "ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index", "is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index", "itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index", "itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index", "itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.33 registry+https://github.com/rust-lang/crates.io-index", "jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.1.22 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"khronos_api 3.1.0 registry+https://github.com/rust-lang/crates.io-index", "khronos_api 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
"lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.171 registry+https://github.com/rust-lang/crates.io-index", "libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.1+1.9.0 registry+https://github.com/rust-lang/crates.io-index", "libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.22 registry+https://github.com/rust-lang/crates.io-index", "libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index",
"linked-hash-map 0.5.6 registry+https://github.com/rust-lang/crates.io-index",
"litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index", "lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.27 registry+https://github.com/rust-lang/crates.io-index", "log 0.4.26 registry+https://github.com/rust-lang/crates.io-index",
"logos 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-codegen 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-derive 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"miette 7.5.0 registry+https://github.com/rust-lang/crates.io-index", "miette 7.5.0 registry+https://github.com/rust-lang/crates.io-index",
"miette-derive 7.5.0 registry+https://github.com/rust-lang/crates.io-index", "miette-derive 7.5.0 registry+https://github.com/rust-lang/crates.io-index",
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index", "mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index", "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index", "miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index", "native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index",
"net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index", "net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index",
@@ -178,13 +154,10 @@
"num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index", "num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index",
"num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index", "num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index", "num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index", "once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index",
"owned_ttf_parser 0.25.0 registry+https://github.com/rust-lang/crates.io-index", "owned_ttf_parser 0.25.0 registry+https://github.com/rust-lang/crates.io-index",
"palette 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"palette_derive 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index", "parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index", "parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index",
"paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index", "paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
@@ -192,10 +165,9 @@
"pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index", "pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
"pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index", "pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index",
"png 0.16.8 registry+https://github.com/rust-lang/crates.io-index",
"png 0.17.16 registry+https://github.com/rust-lang/crates.io-index", "png 0.17.16 registry+https://github.com/rust-lang/crates.io-index",
"powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.21 registry+https://github.com/rust-lang/crates.io-index", "ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", "proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index", "proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index", "proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index",
@@ -203,14 +175,10 @@
"profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index", "profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index", "quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index", "quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.7.3 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index", "rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.5.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index", "rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
"rand_pcg 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index", "rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index", "rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -218,52 +186,42 @@
"regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index", "regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index", "regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index", "regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.15 registry+https://github.com/rust-lang/crates.io-index", "reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index",
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index", "rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index", "rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index", "rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index", "ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index", "serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index", "serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index", "serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index", "serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index",
"serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index", "serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index",
"serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index", "serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index", "serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
"serde_with 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_with_macros 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index", "serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.1.1 registry+https://github.com/rust-lang/crates.io-index", "shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"shell-words 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"shellexpand 2.1.2 registry+https://github.com/rust-lang/crates.io-index",
"shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index", "shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 0.3.11 registry+https://github.com/rust-lang/crates.io-index", "smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.15.0 registry+https://github.com/rust-lang/crates.io-index",
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index", "smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.9 registry+https://github.com/rust-lang/crates.io-index", "socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index",
"stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"supports-color 3.0.2 registry+https://github.com/rust-lang/crates.io-index", "supports-color 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index", "supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
"supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index", "supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index", "syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
"sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index", "sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index", "tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index", "thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index", "thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index", "thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index", "thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index", "thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index", "time 0.3.37 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index", "time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
"ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index", "ttf-parser 0.25.1 registry+https://github.com/rust-lang/crates.io-index",
"typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index", "typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index",
"tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index", "tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index",
@@ -283,59 +241,48 @@
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index", "vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"version_check 0.9.5 registry+https://github.com/rust-lang/crates.io-index", "version_check 0.9.5 registry+https://github.com/rust-lang/crates.io-index",
"web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.4 registry+https://github.com/rust-lang/crates.io-index", "webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index", "weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index",
"winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index", "winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.1 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"winit 0.30.9 registry+https://github.com/rust-lang/crates.io-index", "winit 0.30.9 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index", "wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index",
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index", "write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index", "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index" "zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
@@ -355,7 +302,7 @@
"rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index", "rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index", "v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index" "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index"
] ]
], ],
[ [
@@ -396,7 +343,7 @@
"is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"libloading 0.8.6 registry+https://github.com/rust-lang/crates.io-index", "libloading 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"starship-battery 0.10.1 registry+https://github.com/rust-lang/crates.io-index" "starship-battery 0.10.0 registry+https://github.com/rust-lang/crates.io-index"
] ]
], ],
[ [
@@ -405,7 +352,6 @@
"accesskit 0.17.1 registry+https://github.com/rust-lang/crates.io-index", "accesskit 0.17.1 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index", "accesskit_consumer 0.26.0 registry+https://github.com/rust-lang/crates.io-index",
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index", "accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", "adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index", "ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
"aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index", "aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index",
@@ -416,16 +362,14 @@
"anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index", "anstyle-query 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index", "anstyle-wincon 3.0.7 registry+https://github.com/rust-lang/crates.io-index",
"anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index", "anyhow 1.0.97 registry+https://github.com/rust-lang/crates.io-index",
"arboard 3.5.0 registry+https://github.com/rust-lang/crates.io-index", "arboard 3.4.1 registry+https://github.com/rust-lang/crates.io-index",
"arg_enum_proc_macro 0.3.4 registry+https://github.com/rust-lang/crates.io-index", "arg_enum_proc_macro 0.3.4 registry+https://github.com/rust-lang/crates.io-index",
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index", "arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index", "atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index", "autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index", "backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index", "base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index", "bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index", "bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index", "bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
@@ -434,71 +378,58 @@
"brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index", "brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index",
"built 0.7.7 registry+https://github.com/rust-lang/crates.io-index", "built 0.7.7 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index", "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"bytes 1.10.1 registry+https://github.com/rust-lang/crates.io-index", "bytes 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"calm_io 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"calmio_filters 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f", "catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f",
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index", "cc 1.2.16 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index", "cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index", "cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index", "chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index", "clap 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "clap_builder 4.5.31 registry+https://github.com/rust-lang/crates.io-index",
"clap 4.5.36 registry+https://github.com/rust-lang/crates.io-index", "clap_derive 4.5.28 registry+https://github.com/rust-lang/crates.io-index",
"clap_builder 4.5.36 registry+https://github.com/rust-lang/crates.io-index",
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index", "clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index", "color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"color-thief 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index", "colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index", "crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-channel 0.5.14 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index", "crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index", "ctrlc 3.4.5 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"darling 0.20.11 registry+https://github.com/rust-lang/crates.io-index", "deranged 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"darling_core 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
"darling_macro 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 3.0.2 registry+https://github.com/rust-lang/crates.io-index",
"dirs 4.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index", "dirs 6.0.0 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index", "displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index", "document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index", "dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "ecolor 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "eframe 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index", "egui-phosphor 0.9.0 registry+https://github.com/rust-lang/crates.io-index",
"egui-winit 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui-winit 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui_extras 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "egui_glow 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"either 1.15.0 registry+https://github.com/rust-lang/crates.io-index", "either 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"emath 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "emath 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index", "encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
"enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index", "enum-map 2.7.3 registry+https://github.com/rust-lang/crates.io-index",
"enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index", "enum-map-derive 0.17.0 registry+https://github.com/rust-lang/crates.io-index",
"env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "env_home 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "epaint 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index", "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index",
"equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index", "equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
"eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index", "eyre 0.6.12 registry+https://github.com/rust-lang/crates.io-index",
"fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index", "fastrand 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
"fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index", "fdeflate 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index", "filetime 0.2.25 registry+https://github.com/rust-lang/crates.io-index",
"flate2 1.1.1 registry+https://github.com/rust-lang/crates.io-index", "flate2 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"flavours 0.7.2 git+https://github.com/LGUG2Z/flavours",
"fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index", "fnv 1.0.7 registry+https://github.com/rust-lang/crates.io-index",
"font-loader 0.11.0 registry+https://github.com/rust-lang/crates.io-index", "font-loader 0.11.0 registry+https://github.com/rust-lang/crates.io-index",
"form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index", "form_urlencoded 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -512,79 +443,64 @@
"futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-sink 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index", "futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index", "getrandom 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index", "getrandom 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index", "getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index", "gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index", "git2 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"h2 0.4.8 registry+https://github.com/rust-lang/crates.io-index", "h2 0.4.8 registry+https://github.com/rust-lang/crates.io-index",
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index", "half 2.4.1 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index", "hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index", "hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
"hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index", "hotwatch 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"http 1.3.1 registry+https://github.com/rust-lang/crates.io-index", "http 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"http-body 1.0.1 registry+https://github.com/rust-lang/crates.io-index", "http-body 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"http-body-util 0.1.3 registry+https://github.com/rust-lang/crates.io-index", "http-body-util 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index", "httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
"hyper 1.6.0 registry+https://github.com/rust-lang/crates.io-index", "hyper 1.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index", "hyper-tls 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"hyper-util 0.1.11 registry+https://github.com/rust-lang/crates.io-index", "hyper-util 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index", "iana-time-zone 0.1.61 registry+https://github.com/rust-lang/crates.io-index",
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index", "idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"image 0.23.14 registry+https://github.com/rust-lang/crates.io-index", "image 0.25.5 registry+https://github.com/rust-lang/crates.io-index",
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index", "immutable-chunkmap 2.0.6 registry+https://github.com/rust-lang/crates.io-index",
"indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index", "indenter 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index", "indexmap 2.7.1 registry+https://github.com/rust-lang/crates.io-index",
"indexmap 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index", "ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index", "is_terminal_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index", "itertools 0.12.1 registry+https://github.com/rust-lang/crates.io-index",
"itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index", "itertools 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
"itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index", "itoa 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"jobserver 0.1.33 registry+https://github.com/rust-lang/crates.io-index", "jobserver 0.1.32 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.1.22 registry+https://github.com/rust-lang/crates.io-index",
"jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "jpeg-decoder 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "lazy_static 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"libc 0.2.171 registry+https://github.com/rust-lang/crates.io-index", "libc 0.2.170 registry+https://github.com/rust-lang/crates.io-index",
"libgit2-sys 0.18.1+1.9.0 registry+https://github.com/rust-lang/crates.io-index", "libgit2-sys 0.18.0+1.9.0 registry+https://github.com/rust-lang/crates.io-index",
"libz-sys 1.1.22 registry+https://github.com/rust-lang/crates.io-index", "libz-sys 1.1.21 registry+https://github.com/rust-lang/crates.io-index",
"linked-hash-map 0.5.6 registry+https://github.com/rust-lang/crates.io-index",
"litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "litrs 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index", "lock_api 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"log 0.4.27 registry+https://github.com/rust-lang/crates.io-index", "log 0.4.26 registry+https://github.com/rust-lang/crates.io-index",
"logos 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-codegen 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"logos-derive 0.14.4 registry+https://github.com/rust-lang/crates.io-index",
"loop9 0.1.5 registry+https://github.com/rust-lang/crates.io-index", "loop9 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
"matchers 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "matchers 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"maybe-rayon 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "maybe-rayon 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index", "memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index",
"memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index", "memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index", "mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
"mime_guess2 2.3.0 registry+https://github.com/rust-lang/crates.io-index", "mime_guess2 2.0.5 registry+https://github.com/rust-lang/crates.io-index",
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.3.7 registry+https://github.com/rust-lang/crates.io-index", "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"mio 1.0.3 registry+https://github.com/rust-lang/crates.io-index", "mio 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index", "miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
"nanoid 0.4.0 registry+https://github.com/rust-lang/crates.io-index", "nanoid 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index", "native-tls 0.2.14 registry+https://github.com/rust-lang/crates.io-index",
"net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index", "net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index",
"netdev 0.33.0 registry+https://github.com/rust-lang/crates.io-index", "netdev 0.32.0 registry+https://github.com/rust-lang/crates.io-index",
"new_debug_unreachable 1.0.6 registry+https://github.com/rust-lang/crates.io-index", "new_debug_unreachable 1.0.6 registry+https://github.com/rust-lang/crates.io-index",
"nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"nom 7.1.3 registry+https://github.com/rust-lang/crates.io-index", "nom 7.1.3 registry+https://github.com/rust-lang/crates.io-index",
@@ -598,37 +514,24 @@
"num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "num-derive 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index", "num-integer 0.1.46 registry+https://github.com/rust-lang/crates.io-index",
"num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index", "num-iter 0.1.45 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index", "num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index", "once_cell 1.20.3 registry+https://github.com/rust-lang/crates.io-index",
"os_info 3.10.0 registry+https://github.com/rust-lang/crates.io-index", "os_info 3.10.0 registry+https://github.com/rust-lang/crates.io-index",
"overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"owo-colors 3.5.0 registry+https://github.com/rust-lang/crates.io-index", "owo-colors 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
"owo-colors 4.2.0 registry+https://github.com/rust-lang/crates.io-index", "owo-colors 4.2.0 registry+https://github.com/rust-lang/crates.io-index",
"palette 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"palette_derive 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index", "parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
"parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index", "parking_lot_core 0.9.10 registry+https://github.com/rust-lang/crates.io-index",
"parse-zoneinfo 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index", "paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index",
"percent-encoding 2.3.1 registry+https://github.com/rust-lang/crates.io-index", "percent-encoding 2.3.1 registry+https://github.com/rust-lang/crates.io-index",
"phf 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_codegen 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_codegen 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_generator 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_generator 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"phf_shared 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
"phf_shared 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
"pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index", "pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
"pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "pin-utils 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index", "pkg-config 0.3.32 registry+https://github.com/rust-lang/crates.io-index",
"png 0.16.8 registry+https://github.com/rust-lang/crates.io-index",
"png 0.17.16 registry+https://github.com/rust-lang/crates.io-index", "png 0.17.16 registry+https://github.com/rust-lang/crates.io-index",
"powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "powerfmt 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"powershell_script 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "powershell_script 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"ppv-lite86 0.2.21 registry+https://github.com/rust-lang/crates.io-index", "ppv-lite86 0.2.20 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index", "proc-macro-error-attr2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index", "proc-macro-error2 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index", "proc-macro2 1.0.94 registry+https://github.com/rust-lang/crates.io-index",
@@ -636,15 +539,11 @@
"profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index", "profiling-procmacros 1.0.16 registry+https://github.com/rust-lang/crates.io-index",
"qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index", "qoi 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index", "quick-error 2.0.1 registry+https://github.com/rust-lang/crates.io-index",
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index", "quote 1.0.39 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.7.3 registry+https://github.com/rust-lang/crates.io-index",
"rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index", "rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "rand_chacha 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.5.1 registry+https://github.com/rust-lang/crates.io-index",
"rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index", "rand_core 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
"rand_pcg 0.2.1 registry+https://github.com/rust-lang/crates.io-index", "random_word 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
"random_word 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index", "rayon 1.10.0 registry+https://github.com/rust-lang/crates.io-index",
"rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index", "rayon-core 1.12.1 registry+https://github.com/rust-lang/crates.io-index",
@@ -653,9 +552,8 @@
"regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index", "regex-automata 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index", "regex-syntax 0.6.29 registry+https://github.com/rust-lang/crates.io-index",
"regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index", "regex-syntax 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"reqwest 0.12.15 registry+https://github.com/rust-lang/crates.io-index", "reqwest 0.12.12 registry+https://github.com/rust-lang/crates.io-index",
"rgb 0.8.50 registry+https://github.com/rust-lang/crates.io-index", "rgb 0.8.50 registry+https://github.com/rust-lang/crates.io-index",
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index", "rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index", "rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index", "rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
@@ -664,57 +562,46 @@
"schannel 0.1.27 registry+https://github.com/rust-lang/crates.io-index", "schannel 0.1.27 registry+https://github.com/rust-lang/crates.io-index",
"schemars 0.8.22 registry+https://github.com/rust-lang/crates.io-index", "schemars 0.8.22 registry+https://github.com/rust-lang/crates.io-index",
"schemars_derive 0.8.22 registry+https://github.com/rust-lang/crates.io-index", "schemars_derive 0.8.22 registry+https://github.com/rust-lang/crates.io-index",
"scoped_threadpool 0.1.9 registry+https://github.com/rust-lang/crates.io-index",
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index", "serde 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index", "serde_derive 1.0.218 registry+https://github.com/rust-lang/crates.io-index",
"serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index", "serde_derive_internals 0.29.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index", "serde_json 1.0.140 registry+https://github.com/rust-lang/crates.io-index",
"serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index", "serde_json_lenient 0.2.4 registry+https://github.com/rust-lang/crates.io-index",
"serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index", "serde_urlencoded 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
"serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index", "serde_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
"serde_with 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_with_macros 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
"serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index", "serde_yaml 0.9.34+deprecated registry+https://github.com/rust-lang/crates.io-index",
"shadow-rs 1.1.1 registry+https://github.com/rust-lang/crates.io-index", "shadow-rs 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"sharded-slab 0.1.7 registry+https://github.com/rust-lang/crates.io-index", "sharded-slab 0.1.7 registry+https://github.com/rust-lang/crates.io-index",
"shell-words 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"shellexpand 2.1.2 registry+https://github.com/rust-lang/crates.io-index",
"shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index", "shlex 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
"simd-adler32 0.3.7 registry+https://github.com/rust-lang/crates.io-index", "simd-adler32 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
"simd_helpers 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "simd_helpers 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 0.3.11 registry+https://github.com/rust-lang/crates.io-index",
"siphasher 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
"slab 0.4.9 registry+https://github.com/rust-lang/crates.io-index", "slab 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
"smallvec 1.15.0 registry+https://github.com/rust-lang/crates.io-index", "smallvec 1.14.0 registry+https://github.com/rust-lang/crates.io-index",
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index", "smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
"socket2 0.5.9 registry+https://github.com/rust-lang/crates.io-index", "socket2 0.5.8 registry+https://github.com/rust-lang/crates.io-index",
"stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index", "stable_deref_trait 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "static_assertions 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"strsim 0.11.1 registry+https://github.com/rust-lang/crates.io-index", "strsim 0.11.1 registry+https://github.com/rust-lang/crates.io-index",
"strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index", "strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
"strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index", "strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index", "syn 2.0.99 registry+https://github.com/rust-lang/crates.io-index",
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
"synstructure 0.13.1 registry+https://github.com/rust-lang/crates.io-index", "synstructure 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
"sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index", "sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index",
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index", "tempfile 3.17.1 registry+https://github.com/rust-lang/crates.io-index",
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index", "terminal_size 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
"textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index", "textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index", "thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index", "thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index", "thiserror-impl 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
"thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index", "thiserror-impl 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
"thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index", "thread_local 1.1.8 registry+https://github.com/rust-lang/crates.io-index",
"tiff 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
"tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index", "tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index", "time 0.3.37 registry+https://github.com/rust-lang/crates.io-index",
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index", "time-core 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"tokio 1.44.2 registry+https://github.com/rust-lang/crates.io-index", "tokio 1.43.0 registry+https://github.com/rust-lang/crates.io-index",
"tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"tokio-util 0.7.14 registry+https://github.com/rust-lang/crates.io-index", "tokio-util 0.7.13 registry+https://github.com/rust-lang/crates.io-index",
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
"tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index", "tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
"tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index", "tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
"tower-service 0.3.3 registry+https://github.com/rust-lang/crates.io-index", "tower-service 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
@@ -747,66 +634,54 @@
"walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index", "walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index",
"want 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "want 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"webbrowser 1.0.4 registry+https://github.com/rust-lang/crates.io-index", "webbrowser 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
"weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index", "weezl 0.1.8 registry+https://github.com/rust-lang/crates.io-index",
"which 7.0.3 registry+https://github.com/rust-lang/crates.io-index", "which 7.0.2 registry+https://github.com/rust-lang/crates.io-index",
"winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index", "winapi 0.3.9 registry+https://github.com/rust-lang/crates.io-index",
"winapi-util 0.1.9 registry+https://github.com/rust-lang/crates.io-index", "winapi-util 0.1.9 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index", "windows 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-collections 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-collections 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index", "windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354",
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5", "windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5",
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index", "windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-implement 0.60.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-interface 0.59.1 registry+https://github.com/rust-lang/crates.io-index", "windows-interface 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-link 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-link 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index", "windows-numerics 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-numerics 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-registry 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index", "windows-result 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index", "windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index", "windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index", "windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_i686_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_i686_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_i686_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index", "windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index", "windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
"winput 0.2.5 registry+https://github.com/rust-lang/crates.io-index", "winput 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
"winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index", "winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index",
"winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index", "winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index",
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index", "wmi 0.15.1 registry+https://github.com/rust-lang/crates.io-index",
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index", "write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
"xml-rs 0.8.26 registry+https://github.com/rust-lang/crates.io-index", "xml-rs 0.8.25 registry+https://github.com/rust-lang/crates.io-index",
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index", "zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index", "zerocopy-derive 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index" "zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
@@ -822,20 +697,19 @@
[ [
"MPL-2.0", "MPL-2.0",
[ [
"option-ext 0.2.0 registry+https://github.com/rust-lang/crates.io-index", "option-ext 0.2.0 registry+https://github.com/rust-lang/crates.io-index"
"ramhorns 1.0.1 registry+https://github.com/rust-lang/crates.io-index"
] ]
], ],
[ [
"OFL-1.1", "OFL-1.1",
[ [
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index" "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index"
] ]
], ],
[ [
"Ubuntu-font-1.0", "Ubuntu-font-1.0",
[ [
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index" "epaint_default_fonts 0.31.0 registry+https://github.com/rust-lang/crates.io-index"
] ]
], ],
[ [
@@ -844,11 +718,11 @@
"icu_collections 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_collections 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_locid 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid_transform 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_locid_transform 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_locid_transform_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index", "icu_locid_transform_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_normalizer 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_normalizer 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_normalizer_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index", "icu_normalizer_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_properties 1.5.1 registry+https://github.com/rust-lang/crates.io-index", "icu_properties 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
"icu_properties_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index", "icu_properties_data 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_provider 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_provider 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"icu_provider_macros 1.5.0 registry+https://github.com/rust-lang/crates.io-index", "icu_provider_macros 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
"litemap 0.7.5 registry+https://github.com/rust-lang/crates.io-index", "litemap 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
@@ -879,16 +753,14 @@
[ [
"Zlib", "Zlib",
[ [
"adler32 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index", "bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index", "bytemuck_derive 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
"const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index", "const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
"const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index", "const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index", "cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
"foldhash 0.1.5 registry+https://github.com/rust-lang/crates.io-index", "foldhash 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index", "glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index", "miniz_oxide 0.8.5 registry+https://github.com/rust-lang/crates.io-index",
"miniz_oxide 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index", "raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index", "zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index", "zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
+3 -2
View File
@@ -10,8 +10,9 @@ Options:
Desired ease function for animation Desired ease function for animation
[default: linear] [default: linear]
[possible values: linear, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-cubic, ease-in-out-cubic, ease-in-quart, ease-out-quart, ease-in-out-quart, ease-in-quint, ease-out-quint, ease-in-out-quint, [possible values: linear, ease-in-sine, ease-out-sine, ease-in-out-sine, ease-in-quad, ease-out-quad, ease-in-out-quad, ease-in-cubic, ease-in-out-cubic, ease-in-quart, ease-out-quart,
ease-in-expo, ease-out-expo, ease-in-out-expo, ease-in-circ, ease-out-circ, ease-in-out-circ, ease-in-back, ease-out-back, ease-in-out-back, ease-in-elastic, ease-out-elastic, ease-in-out-elastic, ease-in-bounce, ease-out-bounce, ease-in-out-bounce] ease-in-out-quart, ease-in-quint, ease-out-quint, ease-in-out-quint, ease-in-expo, ease-out-expo, ease-in-out-expo, ease-in-circ, ease-out-circ, ease-in-out-circ, ease-in-back, ease-out-back,
ease-in-out-back, ease-in-elastic, ease-out-elastic, ease-in-out-elastic, ease-in-bounce, ease-out-bounce, ease-in-out-bounce]
-a, --animation-type <ANIMATION_TYPE> -a, --animation-type <ANIMATION_TYPE>
Animation type to apply the style to. If not specified, sets global style Animation type to apply the style to. If not specified, sets global style
-12
View File
@@ -1,12 +0,0 @@
# clear-session-float-rules
```
Clear all session float rules
Usage: komorebic.exe clear-session-float-rules
Options:
-h, --help
Print help
```
-12
View File
@@ -1,12 +0,0 @@
# data-directory
```
Show the path to komorebi's data directory in %LOCALAPPDATA%
Usage: komorebic.exe data-directory
Options:
-h, --help
Print help
```
+1 -1
View File
@@ -7,7 +7,7 @@ Usage: komorebic.exe query <STATE_QUERY>
Arguments: Arguments:
<STATE_QUERY> <STATE_QUERY>
[possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name, focused-workspace-layout, version] [possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name]
Options: Options:
-h, --help -h, --help
-12
View File
@@ -1,12 +0,0 @@
# session-float-rule
```
Add a rule to float the foreground window for the rest of this session
Usage: komorebic.exe session-float-rule
Options:
-h, --help
Print help
```
-12
View File
@@ -1,12 +0,0 @@
# session-float-rules
```
Show all session float rules
Usage: komorebic.exe session-float-rules
Options:
-h, --help
Print help
```
+2 -1
View File
@@ -1,7 +1,8 @@
# toggle-workspace-float-override # toggle-workspace-float-override
``` ```
Enable or disable float override, which makes it so every new window opens in floating mode, for the currently focused workspace. If there was no override value set for the workspace previously it takes the opposite of the global value Enable or disable float override, which makes it so every new window opens in floating mode, for the currently focused workspace. If there was no override value set for the workspace previously it takes
the opposite of the global value
Usage: komorebic.exe toggle-workspace-float-override Usage: komorebic.exe toggle-workspace-float-override
+5 -1
View File
@@ -8,8 +8,12 @@ configuration file.
```json ```json
{ {
"default_workspace_padding": 0, "default_workspace_padding": 0,
"default_container_padding": -1, "default_container_padding": 0,
"border_width": 0,
"border_offset": -1
} }
``` ```
A restart of `komorebi` is required after changing these settings.
[![Watch the tutorial video](https://img.youtube.com/vi/6QYLao953XE/hqdefault.jpg)](https://www.youtube.com/watch?v=6QYLao953XE) [![Watch the tutorial video](https://img.youtube.com/vi/6QYLao953XE/hqdefault.jpg)](https://www.youtube.com/watch?v=6QYLao953XE)
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.bar.json", "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.35/schema.bar.json",
"monitor": 0, "monitor": 0,
"font_family": "JetBrains Mono", "font_family": "JetBrains Mono",
"theme": { "theme": {
+8 -1
View File
@@ -1,5 +1,5 @@
{ {
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.json", "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.35/schema.json",
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json", "app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
"window_hiding_behaviour": "Cloak", "window_hiding_behaviour": "Cloak",
"cross_monitor_move_behaviour": "Insert", "cross_monitor_move_behaviour": "Insert",
@@ -14,6 +14,13 @@
"unfocused_border": "Base03", "unfocused_border": "Base03",
"bar_accent": "Base0D" "bar_accent": "Base0D"
}, },
"stackbar": {
"height": 40,
"mode": "OnStack",
"tabs": {
"width": 300
}
},
"monitors": [ "monitors": [
{ {
"workspaces": [ "workspaces": [
-16
View File
@@ -132,19 +132,3 @@ running `komorebic stop` and `komorebic start`.
We can see the _komorebi_ state is no longer associated with the previous We can see the _komorebi_ state is no longer associated with the previous
device: `null`, suggesting an issue when the display resumes from a suspended device: `null`, suggesting an issue when the display resumes from a suspended
state. state.
## Komorebi Bar does not render transparency on Nvidia GPUs
Users with Nvidia GPUs may have issues with transparency on the Komorebi Bar.
To solve this the user can do the following:
1. Open the Nvidia Control Panel
2. On the left menu tree, under "3D Settings", select "Manage 3D Settings"
3. Select the "Program Settings" tab
4. Press the "Add" button and select "komorebi-bar"
5. Under "3. Specify the settings for this program:", find the feature labelled, "OpenGL GDI compatibility"
6. Change the setting to "Prefer compatibility"
7. At the bottom of the window select "Apply"
8. Restart the Komorebi Bar with "komorebic stop --bar; komorebic start --bar"
This should resolve the issue and your Komorebi Bar should render with the proper transparency.
+77 -143
View File
@@ -14,8 +14,6 @@ use crate::widgets::komorebi::KomorebiNotificationState;
use crate::widgets::widget::BarWidget; use crate::widgets::widget::BarWidget;
use crate::widgets::widget::WidgetConfig; use crate::widgets::widget::WidgetConfig;
use crate::KomorebiEvent; use crate::KomorebiEvent;
use crate::AUTO_SELECT_FILL_COLOUR;
use crate::AUTO_SELECT_TEXT_COLOUR;
use crate::BAR_HEIGHT; use crate::BAR_HEIGHT;
use crate::DEFAULT_PADDING; use crate::DEFAULT_PADDING;
use crate::MAX_LABEL_WIDTH; use crate::MAX_LABEL_WIDTH;
@@ -45,15 +43,12 @@ use eframe::egui::Vec2;
use eframe::egui::Visuals; use eframe::egui::Visuals;
use font_loader::system_fonts; use font_loader::system_fonts;
use font_loader::system_fonts::FontPropertyBuilder; use font_loader::system_fonts::FontPropertyBuilder;
use komorebi_client::Colour;
use komorebi_client::KomorebiTheme; use komorebi_client::KomorebiTheme;
use komorebi_client::MonitorNotification; use komorebi_client::MonitorNotification;
use komorebi_client::NotificationEvent; use komorebi_client::NotificationEvent;
use komorebi_client::PathExt;
use komorebi_client::SocketMessage; use komorebi_client::SocketMessage;
use komorebi_themes::catppuccin_egui; use komorebi_themes::catppuccin_egui;
use komorebi_themes::Base16Value; use komorebi_themes::Base16Value;
use komorebi_themes::Base16Wrapper;
use komorebi_themes::Catppuccin; use komorebi_themes::Catppuccin;
use komorebi_themes::CatppuccinValue; use komorebi_themes::CatppuccinValue;
use std::cell::RefCell; use std::cell::RefCell;
@@ -92,86 +87,75 @@ pub fn apply_theme(
grouping: Option<Grouping>, grouping: Option<Grouping>,
render_config: Rc<RefCell<RenderConfig>>, render_config: Rc<RefCell<RenderConfig>>,
) { ) {
let (auto_select_fill, auto_select_text) = match theme { match theme {
KomobarTheme::Catppuccin { KomobarTheme::Catppuccin {
name: catppuccin, name: catppuccin,
accent: catppuccin_value, accent: catppuccin_value,
auto_select_fill: catppuccin_auto_select_fill, } => match catppuccin {
auto_select_text: catppuccin_auto_select_text, Catppuccin::Frappe => {
} => { catppuccin_egui::set_theme(ctx, catppuccin_egui::FRAPPE);
match catppuccin { let catppuccin_value = catppuccin_value.unwrap_or_default();
Catppuccin::Frappe => { let accent = catppuccin_value.color32(catppuccin.as_theme());
catppuccin_egui::set_theme(ctx, catppuccin_egui::FRAPPE);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| { ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent; style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent; style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent; style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None; style.visuals.override_text_color = None;
}); });
bg_color.replace(catppuccin_egui::FRAPPE.base); bg_color.replace(catppuccin_egui::FRAPPE.base);
}
Catppuccin::Latte => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::LATTE);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::LATTE.base);
}
Catppuccin::Macchiato => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::MACCHIATO);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::MACCHIATO.base);
}
Catppuccin::Mocha => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::MOCHA.base);
}
} }
Catppuccin::Latte => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::LATTE);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
( ctx.style_mut(|style| {
catppuccin_auto_select_fill.map(|c| c.color32(catppuccin.as_theme())), style.visuals.selection.stroke.color = accent;
catppuccin_auto_select_text.map(|c| c.color32(catppuccin.as_theme())), style.visuals.widgets.hovered.fg_stroke.color = accent;
) style.visuals.widgets.active.fg_stroke.color = accent;
} style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::LATTE.base);
}
Catppuccin::Macchiato => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::MACCHIATO);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::MACCHIATO.base);
}
Catppuccin::Mocha => {
catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA);
let catppuccin_value = catppuccin_value.unwrap_or_default();
let accent = catppuccin_value.color32(catppuccin.as_theme());
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
style.visuals.override_text_color = None;
});
bg_color.replace(catppuccin_egui::MOCHA.base);
}
},
KomobarTheme::Base16 { KomobarTheme::Base16 {
name: base16, name: base16,
accent: base16_value, accent: base16_value,
auto_select_fill: base16_auto_select_fill,
auto_select_text: base16_auto_select_text,
} => { } => {
ctx.set_style(base16.style()); ctx.set_style(base16.style());
let base16_value = base16_value.unwrap_or_default(); let base16_value = base16_value.unwrap_or_default();
let accent = base16_value.color32(Base16Wrapper::Base16(base16)); let accent = base16_value.color32(base16);
ctx.style_mut(|style| { ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent; style.visuals.selection.stroke.color = accent;
@@ -180,46 +164,8 @@ pub fn apply_theme(
}); });
bg_color.replace(base16.background()); bg_color.replace(base16.background());
(
base16_auto_select_fill.map(|c| c.color32(Base16Wrapper::Base16(base16))),
base16_auto_select_text.map(|c| c.color32(Base16Wrapper::Base16(base16))),
)
} }
KomobarTheme::Custom { }
colours,
accent: base16_value,
auto_select_fill: base16_auto_select_fill,
auto_select_text: base16_auto_select_text,
} => {
let background = colours.background();
ctx.set_style(colours.style());
let base16_value = base16_value.unwrap_or_default();
let accent = base16_value.color32(Base16Wrapper::Custom(colours.clone()));
ctx.style_mut(|style| {
style.visuals.selection.stroke.color = accent;
style.visuals.widgets.hovered.fg_stroke.color = accent;
style.visuals.widgets.active.fg_stroke.color = accent;
});
bg_color.replace(background);
(
base16_auto_select_fill.map(|c| c.color32(Base16Wrapper::Custom(colours.clone()))),
base16_auto_select_text.map(|c| c.color32(Base16Wrapper::Custom(colours.clone()))),
)
}
};
AUTO_SELECT_FILL_COLOUR.store(
auto_select_fill.map_or(0, |c| Colour::from(c).into()),
Ordering::SeqCst,
);
AUTO_SELECT_TEXT_COLOUR.store(
auto_select_text.map_or(0, |c| Colour::from(c).into()),
Ordering::SeqCst,
);
// Apply transparency_alpha // Apply transparency_alpha
let theme_color = *bg_color.borrow(); let theme_color = *bg_color.borrow();
@@ -485,11 +431,11 @@ impl Komobar {
} }
fn try_apply_theme(&mut self, ctx: &Context) { fn try_apply_theme(&mut self, ctx: &Context) {
match &self.config.theme { match self.config.theme {
Some(theme) => { Some(theme) => {
apply_theme( apply_theme(
ctx, ctx,
theme.clone(), theme,
self.bg_color.clone(), self.bg_color.clone(),
self.bg_color_with_alpha.clone(), self.bg_color_with_alpha.clone(),
self.config.transparency_alpha, self.config.transparency_alpha,
@@ -501,16 +447,13 @@ impl Komobar {
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else( let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|_| dirs::home_dir().expect("there is no home directory"), |_| dirs::home_dir().expect("there is no home directory"),
|home_path| { |home_path| {
let home = home_path.replace_env(); let home = PathBuf::from(&home_path);
assert!(
home.is_dir(),
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory",
home_path
);
home
if home.as_path().is_dir() {
home
} else {
panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory");
}
}, },
); );
@@ -520,26 +463,6 @@ impl Komobar {
match komorebi_client::StaticConfig::read(&config) { match komorebi_client::StaticConfig::read(&config) {
Ok(config) => { Ok(config) => {
if let Some(theme) = config.theme { if let Some(theme) = config.theme {
let stack_accent = match theme {
KomorebiTheme::Catppuccin {
name, stack_border, ..
} => stack_border
.unwrap_or(CatppuccinValue::Green)
.color32(name.as_theme()),
KomorebiTheme::Base16 {
name, stack_border, ..
} => stack_border
.unwrap_or(Base16Value::Base0B)
.color32(Base16Wrapper::Base16(name)),
KomorebiTheme::Custom {
ref colours,
stack_border,
..
} => stack_border
.unwrap_or(Base16Value::Base0B)
.color32(Base16Wrapper::Custom(colours.clone())),
};
apply_theme( apply_theme(
ctx, ctx,
KomobarTheme::from(theme), KomobarTheme::from(theme),
@@ -550,6 +473,17 @@ impl Komobar {
self.render_config.clone(), self.render_config.clone(),
); );
let stack_accent = match theme {
KomorebiTheme::Catppuccin {
name, stack_border, ..
} => stack_border
.unwrap_or(CatppuccinValue::Green)
.color32(name.as_theme()),
KomorebiTheme::Base16 {
name, stack_border, ..
} => stack_border.unwrap_or(Base16Value::Base0B).color32(name),
};
if let Some(state) = &self.komorebi_notification_state { if let Some(state) = &self.komorebi_notification_state {
state.borrow_mut().stack_accent = Some(stack_accent); state.borrow_mut().stack_accent = Some(stack_accent);
} }
@@ -848,7 +782,7 @@ impl eframe::App for Komobar {
self.bg_color_with_alpha.clone(), self.bg_color_with_alpha.clone(),
self.config.transparency_alpha, self.config.transparency_alpha,
self.config.grouping, self.config.grouping,
self.config.theme.clone(), self.config.theme,
self.render_config.clone(), self.render_config.clone(),
); );
} }
+1 -27
View File
@@ -373,7 +373,7 @@ impl From<Position> for Pos2 {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "palette")] #[serde(tag = "palette")]
pub enum KomobarTheme { pub enum KomobarTheme {
@@ -382,24 +382,12 @@ pub enum KomobarTheme {
/// Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin) /// Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)
name: komorebi_themes::Catppuccin, name: komorebi_themes::Catppuccin,
accent: Option<komorebi_themes::CatppuccinValue>, accent: Option<komorebi_themes::CatppuccinValue>,
auto_select_fill: Option<komorebi_themes::CatppuccinValue>,
auto_select_text: Option<komorebi_themes::CatppuccinValue>,
}, },
/// A theme from base16-egui-themes /// A theme from base16-egui-themes
Base16 { Base16 {
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/) /// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)
name: komorebi_themes::Base16, name: komorebi_themes::Base16,
accent: Option<komorebi_themes::Base16Value>, accent: Option<komorebi_themes::Base16Value>,
auto_select_fill: Option<komorebi_themes::Base16Value>,
auto_select_text: Option<komorebi_themes::Base16Value>,
},
/// A custom Base16 theme
Custom {
/// Colours of the custom Base16 theme palette
colours: Box<komorebi_themes::Base16ColourPalette>,
accent: Option<komorebi_themes::Base16Value>,
auto_select_fill: Option<komorebi_themes::Base16Value>,
auto_select_text: Option<komorebi_themes::Base16Value>,
}, },
} }
@@ -411,26 +399,12 @@ impl From<KomorebiTheme> for KomobarTheme {
} => Self::Catppuccin { } => Self::Catppuccin {
name, name,
accent: bar_accent, accent: bar_accent,
auto_select_fill: None,
auto_select_text: None,
}, },
KomorebiTheme::Base16 { KomorebiTheme::Base16 {
name, bar_accent, .. name, bar_accent, ..
} => Self::Base16 { } => Self::Base16 {
name, name,
accent: bar_accent, accent: bar_accent,
auto_select_fill: None,
auto_select_text: None,
},
KomorebiTheme::Custom {
colours,
bar_accent,
..
} => Self::Custom {
colours,
accent: bar_accent,
auto_select_fill: None,
auto_select_text: None,
}, },
} }
} }
+26 -24
View File
@@ -16,8 +16,6 @@ use font_loader::system_fonts;
use hotwatch::EventKind; use hotwatch::EventKind;
use hotwatch::Hotwatch; use hotwatch::Hotwatch;
use image::RgbaImage; use image::RgbaImage;
use komorebi_client::replace_env_in_path;
use komorebi_client::PathExt;
use komorebi_client::SocketMessage; use komorebi_client::SocketMessage;
use komorebi_client::SubscribeOptions; use komorebi_client::SubscribeOptions;
use std::collections::HashMap; use std::collections::HashMap;
@@ -25,7 +23,6 @@ use std::io::BufReader;
use std::io::Read; use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::AtomicI32; use std::sync::atomic::AtomicI32;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::LazyLock; use std::sync::LazyLock;
@@ -50,9 +47,6 @@ pub static MONITOR_INDEX: AtomicUsize = AtomicUsize::new(0);
pub static BAR_HEIGHT: f32 = 50.0; pub static BAR_HEIGHT: f32 = 50.0;
pub static DEFAULT_PADDING: f32 = 10.0; pub static DEFAULT_PADDING: f32 = 10.0;
pub static AUTO_SELECT_FILL_COLOUR: AtomicU32 = AtomicU32::new(0);
pub static AUTO_SELECT_TEXT_COLOUR: AtomicU32 = AtomicU32::new(0);
pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> = pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> =
LazyLock::new(|| Mutex::new(HashMap::new())); LazyLock::new(|| Mutex::new(HashMap::new()));
@@ -67,7 +61,6 @@ struct Opts {
fonts: bool, fonts: bool,
/// Path to a JSON or YAML configuration file /// Path to a JSON or YAML configuration file
#[clap(short, long)] #[clap(short, long)]
#[clap(value_parser = replace_env_in_path)]
config: Option<PathBuf>, config: Option<PathBuf>,
/// Write an example komorebi.bar.json to disk /// Write an example komorebi.bar.json to disk
#[clap(long)] #[clap(long)]
@@ -162,15 +155,13 @@ fn main() -> color_eyre::Result<()> {
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else( let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|_| dirs::home_dir().expect("there is no home directory"), |_| dirs::home_dir().expect("there is no home directory"),
|home_path| { |home_path| {
let home = home_path.replace_env(); let home = PathBuf::from(&home_path);
assert!( if home.as_path().is_dir() {
home.is_dir(), home
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory", } else {
home_path panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory");
); }
home
}, },
); );
@@ -179,7 +170,7 @@ fn main() -> color_eyre::Result<()> {
std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?; std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?;
println!( println!(
"Example komorebi.bar.json file written to {}", "Example komorebi.bar.json file written to {}",
home_dir.display() home_dir.as_path().display()
); );
std::process::exit(0); std::process::exit(0);
@@ -187,11 +178,16 @@ fn main() -> color_eyre::Result<()> {
let default_config_path = home_dir.join("komorebi.bar.json"); let default_config_path = home_dir.join("komorebi.bar.json");
let config_path = opts.config.or_else(|| { let config_path = opts.config.map_or_else(
default_config_path || {
.is_file() if !default_config_path.is_file() {
.then_some(default_config_path.clone()) None
}); } else {
Some(default_config_path.clone())
}
},
Option::from,
);
let mut config = match config_path { let mut config = match config_path {
None => { None => {
@@ -201,14 +197,17 @@ fn main() -> color_eyre::Result<()> {
std::fs::write(&default_config_path, komorebi_bar_json)?; std::fs::write(&default_config_path, komorebi_bar_json)?;
tracing::info!( tracing::info!(
"created example configuration file: {}", "created example configuration file: {}",
default_config_path.display() default_config_path.as_path().display()
); );
KomobarConfig::read(&default_config_path)? KomobarConfig::read(&default_config_path)?
} }
Some(ref config) => { Some(ref config) => {
if !opts.aliases { if !opts.aliases {
tracing::info!("found configuration file: {}", config.display()); tracing::info!(
"found configuration file: {}",
config.as_path().to_string_lossy()
);
} }
KomobarConfig::read(config)? KomobarConfig::read(config)?
@@ -308,7 +307,10 @@ fn main() -> color_eyre::Result<()> {
hotwatch.watch(config_path, move |event| match event.kind { hotwatch.watch(config_path, move |event| match event.kind {
EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) { EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) {
Ok(updated) => { Ok(updated) => {
tracing::info!("configuration file updated: {}", config_path_cl.display()); tracing::info!(
"configuration file updated: {}",
config_path_cl.as_path().to_string_lossy()
);
if let Err(error) = tx_config.send(updated) { if let Err(error) = tx_config.send(updated) {
tracing::error!("could not send configuration update to gui: {error}") tracing::error!("could not send configuration update to gui: {error}")
-15
View File
@@ -1,8 +1,6 @@
use crate::bar::Alignment; use crate::bar::Alignment;
use crate::config::KomobarConfig; use crate::config::KomobarConfig;
use crate::config::MonitorConfigOrIndex; use crate::config::MonitorConfigOrIndex;
use crate::AUTO_SELECT_FILL_COLOUR;
use crate::AUTO_SELECT_TEXT_COLOUR;
use eframe::egui::Color32; use eframe::egui::Color32;
use eframe::egui::Context; use eframe::egui::Context;
use eframe::egui::CornerRadius; use eframe::egui::CornerRadius;
@@ -13,11 +11,8 @@ use eframe::egui::Margin;
use eframe::egui::Shadow; use eframe::egui::Shadow;
use eframe::egui::TextStyle; use eframe::egui::TextStyle;
use eframe::egui::Ui; use eframe::egui::Ui;
use komorebi_client::Colour;
use komorebi_client::Rgb;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::num::NonZeroU32;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
@@ -60,10 +55,6 @@ pub struct RenderConfig {
pub icon_font_id: FontId, pub icon_font_id: FontId,
/// Show all icons on the workspace section of the Komorebi widget /// Show all icons on the workspace section of the Komorebi widget
pub show_all_icons: bool, pub show_all_icons: bool,
/// Background color of the selected frame
pub auto_select_fill: Option<Color32>,
/// Text color of the selected frame
pub auto_select_text: Option<Color32>,
} }
pub trait RenderExt { pub trait RenderExt {
@@ -117,10 +108,6 @@ impl RenderExt for &KomobarConfig {
text_font_id, text_font_id,
icon_font_id, icon_font_id,
show_all_icons, show_all_icons,
auto_select_fill: NonZeroU32::new(AUTO_SELECT_FILL_COLOUR.load(Ordering::SeqCst))
.map(|c| Colour::Rgb(Rgb::from(c.get())).into()),
auto_select_text: NonZeroU32::new(AUTO_SELECT_TEXT_COLOUR.load(Ordering::SeqCst))
.map(|c| Colour::Rgb(Rgb::from(c.get())).into()),
} }
} }
} }
@@ -146,8 +133,6 @@ impl RenderConfig {
text_font_id: FontId::default(), text_font_id: FontId::default(),
icon_font_id: FontId::default(), icon_font_id: FontId::default(),
show_all_icons: false, show_all_icons: false,
auto_select_fill: None,
auto_select_text: None,
} }
} }
+4 -27
View File
@@ -10,29 +10,15 @@ use eframe::egui::Ui;
/// Same as SelectableLabel, but supports all content /// Same as SelectableLabel, but supports all content
pub struct SelectableFrame { pub struct SelectableFrame {
selected: bool, selected: bool,
selected_fill: Option<Color32>,
} }
impl SelectableFrame { impl SelectableFrame {
pub fn new(selected: bool) -> Self { pub fn new(selected: bool) -> Self {
Self { Self { selected }
selected,
selected_fill: None,
}
}
pub fn new_auto(selected: bool, selected_fill: Option<Color32>) -> Self {
Self {
selected,
selected_fill,
}
} }
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> Response { pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> Response {
let Self { let Self { selected } = self;
selected,
selected_fill,
} = self;
Frame::NONE Frame::NONE
.show(ui, |ui| { .show(ui, |ui| {
@@ -46,16 +32,7 @@ impl SelectableFrame {
); );
// since the stroke is drawn inside the frame, we always reserve space for it // since the stroke is drawn inside the frame, we always reserve space for it
if selected && response.hovered() { if response.hovered() || response.highlighted() || response.has_focus() {
let visuals = ui.style().interact_selectable(&response, selected);
Frame::NONE
.stroke(Stroke::new(1.0, visuals.bg_stroke.color))
.corner_radius(visuals.corner_radius)
.fill(selected_fill.unwrap_or(visuals.bg_fill))
.inner_margin(inner_margin)
.show(ui, add_contents);
} else if response.hovered() || response.highlighted() || response.has_focus() {
let visuals = ui.style().interact_selectable(&response, selected); let visuals = ui.style().interact_selectable(&response, selected);
Frame::NONE Frame::NONE
@@ -70,7 +47,7 @@ impl SelectableFrame {
Frame::NONE Frame::NONE
.stroke(Stroke::new(1.0, visuals.bg_fill)) .stroke(Stroke::new(1.0, visuals.bg_fill))
.corner_radius(visuals.corner_radius) .corner_radius(visuals.corner_radius)
.fill(selected_fill.unwrap_or(visuals.bg_fill)) .fill(visuals.bg_fill)
.inner_margin(inner_margin) .inner_margin(inner_margin)
.show(ui, add_contents); .show(ui, add_contents);
} else { } else {
+19 -56
View File
@@ -28,8 +28,6 @@ pub struct BatteryConfig {
pub data_refresh_interval: Option<u64>, pub data_refresh_interval: Option<u64>,
/// Display label prefix /// Display label prefix
pub label_prefix: Option<LabelPrefix>, pub label_prefix: Option<LabelPrefix>,
/// Select when the current percentage is under this value [[1-100]]
pub auto_select_under: Option<u8>,
} }
impl From<BatteryConfig> for Battery { impl From<BatteryConfig> for Battery {
@@ -40,10 +38,9 @@ impl From<BatteryConfig> for Battery {
enable: value.enable, enable: value.enable,
hide_on_full_charge: value.hide_on_full_charge.unwrap_or(false), hide_on_full_charge: value.hide_on_full_charge.unwrap_or(false),
manager: Manager::new().unwrap(), manager: Manager::new().unwrap(),
last_state: None, last_state: String::new(),
data_refresh_interval, data_refresh_interval,
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
auto_select_under: value.auto_select_under.map(|u| u.clamp(1, 100)),
state: BatteryState::Discharging, state: BatteryState::Discharging,
last_updated: Instant::now() last_updated: Instant::now()
.checked_sub(Duration::from_secs(data_refresh_interval)) .checked_sub(Duration::from_secs(data_refresh_interval))
@@ -55,16 +52,6 @@ impl From<BatteryConfig> for Battery {
pub enum BatteryState { pub enum BatteryState {
Charging, Charging,
Discharging, Discharging,
High,
Medium,
Low,
Warning,
}
#[derive(Clone, Debug)]
struct BatteryOutput {
label: String,
selected: bool,
} }
pub struct Battery { pub struct Battery {
@@ -74,53 +61,37 @@ pub struct Battery {
pub state: BatteryState, pub state: BatteryState,
data_refresh_interval: u64, data_refresh_interval: u64,
label_prefix: LabelPrefix, label_prefix: LabelPrefix,
auto_select_under: Option<u8>, last_state: String,
last_state: Option<BatteryOutput>,
last_updated: Instant, last_updated: Instant,
} }
impl Battery { impl Battery {
fn output(&mut self) -> Option<BatteryOutput> { fn output(&mut self) -> String {
let mut output = self.last_state.clone(); let mut output = self.last_state.clone();
let now = Instant::now(); let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
output = None; output.clear();
if let Ok(mut batteries) = self.manager.batteries() { if let Ok(mut batteries) = self.manager.batteries() {
if let Some(Ok(first)) = batteries.nth(0) { if let Some(Ok(first)) = batteries.nth(0) {
let percentage = first.state_of_charge().get::<percent>().round() as u8; let percentage = first.state_of_charge().get::<percent>();
if percentage == 100 && self.hide_on_full_charge { if percentage == 100.0 && self.hide_on_full_charge {
output = None output = String::new()
} else { } else {
match first.state() { match first.state() {
State::Charging => self.state = BatteryState::Charging, State::Charging => self.state = BatteryState::Charging,
State::Discharging => { State::Discharging => self.state = BatteryState::Discharging,
self.state = match percentage {
p if p > 75 => BatteryState::Discharging,
p if p > 50 => BatteryState::High,
p if p > 25 => BatteryState::Medium,
p if p > 10 => BatteryState::Low,
_ => BatteryState::Warning,
}
}
_ => {} _ => {}
} }
let selected = self.auto_select_under.is_some_and(|u| percentage <= u); output = match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => {
output = Some(BatteryOutput { format!("BAT: {percentage:.0}%")
label: match self.label_prefix { }
LabelPrefix::Text | LabelPrefix::IconAndText => { LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"),
format!("BAT: {percentage}%") }
}
LabelPrefix::None | LabelPrefix::Icon => {
format!("{percentage}%")
}
},
selected,
})
} }
} }
} }
@@ -137,43 +108,35 @@ impl BarWidget for Battery {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable { if self.enable {
let output = self.output(); let output = self.output();
if let Some(output) = output { if !output.is_empty() {
let emoji = match self.state { let emoji = match self.state {
BatteryState::Charging => egui_phosphor::regular::BATTERY_CHARGING, BatteryState::Charging => egui_phosphor::regular::BATTERY_CHARGING,
BatteryState::Discharging => egui_phosphor::regular::BATTERY_FULL, BatteryState::Discharging => egui_phosphor::regular::BATTERY_FULL,
BatteryState::High => egui_phosphor::regular::BATTERY_HIGH,
BatteryState::Medium => egui_phosphor::regular::BATTERY_MEDIUM,
BatteryState::Low => egui_phosphor::regular::BATTERY_LOW,
BatteryState::Warning => egui_phosphor::regular::BATTERY_WARNING,
}; };
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
let mut layout_job = LayoutJob::simple( let mut layout_job = LayoutJob::simple(
match self.label_prefix { match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(), LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(),
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), config.icon_font_id.clone(),
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color), ctx.style().visuals.selection.stroke.color,
100.0, 100.0,
); );
layout_job.append( layout_job.append(
&output.label, &output,
10.0, 10.0,
TextFormat { TextFormat {
font_id: config.text_font_id.clone(), font_id: config.text_font_id.clone(),
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()), color: ctx.style().visuals.text_color(),
valign: Align::Center, valign: Align::Center,
..Default::default() ..Default::default()
}, },
); );
let auto_focus_fill = config.auto_select_fill;
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
if SelectableFrame::new_auto(output.selected, auto_focus_fill) if SelectableFrame::new(false)
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false))) .show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
.clicked() .clicked()
{ {
+10 -29
View File
@@ -25,8 +25,6 @@ pub struct CpuConfig {
pub data_refresh_interval: Option<u64>, pub data_refresh_interval: Option<u64>,
/// Display label prefix /// Display label prefix
pub label_prefix: Option<LabelPrefix>, pub label_prefix: Option<LabelPrefix>,
/// Select when the current percentage is over this value [[1-100]]
pub auto_select_over: Option<u8>,
} }
impl From<CpuConfig> for Cpu { impl From<CpuConfig> for Cpu {
@@ -40,7 +38,6 @@ impl From<CpuConfig> for Cpu {
), ),
data_refresh_interval, data_refresh_interval,
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
last_updated: Instant::now() last_updated: Instant::now()
.checked_sub(Duration::from_secs(data_refresh_interval)) .checked_sub(Duration::from_secs(data_refresh_interval))
.unwrap(), .unwrap(),
@@ -48,38 +45,26 @@ impl From<CpuConfig> for Cpu {
} }
} }
#[derive(Clone, Debug)]
struct CpuOutput {
label: String,
selected: bool,
}
pub struct Cpu { pub struct Cpu {
pub enable: bool, pub enable: bool,
system: System, system: System,
data_refresh_interval: u64, data_refresh_interval: u64,
label_prefix: LabelPrefix, label_prefix: LabelPrefix,
auto_select_over: Option<u8>,
last_updated: Instant, last_updated: Instant,
} }
impl Cpu { impl Cpu {
fn output(&mut self) -> CpuOutput { fn output(&mut self) -> String {
let now = Instant::now(); let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
self.system.refresh_cpu_usage(); self.system.refresh_cpu_usage();
self.last_updated = now; self.last_updated = now;
} }
let used = self.system.global_cpu_usage() as u8; let used = self.system.global_cpu_usage();
let selected = self.auto_select_over.is_some_and(|o| used >= o); match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {:.0}%", used),
CpuOutput { LabelPrefix::None | LabelPrefix::Icon => format!("{:.0}%", used),
label: match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {}%", used),
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", used),
},
selected,
} }
} }
} }
@@ -88,9 +73,7 @@ impl BarWidget for Cpu {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable { if self.enable {
let output = self.output(); let output = self.output();
if !output.label.is_empty() { if !output.is_empty() {
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
let mut layout_job = LayoutJob::simple( let mut layout_job = LayoutJob::simple(
match self.label_prefix { match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => { LabelPrefix::Icon | LabelPrefix::IconAndText => {
@@ -99,25 +82,23 @@ impl BarWidget for Cpu {
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), config.icon_font_id.clone(),
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color), ctx.style().visuals.selection.stroke.color,
100.0, 100.0,
); );
layout_job.append( layout_job.append(
&output.label, &output,
10.0, 10.0,
TextFormat { TextFormat {
font_id: config.text_font_id.clone(), font_id: config.text_font_id.clone(),
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()), color: ctx.style().visuals.text_color(),
valign: Align::Center, valign: Align::Center,
..Default::default() ..Default::default()
}, },
); );
let auto_focus_fill = config.auto_select_fill;
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
if SelectableFrame::new_auto(output.selected, auto_focus_fill) if SelectableFrame::new(false)
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false))) .show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
.clicked() .clicked()
{ {
+105 -167
View File
@@ -11,9 +11,7 @@ use crate::widgets::widget::BarWidget;
use crate::ICON_CACHE; use crate::ICON_CACHE;
use crate::MAX_LABEL_WIDTH; use crate::MAX_LABEL_WIDTH;
use crate::MONITOR_INDEX; use crate::MONITOR_INDEX;
use eframe::egui::text::LayoutJob;
use eframe::egui::vec2; use eframe::egui::vec2;
use eframe::egui::Align;
use eframe::egui::Color32; use eframe::egui::Color32;
use eframe::egui::ColorImage; use eframe::egui::ColorImage;
use eframe::egui::Context; use eframe::egui::Context;
@@ -26,7 +24,6 @@ use eframe::egui::RichText;
use eframe::egui::Sense; use eframe::egui::Sense;
use eframe::egui::Stroke; use eframe::egui::Stroke;
use eframe::egui::StrokeKind; use eframe::egui::StrokeKind;
use eframe::egui::TextFormat;
use eframe::egui::TextureHandle; use eframe::egui::TextureHandle;
use eframe::egui::TextureOptions; use eframe::egui::TextureOptions;
use eframe::egui::Ui; use eframe::egui::Ui;
@@ -58,11 +55,8 @@ pub struct KomorebiConfig {
pub layout: Option<KomorebiLayoutConfig>, pub layout: Option<KomorebiLayoutConfig>,
/// Configure the Workspace Layer widget /// Configure the Workspace Layer widget
pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>, pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>,
/// Configure the Focused Container widget /// Configure the Focused Window widget
#[serde(alias = "focused_window")] pub focused_window: Option<KomorebiFocusedWindowConfig>,
pub focused_container: Option<KomorebiFocusedContainerConfig>,
/// Configure the Locked Container widget
pub locked_container: Option<KomorebiLockedContainerConfig>,
/// Configure the Configuration Switcher widget /// Configure the Configuration Switcher widget
pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>, pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>,
} }
@@ -102,26 +96,15 @@ pub struct KomorebiWorkspaceLayerConfig {
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct KomorebiFocusedContainerConfig { pub struct KomorebiFocusedWindowConfig {
/// Enable the Komorebi Focused Container widget /// Enable the Komorebi Focused Window widget
pub enable: bool, pub enable: bool,
/// DEPRECATED: use 'display' instead (Show the icon of the currently focused container) /// DEPRECATED: use 'display' instead (Show the icon of the currently focused window)
pub show_icon: Option<bool>, pub show_icon: Option<bool>,
/// Display format of the currently focused container /// Display format of the currently focused window
pub display: Option<DisplayFormat>, pub display: Option<DisplayFormat>,
} }
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct KomorebiLockedContainerConfig {
/// Enable the Komorebi Locked Container widget
pub enable: bool,
/// Display format of the current locked state
pub display: Option<DisplayFormat>,
/// Show the widget event if the layer is unlocked
pub show_when_unlocked: Option<bool>,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct KomorebiConfigurationSwitcherConfig { pub struct KomorebiConfigurationSwitcherConfig {
@@ -157,19 +140,15 @@ impl From<&KomorebiConfig> for Komorebi {
.unwrap_or_default(), .unwrap_or_default(),
mouse_follows_focus: true, mouse_follows_focus: true,
work_area_offset: None, work_area_offset: None,
focused_container_information: ( focused_container_information: KomorebiNotificationStateContainerInformation::EMPTY,
false,
KomorebiNotificationStateContainerInformation::EMPTY,
),
stack_accent: None, stack_accent: None,
monitor_index: MONITOR_INDEX.load(Ordering::SeqCst), monitor_index: MONITOR_INDEX.load(Ordering::SeqCst),
monitor_usr_idx_map: HashMap::new(), monitor_usr_idx_map: HashMap::new(),
})), })),
workspaces: value.workspaces, workspaces: value.workspaces,
layout: value.layout.clone(), layout: value.layout.clone(),
focused_container: value.focused_container, focused_window: value.focused_window,
workspace_layer: value.workspace_layer, workspace_layer: value.workspace_layer,
locked_container: value.locked_container,
configuration_switcher, configuration_switcher,
} }
} }
@@ -180,9 +159,8 @@ pub struct Komorebi {
pub komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>, pub komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>,
pub workspaces: Option<KomorebiWorkspacesConfig>, pub workspaces: Option<KomorebiWorkspacesConfig>,
pub layout: Option<KomorebiLayoutConfig>, pub layout: Option<KomorebiLayoutConfig>,
pub focused_container: Option<KomorebiFocusedContainerConfig>, pub focused_window: Option<KomorebiFocusedWindowConfig>,
pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>, pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>,
pub locked_container: Option<KomorebiLockedContainerConfig>,
pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>, pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>,
} }
@@ -200,10 +178,9 @@ impl BarWidget for Komorebi {
let format = workspaces.display.unwrap_or(DisplayFormat::Text.into()); let format = workspaces.display.unwrap_or(DisplayFormat::Text.into());
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
for (i, (ws, containers, _, should_show)) in for (i, (ws, containers, _)) in
komorebi_notification_state.workspaces.iter().enumerate() komorebi_notification_state.workspaces.iter().enumerate()
{ {
if *should_show {
let is_selected = komorebi_notification_state.selected_workspace.eq(ws); let is_selected = komorebi_notification_state.selected_workspace.eq(ws);
if SelectableFrame::new( if SelectableFrame::new(
@@ -292,6 +269,7 @@ impl BarWidget for Komorebi {
komorebi_notification_state.monitor_index, komorebi_notification_state.monitor_index,
i, i,
), ),
SocketMessage::RetileWithResizeDimensions,
SocketMessage::MouseFollowsFocus(true), SocketMessage::MouseFollowsFocus(true),
]) ])
.is_err() .is_err()
@@ -300,6 +278,7 @@ impl BarWidget for Komorebi {
"could not send the following batch of messages to komorebi:\n "could not send the following batch of messages to komorebi:\n
MouseFollowsFocus(false)\n MouseFollowsFocus(false)\n
FocusMonitorWorkspaceNumber({}, {})\n FocusMonitorWorkspaceNumber({}, {})\n
RetileWithResizeDimensions
MouseFollowsFocus(true)\n", MouseFollowsFocus(true)\n",
komorebi_notification_state.monitor_index, komorebi_notification_state.monitor_index,
i, i,
@@ -310,18 +289,19 @@ impl BarWidget for Komorebi {
komorebi_notification_state.monitor_index, komorebi_notification_state.monitor_index,
i, i,
), ),
SocketMessage::RetileWithResizeDimensions,
]) ])
.is_err() .is_err()
{ {
tracing::error!( tracing::error!(
"could not send the following batch of messages to komorebi:\n "could not send the following batch of messages to komorebi:\n
FocusMonitorWorkspaceNumber({}, {})\n", FocusMonitorWorkspaceNumber({}, {})\n
RetileWithResizeDimensions",
komorebi_notification_state.monitor_index, komorebi_notification_state.monitor_index,
i, i,
); );
} }
} }
}
} }
}); });
} }
@@ -338,7 +318,7 @@ impl BarWidget for Komorebi {
.workspaces .workspaces
.iter() .iter()
.find(|o| komorebi_notification_state.selected_workspace.eq(&o.0)) .find(|o| komorebi_notification_state.selected_workspace.eq(&o.0))
.map(|(_, _, layer, _)| layer); .map(|(_, _, layer)| layer);
if let Some(layer) = layer { if let Some(layer) = layer {
if (layer_config.show_when_tiling.unwrap_or_default() if (layer_config.show_when_tiling.unwrap_or_default()
@@ -355,7 +335,7 @@ impl BarWidget for Komorebi {
if matches!(layer, WorkspaceLayer::Tiling) { if matches!(layer, WorkspaceLayer::Tiling) {
let (response, painter) = let (response, painter) =
ui.allocate_painter(size, Sense::hover()); ui.allocate_painter(size, Sense::hover());
let color = ctx.style().visuals.selection.stroke.color; let color = ui.style().visuals.text_color();
let stroke = Stroke::new(1.0, color); let stroke = Stroke::new(1.0, color);
let mut rect = response.rect; let mut rect = response.rect;
let corner = let corner =
@@ -385,7 +365,7 @@ impl BarWidget for Komorebi {
} else { } else {
let (response, painter) = let (response, painter) =
ui.allocate_painter(size, Sense::hover()); ui.allocate_painter(size, Sense::hover());
let color = ctx.style().visuals.selection.stroke.color; let color = ui.style().visuals.text_color();
let stroke = Stroke::new(1.0, color); let stroke = Stroke::new(1.0, color);
let mut rect = response.rect; let mut rect = response.rect;
let corner = let corner =
@@ -468,109 +448,72 @@ impl BarWidget for Komorebi {
for (name, location) in configuration_switcher.configurations.iter() { for (name, location) in configuration_switcher.configurations.iter() {
let path = PathBuf::from(location); let path = PathBuf::from(location);
if path.is_file() { if path.is_file() {
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui,|ui|{
if SelectableFrame::new(false) if SelectableFrame::new(false).show(ui, |ui|{
.show(ui, |ui| ui.add(Label::new(name).selectable(false))) ui.add(Label::new(name).selectable(false))
.clicked() })
.clicked()
{
let canonicalized = dunce::canonicalize(path.clone()).unwrap_or(path);
let mut proceed = true;
if komorebi_client::send_message(&SocketMessage::ReplaceConfiguration(
canonicalized,
))
.is_err()
{ {
let canonicalized = tracing::error!(
dunce::canonicalize(path.clone()).unwrap_or(path); "could not send message to komorebi: ReplaceConfiguration"
);
proceed = false;
}
if komorebi_client::send_message( if let Some(rect) = komorebi_notification_state.work_area_offset {
&SocketMessage::ReplaceConfiguration(canonicalized), if proceed {
) match komorebi_client::send_query(&SocketMessage::Query(
.is_err() komorebi_client::StateQuery::FocusedMonitorIndex,
{ )) {
tracing::error!( Ok(idx) => {
"could not send message to komorebi: ReplaceConfiguration" if let Ok(monitor_idx) = idx.parse::<usize>() {
); if komorebi_client::send_message(
&SocketMessage::MonitorWorkAreaOffset(
monitor_idx,
rect,
),
)
.is_err()
{
tracing::error!(
"could not send message to komorebi: MonitorWorkAreaOffset"
);
}
}
}
Err(_) => {
tracing::error!(
"could not send message to komorebi: Query"
);
}
}
} }
} }
}); }});
} }
} }
} }
} }
if let Some(locked_container_config) = self.locked_container { if let Some(focused_window) = self.focused_window {
if locked_container_config.enable { if focused_window.enable {
let is_locked = komorebi_notification_state.focused_container_information.0;
if locked_container_config
.show_when_unlocked
.unwrap_or_default()
|| is_locked
{
let titles = &komorebi_notification_state
.focused_container_information
.1
.titles;
if !titles.is_empty() {
let display_format = locked_container_config
.display
.unwrap_or(DisplayFormat::Text);
let mut layout_job = LayoutJob::simple(
if display_format != DisplayFormat::Text {
if is_locked {
egui_phosphor::regular::LOCK_KEY.to_string()
} else {
egui_phosphor::regular::LOCK_SIMPLE_OPEN.to_string()
}
} else {
String::new()
},
config.icon_font_id.clone(),
ctx.style().visuals.selection.stroke.color,
100.0,
);
if display_format != DisplayFormat::Icon {
layout_job.append(
if is_locked { "Locked" } else { "Unlocked" },
10.0,
TextFormat {
font_id: config.text_font_id.clone(),
color: ctx.style().visuals.text_color(),
valign: Align::Center,
..Default::default()
},
);
}
config.apply_on_widget(false, ui, |ui| {
if SelectableFrame::new(false)
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
.clicked()
&& komorebi_client::send_batch([
SocketMessage::FocusMonitorAtCursor,
SocketMessage::ToggleLock,
])
.is_err()
{
tracing::error!("could not send ToggleLock");
}
});
}
}
}
}
if let Some(focused_container_config) = self.focused_container {
if focused_container_config.enable {
let titles = &komorebi_notification_state let titles = &komorebi_notification_state
.focused_container_information .focused_container_information
.1
.titles; .titles;
if !titles.is_empty() { if !titles.is_empty() {
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
let icons = &komorebi_notification_state let icons = &komorebi_notification_state
.focused_container_information.1 .focused_container_information
.icons; .icons;
let focused_window_idx = komorebi_notification_state let focused_window_idx = komorebi_notification_state
.focused_container_information.1 .focused_container_information
.focused_window_idx; .focused_window_idx;
let iter = titles.iter().zip(icons.iter()); let iter = titles.iter().zip(icons.iter());
@@ -578,13 +521,13 @@ impl BarWidget for Komorebi {
for (i, (title, icon)) in iter.enumerate() { for (i, (title, icon)) in iter.enumerate() {
let selected = i == focused_window_idx && len != 1; let selected = i == focused_window_idx && len != 1;
let text_color = if selected { ctx.style().visuals.selection.stroke.color } else { ui.style().visuals.text_color() }; let text_color = if selected { ctx.style().visuals.selection.stroke.color} else { ui.style().visuals.text_color() };
if SelectableFrame::new(selected) if SelectableFrame::new(selected)
.show(ui, |ui| { .show(ui, |ui| {
// handle legacy setting // handle legacy setting
let format = focused_container_config.display.unwrap_or( let format = focused_window.display.unwrap_or(
if focused_container_config.show_icon.unwrap_or(false) { if focused_window.show_icon.unwrap_or(false) {
DisplayFormat::IconAndText DisplayFormat::IconAndText
} else { } else {
DisplayFormat::Text DisplayFormat::Text
@@ -684,10 +627,9 @@ pub struct KomorebiNotificationState {
String, String,
Vec<(bool, KomorebiNotificationStateContainerInformation)>, Vec<(bool, KomorebiNotificationStateContainerInformation)>,
WorkspaceLayer, WorkspaceLayer,
bool,
)>, )>,
pub selected_workspace: String, pub selected_workspace: String,
pub focused_container_information: (bool, KomorebiNotificationStateContainerInformation), pub focused_container_information: KomorebiNotificationStateContainerInformation,
pub layout: KomorebiLayout, pub layout: KomorebiLayout,
pub hide_empty_workspaces: bool, pub hide_empty_workspaces: bool,
pub mouse_follows_focus: bool, pub mouse_follows_focus: bool,
@@ -753,7 +695,7 @@ impl KomorebiNotificationState {
SocketMessage::Theme(theme) => { SocketMessage::Theme(theme) => {
apply_theme( apply_theme(
ctx, ctx,
KomobarTheme::from(*theme), KomobarTheme::from(theme),
bg_color, bg_color,
bg_color_with_alpha.clone(), bg_color_with_alpha.clone(),
transparency_alpha, transparency_alpha,
@@ -800,41 +742,42 @@ impl KomorebiNotificationState {
true true
}; };
workspaces.push(( if should_show {
ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)), workspaces.push((
if show_all_icons { ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)),
let mut containers = vec![]; if show_all_icons {
let mut has_monocle = false; let mut containers = vec![];
let mut has_monocle = false;
// add monocle container // add monocle container
if let Some(container) = ws.monocle_container() { if let Some(container) = ws.monocle_container() {
containers.push((true, container.into())); containers.push((true, container.into()));
has_monocle = true; has_monocle = true;
} }
// add all tiled windows // add all tiled windows
for (i, container) in ws.containers().iter().enumerate() { for (i, container) in ws.containers().iter().enumerate() {
containers.push(( containers.push((
!has_monocle && i == ws.focused_container_idx(), !has_monocle && i == ws.focused_container_idx(),
container.into(), container.into(),
)); ));
} }
// add all floating windows // add all floating windows
for floating_window in ws.floating_windows() { for floating_window in ws.floating_windows() {
containers.push(( containers.push((
!has_monocle && floating_window.is_focused(), !has_monocle && floating_window.is_focused(),
floating_window.into(), floating_window.into(),
)); ));
} }
containers containers
} else { } else {
vec![(true, ws.into())] vec![(true, ws.into())]
}, },
ws.layer().to_owned(), ws.layer().to_owned(),
should_show, ));
)); }
} }
self.workspaces = workspaces; self.workspaces = workspaces;
@@ -855,12 +798,7 @@ impl KomorebiNotificationState {
}; };
} }
let focused_workspace = &monitor.workspaces()[focused_workspace_idx]; self.focused_container_information = (&monitor.workspaces()[focused_workspace_idx]).into();
let is_focused = focused_workspace
.locked_containers()
.contains(&focused_workspace.focused_container_idx());
self.focused_container_information = (is_focused, focused_workspace.into());
} }
} }
+1 -1
View File
@@ -251,7 +251,7 @@ impl KomorebiLayout {
let layout_frame = SelectableFrame::new(false) let layout_frame = SelectableFrame::new(false)
.show(ui, |ui| { .show(ui, |ui| {
if let DisplayFormat::Icon | DisplayFormat::IconAndText = format { if let DisplayFormat::Icon | DisplayFormat::IconAndText = format {
self.show_icon(true, font_id.clone(), ctx, ui); self.show_icon(false, font_id.clone(), ctx, ui);
} }
if let DisplayFormat::Text | DisplayFormat::IconAndText = format { if let DisplayFormat::Text | DisplayFormat::IconAndText = format {
+11 -31
View File
@@ -25,8 +25,6 @@ pub struct MemoryConfig {
pub data_refresh_interval: Option<u64>, pub data_refresh_interval: Option<u64>,
/// Display label prefix /// Display label prefix
pub label_prefix: Option<LabelPrefix>, pub label_prefix: Option<LabelPrefix>,
/// Select when the current percentage is over this value [[1-100]]
pub auto_select_over: Option<u8>,
} }
impl From<MemoryConfig> for Memory { impl From<MemoryConfig> for Memory {
@@ -40,7 +38,6 @@ impl From<MemoryConfig> for Memory {
), ),
data_refresh_interval, data_refresh_interval,
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
last_updated: Instant::now() last_updated: Instant::now()
.checked_sub(Duration::from_secs(data_refresh_interval)) .checked_sub(Duration::from_secs(data_refresh_interval))
.unwrap(), .unwrap(),
@@ -48,23 +45,16 @@ impl From<MemoryConfig> for Memory {
} }
} }
#[derive(Clone, Debug)]
struct MemoryOutput {
label: String,
selected: bool,
}
pub struct Memory { pub struct Memory {
pub enable: bool, pub enable: bool,
system: System, system: System,
data_refresh_interval: u64, data_refresh_interval: u64,
label_prefix: LabelPrefix, label_prefix: LabelPrefix,
auto_select_over: Option<u8>,
last_updated: Instant, last_updated: Instant,
} }
impl Memory { impl Memory {
fn output(&mut self) -> MemoryOutput { fn output(&mut self) -> String {
let now = Instant::now(); let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
self.system.refresh_memory(); self.system.refresh_memory();
@@ -73,17 +63,11 @@ impl Memory {
let used = self.system.used_memory(); let used = self.system.used_memory();
let total = self.system.total_memory(); let total = self.system.total_memory();
let usage = ((used * 100) / total) as u8; match self.label_prefix {
let selected = self.auto_select_over.is_some_and(|o| usage >= o); LabelPrefix::Text | LabelPrefix::IconAndText => {
format!("RAM: {}%", (used * 100) / total)
MemoryOutput { }
label: match self.label_prefix { LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
LabelPrefix::Text | LabelPrefix::IconAndText => {
format!("RAM: {}%", usage)
}
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", usage),
},
selected,
} }
} }
} }
@@ -92,9 +76,7 @@ impl BarWidget for Memory {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable { if self.enable {
let output = self.output(); let output = self.output();
if !output.label.is_empty() { if !output.is_empty() {
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
let mut layout_job = LayoutJob::simple( let mut layout_job = LayoutJob::simple(
match self.label_prefix { match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => { LabelPrefix::Icon | LabelPrefix::IconAndText => {
@@ -103,25 +85,23 @@ impl BarWidget for Memory {
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), config.icon_font_id.clone(),
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color), ctx.style().visuals.selection.stroke.color,
100.0, 100.0,
); );
layout_job.append( layout_job.append(
&output.label, &output,
10.0, 10.0,
TextFormat { TextFormat {
font_id: config.text_font_id.clone(), font_id: config.text_font_id.clone(),
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()), color: ctx.style().visuals.text_color(),
valign: Align::Center, valign: Align::Center,
..Default::default() ..Default::default()
}, },
); );
let auto_focus_fill = config.auto_select_fill;
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
if SelectableFrame::new_auto(output.selected, auto_focus_fill) if SelectableFrame::new(false)
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false))) .show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
.clicked() .clicked()
{ {
+88 -252
View File
@@ -1,11 +1,9 @@
use crate::bar::Alignment;
use crate::config::LabelPrefix; use crate::config::LabelPrefix;
use crate::render::RenderConfig; use crate::render::RenderConfig;
use crate::selected_frame::SelectableFrame; use crate::selected_frame::SelectableFrame;
use crate::widgets::widget::BarWidget; use crate::widgets::widget::BarWidget;
use eframe::egui::text::LayoutJob; use eframe::egui::text::LayoutJob;
use eframe::egui::Align; use eframe::egui::Align;
use eframe::egui::Color32;
use eframe::egui::Context; use eframe::egui::Context;
use eframe::egui::Label; use eframe::egui::Label;
use eframe::egui::TextFormat; use eframe::egui::TextFormat;
@@ -24,36 +22,18 @@ use sysinfo::Networks;
pub struct NetworkConfig { pub struct NetworkConfig {
/// Enable the Network widget /// Enable the Network widget
pub enable: bool, pub enable: bool,
/// Show total received and transmitted activity /// Show total data transmitted
#[serde(alias = "show_total_data_transmitted")] pub show_total_data_transmitted: bool,
pub show_total_activity: bool, /// Show network activity
/// Show received and transmitted activity pub show_network_activity: bool,
#[serde(alias = "show_network_activity")]
pub show_activity: bool,
/// Show default interface /// Show default interface
pub show_default_interface: Option<bool>, pub show_default_interface: Option<bool>,
/// Characters to reserve for received and transmitted activity /// Characters to reserve for network activity data
#[serde(alias = "network_activity_fill_characters")] pub network_activity_fill_characters: Option<usize>,
pub activity_left_padding: Option<usize>,
/// Data refresh interval (default: 10 seconds) /// Data refresh interval (default: 10 seconds)
pub data_refresh_interval: Option<u64>, pub data_refresh_interval: Option<u64>,
/// Display label prefix /// Display label prefix
pub label_prefix: Option<LabelPrefix>, pub label_prefix: Option<LabelPrefix>,
/// Select when the value is over a limit (1MiB is 1048576 bytes (1024*1024))
pub auto_select: Option<NetworkSelectConfig>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct NetworkSelectConfig {
/// Select the total received data when it's over this value
pub total_received_over: Option<u64>,
/// Select the total transmitted data when it's over this value
pub total_transmitted_over: Option<u64>,
/// Select the received data when it's over this value
pub received_over: Option<u64>,
/// Select the transmitted data when it's over this value
pub transmitted_over: Option<u64>,
} }
impl From<NetworkConfig> for Network { impl From<NetworkConfig> for Network {
@@ -62,15 +42,16 @@ impl From<NetworkConfig> for Network {
Self { Self {
enable: value.enable, enable: value.enable,
show_total_activity: value.show_total_activity, show_total_activity: value.show_total_data_transmitted,
show_activity: value.show_activity, show_activity: value.show_network_activity,
show_default_interface: value.show_default_interface.unwrap_or(true), show_default_interface: value.show_default_interface.unwrap_or(true),
networks_network_activity: Networks::new_with_refreshed_list(), networks_network_activity: Networks::new_with_refreshed_list(),
default_interface: String::new(), default_interface: String::new(),
data_refresh_interval, data_refresh_interval,
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon), label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
auto_select: value.auto_select, network_activity_fill_characters: value
activity_left_padding: value.activity_left_padding.unwrap_or_default(), .network_activity_fill_characters
.unwrap_or_default(),
last_state_total_activity: vec![], last_state_total_activity: vec![],
last_state_activity: vec![], last_state_activity: vec![],
last_updated_network_activity: Instant::now() last_updated_network_activity: Instant::now()
@@ -88,12 +69,11 @@ pub struct Network {
networks_network_activity: Networks, networks_network_activity: Networks,
data_refresh_interval: u64, data_refresh_interval: u64,
label_prefix: LabelPrefix, label_prefix: LabelPrefix,
auto_select: Option<NetworkSelectConfig>,
default_interface: String, default_interface: String,
last_state_total_activity: Vec<NetworkReading>, last_state_total_activity: Vec<NetworkReading>,
last_state_activity: Vec<NetworkReading>, last_state_activity: Vec<NetworkReading>,
last_updated_network_activity: Instant, last_updated_network_activity: Instant,
activity_left_padding: usize, network_activity_fill_characters: usize,
} }
impl Network { impl Network {
@@ -125,32 +105,24 @@ impl Network {
for (interface_name, data) in &self.networks_network_activity { for (interface_name, data) in &self.networks_network_activity {
if friendly_name.eq(interface_name) { if friendly_name.eq(interface_name) {
if self.show_activity { if self.show_activity {
let received = Self::to_pretty_bytes(
data.received(),
self.data_refresh_interval,
);
let transmitted = Self::to_pretty_bytes(
data.transmitted(),
self.data_refresh_interval,
);
activity.push(NetworkReading::new( activity.push(NetworkReading::new(
NetworkReadingFormat::Speed, NetworkReadingFormat::Speed,
ReadingValue::from(received), Self::to_pretty_bytes(
ReadingValue::from(transmitted), data.received(),
self.data_refresh_interval,
),
Self::to_pretty_bytes(
data.transmitted(),
self.data_refresh_interval,
),
)); ));
} }
if self.show_total_activity { if self.show_total_activity {
let total_received =
Self::to_pretty_bytes(data.total_received(), 1);
let total_transmitted =
Self::to_pretty_bytes(data.total_transmitted(), 1);
total_activity.push(NetworkReading::new( total_activity.push(NetworkReading::new(
NetworkReadingFormat::Total, NetworkReadingFormat::Total,
ReadingValue::from(total_received), Self::to_pretty_bytes(data.total_received(), 1),
ReadingValue::from(total_transmitted), Self::to_pretty_bytes(data.total_transmitted(), 1),
)) ))
} }
} }
@@ -166,121 +138,105 @@ impl Network {
(activity, total_activity) (activity, total_activity)
} }
fn reading_to_labels( fn reading_to_label(
&self, &self,
select_received: bool,
select_transmitted: bool,
ctx: &Context, ctx: &Context,
reading: &NetworkReading, reading: NetworkReading,
config: RenderConfig, config: RenderConfig,
) -> (Label, Label) { ) -> Label {
let (text_down, text_up) = match self.label_prefix { let (text_down, text_up) = match self.label_prefix {
LabelPrefix::None | LabelPrefix::Icon => match reading.format { LabelPrefix::None | LabelPrefix::Icon => match reading.format {
NetworkReadingFormat::Speed => ( NetworkReadingFormat::Speed => (
format!( format!(
"{: >width$}/s ", "{: >width$}/s ",
reading.received.pretty, reading.received_text,
width = self.activity_left_padding width = self.network_activity_fill_characters
), ),
format!( format!(
"{: >width$}/s", "{: >width$}/s",
reading.transmitted.pretty, reading.transmitted_text,
width = self.activity_left_padding width = self.network_activity_fill_characters
), ),
), ),
NetworkReadingFormat::Total => ( NetworkReadingFormat::Total => (
format!("{} ", reading.received.pretty), format!("{} ", reading.received_text),
reading.transmitted.pretty.clone(), reading.transmitted_text,
), ),
}, },
LabelPrefix::Text | LabelPrefix::IconAndText => match reading.format { LabelPrefix::Text | LabelPrefix::IconAndText => match reading.format {
NetworkReadingFormat::Speed => ( NetworkReadingFormat::Speed => (
format!( format!(
"DOWN: {: >width$}/s ", "DOWN: {: >width$}/s ",
reading.received.pretty, reading.received_text,
width = self.activity_left_padding width = self.network_activity_fill_characters
), ),
format!( format!(
"UP: {: >width$}/s", "UP: {: >width$}/s",
reading.transmitted.pretty, reading.transmitted_text,
width = self.activity_left_padding width = self.network_activity_fill_characters
), ),
), ),
NetworkReadingFormat::Total => ( NetworkReadingFormat::Total => (
format!("\u{2211}DOWN: {}/s ", reading.received.pretty), format!("\u{2211}DOWN: {}/s ", reading.received_text),
format!("\u{2211}UP: {}/s", reading.transmitted.pretty), format!("\u{2211}UP: {}/s", reading.transmitted_text),
), ),
}, },
}; };
let auto_text_color_received = config.auto_select_text.filter(|_| select_received); let icon_format = TextFormat::simple(
let auto_text_color_transmitted = config.auto_select_text.filter(|_| select_transmitted); config.icon_font_id.clone(),
ctx.style().visuals.selection.stroke.color,
);
let text_format = TextFormat {
font_id: config.text_font_id.clone(),
color: ctx.style().visuals.text_color(),
valign: Align::Center,
..Default::default()
};
// icon // icon
let mut layout_job_down = LayoutJob::simple( let mut layout_job = LayoutJob::simple(
match self.label_prefix { match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => { LabelPrefix::Icon | LabelPrefix::IconAndText => {
if select_received { egui_phosphor::regular::ARROW_FAT_DOWN.to_string()
egui_phosphor::regular::ARROW_FAT_LINES_DOWN.to_string()
} else {
egui_phosphor::regular::ARROW_FAT_DOWN.to_string()
}
} }
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), icon_format.font_id.clone(),
auto_text_color_received.unwrap_or(ctx.style().visuals.selection.stroke.color), icon_format.color,
100.0, 100.0,
); );
// text // text
layout_job_down.append( layout_job.append(
&text_down, &text_down,
ctx.style().spacing.item_spacing.x, ctx.style().spacing.item_spacing.x,
TextFormat { text_format.clone(),
font_id: config.text_font_id.clone(),
color: auto_text_color_received.unwrap_or(ctx.style().visuals.text_color()),
valign: Align::Center,
..Default::default()
},
); );
// icon // icon
let mut layout_job_up = LayoutJob::simple( layout_job.append(
match self.label_prefix { &match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => { LabelPrefix::Icon | LabelPrefix::IconAndText => {
if select_transmitted { egui_phosphor::regular::ARROW_FAT_UP.to_string()
egui_phosphor::regular::ARROW_FAT_LINES_UP.to_string()
} else {
egui_phosphor::regular::ARROW_FAT_UP.to_string()
}
} }
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), 0.0,
auto_text_color_transmitted.unwrap_or(ctx.style().visuals.selection.stroke.color), icon_format.clone(),
100.0,
); );
// text // text
layout_job_up.append( layout_job.append(
&text_up, &text_up,
ctx.style().spacing.item_spacing.x, ctx.style().spacing.item_spacing.x,
TextFormat { text_format.clone(),
font_id: config.text_font_id.clone(),
color: auto_text_color_transmitted.unwrap_or(ctx.style().visuals.text_color()),
valign: Align::Center,
..Default::default()
},
); );
( Label::new(layout_job).selectable(false)
Label::new(layout_job_down).selectable(false),
Label::new(layout_job_up).selectable(false),
)
} }
fn to_pretty_bytes(input_in_bytes: u64, timespan_in_s: u64) -> (u64, String) { fn to_pretty_bytes(input_in_bytes: u64, timespan_in_s: u64) -> String {
let input = input_in_bytes as f32 / timespan_in_s as f32; let input = input_in_bytes as f32 / timespan_in_s as f32;
let mut magnitude = input.log(1024f32) as u32; let mut magnitude = input.log(1024f32) as u32;
@@ -292,30 +248,10 @@ impl Network {
let base: Option<DataUnit> = num::FromPrimitive::from_u32(magnitude); let base: Option<DataUnit> = num::FromPrimitive::from_u32(magnitude);
let result = input / ((1u64) << (magnitude * 10)) as f32; let result = input / ((1u64) << (magnitude * 10)) as f32;
( match base {
input as u64, Some(DataUnit::B) => format!("{result:.1} B"),
match base { Some(unit) => format!("{result:.1} {unit}iB"),
Some(DataUnit::B) => format!("{result:.1} B"), None => String::from("Unknown data unit"),
Some(unit) => format!("{result:.1} {unit}iB"),
None => String::from("Unknown data unit"),
},
)
}
fn show_frame<R>(
&self,
selected: bool,
auto_focus_fill: Option<Color32>,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) {
if SelectableFrame::new_auto(selected, auto_focus_fill)
.show(ui, add_contents)
.clicked()
{
if let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn() {
eprintln!("{}", error);
}
} }
} }
} }
@@ -323,8 +259,6 @@ impl Network {
impl BarWidget for Network { impl BarWidget for Network {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable { if self.enable {
let is_reversed = matches!(config.alignment, Some(Alignment::Right));
// widget spacing: make sure to use the same config to call the apply_on_widget function // widget spacing: make sure to use the same config to call the apply_on_widget function
let mut render_config = config.clone(); let mut render_config = config.clone();
@@ -332,102 +266,17 @@ impl BarWidget for Network {
let (activity, total_activity) = self.network_activity(); let (activity, total_activity) = self.network_activity();
if self.show_total_activity { if self.show_total_activity {
for reading in &total_activity { for reading in total_activity {
render_config.apply_on_widget(false, ui, |ui| { render_config.apply_on_widget(true, ui, |ui| {
let select_received = self.auto_select.is_some_and(|f| { ui.add(self.reading_to_label(ctx, reading, config.clone()));
f.total_received_over
.is_some_and(|o| reading.received.value > o)
});
let select_transmitted = self.auto_select.is_some_and(|f| {
f.total_transmitted_over
.is_some_and(|o| reading.transmitted.value > o)
});
let labels = self.reading_to_labels(
select_received,
select_transmitted,
ctx,
reading,
config.clone(),
);
if is_reversed {
self.show_frame(
select_transmitted,
config.auto_select_fill,
ui,
|ui| ui.add(labels.1),
);
self.show_frame(
select_received,
config.auto_select_fill,
ui,
|ui| ui.add(labels.0),
);
} else {
self.show_frame(
select_received,
config.auto_select_fill,
ui,
|ui| ui.add(labels.0),
);
self.show_frame(
select_transmitted,
config.auto_select_fill,
ui,
|ui| ui.add(labels.1),
);
}
}); });
} }
} }
if self.show_activity { if self.show_activity {
for reading in &activity { for reading in activity {
render_config.apply_on_widget(false, ui, |ui| { render_config.apply_on_widget(true, ui, |ui| {
let select_received = self.auto_select.is_some_and(|f| { ui.add(self.reading_to_label(ctx, reading, config.clone()));
f.received_over.is_some_and(|o| reading.received.value > o)
});
let select_transmitted = self.auto_select.is_some_and(|f| {
f.transmitted_over
.is_some_and(|o| reading.transmitted.value > o)
});
let labels = self.reading_to_labels(
select_received,
select_transmitted,
ctx,
reading,
config.clone(),
);
if is_reversed {
self.show_frame(
select_transmitted,
config.auto_select_fill,
ui,
|ui| ui.add(labels.1),
);
self.show_frame(
select_received,
config.auto_select_fill,
ui,
|ui| ui.add(labels.0),
);
} else {
self.show_frame(
select_received,
config.auto_select_fill,
ui,
|ui| ui.add(labels.0),
);
self.show_frame(
select_transmitted,
config.auto_select_fill,
ui,
|ui| ui.add(labels.1),
);
}
}); });
} }
} }
@@ -465,9 +314,15 @@ impl BarWidget for Network {
); );
render_config.apply_on_widget(false, ui, |ui| { render_config.apply_on_widget(false, ui, |ui| {
self.show_frame(false, None, ui, |ui| { if SelectableFrame::new(false)
ui.add(Label::new(layout_job).selectable(false)) .show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
}); .clicked()
{
if let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn()
{
eprintln!("{}", error)
}
}
}); });
} }
} }
@@ -484,38 +339,19 @@ enum NetworkReadingFormat {
Total = 1, Total = 1,
} }
#[derive(Clone)]
struct ReadingValue {
value: u64,
pretty: String,
}
impl From<(u64, String)> for ReadingValue {
fn from(value: (u64, String)) -> Self {
Self {
value: value.0,
pretty: value.1,
}
}
}
#[derive(Clone)] #[derive(Clone)]
struct NetworkReading { struct NetworkReading {
format: NetworkReadingFormat, pub format: NetworkReadingFormat,
received: ReadingValue, pub received_text: String,
transmitted: ReadingValue, pub transmitted_text: String,
} }
impl NetworkReading { impl NetworkReading {
fn new( pub fn new(format: NetworkReadingFormat, received: String, transmitted: String) -> Self {
format: NetworkReadingFormat, NetworkReading {
received: ReadingValue,
transmitted: ReadingValue,
) -> Self {
Self {
format, format,
received, received_text: received,
transmitted, transmitted_text: transmitted,
} }
} }
} }
+15 -49
View File
@@ -1,4 +1,3 @@
use crate::bar::Alignment;
use crate::config::LabelPrefix; use crate::config::LabelPrefix;
use crate::render::RenderConfig; use crate::render::RenderConfig;
use crate::selected_frame::SelectableFrame; use crate::selected_frame::SelectableFrame;
@@ -25,10 +24,6 @@ pub struct StorageConfig {
pub data_refresh_interval: Option<u64>, pub data_refresh_interval: Option<u64>,
/// Display label prefix /// Display label prefix
pub label_prefix: Option<LabelPrefix>, pub label_prefix: Option<LabelPrefix>,
/// Select when the current percentage is over this value [[1-100]]
pub auto_select_over: Option<u8>,
/// Hide when the current percentage is under this value [[1-100]]
pub auto_hide_under: Option<u8>,
} }
impl From<StorageConfig> for Storage { impl From<StorageConfig> for Storage {
@@ -38,30 +33,21 @@ impl From<StorageConfig> for Storage {
disks: Disks::new_with_refreshed_list(), disks: Disks::new_with_refreshed_list(),
data_refresh_interval: value.data_refresh_interval.unwrap_or(10), data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText), label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
auto_select_over: value.auto_select_over.map(|o| o.clamp(1, 100)),
auto_hide_under: value.auto_hide_under.map(|o| o.clamp(1, 100)),
last_updated: Instant::now(), last_updated: Instant::now(),
} }
} }
} }
struct StorageDisk {
label: String,
selected: bool,
}
pub struct Storage { pub struct Storage {
pub enable: bool, pub enable: bool,
disks: Disks, disks: Disks,
data_refresh_interval: u64, data_refresh_interval: u64,
label_prefix: LabelPrefix, label_prefix: LabelPrefix,
auto_select_over: Option<u8>,
auto_hide_under: Option<u8>,
last_updated: Instant, last_updated: Instant,
} }
impl Storage { impl Storage {
fn output(&mut self) -> Vec<StorageDisk> { fn output(&mut self) -> Vec<String> {
let now = Instant::now(); let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) { if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
self.disks.refresh(true); self.disks.refresh(true);
@@ -75,26 +61,17 @@ impl Storage {
let total = disk.total_space(); let total = disk.total_space();
let available = disk.available_space(); let available = disk.available_space();
let used = total - available; let used = total - available;
let percentage = ((used * 100) / total) as u8;
let hide = self.auto_hide_under.is_some_and(|u| percentage <= u); disks.push(match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => {
if !hide { format!("{} {}%", mount.to_string_lossy(), (used * 100) / total)
let selected = self.auto_select_over.is_some_and(|o| percentage >= o); }
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
disks.push(StorageDisk { })
label: match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => {
format!("{} {}%", mount.to_string_lossy(), percentage)
}
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", percentage),
},
selected,
})
}
} }
disks.sort_by(|a, b| a.label.cmp(&b.label)); disks.sort();
disks.reverse();
disks disks
} }
@@ -103,16 +80,7 @@ impl Storage {
impl BarWidget for Storage { impl BarWidget for Storage {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) { fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable { if self.enable {
let mut output = self.output(); for output in self.output() {
let is_reversed = matches!(config.alignment, Some(Alignment::Right));
if is_reversed {
output.reverse();
}
for output in output {
let auto_text_color = config.auto_select_text.filter(|_| output.selected);
let mut layout_job = LayoutJob::simple( let mut layout_job = LayoutJob::simple(
match self.label_prefix { match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => { LabelPrefix::Icon | LabelPrefix::IconAndText => {
@@ -121,25 +89,23 @@ impl BarWidget for Storage {
LabelPrefix::None | LabelPrefix::Text => String::new(), LabelPrefix::None | LabelPrefix::Text => String::new(),
}, },
config.icon_font_id.clone(), config.icon_font_id.clone(),
auto_text_color.unwrap_or(ctx.style().visuals.selection.stroke.color), ctx.style().visuals.selection.stroke.color,
100.0, 100.0,
); );
layout_job.append( layout_job.append(
&output.label, &output,
10.0, 10.0,
TextFormat { TextFormat {
font_id: config.text_font_id.clone(), font_id: config.text_font_id.clone(),
color: auto_text_color.unwrap_or(ctx.style().visuals.text_color()), color: ctx.style().visuals.text_color(),
valign: Align::Center, valign: Align::Center,
..Default::default() ..Default::default()
}, },
); );
let auto_focus_fill = config.auto_select_fill;
config.apply_on_widget(false, ui, |ui| { config.apply_on_widget(false, ui, |ui| {
if SelectableFrame::new_auto(output.selected, auto_focus_fill) if SelectableFrame::new(false)
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false))) .show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
.clicked() .clicked()
{ {
@@ -147,7 +113,7 @@ impl BarWidget for Storage {
.args([ .args([
"/C", "/C",
"explorer.exe", "explorer.exe",
output.label.split(' ').collect::<Vec<&str>>()[0], output.split(' ').collect::<Vec<&str>>()[0],
]) ])
.spawn() .spawn()
{ {
+1 -1
View File
@@ -72,7 +72,7 @@ impl WidgetConfig {
WidgetConfig::Komorebi(config) => { WidgetConfig::Komorebi(config) => {
config.workspaces.as_ref().is_some_and(|w| w.enable) config.workspaces.as_ref().is_some_and(|w| w.enable)
|| config.layout.as_ref().is_some_and(|w| w.enable) || config.layout.as_ref().is_some_and(|w| w.enable)
|| config.focused_container.as_ref().is_some_and(|w| w.enable) || config.focused_window.as_ref().is_some_and(|w| w.enable)
|| config || config
.configuration_switcher .configuration_switcher
.as_ref() .as_ref()
+3 -3
View File
@@ -5,6 +5,8 @@ pub use komorebi::animation::prefix::AnimationPrefix;
pub use komorebi::animation::PerAnimationPrefixConfig; pub use komorebi::animation::PerAnimationPrefixConfig;
pub use komorebi::asc::ApplicationSpecificConfiguration; pub use komorebi::asc::ApplicationSpecificConfiguration;
pub use komorebi::border_manager::BorderInfo; pub use komorebi::border_manager::BorderInfo;
pub use komorebi::colour::Colour;
pub use komorebi::colour::Rgb;
pub use komorebi::config_generation::ApplicationConfiguration; pub use komorebi::config_generation::ApplicationConfiguration;
pub use komorebi::config_generation::IdWithIdentifier; pub use komorebi::config_generation::IdWithIdentifier;
pub use komorebi::config_generation::IdWithIdentifierAndComment; pub use komorebi::config_generation::IdWithIdentifierAndComment;
@@ -12,7 +14,7 @@ pub use komorebi::config_generation::MatchingRule;
pub use komorebi::config_generation::MatchingStrategy; pub use komorebi::config_generation::MatchingStrategy;
pub use komorebi::container::Container; pub use komorebi::container::Container;
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator; pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
pub use komorebi::core::replace_env_in_path; pub use komorebi::core::resolve_home_path;
pub use komorebi::core::AnimationStyle; pub use komorebi::core::AnimationStyle;
pub use komorebi::core::ApplicationIdentifier; pub use komorebi::core::ApplicationIdentifier;
pub use komorebi::core::Arrangement; pub use komorebi::core::Arrangement;
@@ -55,7 +57,6 @@ pub use komorebi::AnimationsConfig;
pub use komorebi::AppSpecificConfigurationPath; pub use komorebi::AppSpecificConfigurationPath;
pub use komorebi::AspectRatio; pub use komorebi::AspectRatio;
pub use komorebi::BorderColours; pub use komorebi::BorderColours;
pub use komorebi::Colour;
pub use komorebi::CrossBoundaryBehaviour; pub use komorebi::CrossBoundaryBehaviour;
pub use komorebi::GlobalState; pub use komorebi::GlobalState;
pub use komorebi::KomorebiTheme; pub use komorebi::KomorebiTheme;
@@ -63,7 +64,6 @@ pub use komorebi::MonitorConfig;
pub use komorebi::Notification; pub use komorebi::Notification;
pub use komorebi::NotificationEvent; pub use komorebi::NotificationEvent;
pub use komorebi::PredefinedAspectRatio; pub use komorebi::PredefinedAspectRatio;
pub use komorebi::Rgb;
pub use komorebi::RuleDebug; pub use komorebi::RuleDebug;
pub use komorebi::StackbarConfig; pub use komorebi::StackbarConfig;
pub use komorebi::State; pub use komorebi::State;
-36
View File
@@ -41,9 +41,7 @@ struct BorderColours {
single: Color32, single: Color32,
stack: Color32, stack: Color32,
monocle: Color32, monocle: Color32,
floating: Color32,
unfocused: Color32, unfocused: Color32,
unfocused_locked: Color32,
} }
struct BorderConfig { struct BorderConfig {
@@ -156,9 +154,7 @@ impl KomorebiGui {
single: colour32(global_state.border_colours.single), single: colour32(global_state.border_colours.single),
stack: colour32(global_state.border_colours.stack), stack: colour32(global_state.border_colours.stack),
monocle: colour32(global_state.border_colours.monocle), monocle: colour32(global_state.border_colours.monocle),
floating: colour32(global_state.border_colours.floating),
unfocused: colour32(global_state.border_colours.unfocused), unfocused: colour32(global_state.border_colours.unfocused),
unfocused_locked: colour32(global_state.border_colours.unfocused_locked),
}; };
let border_config = BorderConfig { let border_config = BorderConfig {
@@ -381,22 +377,6 @@ impl eframe::App for KomorebiGui {
} }
}); });
ui.collapsing("Floating", |ui| {
if egui::color_picker::color_picker_color32(
ui,
&mut self.border_config.border_colours.floating,
Alpha::Opaque,
) {
komorebi_client::send_message(&SocketMessage::BorderColour(
WindowKind::Floating,
self.border_config.border_colours.floating.r() as u32,
self.border_config.border_colours.floating.g() as u32,
self.border_config.border_colours.floating.b() as u32,
))
.unwrap();
}
});
ui.collapsing("Unfocused", |ui| { ui.collapsing("Unfocused", |ui| {
if egui::color_picker::color_picker_color32( if egui::color_picker::color_picker_color32(
ui, ui,
@@ -411,22 +391,6 @@ impl eframe::App for KomorebiGui {
)) ))
.unwrap(); .unwrap();
} }
});
ui.collapsing("Unfocused Locked", |ui| {
if egui::color_picker::color_picker_color32(
ui,
&mut self.border_config.border_colours.unfocused_locked,
Alpha::Opaque,
) {
komorebi_client::send_message(&SocketMessage::BorderColour(
WindowKind::UnfocusedLocked,
self.border_config.border_colours.unfocused_locked.r() as u32,
self.border_config.border_colours.unfocused_locked.g() as u32,
self.border_config.border_colours.unfocused_locked.b() as u32,
))
.unwrap();
}
}) })
}); });
+1 -7
View File
@@ -8,13 +8,7 @@ base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev
catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "bdaff30959512c4f7ee7304117076a48633d777f", default-features = false, features = ["egui31"] } catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "bdaff30959512c4f7ee7304117076a48633d777f", default-features = false, features = ["egui31"] }
#catppuccin-egui = { version = "5", default-features = false, features = ["egui30"] } #catppuccin-egui = { version = "5", default-features = false, features = ["egui30"] }
eframe = { workspace = true } eframe = { workspace = true }
schemars = { workspace = true, optional = true } schemars = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_variant = "0.1" serde_variant = "0.1"
strum = { workspace = true } strum = { workspace = true }
hex_color = { version = "3", features = ["serde"] }
flavours = { git = "https://github.com/LGUG2Z/flavours", version = "0.7.2" }
[features]
default = ["schemars"]
schemars = ["dep:schemars"]
-77
View File
@@ -1,77 +0,0 @@
use crate::colour::Colour;
use crate::colour::Hex;
use crate::Base16ColourPalette;
use hex_color::HexColor;
use std::collections::VecDeque;
use std::fmt::Display;
use std::fmt::Formatter;
use std::path::Path;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ThemeVariant {
#[default]
Dark,
Light,
}
impl Display for ThemeVariant {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ThemeVariant::Dark => write!(f, "dark"),
ThemeVariant::Light => write!(f, "light"),
}
}
}
impl From<ThemeVariant> for flavours::operations::generate::Mode {
fn from(value: ThemeVariant) -> Self {
match value {
ThemeVariant::Dark => Self::Dark,
ThemeVariant::Light => Self::Light,
}
}
}
pub fn generate_base16_palette(
image_path: &Path,
variant: ThemeVariant,
) -> Result<Base16ColourPalette, hex_color::ParseHexColorError> {
Base16ColourPalette::try_from(
&flavours::operations::generate::generate(image_path, variant.into(), false)
.unwrap_or_default(),
)
}
impl TryFrom<&VecDeque<String>> for Base16ColourPalette {
type Error = hex_color::ParseHexColorError;
fn try_from(value: &VecDeque<String>) -> Result<Self, Self::Error> {
let fixed = value.iter().map(|s| format!("#{s}")).collect::<Vec<_>>();
if fixed.len() != 16 {
return Err(hex_color::ParseHexColorError::Empty);
}
Ok(Self {
base_00: Colour::Hex(Hex(HexColor::parse(&fixed[0])?)),
base_01: Colour::Hex(Hex(HexColor::parse(&fixed[1])?)),
base_02: Colour::Hex(Hex(HexColor::parse(&fixed[2])?)),
base_03: Colour::Hex(Hex(HexColor::parse(&fixed[3])?)),
base_04: Colour::Hex(Hex(HexColor::parse(&fixed[4])?)),
base_05: Colour::Hex(Hex(HexColor::parse(&fixed[5])?)),
base_06: Colour::Hex(Hex(HexColor::parse(&fixed[6])?)),
base_07: Colour::Hex(Hex(HexColor::parse(&fixed[7])?)),
base_08: Colour::Hex(Hex(HexColor::parse(&fixed[8])?)),
base_09: Colour::Hex(Hex(HexColor::parse(&fixed[9])?)),
base_0a: Colour::Hex(Hex(HexColor::parse(&fixed[10])?)),
base_0b: Colour::Hex(Hex(HexColor::parse(&fixed[11])?)),
base_0c: Colour::Hex(Hex(HexColor::parse(&fixed[12])?)),
base_0d: Colour::Hex(Hex(HexColor::parse(&fixed[13])?)),
base_0e: Colour::Hex(Hex(HexColor::parse(&fixed[14])?)),
base_0f: Colour::Hex(Hex(HexColor::parse(&fixed[15])?)),
})
}
}
+19 -193
View File
@@ -1,32 +1,18 @@
#![warn(clippy::all)] #![warn(clippy::all)]
#![allow(clippy::missing_errors_doc)] #![allow(clippy::missing_errors_doc)]
pub mod colour;
mod generator;
pub use generator::generate_base16_palette;
pub use generator::ThemeVariant;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use strum::Display; use strum::Display;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::colour::Colour;
pub use base16_egui_themes::Base16; pub use base16_egui_themes::Base16;
pub use catppuccin_egui; pub use catppuccin_egui;
use eframe::egui::style::Selection;
use eframe::egui::style::WidgetVisuals;
use eframe::egui::style::Widgets;
pub use eframe::egui::Color32; pub use eframe::egui::Color32;
use eframe::egui::Shadow;
use eframe::egui::Stroke;
use eframe::egui::Style;
use eframe::egui::Visuals;
use serde_variant::to_variant_name; use serde_variant::to_variant_name;
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Theme { pub enum Theme {
/// A theme from catppuccin-egui /// A theme from catppuccin-egui
@@ -39,140 +25,6 @@ pub enum Theme {
name: Base16, name: Base16,
accent: Option<Base16Value>, accent: Option<Base16Value>,
}, },
/// A custom base16 palette
Custom {
palette: Box<Base16ColourPalette>,
accent: Option<Base16Value>,
},
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct Base16ColourPalette {
pub base_00: Colour,
pub base_01: Colour,
pub base_02: Colour,
pub base_03: Colour,
pub base_04: Colour,
pub base_05: Colour,
pub base_06: Colour,
pub base_07: Colour,
pub base_08: Colour,
pub base_09: Colour,
pub base_0a: Colour,
pub base_0b: Colour,
pub base_0c: Colour,
pub base_0d: Colour,
pub base_0e: Colour,
pub base_0f: Colour,
}
impl Base16ColourPalette {
pub fn background(self) -> Color32 {
self.base_01.into()
}
pub fn style(self) -> Style {
let original = Style::default();
Style {
visuals: Visuals {
widgets: Widgets {
noninteractive: WidgetVisuals {
bg_fill: self.base_01.into(),
weak_bg_fill: self.base_01.into(),
bg_stroke: Stroke {
color: self.base_02.into(),
..original.visuals.widgets.noninteractive.bg_stroke
},
fg_stroke: Stroke {
color: self.base_05.into(),
..original.visuals.widgets.noninteractive.fg_stroke
},
..original.visuals.widgets.noninteractive
},
inactive: WidgetVisuals {
bg_fill: self.base_02.into(),
weak_bg_fill: self.base_02.into(),
bg_stroke: Stroke {
color: Color32::from_rgba_premultiplied(0, 0, 0, 0),
..original.visuals.widgets.inactive.bg_stroke
},
fg_stroke: Stroke {
color: self.base_05.into(),
..original.visuals.widgets.inactive.fg_stroke
},
..original.visuals.widgets.inactive
},
hovered: WidgetVisuals {
bg_fill: self.base_02.into(),
weak_bg_fill: self.base_02.into(),
bg_stroke: Stroke {
color: self.base_03.into(),
..original.visuals.widgets.hovered.bg_stroke
},
fg_stroke: Stroke {
color: self.base_06.into(),
..original.visuals.widgets.hovered.fg_stroke
},
..original.visuals.widgets.hovered
},
active: WidgetVisuals {
bg_fill: self.base_02.into(),
weak_bg_fill: self.base_02.into(),
bg_stroke: Stroke {
color: self.base_03.into(),
..original.visuals.widgets.hovered.bg_stroke
},
fg_stroke: Stroke {
color: self.base_06.into(),
..original.visuals.widgets.hovered.fg_stroke
},
..original.visuals.widgets.active
},
open: WidgetVisuals {
bg_fill: self.base_01.into(),
weak_bg_fill: self.base_01.into(),
bg_stroke: Stroke {
color: self.base_02.into(),
..original.visuals.widgets.open.bg_stroke
},
fg_stroke: Stroke {
color: self.base_06.into(),
..original.visuals.widgets.open.fg_stroke
},
..original.visuals.widgets.open
},
},
selection: Selection {
bg_fill: self.base_02.into(),
stroke: Stroke {
color: self.base_06.into(),
..original.visuals.selection.stroke
},
},
hyperlink_color: self.base_08.into(),
faint_bg_color: Color32::from_rgba_premultiplied(0, 0, 0, 0),
extreme_bg_color: self.base_00.into(),
code_bg_color: self.base_02.into(),
warn_fg_color: self.base_0c.into(),
error_fg_color: self.base_0b.into(),
window_shadow: Shadow {
color: Color32::from_rgba_premultiplied(0, 0, 0, 96),
..original.visuals.window_shadow
},
window_fill: self.base_01.into(),
window_stroke: Stroke {
color: self.base_02.into(),
..original.visuals.window_stroke
},
panel_fill: self.base_01.into(),
popup_shadow: Shadow {
color: Color32::from_rgba_premultiplied(0, 0, 0, 96),
..original.visuals.popup_shadow
},
..original.visuals
},
..original
}
}
} }
impl Theme { impl Theme {
@@ -193,7 +45,6 @@ impl Theme {
.to_string() .to_string()
}) })
.collect(), .collect(),
Theme::Custom { .. } => vec!["Custom".to_string()],
} }
} }
} }
@@ -219,50 +70,25 @@ pub enum Base16Value {
Base0F, Base0F,
} }
pub enum Base16Wrapper {
Base16(Base16),
Custom(Box<Base16ColourPalette>),
}
impl Base16Value { impl Base16Value {
pub fn color32(&self, theme: Base16Wrapper) -> Color32 { pub fn color32(&self, theme: Base16) -> Color32 {
match theme { match self {
Base16Wrapper::Base16(theme) => match self { Base16Value::Base00 => theme.base00(),
Base16Value::Base00 => theme.base00(), Base16Value::Base01 => theme.base01(),
Base16Value::Base01 => theme.base01(), Base16Value::Base02 => theme.base02(),
Base16Value::Base02 => theme.base02(), Base16Value::Base03 => theme.base03(),
Base16Value::Base03 => theme.base03(), Base16Value::Base04 => theme.base04(),
Base16Value::Base04 => theme.base04(), Base16Value::Base05 => theme.base05(),
Base16Value::Base05 => theme.base05(), Base16Value::Base06 => theme.base06(),
Base16Value::Base06 => theme.base06(), Base16Value::Base07 => theme.base07(),
Base16Value::Base07 => theme.base07(), Base16Value::Base08 => theme.base08(),
Base16Value::Base08 => theme.base08(), Base16Value::Base09 => theme.base09(),
Base16Value::Base09 => theme.base09(), Base16Value::Base0A => theme.base0a(),
Base16Value::Base0A => theme.base0a(), Base16Value::Base0B => theme.base0b(),
Base16Value::Base0B => theme.base0b(), Base16Value::Base0C => theme.base0c(),
Base16Value::Base0C => theme.base0c(), Base16Value::Base0D => theme.base0d(),
Base16Value::Base0D => theme.base0d(), Base16Value::Base0E => theme.base0e(),
Base16Value::Base0E => theme.base0e(), Base16Value::Base0F => theme.base0f(),
Base16Value::Base0F => theme.base0f(),
},
Base16Wrapper::Custom(colours) => match self {
Base16Value::Base00 => colours.base_00.into(),
Base16Value::Base01 => colours.base_01.into(),
Base16Value::Base02 => colours.base_02.into(),
Base16Value::Base03 => colours.base_03.into(),
Base16Value::Base04 => colours.base_04.into(),
Base16Value::Base05 => colours.base_05.into(),
Base16Value::Base06 => colours.base_06.into(),
Base16Value::Base07 => colours.base_07.into(),
Base16Value::Base08 => colours.base_08.into(),
Base16Value::Base09 => colours.base_09.into(),
Base16Value::Base0A => colours.base_0a.into(),
Base16Value::Base0B => colours.base_0b.into(),
Base16Value::Base0C => colours.base_0c.into(),
Base16Value::Base0D => colours.base_0d.into(),
Base16Value::Base0E => colours.base_0e.into(),
Base16Value::Base0F => colours.base_0f.into(),
},
} }
} }
} }
+1 -2
View File
@@ -19,6 +19,7 @@ ctrlc = { version = "3", features = ["termination"] }
dirs = { workspace = true } dirs = { workspace = true }
dunce = { workspace = true } dunce = { workspace = true }
getset = "0.1" getset = "0.1"
hex_color = { version = "3", features = ["serde"] }
hotwatch = { workspace = true } hotwatch = { workspace = true }
lazy_static = { workspace = true } lazy_static = { workspace = true }
miow = "0.6" miow = "0.6"
@@ -27,7 +28,6 @@ net2 = "0.2"
os_info = "3.10" os_info = "3.10"
parking_lot = "0.12" parking_lot = "0.12"
paste = { workspace = true } paste = { workspace = true }
powershell_script = "1.0"
regex = "1" regex = "1"
schemars = { workspace = true, optional = true } schemars = { workspace = true, optional = true }
serde = { workspace = true } serde = { workspace = true }
@@ -49,7 +49,6 @@ windows-implement = { workspace = true }
windows-interface = { workspace = true } windows-interface = { workspace = true }
winput = "0.2" winput = "0.2"
winreg = "0.55" winreg = "0.55"
serde_with = { version = "3.12", features = ["schemars_0_8"] }
[build-dependencies] [build-dependencies]
shadow-rs = { workspace = true } shadow-rs = { workspace = true }
+21 -19
View File
@@ -9,11 +9,13 @@ use crate::core::Rect;
use crate::windows_api; use crate::windows_api;
use crate::WindowsApi; use crate::WindowsApi;
use crate::WINDOWS_11; use crate::WINDOWS_11;
use color_eyre::eyre::anyhow;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Deref; use std::ops::Deref;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::mpsc; use std::sync::mpsc;
use std::sync::LazyLock; use std::sync::LazyLock;
use std::sync::OnceLock;
use windows::Win32::Foundation::FALSE; use windows::Win32::Foundation::FALSE;
use windows::Win32::Foundation::HWND; use windows::Win32::Foundation::HWND;
use windows::Win32::Foundation::LPARAM; use windows::Win32::Foundation::LPARAM;
@@ -116,7 +118,7 @@ pub struct Border {
pub hwnd: isize, pub hwnd: isize,
pub id: String, pub id: String,
pub monitor_idx: Option<usize>, pub monitor_idx: Option<usize>,
pub render_target: Option<RenderTarget>, pub render_target: OnceLock<RenderTarget>,
pub tracking_hwnd: isize, pub tracking_hwnd: isize,
pub window_rect: Rect, pub window_rect: Rect,
pub window_kind: WindowKind, pub window_kind: WindowKind,
@@ -134,7 +136,7 @@ impl From<isize> for Border {
hwnd: value, hwnd: value,
id: String::new(), id: String::new(),
monitor_idx: None, monitor_idx: None,
render_target: None, render_target: OnceLock::new(),
tracking_hwnd: 0, tracking_hwnd: 0,
window_rect: Rect::default(), window_rect: Rect::default(),
window_kind: WindowKind::Unfocused, window_kind: WindowKind::Unfocused,
@@ -182,7 +184,7 @@ impl Border {
hwnd: 0, hwnd: 0,
id: container_id, id: container_id,
monitor_idx: Some(monitor_idx), monitor_idx: Some(monitor_idx),
render_target: None, render_target: OnceLock::new(),
tracking_hwnd, tracking_hwnd,
window_rect: WindowsApi::window_rect(tracking_hwnd).unwrap_or_default(), window_rect: WindowsApi::window_rect(tracking_hwnd).unwrap_or_default(),
window_kind: WindowKind::Unfocused, window_kind: WindowKind::Unfocused,
@@ -241,14 +243,8 @@ impl Border {
let _ = DwmEnableBlurBehindWindow(border.hwnd(), &bh); let _ = DwmEnableBlurBehindWindow(border.hwnd(), &bh);
} }
border.update_brushes()?;
Ok(border)
}
pub fn update_brushes(&mut self) -> color_eyre::Result<()> {
let hwnd_render_target_properties = D2D1_HWND_RENDER_TARGET_PROPERTIES { let hwnd_render_target_properties = D2D1_HWND_RENDER_TARGET_PROPERTIES {
hwnd: HWND(windows_api::as_ptr!(self.hwnd)), hwnd: HWND(windows_api::as_ptr!(border.hwnd)),
pixelSize: Default::default(), pixelSize: Default::default(),
presentOptions: D2D1_PRESENT_OPTIONS_IMMEDIATELY, presentOptions: D2D1_PRESENT_OPTIONS_IMMEDIATELY,
}; };
@@ -269,7 +265,7 @@ impl Border {
.CreateHwndRenderTarget(&render_target_properties, &hwnd_render_target_properties) .CreateHwndRenderTarget(&render_target_properties, &hwnd_render_target_properties)
} { } {
Ok(render_target) => unsafe { Ok(render_target) => unsafe {
self.brush_properties = *BRUSH_PROPERTIES.deref(); border.brush_properties = *BRUSH_PROPERTIES.deref();
for window_kind in [ for window_kind in [
WindowKind::Single, WindowKind::Single,
WindowKind::Stack, WindowKind::Stack,
@@ -287,18 +283,24 @@ impl Border {
}; };
if let Ok(brush) = if let Ok(brush) =
render_target.CreateSolidColorBrush(&color, Some(&self.brush_properties)) render_target.CreateSolidColorBrush(&color, Some(&border.brush_properties))
{ {
self.brushes.insert(window_kind, brush); border.brushes.insert(window_kind, brush);
} }
} }
render_target.SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); render_target.SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
self.render_target = Some(RenderTarget(render_target)); if border
.render_target
.set(RenderTarget(render_target.clone()))
.is_err()
{
return Err(anyhow!("could not store border render target"));
}
self.rounded_rect = { border.rounded_rect = {
let radius = 8.0 + self.width as f32 / 2.0; let radius = 8.0 + border.width as f32 / 2.0;
D2D1_ROUNDED_RECT { D2D1_ROUNDED_RECT {
rect: Default::default(), rect: Default::default(),
radiusX: radius, radiusX: radius,
@@ -306,7 +308,7 @@ impl Border {
} }
}; };
Ok(()) Ok(border)
}, },
Err(error) => Err(error.into()), Err(error) => Err(error.into()),
} }
@@ -393,7 +395,7 @@ impl Border {
} }
if !rect.is_same_size_as(&old_rect) { if !rect.is_same_size_as(&old_rect) {
if let Some(render_target) = (*border_pointer).render_target.as_ref() { if let Some(render_target) = (*border_pointer).render_target.get() {
let border_width = (*border_pointer).width; let border_width = (*border_pointer).width;
let border_offset = (*border_pointer).offset; let border_offset = (*border_pointer).offset;
@@ -475,7 +477,7 @@ impl Border {
tracing::error!("failed to update border position {error}"); tracing::error!("failed to update border position {error}");
} }
if let Some(render_target) = (*border_pointer).render_target.as_ref() { if let Some(render_target) = (*border_pointer).render_target.get() {
(*border_pointer).width = BORDER_WIDTH.load(Ordering::Relaxed); (*border_pointer).width = BORDER_WIDTH.load(Ordering::Relaxed);
(*border_pointer).offset = BORDER_OFFSET.load(Ordering::Relaxed); (*border_pointer).offset = BORDER_OFFSET.load(Ordering::Relaxed);
+65 -108
View File
@@ -7,6 +7,8 @@ use crate::core::WindowKind;
use crate::ring::Ring; use crate::ring::Ring;
use crate::windows_api; use crate::windows_api;
use crate::workspace::WorkspaceLayer; use crate::workspace::WorkspaceLayer;
use crate::Colour;
use crate::Rgb;
use crate::WindowManager; use crate::WindowManager;
use crate::WindowsApi; use crate::WindowsApi;
use border::border_hwnds; use border::border_hwnds;
@@ -15,8 +17,6 @@ use crossbeam_channel::Receiver;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use crossbeam_utils::atomic::AtomicCell; use crossbeam_utils::atomic::AtomicCell;
use crossbeam_utils::atomic::AtomicConsume; use crossbeam_utils::atomic::AtomicConsume;
use komorebi_themes::colour::Colour;
use komorebi_themes::colour::Rgb;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use parking_lot::Mutex; use parking_lot::Mutex;
use serde::Deserialize; use serde::Deserialize;
@@ -73,10 +73,7 @@ impl Deref for RenderTarget {
} }
} }
pub enum Notification { pub struct Notification(pub Option<isize>);
Update(Option<isize>),
ForceUpdate,
}
#[derive(Debug, Default, Clone, Copy, PartialEq)] #[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct BorderInfo { pub struct BorderInfo {
@@ -105,21 +102,16 @@ fn event_rx() -> Receiver<Notification> {
} }
pub fn window_border(hwnd: isize) -> Option<BorderInfo> { pub fn window_border(hwnd: isize) -> Option<BorderInfo> {
let id = WINDOWS_BORDERS.lock().get(&hwnd)?.clone(); WINDOWS_BORDERS.lock().get(&hwnd).and_then(|id| {
BORDER_STATE.lock().get(&id).map(|b| BorderInfo { BORDER_STATE.lock().get(id).map(|b| BorderInfo {
border_hwnd: b.hwnd, border_hwnd: b.hwnd,
window_kind: b.window_kind, window_kind: b.window_kind,
})
}) })
} }
pub fn send_notification(hwnd: Option<isize>) { pub fn send_notification(hwnd: Option<isize>) {
if event_tx().try_send(Notification::Update(hwnd)).is_err() { if event_tx().try_send(Notification(hwnd)).is_err() {
tracing::warn!("channel is full; dropping notification")
}
}
pub fn send_force_update() {
if event_tx().try_send(Notification::ForceUpdate).is_err() {
tracing::warn!("channel is full; dropping notification") tracing::warn!("channel is full; dropping notification")
} }
} }
@@ -135,8 +127,6 @@ pub fn destroy_all_borders() -> color_eyre::Result<()> {
let _ = destroy_border(border); let _ = destroy_border(border);
} }
drop(borders);
WINDOWS_BORDERS.lock().clear(); WINDOWS_BORDERS.lock().clear();
let mut remaining_hwnds = vec![]; let mut remaining_hwnds = vec![];
@@ -185,7 +175,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
tracing::info!("listening"); tracing::info!("listening");
let receiver = event_rx(); let receiver = event_rx();
event_tx().send(Notification::Update(None))?; event_tx().send(Notification(None))?;
let mut previous_snapshot = Ring::default(); let mut previous_snapshot = Ring::default();
let mut previous_pending_move_op = None; let mut previous_pending_move_op = None;
@@ -271,75 +261,64 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
} }
} }
BorderImplementation::Komorebi => { BorderImplementation::Komorebi => {
let should_process_notification = match notification { let mut should_process_notification = true;
Notification::Update(notification_hwnd) => {
let mut should_process_notification = true;
if monitors == previous_snapshot if monitors == previous_snapshot
// handle the window dragging edge case // handle the window dragging edge case
&& pending_move_op == previous_pending_move_op && pending_move_op == previous_pending_move_op
{ {
should_process_notification = false; should_process_notification = false;
} }
// handle the pause edge case // handle the pause edge case
if is_paused && !previous_is_paused { if is_paused && !previous_is_paused {
should_process_notification = true;
}
// handle the unpause edge case
if previous_is_paused && !is_paused {
should_process_notification = true;
}
// handle the retile edge case
if !should_process_notification && BORDER_STATE.lock().is_empty() {
should_process_notification = true;
}
// when we switch focus to/from a floating window
let switch_focus_to_from_floating_window = floating_window_hwnds.iter().any(|fw| {
// if we switch focus to a floating window
fw == &notification.0.unwrap_or_default() ||
// if there is any floating window with a `WindowKind::Floating` border
// that no longer is the foreground window then we need to update that
// border.
(fw != &foreground_window
&& window_border(*fw)
.is_some_and(|b| b.window_kind == WindowKind::Floating))
});
// when the focused window has an `Unfocused` border kind, usually this happens if
// we focus an admin window and then refocus the previously focused window. For
// komorebi it will have the same state has before, however the previously focused
// window changed its border to unfocused so now we need to update it again.
if !should_process_notification
&& window_border(notification.0.unwrap_or_default())
.is_some_and(|b| b.window_kind == WindowKind::Unfocused)
{
should_process_notification = true;
}
if !should_process_notification && switch_focus_to_from_floating_window {
should_process_notification = true;
}
if !should_process_notification {
if let Some(ref previous) = previous_notification {
if previous.0.unwrap_or_default() != notification.0.unwrap_or_default() {
should_process_notification = true; should_process_notification = true;
} }
// handle the unpause edge case
if previous_is_paused && !is_paused {
should_process_notification = true;
}
// handle the retile edge case
if !should_process_notification && BORDER_STATE.lock().is_empty() {
should_process_notification = true;
}
// when we switch focus to/from a floating window
let switch_focus_to_from_floating_window =
floating_window_hwnds.iter().any(|fw| {
// if we switch focus to a floating window
fw == &notification_hwnd.unwrap_or_default() ||
// if there is any floating window with a `WindowKind::Floating` border
// that no longer is the foreground window then we need to update that
// border.
(fw != &foreground_window
&& window_border(*fw)
.is_some_and(|b| b.window_kind == WindowKind::Floating))
});
// when the focused window has an `Unfocused` border kind, usually this happens if
// we focus an admin window and then refocus the previously focused window. For
// komorebi it will have the same state has before, however the previously focused
// window changed its border to unfocused so now we need to update it again.
if !should_process_notification
&& window_border(notification_hwnd.unwrap_or_default())
.is_some_and(|b| b.window_kind == WindowKind::Unfocused)
{
should_process_notification = true;
}
if !should_process_notification && switch_focus_to_from_floating_window {
should_process_notification = true;
}
if !should_process_notification {
if let Some(Notification::Update(ref previous)) = previous_notification
{
if previous.unwrap_or_default()
!= notification_hwnd.unwrap_or_default()
{
should_process_notification = true;
}
}
}
should_process_notification
} }
Notification::ForceUpdate => true, }
};
if !should_process_notification { if !should_process_notification {
tracing::trace!("monitor state matches latest snapshot, skipping notification"); tracing::trace!("monitor state matches latest snapshot, skipping notification");
@@ -436,11 +415,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
if new_border { if new_border {
border.set_position(&rect, focused_window_hwnd)?; border.set_position(&rect, focused_window_hwnd)?;
} else if matches!(notification, Notification::ForceUpdate) {
// Update the border brushes if there was a forced update
// notification and this is not a new border (new border's
// already have their brushes updated on creation)
border.update_brushes()?;
} }
border.invalidate(); border.invalidate();
@@ -570,20 +544,12 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
border.window_rect = rect; border.window_rect = rect;
let layer_changed = previous_layer != workspace_layer; let layer_changed = previous_layer != workspace_layer;
let forced_update = matches!(notification, Notification::ForceUpdate);
let should_invalidate = new_border let should_invalidate = new_border
|| (last_focus_state != new_focus_state) || (last_focus_state != new_focus_state)
|| layer_changed || layer_changed;
|| forced_update;
if should_invalidate { if should_invalidate {
if forced_update && !new_border {
// Update the border brushes if there was a forced update
// notification and this is not a new border (new border's
// already have their brushes updated on creation)
border.update_brushes()?;
}
border.set_position(&rect, focused_window_hwnd)?; border.set_position(&rect, focused_window_hwnd)?;
border.invalidate(); border.invalidate();
} }
@@ -628,21 +594,12 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
border.window_rect = rect; border.window_rect = rect;
let layer_changed = previous_layer != workspace_layer; let layer_changed = previous_layer != workspace_layer;
let forced_update =
matches!(notification, Notification::ForceUpdate);
let should_invalidate = new_border let should_invalidate = new_border
|| (last_focus_state != new_focus_state) || (last_focus_state != new_focus_state)
|| layer_changed || layer_changed;
|| forced_update;
if should_invalidate { if should_invalidate {
if forced_update && !new_border {
// Update the border brushes if there was a forced update
// notification and this is not a new border (new border's
// already have their brushes updated on creation)
border.update_brushes()?;
}
border.set_position(&rect, window.hwnd)?; border.set_position(&rect, window.hwnd)?;
border.invalidate(); border.invalidate();
} }
@@ -1,4 +1,5 @@
use hex_color::HexColor; use hex_color::HexColor;
use komorebi_themes::Color32;
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
use schemars::gen::SchemaGenerator; use schemars::gen::SchemaGenerator;
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
@@ -8,7 +9,6 @@ use schemars::schema::Schema;
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
use schemars::schema::SchemaObject; use schemars::schema::SchemaObject;
use crate::Color32;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@@ -57,7 +57,7 @@ impl From<Colour> for Color32 {
} }
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
pub struct Hex(pub HexColor); pub struct Hex(HexColor);
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
impl schemars::JsonSchema for Hex { impl schemars::JsonSchema for Hex {
+48 -44
View File
@@ -1,10 +1,12 @@
#![warn(clippy::all)] #![warn(clippy::all)]
#![allow(clippy::missing_errors_doc, clippy::use_self, clippy::doc_markdown)] #![allow(clippy::missing_errors_doc, clippy::use_self, clippy::doc_markdown)]
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use clap::ValueEnum; use clap::ValueEnum;
use color_eyre::eyre::anyhow;
use color_eyre::Result; use color_eyre::Result;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@@ -26,10 +28,7 @@ pub use default_layout::DefaultLayout;
pub use direction::Direction; pub use direction::Direction;
pub use layout::Layout; pub use layout::Layout;
pub use operation_direction::OperationDirection; pub use operation_direction::OperationDirection;
pub use pathext::replace_env_in_path;
pub use pathext::resolve_option_hashmap_usize_path;
pub use pathext::PathExt; pub use pathext::PathExt;
pub use pathext::ResolvedPathBuf;
pub use rect::Rect; pub use rect::Rect;
pub mod animation; pub mod animation;
@@ -45,8 +44,6 @@ pub mod operation_direction;
pub mod pathext; pub mod pathext;
pub mod rect; pub mod rect;
// serde_as must be before derive
#[serde_with::serde_as]
#[derive(Clone, Debug, Serialize, Deserialize, Display)] #[derive(Clone, Debug, Serialize, Deserialize, Display)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "type", content = "content")] #[serde(tag = "type", content = "content")]
@@ -108,7 +105,7 @@ pub enum SocketMessage {
AdjustWorkspacePadding(Sizing, i32), AdjustWorkspacePadding(Sizing, i32),
ChangeLayout(DefaultLayout), ChangeLayout(DefaultLayout),
CycleLayout(CycleDirection), CycleLayout(CycleDirection),
ChangeLayoutCustom(#[serde_as(as = "ResolvedPathBuf")] PathBuf), ChangeLayoutCustom(PathBuf),
FlipLayout(Axis), FlipLayout(Axis),
ToggleWorkspaceWindowContainerBehaviour, ToggleWorkspaceWindowContainerBehaviour,
ToggleWorkspaceFloatOverride, ToggleWorkspaceFloatOverride,
@@ -126,8 +123,8 @@ pub enum SocketMessage {
RetileWithResizeDimensions, RetileWithResizeDimensions,
QuickSave, QuickSave,
QuickLoad, QuickLoad,
Save(#[serde_as(as = "ResolvedPathBuf")] PathBuf), Save(PathBuf),
Load(#[serde_as(as = "ResolvedPathBuf")] PathBuf), Load(PathBuf),
CycleFocusMonitor(CycleDirection), CycleFocusMonitor(CycleDirection),
CycleFocusWorkspace(CycleDirection), CycleFocusWorkspace(CycleDirection),
CycleFocusEmptyWorkspace(CycleDirection), CycleFocusEmptyWorkspace(CycleDirection),
@@ -150,28 +147,23 @@ pub enum SocketMessage {
WorkspaceName(usize, usize, String), WorkspaceName(usize, usize, String),
WorkspaceLayout(usize, usize, DefaultLayout), WorkspaceLayout(usize, usize, DefaultLayout),
NamedWorkspaceLayout(String, DefaultLayout), NamedWorkspaceLayout(String, DefaultLayout),
WorkspaceLayoutCustom(usize, usize, #[serde_as(as = "ResolvedPathBuf")] PathBuf), WorkspaceLayoutCustom(usize, usize, PathBuf),
NamedWorkspaceLayoutCustom(String, #[serde_as(as = "ResolvedPathBuf")] PathBuf), NamedWorkspaceLayoutCustom(String, PathBuf),
WorkspaceLayoutRule(usize, usize, usize, DefaultLayout), WorkspaceLayoutRule(usize, usize, usize, DefaultLayout),
NamedWorkspaceLayoutRule(String, usize, DefaultLayout), NamedWorkspaceLayoutRule(String, usize, DefaultLayout),
WorkspaceLayoutCustomRule( WorkspaceLayoutCustomRule(usize, usize, usize, PathBuf),
usize, NamedWorkspaceLayoutCustomRule(String, usize, PathBuf),
usize,
usize,
#[serde_as(as = "ResolvedPathBuf")] PathBuf,
),
NamedWorkspaceLayoutCustomRule(String, usize, #[serde_as(as = "ResolvedPathBuf")] PathBuf),
ClearWorkspaceLayoutRules(usize, usize), ClearWorkspaceLayoutRules(usize, usize),
ClearNamedWorkspaceLayoutRules(String), ClearNamedWorkspaceLayoutRules(String),
ToggleWorkspaceLayer, ToggleWorkspaceLayer,
// Configuration // Configuration
ReloadConfiguration, ReloadConfiguration,
ReplaceConfiguration(#[serde_as(as = "ResolvedPathBuf")] PathBuf), ReplaceConfiguration(PathBuf),
ReloadStaticConfiguration(#[serde_as(as = "ResolvedPathBuf")] PathBuf), ReloadStaticConfiguration(PathBuf),
WatchConfiguration(bool), WatchConfiguration(bool),
CompleteConfiguration, CompleteConfiguration,
AltFocusHack(bool), AltFocusHack(bool),
Theme(Box<KomorebiTheme>), Theme(KomorebiTheme),
Animation(bool, Option<AnimationPrefix>), Animation(bool, Option<AnimationPrefix>),
AnimationDuration(u64, Option<AnimationPrefix>), AnimationDuration(u64, Option<AnimationPrefix>),
AnimationFps(u64), AnimationFps(u64),
@@ -210,9 +202,6 @@ pub enum SocketMessage {
ClearNamedWorkspaceRules(String), ClearNamedWorkspaceRules(String),
ClearAllWorkspaceRules, ClearAllWorkspaceRules,
EnforceWorkspaceRules, EnforceWorkspaceRules,
SessionFloatRule,
SessionFloatRules,
ClearSessionFloatRules,
#[serde(alias = "FloatRule")] #[serde(alias = "FloatRule")]
IgnoreRule(ApplicationIdentifier, String), IgnoreRule(ApplicationIdentifier, String),
ManageRule(ApplicationIdentifier, String), ManageRule(ApplicationIdentifier, String),
@@ -340,8 +329,6 @@ pub enum StateQuery {
FocusedContainerIndex, FocusedContainerIndex,
FocusedWindowIndex, FocusedWindowIndex,
FocusedWorkspaceName, FocusedWorkspaceName,
FocusedWorkspaceLayout,
Version,
} }
#[derive( #[derive(
@@ -466,28 +453,45 @@ impl Sizing {
} }
} }
#[cfg(test)] pub fn resolve_home_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
mod tests { let mut resolved_path = PathBuf::new();
use super::*; let mut resolved = false;
for c in path.as_ref().components() {
match c {
std::path::Component::Normal(c)
if (c == "~" || c == "$Env:USERPROFILE" || c == "$HOME") && !resolved =>
{
let home = dirs::home_dir().ok_or_else(|| anyhow!("there is no home directory"))?;
#[test] resolved_path.extend(home.components());
fn deserializes() { resolved = true;
// Set a variable for testing }
std::env::set_var("VAR", "VALUE");
let json = r#"{"type":"WorkspaceLayoutCustomRule","content":[0,0,0,"/path/%VAR%/d"]}"#; std::path::Component::Normal(c) if (c == "$Env:KOMOREBI_CONFIG_HOME") && !resolved => {
let message: SocketMessage = serde_json::from_str(json).unwrap(); let komorebi_config_home =
PathBuf::from(std::env::var("KOMOREBI_CONFIG_HOME").ok().ok_or_else(|| {
anyhow!("there is no KOMOREBI_CONFIG_HOME environment variable set")
})?);
let SocketMessage::WorkspaceLayoutCustomRule( resolved_path.extend(komorebi_config_home.components());
_workspace_index, resolved = true;
_workspace_number, }
_monitor_index,
path,
) = message
else {
panic!("Expected WorkspaceLayoutCustomRule");
};
assert_eq!(path, PathBuf::from("/path/VALUE/d")); _ => resolved_path.push(c),
}
} }
let parent = resolved_path
.parent()
.ok_or_else(|| anyhow!("cannot parse parent directory"))?;
Ok(if parent.is_dir() {
let file = resolved_path
.components()
.last()
.ok_or_else(|| anyhow!("cannot parse filename"))?;
dunce::canonicalize(parent)?.join(file)
} else {
resolved_path
})
} }
+28 -172
View File
@@ -1,192 +1,48 @@
use std::collections::HashMap;
use std::env; use std::env;
use std::ffi::OsStr;
use std::path::Component; use std::path::Component;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use serde::Deserialize;
use serde::Serialize;
/// Path extension trait
pub trait PathExt { pub trait PathExt {
/// Resolve environment variables components in a path.
///
/// Resolves the follwing formats:
/// - CMD: `%variable%`
/// - PowerShell: `$Env:variable`
/// - Bash: `$variable`.
fn replace_env(&self) -> PathBuf; fn replace_env(&self) -> PathBuf;
} }
/// Blanket implementation for all types that can be converted to a `Path`. impl PathExt for PathBuf {
impl<P: AsRef<Path>> PathExt for P {
fn replace_env(&self) -> PathBuf { fn replace_env(&self) -> PathBuf {
let mut out = PathBuf::new(); let mut result = PathBuf::new();
for c in self.as_ref().components() { for component in self.components() {
match c { match component {
Component::Normal(mut c) => { Component::Normal(segment) => {
// Special case for ~ and $HOME, replace with $Env:USERPROFILE // Check if it starts with `$` or `$Env:`
if c == OsStr::new("~") || c.eq_ignore_ascii_case("$HOME") { if let Some(stripped_segment) = segment.to_string_lossy().strip_prefix('$') {
c = OsStr::new("$Env:USERPROFILE"); let var_name = if let Some(env_name) = stripped_segment.strip_prefix("Env:")
} {
// Extract the variable name after `$Env:`
let bytes = c.as_encoded_bytes(); env_name
} else if stripped_segment == "HOME" {
// %LOCALAPPDATA% // Special case for `$HOME`
let var = if bytes[0] == b'%' && bytes[bytes.len() - 1] == b'%' { "USERPROFILE"
Some(&bytes[1..bytes.len() - 1])
} else {
// prefix length is 5 for $Env: and 1 for $
// so we take the minimum of 5 and the length of the bytes
let prefix = &bytes[..5.min(bytes.len())];
let prefix = unsafe { OsStr::from_encoded_bytes_unchecked(prefix) };
// $Env:LOCALAPPDATA
if prefix.eq_ignore_ascii_case("$Env:") {
Some(&bytes[5..])
} else if bytes[0] == b'$' {
// $LOCALAPPDATA
Some(&bytes[1..])
} else { } else {
// not a variable // Extract the variable name after `$`
None stripped_segment
} };
};
// if component is a variable, get the value from the environment if let Ok(value) = env::var(var_name) {
if let Some(var) = var { result.push(&value); // Replace with the value
let var = unsafe { OsStr::from_encoded_bytes_unchecked(var) }; } else {
if let Some(value) = env::var_os(var) { result.push(segment); // Keep as-is if variable is not found
out.push(value);
continue;
} }
} else {
result.push(segment); // Keep as-is if not an environment variable
} }
// if not a variable, or a value couldn't be obtained from environemnt
// then push the component as is
out.push(c);
} }
_ => {
// other components are pushed as is // Add other components (e.g., root, parent) as-is
_ => out.push(c), result.push(component.as_os_str());
}
} }
} }
out result
}
}
/// Replace environment variables in a path. This is a wrapper around
/// [`PathExt::replace_env`] to be used in Clap arguments parsing.
pub fn replace_env_in_path(input: &str) -> Result<PathBuf, std::convert::Infallible> {
Ok(input.replace_env())
}
/// A wrapper around [`PathBuf`] that has a custom [Deserialize] implementation
/// that uses [`PathExt::replace_env`] to resolve environment variables
#[derive(Clone, Debug)]
pub struct ResolvedPathBuf(PathBuf);
impl ResolvedPathBuf {
/// Create a new [`ResolvedPathBuf`] from a [`PathBuf`]
pub fn new(path: PathBuf) -> Self {
Self(path.replace_env())
}
}
impl From<ResolvedPathBuf> for PathBuf {
fn from(path: ResolvedPathBuf) -> Self {
path.0
}
}
impl serde_with::SerializeAs<PathBuf> for ResolvedPathBuf {
fn serialize_as<S>(path: &PathBuf, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
path.serialize(serializer)
}
}
impl<'de> serde_with::DeserializeAs<'de, PathBuf> for ResolvedPathBuf {
fn deserialize_as<D>(deserializer: D) -> Result<PathBuf, D::Error>
where
D: serde::Deserializer<'de>,
{
let path = PathBuf::deserialize(deserializer)?;
Ok(path.replace_env())
}
}
#[cfg(feature = "schemars")]
impl serde_with::schemars_0_8::JsonSchemaAs<PathBuf> for ResolvedPathBuf {
fn schema_name() -> String {
"PathBuf".to_owned()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
<PathBuf as schemars::JsonSchema>::json_schema(gen)
}
}
/// Custom deserializer for [`Option<HashMap<usize, PathBuf>>`] that uses
/// [`PathExt::replace_env`] to resolve environment variables in the paths.
///
/// This is used in `WorkspaceConfig` struct because we can't use
/// #[serde_with::serde_as] as it doesn't handle [`Option<HashMap<usize, ResolvedPathBuf>>`]
/// quite well and generated compiler errors that can't be fixed because of Rust's orphan rule.
pub fn resolve_option_hashmap_usize_path<'de, D>(
deserializer: D,
) -> Result<Option<HashMap<usize, PathBuf>>, D::Error>
where
D: serde::Deserializer<'de>,
{
let map = Option::<HashMap<usize, PathBuf>>::deserialize(deserializer)?;
Ok(map.map(|map| map.into_iter().map(|(k, v)| (k, v.replace_env())).collect()))
}
#[cfg(test)]
mod tests {
use super::*;
// helper functions
fn expected<P: AsRef<Path>>(p: P) -> PathBuf {
// Ensure that the path is using the correct path separator for the OS.
p.as_ref().components().collect::<PathBuf>()
}
fn resolve<P: AsRef<Path>>(p: P) -> PathBuf {
p.replace_env()
}
#[test]
fn resolves_env_vars() {
// Set a variable for testing
std::env::set_var("VAR", "VALUE");
// %VAR% format
assert_eq!(resolve("/path/%VAR%/d"), expected("/path/VALUE/d"));
// $env:VAR format
assert_eq!(resolve("/path/$env:VAR/d"), expected("/path/VALUE/d"));
// $VAR format
assert_eq!(resolve("/path/$VAR/d"), expected("/path/VALUE/d"));
// non-existent variable
assert_eq!(resolve("/path/%ASD%/to/d"), expected("/path/%ASD%/to/d"));
assert_eq!(
resolve("/path/$env:ASD/to/d"),
expected("/path/$env:ASD/to/d")
);
assert_eq!(resolve("/path/$ASD/to/d"), expected("/path/$ASD/to/d"));
// Set a $env:USERPROFILE variable for testing
std::env::set_var("USERPROFILE", "C:\\Users\\user");
// ~ and $HOME should be replaced with $Env:USERPROFILE
assert_eq!(resolve("~"), expected("C:\\Users\\user"));
assert_eq!(resolve("$HOME"), expected("C:\\Users\\user"));
} }
} }
+10 -13
View File
@@ -5,6 +5,7 @@ pub mod border_manager;
pub mod com; pub mod com;
#[macro_use] #[macro_use]
pub mod ring; pub mod ring;
pub mod colour;
pub mod container; pub mod container;
pub mod core; pub mod core;
pub mod focus_manager; pub mod focus_manager;
@@ -46,8 +47,8 @@ use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
pub use colour::*;
pub use core::*; pub use core::*;
pub use komorebi_themes::colour::*;
pub use process_command::*; pub use process_command::*;
pub use process_event::*; pub use process_event::*;
pub use static_config::*; pub use static_config::*;
@@ -158,7 +159,6 @@ lazy_static! {
matching_strategy: Option::from(MatchingStrategy::Equals), matching_strategy: Option::from(MatchingStrategy::Equals),
}) })
])); ]));
static ref SESSION_FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new())); static ref FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![ static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"Chrome_RenderWidgetHostHWND".to_string(), "Chrome_RenderWidgetHostHWND".to_string(),
@@ -188,16 +188,15 @@ lazy_static! {
Arc::new(Mutex::new(HidingBehaviour::Cloak)); Arc::new(Mutex::new(HidingBehaviour::Cloak));
pub static ref HOME_DIR: PathBuf = { pub static ref HOME_DIR: PathBuf = {
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(|_| dirs::home_dir().expect("there is no home directory"), |home_path| { std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(|_| dirs::home_dir().expect("there is no home directory"), |home_path| {
let home = home_path.replace_env(); let home = PathBuf::from(&home_path);
assert!( if home.as_path().is_dir() {
home.is_dir(), home
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory", } else {
home_path panic!(
); "$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory",
);
}
home
}) })
}; };
pub static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi"); pub static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi");
@@ -240,8 +239,6 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20); pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20);
shadow_rs::shadow!(build);
#[must_use] #[must_use]
pub fn current_virtual_desktop() -> Option<Vec<u8>> { pub fn current_virtual_desktop() -> Option<Vec<u8>> {
let hkcu = RegKey::predef(HKEY_CURRENT_USER); let hkcu = RegKey::predef(HKEY_CURRENT_USER);
+3 -3
View File
@@ -22,7 +22,6 @@ use crossbeam_utils::Backoff;
use komorebi::animation::AnimationEngine; use komorebi::animation::AnimationEngine;
use komorebi::animation::ANIMATION_ENABLED_GLOBAL; use komorebi::animation::ANIMATION_ENABLED_GLOBAL;
use komorebi::animation::ANIMATION_ENABLED_PER_ANIMATION; use komorebi::animation::ANIMATION_ENABLED_PER_ANIMATION;
use komorebi::replace_env_in_path;
#[cfg(feature = "deadlock_detection")] #[cfg(feature = "deadlock_detection")]
use parking_lot::deadlock; use parking_lot::deadlock;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -57,6 +56,8 @@ use komorebi::HOME_DIR;
use komorebi::INITIAL_CONFIGURATION_LOADED; use komorebi::INITIAL_CONFIGURATION_LOADED;
use komorebi::SESSION_ID; use komorebi::SESSION_ID;
shadow_rs::shadow!(build);
fn setup(log_level: LogLevel) -> Result<(WorkerGuard, WorkerGuard)> { fn setup(log_level: LogLevel) -> Result<(WorkerGuard, WorkerGuard)> {
if std::env::var("RUST_LIB_BACKTRACE").is_err() { if std::env::var("RUST_LIB_BACKTRACE").is_err() {
std::env::set_var("RUST_LIB_BACKTRACE", "1"); std::env::set_var("RUST_LIB_BACKTRACE", "1");
@@ -164,7 +165,7 @@ enum LogLevel {
} }
#[derive(Parser)] #[derive(Parser)]
#[clap(author, about, version = komorebi::build::CLAP_LONG_VERSION)] #[clap(author, about, version = build::CLAP_LONG_VERSION)]
struct Opts { struct Opts {
/// Allow the use of komorebi's custom focus-follows-mouse implementation /// Allow the use of komorebi's custom focus-follows-mouse implementation
#[clap(short, long = "ffm")] #[clap(short, long = "ffm")]
@@ -177,7 +178,6 @@ struct Opts {
tcp_port: Option<usize>, tcp_port: Option<usize>,
/// Path to a static configuration JSON file /// Path to a static configuration JSON file
#[clap(short, long)] #[clap(short, long)]
#[clap(value_parser = replace_env_in_path)]
config: Option<PathBuf>, config: Option<PathBuf>,
/// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi /// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi
#[clap(long)] #[clap(long)]
+17 -188
View File
@@ -12,21 +12,15 @@ use getset::Setters;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::border_manager::BORDER_ENABLED;
use crate::border_manager::BORDER_OFFSET;
use crate::border_manager::BORDER_WIDTH;
use crate::core::Rect; use crate::core::Rect;
use crate::container::Container; use crate::container::Container;
use crate::ring::Ring; use crate::ring::Ring;
use crate::workspace::Workspace; use crate::workspace::Workspace;
use crate::workspace::WorkspaceGlobals;
use crate::workspace::WorkspaceLayer; use crate::workspace::WorkspaceLayer;
use crate::DefaultLayout; use crate::DefaultLayout;
use crate::FloatingLayerBehaviour;
use crate::Layout; use crate::Layout;
use crate::OperationDirection; use crate::OperationDirection;
use crate::Wallpaper;
use crate::WindowsApi; use crate::WindowsApi;
use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING; use crate::DEFAULT_WORKSPACE_PADDING;
@@ -66,10 +60,6 @@ pub struct Monitor {
pub container_padding: Option<i32>, pub container_padding: Option<i32>,
#[getset(get_copy = "pub", set = "pub")] #[getset(get_copy = "pub", set = "pub")]
pub workspace_padding: Option<i32>, pub workspace_padding: Option<i32>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub wallpaper: Option<Wallpaper>,
#[getset(get_copy = "pub", set = "pub")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
} }
impl_ring_elements!(Monitor, Workspace); impl_ring_elements!(Monitor, Workspace);
@@ -125,8 +115,6 @@ pub fn new(
workspace_names: HashMap::default(), workspace_names: HashMap::default(),
container_padding: None, container_padding: None,
workspace_padding: None, workspace_padding: None,
wallpaper: None,
floating_layer_behaviour: None,
} }
} }
@@ -168,8 +156,6 @@ impl Monitor {
workspace_names: Default::default(), workspace_names: Default::default(),
container_padding: None, container_padding: None,
workspace_padding: None, workspace_padding: None,
wallpaper: None,
floating_layer_behaviour: None,
} }
} }
@@ -179,23 +165,11 @@ impl Monitor {
.unwrap_or(None) .unwrap_or(None)
} }
pub fn focused_workspace_layout(&self) -> Option<Layout> {
self.focused_workspace().and_then(|workspace| {
if *workspace.tile() {
Some(workspace.layout().clone())
} else {
None
}
})
}
pub fn load_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> { pub fn load_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> {
let focused_idx = self.focused_workspace_idx(); let focused_idx = self.focused_workspace_idx();
let hmonitor = self.id();
let monitor_wp = self.wallpaper.clone();
for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() { for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() {
if i == focused_idx { if i == focused_idx {
workspace.restore(mouse_follows_focus, hmonitor, &monitor_wp)?; workspace.restore(mouse_follows_focus)?;
} else { } else {
workspace.hide(None); workspace.hide(None);
} }
@@ -212,34 +186,18 @@ impl Monitor {
let workspace_padding = self let workspace_padding = self
.workspace_padding() .workspace_padding()
.or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst))); .or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst)));
let (border_width, border_offset) = {
let border_enabled = BORDER_ENABLED.load(Ordering::SeqCst);
if border_enabled {
let border_width = BORDER_WIDTH.load(Ordering::SeqCst);
let border_offset = BORDER_OFFSET.load(Ordering::SeqCst);
(border_width, border_offset)
} else {
(0, 0)
}
};
let work_area = *self.work_area_size(); let work_area = *self.work_area_size();
let work_area_offset = self.work_area_offset.or(offset); let offset = self.work_area_offset.or(offset);
let window_based_work_area_offset = self.window_based_work_area_offset(); let window_based_work_area_offset = self.window_based_work_area_offset();
let window_based_work_area_offset_limit = self.window_based_work_area_offset_limit(); let limit = self.window_based_work_area_offset_limit();
let floating_layer_behaviour = self.floating_layer_behaviour();
for workspace in self.workspaces_mut() { for workspace in self.workspaces_mut() {
workspace.globals = WorkspaceGlobals { workspace.globals_mut().container_padding = container_padding;
container_padding, workspace.globals_mut().workspace_padding = workspace_padding;
workspace_padding, workspace.globals_mut().work_area = work_area;
border_width, workspace.globals_mut().work_area_offset = offset;
border_offset, workspace.globals_mut().window_based_work_area_offset = window_based_work_area_offset;
work_area, workspace.globals_mut().window_based_work_area_offset_limit = limit;
work_area_offset,
window_based_work_area_offset,
window_based_work_area_offset_limit,
floating_layer_behaviour,
}
} }
} }
@@ -251,34 +209,18 @@ impl Monitor {
let workspace_padding = self let workspace_padding = self
.workspace_padding() .workspace_padding()
.or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst))); .or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst)));
let (border_width, border_offset) = {
let border_enabled = BORDER_ENABLED.load(Ordering::SeqCst);
if border_enabled {
let border_width = BORDER_WIDTH.load(Ordering::SeqCst);
let border_offset = BORDER_OFFSET.load(Ordering::SeqCst);
(border_width, border_offset)
} else {
(0, 0)
}
};
let work_area = *self.work_area_size(); let work_area = *self.work_area_size();
let work_area_offset = self.work_area_offset.or(offset); let offset = self.work_area_offset.or(offset);
let window_based_work_area_offset = self.window_based_work_area_offset(); let window_based_work_area_offset = self.window_based_work_area_offset();
let window_based_work_area_offset_limit = self.window_based_work_area_offset_limit(); let limit = self.window_based_work_area_offset_limit();
let floating_layer_behaviour = self.floating_layer_behaviour();
if let Some(workspace) = self.workspaces_mut().get_mut(workspace_idx) { if let Some(workspace) = self.workspaces_mut().get_mut(workspace_idx) {
workspace.globals = WorkspaceGlobals { workspace.globals_mut().container_padding = container_padding;
container_padding, workspace.globals_mut().workspace_padding = workspace_padding;
workspace_padding, workspace.globals_mut().work_area = work_area;
border_width, workspace.globals_mut().work_area_offset = offset;
border_offset, workspace.globals_mut().window_based_work_area_offset = window_based_work_area_offset;
work_area, workspace.globals_mut().window_based_work_area_offset_limit = limit;
work_area_offset,
window_based_work_area_offset,
window_based_work_area_offset_limit,
floating_layer_behaviour,
}
} }
} }
@@ -661,117 +603,4 @@ mod tests {
// Should be the last workspace index: 1 // Should be the last workspace index: 1
assert_eq!(new_workspace_index, 1); assert_eq!(new_workspace_index, 1);
} }
#[test]
fn test_move_container_to_workspace() {
let mut m = Monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
let new_workspace_index = m.new_workspace_idx();
assert_eq!(new_workspace_index, 1);
{
// Create workspace 1 and add 3 containers
let workspace = m.focused_workspace_mut().unwrap();
for _ in 0..3 {
let container = Container::default();
workspace.add_container_to_back(container);
}
// Should have 3 containers in workspace 1
assert_eq!(m.focused_workspace().unwrap().containers().len(), 3);
}
// Create and focus workspace 2
m.focus_workspace(new_workspace_index).unwrap();
// Focus workspace 1
m.focus_workspace(0).unwrap();
// Move container to workspace 2
m.move_container_to_workspace(1, true, None).unwrap();
// Should be focused on workspace 2
assert_eq!(m.focused_workspace_idx(), 1);
// Workspace 2 should have 1 container now
assert_eq!(m.focused_workspace().unwrap().containers().len(), 1);
// Move to workspace 1
m.focus_workspace(0).unwrap();
// Workspace 1 should have 2 containers
assert_eq!(m.focused_workspace().unwrap().containers().len(), 2);
// Move a another container from workspace 1 to workspace 2 without following
m.move_container_to_workspace(1, false, None).unwrap();
// Should have 1 container
assert_eq!(m.focused_workspace().unwrap().containers().len(), 1);
// Should still be focused on workspace 1
assert_eq!(m.focused_workspace_idx(), 0);
// Switch to workspace 2
m.focus_workspace(1).unwrap();
// Workspace 2 should now have 2 containers
assert_eq!(m.focused_workspace().unwrap().containers().len(), 2);
}
#[test]
fn test_ensure_workspace_count_workspace_contains_two_workspaces() {
let mut m = Monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create and focus another workspace
let new_workspace_index = m.new_workspace_idx();
m.focus_workspace(new_workspace_index).unwrap();
// Should have 2 workspaces now
assert_eq!(m.workspaces().len(), 2, "Monitor should have 2 workspaces");
// Ensure the monitor has at least 5 workspaces
m.ensure_workspace_count(5);
// Monitor should have 5 workspaces
assert_eq!(m.workspaces().len(), 5, "Monitor should have 5 workspaces");
}
#[test]
fn test_ensure_workspace_count_only_default_workspace() {
let mut m = Monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Ensure the monitor has at least 5 workspaces
m.ensure_workspace_count(5);
// Monitor should have 5 workspaces
assert_eq!(m.workspaces().len(), 5, "Monitor should have 5 workspaces");
// Try to call the ensure workspace count again to ensure it doesn't change
m.ensure_workspace_count(3);
assert_eq!(m.workspaces().len(), 5, "Monitor should have 5 workspaces");
}
} }
@@ -553,8 +553,6 @@ where
workspace_names: cached.workspace_names.clone(), workspace_names: cached.workspace_names.clone(),
container_padding: cached.container_padding, container_padding: cached.container_padding,
workspace_padding: cached.workspace_padding, workspace_padding: cached.workspace_padding,
wallpaper: cached.wallpaper.clone(),
floating_layer_behaviour: cached.floating_layer_behaviour,
}; };
let focused_workspace_idx = m.focused_workspace_idx(); let focused_workspace_idx = m.focused_workspace_idx();
+36 -177
View File
@@ -1,7 +1,6 @@
use color_eyre::eyre::anyhow; use color_eyre::eyre::anyhow;
use color_eyre::eyre::OptionExt; use color_eyre::eyre::OptionExt;
use color_eyre::Result; use color_eyre::Result;
use komorebi_themes::colour::Rgb;
use miow::pipe::connect; use miow::pipe::connect;
use net2::TcpStreamExt; use net2::TcpStreamExt;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -20,18 +19,9 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use uds_windows::UnixStream; use uds_windows::UnixStream;
use crate::animation::ANIMATION_DURATION_GLOBAL;
use crate::animation::ANIMATION_DURATION_PER_ANIMATION; use crate::animation::ANIMATION_DURATION_PER_ANIMATION;
use crate::animation::ANIMATION_ENABLED_GLOBAL;
use crate::animation::ANIMATION_ENABLED_PER_ANIMATION; use crate::animation::ANIMATION_ENABLED_PER_ANIMATION;
use crate::animation::ANIMATION_FPS;
use crate::animation::ANIMATION_STYLE_GLOBAL;
use crate::animation::ANIMATION_STYLE_PER_ANIMATION; use crate::animation::ANIMATION_STYLE_PER_ANIMATION;
use crate::border_manager;
use crate::border_manager::IMPLEMENTATION;
use crate::border_manager::STYLE;
use crate::build;
use crate::config_generation::WorkspaceMatchingRule;
use crate::core::config_generation::IdWithIdentifier; use crate::core::config_generation::IdWithIdentifier;
use crate::core::config_generation::MatchingRule; use crate::core::config_generation::MatchingRule;
use crate::core::config_generation::MatchingStrategy; use crate::core::config_generation::MatchingStrategy;
@@ -48,6 +38,16 @@ use crate::core::SocketMessage;
use crate::core::StateQuery; use crate::core::StateQuery;
use crate::core::WindowContainerBehaviour; use crate::core::WindowContainerBehaviour;
use crate::core::WindowKind; use crate::core::WindowKind;
use crate::animation::ANIMATION_DURATION_GLOBAL;
use crate::animation::ANIMATION_ENABLED_GLOBAL;
use crate::animation::ANIMATION_FPS;
use crate::animation::ANIMATION_STYLE_GLOBAL;
use crate::border_manager;
use crate::border_manager::IMPLEMENTATION;
use crate::border_manager::STYLE;
use crate::colour::Rgb;
use crate::config_generation::WorkspaceMatchingRule;
use crate::current_virtual_desktop; use crate::current_virtual_desktop;
use crate::monitor::MonitorInformation; use crate::monitor::MonitorInformation;
use crate::notify_subscribers; use crate::notify_subscribers;
@@ -72,7 +72,6 @@ use crate::State;
use crate::CUSTOM_FFM; use crate::CUSTOM_FFM;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES; use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOATING_APPLICATIONS;
use crate::HIDING_BEHAVIOUR; use crate::HIDING_BEHAVIOUR;
use crate::IGNORE_IDENTIFIERS; use crate::IGNORE_IDENTIFIERS;
use crate::INITIAL_CONFIGURATION_LOADED; use crate::INITIAL_CONFIGURATION_LOADED;
@@ -82,7 +81,6 @@ use crate::MONITOR_INDEX_PREFERENCES;
use crate::NO_TITLEBAR; use crate::NO_TITLEBAR;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::REMOVE_TITLEBARS; use crate::REMOVE_TITLEBARS;
use crate::SESSION_FLOATING_APPLICATIONS;
use crate::SUBSCRIPTION_PIPES; use crate::SUBSCRIPTION_PIPES;
use crate::SUBSCRIPTION_SOCKETS; use crate::SUBSCRIPTION_SOCKETS;
use crate::SUBSCRIPTION_SOCKET_OPTIONS; use crate::SUBSCRIPTION_SOCKET_OPTIONS;
@@ -226,7 +224,6 @@ impl WindowManager {
_ => {} _ => {}
}; };
let mut force_update_borders = false;
match message { match message {
SocketMessage::Promote => self.promote_container_to_front()?, SocketMessage::Promote => self.promote_container_to_front()?,
SocketMessage::PromoteFocus => self.promote_focus_to_front()?, SocketMessage::PromoteFocus => self.promote_focus_to_front()?,
@@ -398,7 +395,7 @@ impl WindowManager {
workspace.locked_containers.remove(&container_idx); workspace.locked_containers.remove(&container_idx);
} }
SocketMessage::ToggleLock => self.toggle_lock()?, SocketMessage::ToggleLock => self.toggle_lock()?,
SocketMessage::ToggleFloat => self.toggle_float(false)?, SocketMessage::ToggleFloat => self.toggle_float()?,
SocketMessage::ToggleMonocle => self.toggle_monocle()?, SocketMessage::ToggleMonocle => self.toggle_monocle()?,
SocketMessage::ToggleMaximize => self.toggle_maximize()?, SocketMessage::ToggleMaximize => self.toggle_maximize()?,
SocketMessage::ContainerPadding(monitor_idx, workspace_idx, size) => { SocketMessage::ContainerPadding(monitor_idx, workspace_idx, size) => {
@@ -545,53 +542,6 @@ impl WindowManager {
})); }));
} }
} }
SocketMessage::SessionFloatRule => {
let foreground_window = WindowsApi::foreground_window()?;
let window = Window::from(foreground_window);
if let (Ok(exe), Ok(title), Ok(class)) =
(window.exe(), window.title(), window.class())
{
let rule = MatchingRule::Composite(vec![
IdWithIdentifier {
kind: ApplicationIdentifier::Exe,
id: exe,
matching_strategy: Option::from(MatchingStrategy::Equals),
},
IdWithIdentifier {
kind: ApplicationIdentifier::Title,
id: title,
matching_strategy: Option::from(MatchingStrategy::Equals),
},
IdWithIdentifier {
kind: ApplicationIdentifier::Class,
id: class,
matching_strategy: Option::from(MatchingStrategy::Equals),
},
]);
let mut floating_applications = FLOATING_APPLICATIONS.lock();
floating_applications.push(rule.clone());
let mut session_floating_applications = SESSION_FLOATING_APPLICATIONS.lock();
session_floating_applications.push(rule.clone());
self.toggle_float(true)?;
}
}
SocketMessage::SessionFloatRules => {
let session_floating_applications = SESSION_FLOATING_APPLICATIONS.lock();
let rules = match serde_json::to_string_pretty(&*session_floating_applications) {
Ok(rules) => rules,
Err(error) => error.to_string(),
};
reply.write_all(rules.as_bytes())?;
}
SocketMessage::ClearSessionFloatRules => {
let mut floating_applications = FLOATING_APPLICATIONS.lock();
let mut session_floating_applications = SESSION_FLOATING_APPLICATIONS.lock();
floating_applications.retain(|r| !session_floating_applications.contains(r));
session_floating_applications.clear()
}
SocketMessage::IgnoreRule(identifier, ref id) => { SocketMessage::IgnoreRule(identifier, ref id) => {
let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock(); let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock();
@@ -911,12 +861,10 @@ impl WindowManager {
} }
SocketMessage::Retile => { SocketMessage::Retile => {
border_manager::destroy_all_borders()?; border_manager::destroy_all_borders()?;
force_update_borders = true;
self.retile_all(false)? self.retile_all(false)?
} }
SocketMessage::RetileWithResizeDimensions => { SocketMessage::RetileWithResizeDimensions => {
border_manager::destroy_all_borders()?; border_manager::destroy_all_borders()?;
force_update_borders = true;
self.retile_all(true)? self.retile_all(true)?
} }
SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?, SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?,
@@ -1429,20 +1377,6 @@ impl WindowManager {
.focused_workspace_name() .focused_workspace_name()
.unwrap_or_else(|| focused_monitor.focused_workspace_idx().to_string()) .unwrap_or_else(|| focused_monitor.focused_workspace_idx().to_string())
} }
StateQuery::Version => build::RUST_VERSION.to_string(),
StateQuery::FocusedWorkspaceLayout => {
let focused_monitor = self
.focused_monitor()
.ok_or_else(|| anyhow!("there is no monitor"))?;
focused_monitor.focused_workspace_layout().map_or_else(
|| "None".to_string(),
|layout| match layout {
Layout::Default(default_layout) => default_layout.to_string(),
Layout::Custom(_) => "Custom".to_string(),
},
)
}
}; };
reply.write_all(response.as_bytes())?; reply.write_all(response.as_bytes())?;
@@ -1652,7 +1586,6 @@ impl WindowManager {
} }
SocketMessage::ReloadConfiguration => { SocketMessage::ReloadConfiguration => {
Self::reload_configuration(); Self::reload_configuration();
force_update_borders = true;
} }
SocketMessage::ReplaceConfiguration(ref config) => { SocketMessage::ReplaceConfiguration(ref config) => {
// Check that this is a valid static config file first // Check that this is a valid static config file first
@@ -1681,78 +1614,15 @@ impl WindowManager {
// Set self to the new wm instance // Set self to the new wm instance
*self = wm; *self = wm;
// check if there are any bars
let mut system = sysinfo::System::new_all();
system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
let has_bar = system
.processes_by_name("komorebi-bar.exe".as_ref())
.next()
.is_some();
// stop bar(s)
if has_bar {
let script = r"
Stop-Process -Name:komorebi-bar -ErrorAction SilentlyContinue
";
match powershell_script::run(script) {
Ok(_) => {
println!("{script}");
// start new bar(s)
let mut config = StaticConfig::read(config)?;
if let Some(display_bar_configurations) =
&mut config.bar_configurations
{
for config_file_path in &mut *display_bar_configurations {
let script = r#"Start-Process "komorebi-bar" '"--config" "CONFIGFILE"' -WindowStyle hidden"#
.replace("CONFIGFILE", &config_file_path.to_string_lossy());
match powershell_script::run(&script) {
Ok(_) => {
println!("{script}");
}
Err(error) => {
println!("Error: {error}");
}
}
}
} else {
let script = r"
if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
{
Start-Process komorebi-bar -WindowStyle hidden
}
";
match powershell_script::run(script) {
Ok(_) => {
println!("{script}");
}
Err(error) => {
println!("Error: {error}");
}
}
}
}
Err(error) => {
println!("Error: {error}");
}
}
}
force_update_borders = true;
} }
} }
SocketMessage::ReloadStaticConfiguration(ref pathbuf) => { SocketMessage::ReloadStaticConfiguration(ref pathbuf) => {
self.reload_static_configuration(pathbuf)?; self.reload_static_configuration(pathbuf)?;
force_update_borders = true;
} }
SocketMessage::CompleteConfiguration => { SocketMessage::CompleteConfiguration => {
if !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) { if !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) {
INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst); INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst);
self.update_focused_workspace(false, false)?; self.update_focused_workspace(false, false)?;
force_update_borders = true;
} }
} }
SocketMessage::WatchConfiguration(enable) => { SocketMessage::WatchConfiguration(enable) => {
@@ -2010,8 +1880,6 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
self.remove_all_accents()?; self.remove_all_accents()?;
} }
} }
} else if matches!(IMPLEMENTATION.load(), BorderImplementation::Komorebi) {
force_update_borders = true;
} }
} }
SocketMessage::BorderImplementation(implementation) => { SocketMessage::BorderImplementation(implementation) => {
@@ -2024,49 +1892,44 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
match IMPLEMENTATION.load() { match IMPLEMENTATION.load() {
BorderImplementation::Komorebi => { BorderImplementation::Komorebi => {
self.remove_all_accents()?; self.remove_all_accents()?;
force_update_borders = true;
} }
BorderImplementation::Windows => { BorderImplementation::Windows => {
border_manager::destroy_all_borders()?; border_manager::destroy_all_borders()?;
} }
} }
border_manager::send_notification(None);
} }
} }
SocketMessage::BorderColour(kind, r, g, b) => { SocketMessage::BorderColour(kind, r, g, b) => match kind {
match kind { WindowKind::Single => {
WindowKind::Single => { border_manager::FOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
border_manager::FOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Stack => {
border_manager::STACK.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Monocle => {
border_manager::MONOCLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Unfocused => {
border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::UnfocusedLocked => {
border_manager::UNFOCUSED_LOCKED
.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Floating => {
border_manager::FLOATING.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
} }
force_update_borders = true; WindowKind::Stack => {
} border_manager::STACK.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Monocle => {
border_manager::MONOCLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Unfocused => {
border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::UnfocusedLocked => {
border_manager::UNFOCUSED_LOCKED
.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
WindowKind::Floating => {
border_manager::FLOATING.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
},
SocketMessage::BorderStyle(style) => { SocketMessage::BorderStyle(style) => {
STYLE.store(style); STYLE.store(style);
force_update_borders = true;
} }
SocketMessage::BorderWidth(width) => { SocketMessage::BorderWidth(width) => {
border_manager::BORDER_WIDTH.store(width, Ordering::SeqCst); border_manager::BORDER_WIDTH.store(width, Ordering::SeqCst);
force_update_borders = true;
} }
SocketMessage::BorderOffset(offset) => { SocketMessage::BorderOffset(offset) => {
border_manager::BORDER_OFFSET.store(offset, Ordering::SeqCst); border_manager::BORDER_OFFSET.store(offset, Ordering::SeqCst);
force_update_borders = true;
} }
SocketMessage::Animation(enable, prefix) => match prefix { SocketMessage::Animation(enable, prefix) => match prefix {
Some(prefix) => { Some(prefix) => {
@@ -2228,8 +2091,8 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
reply.write_all(schema.as_bytes())?; reply.write_all(schema.as_bytes())?;
} }
SocketMessage::Theme(ref theme) => { SocketMessage::Theme(theme) => {
theme_manager::send_notification(*theme.clone()); theme_manager::send_notification(theme);
} }
// Deprecated commands // Deprecated commands
SocketMessage::AltFocusHack(_) SocketMessage::AltFocusHack(_)
@@ -2247,11 +2110,7 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
initial_state.has_been_modified(self.as_ref()), initial_state.has_been_modified(self.as_ref()),
)?; )?;
if force_update_borders { border_manager::send_notification(None);
border_manager::send_force_update();
} else {
border_manager::send_notification(None);
}
transparency_manager::send_notification(); transparency_manager::send_notification();
stackbar_manager::send_notification(); stackbar_manager::send_notification();
+14 -2
View File
@@ -296,8 +296,8 @@ impl WindowManager {
tracing::info!("ignoring uncloak after monocle move by mouse across monitors"); tracing::info!("ignoring uncloak after monocle move by mouse across monitors");
self.uncloack_to_ignore = self.uncloack_to_ignore.saturating_sub(1); self.uncloack_to_ignore = self.uncloack_to_ignore.saturating_sub(1);
} else { } else {
let focused_monitor_idx = self.focused_monitor_idx(); let mut focused_monitor_idx = self.focused_monitor_idx();
let focused_workspace_idx = let mut focused_workspace_idx =
self.focused_workspace_idx_for_monitor_idx(focused_monitor_idx)?; self.focused_workspace_idx_for_monitor_idx(focused_monitor_idx)?;
let mut needs_reconciliation = None; let mut needs_reconciliation = None;
@@ -346,6 +346,18 @@ impl WindowManager {
} }
if proceed { if proceed {
if matches!(event, WindowManagerEvent::Show(_, _)) {
let initial_monitor_idx = initial_state.monitors.focused_idx();
if focused_monitor_idx != initial_monitor_idx {
tracing::info!("assuming focused monitor index should be {initial_monitor_idx} for WindowManagerEvent::Show");
self.focus_monitor(initial_monitor_idx)?;
}
focused_monitor_idx = self.focused_monitor_idx();
focused_workspace_idx =
self.focused_workspace_idx_for_monitor_idx(focused_monitor_idx)?;
}
let mut behaviour = self.window_management_behaviour( let mut behaviour = self.window_management_behaviour(
focused_monitor_idx, focused_monitor_idx,
focused_workspace_idx, focused_workspace_idx,
+53 -177
View File
@@ -13,12 +13,14 @@ use crate::border_manager;
use crate::border_manager::ZOrder; use crate::border_manager::ZOrder;
use crate::border_manager::IMPLEMENTATION; use crate::border_manager::IMPLEMENTATION;
use crate::border_manager::STYLE; use crate::border_manager::STYLE;
use crate::colour::Colour;
use crate::config_generation::WorkspaceMatchingRule; use crate::config_generation::WorkspaceMatchingRule;
use crate::core::config_generation::ApplicationConfiguration; use crate::core::config_generation::ApplicationConfiguration;
use crate::core::config_generation::ApplicationConfigurationGenerator; use crate::core::config_generation::ApplicationConfigurationGenerator;
use crate::core::config_generation::ApplicationOptions; use crate::core::config_generation::ApplicationOptions;
use crate::core::config_generation::MatchingRule; use crate::core::config_generation::MatchingRule;
use crate::core::config_generation::MatchingStrategy; use crate::core::config_generation::MatchingStrategy;
use crate::core::resolve_home_path;
use crate::core::AnimationStyle; use crate::core::AnimationStyle;
use crate::core::BorderImplementation; use crate::core::BorderImplementation;
use crate::core::BorderStyle; use crate::core::BorderStyle;
@@ -38,7 +40,6 @@ use crate::current_virtual_desktop;
use crate::monitor; use crate::monitor;
use crate::monitor::Monitor; use crate::monitor::Monitor;
use crate::monitor_reconciliator; use crate::monitor_reconciliator;
use crate::resolve_option_hashmap_usize_path;
use crate::ring::Ring; use crate::ring::Ring;
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR; use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
use crate::stackbar_manager::STACKBAR_FONT_FAMILY; use crate::stackbar_manager::STACKBAR_FONT_FAMILY;
@@ -61,7 +62,6 @@ use crate::Axis;
use crate::CrossBoundaryBehaviour; use crate::CrossBoundaryBehaviour;
use crate::FloatingLayerBehaviour; use crate::FloatingLayerBehaviour;
use crate::PredefinedAspectRatio; use crate::PredefinedAspectRatio;
use crate::ResolvedPathBuf;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING; use crate::DEFAULT_WORKSPACE_PADDING;
@@ -87,7 +87,6 @@ use color_eyre::Result;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use hotwatch::EventKind; use hotwatch::EventKind;
use hotwatch::Hotwatch; use hotwatch::Hotwatch;
use komorebi_themes::colour::Colour;
use parking_lot::Mutex; use parking_lot::Mutex;
use regex::Regex; use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
@@ -120,66 +119,8 @@ pub struct BorderColours {
/// Border colour when the container is unfocused /// Border colour when the container is unfocused
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub unfocused: Option<Colour>, pub unfocused: Option<Colour>,
/// Border colour when the container is unfocused and locked
#[serde(skip_serializing_if = "Option::is_none")]
pub unfocused_locked: Option<Colour>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ThemeOptions {
/// Specify Light or Dark variant for theme generation (default: Dark)
#[serde(skip_serializing_if = "Option::is_none")]
pub theme_variant: Option<komorebi_themes::ThemeVariant>,
/// Border colour when the container contains a single window (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
pub single_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container contains multiple windows (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
pub stack_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is in monocle mode (default: Base0F)
#[serde(skip_serializing_if = "Option::is_none")]
pub monocle_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the window is floating (default: Base09)
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
pub unfocused_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused and locked (default: Base08)
#[serde(skip_serializing_if = "Option::is_none")]
pub unfocused_locked_border: Option<komorebi_themes::Base16Value>,
/// Stackbar focused tab text colour (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
pub stackbar_focused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar unfocused tab text colour (default: Base05)
#[serde(skip_serializing_if = "Option::is_none")]
pub stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar tab background colour (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
pub stackbar_background: Option<komorebi_themes::Base16Value>,
/// Komorebi status bar accent (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
pub bar_accent: Option<komorebi_themes::Base16Value>,
}
#[serde_with::serde_as]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Wallpaper {
/// Path to the wallpaper image file
#[serde_as(as = "ResolvedPathBuf")]
pub path: PathBuf,
/// Generate and apply Base16 theme for this wallpaper (default: true)
#[serde(skip_serializing_if = "Option::is_none")]
pub generate_theme: Option<bool>,
/// Specify Light or Dark variant for theme generation (default: Dark)
#[serde(skip_serializing_if = "Option::is_none")]
pub theme_options: Option<ThemeOptions>,
}
// serde_as must be before derive
#[serde_with::serde_as]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct WorkspaceConfig { pub struct WorkspaceConfig {
@@ -190,14 +131,12 @@ pub struct WorkspaceConfig {
pub layout: Option<DefaultLayout>, pub layout: Option<DefaultLayout>,
/// END OF LIFE FEATURE: Custom Layout (default: None) /// END OF LIFE FEATURE: Custom Layout (default: None)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde_as(as = "Option<ResolvedPathBuf>")]
pub custom_layout: Option<PathBuf>, pub custom_layout: Option<PathBuf>,
/// Layout rules in the format of threshold => layout (default: None) /// Layout rules in the format of threshold => layout (default: None)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub layout_rules: Option<HashMap<usize, DefaultLayout>>, pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
/// END OF LIFE FEATURE: Custom layout rules (default: None) /// END OF LIFE FEATURE: Custom layout rules (default: None)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(deserialize_with = "resolve_option_hashmap_usize_path", default)]
pub custom_layout_rules: Option<HashMap<usize, PathBuf>>, pub custom_layout_rules: Option<HashMap<usize, PathBuf>>,
/// Container padding (default: global) /// Container padding (default: global)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@@ -229,9 +168,6 @@ pub struct WorkspaceConfig {
/// Determine what happens to a new window when the Floating workspace layer is active (default: Tile) /// Determine what happens to a new window when the Floating workspace layer is active (default: Tile)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>, pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
/// Specify a wallpaper for this workspace
#[serde(skip_serializing_if = "Option::is_none")]
pub wallpaper: Option<Wallpaper>,
} }
impl From<&Workspace> for WorkspaceConfig { impl From<&Workspace> for WorkspaceConfig {
@@ -307,8 +243,7 @@ impl From<&Workspace> for WorkspaceConfig {
window_container_behaviour_rules: Option::from(window_container_behaviour_rules), window_container_behaviour_rules: Option::from(window_container_behaviour_rules),
float_override: *value.float_override(), float_override: *value.float_override(),
layout_flip: value.layout_flip(), layout_flip: value.layout_flip(),
floating_layer_behaviour: value.floating_layer_behaviour(), floating_layer_behaviour: Option::from(*value.floating_layer_behaviour()),
wallpaper: None,
} }
} }
} }
@@ -333,12 +268,6 @@ pub struct MonitorConfig {
/// Workspace padding (default: global) /// Workspace padding (default: global)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub workspace_padding: Option<i32>, pub workspace_padding: Option<i32>,
/// Specify a wallpaper for this monitor
#[serde(skip_serializing_if = "Option::is_none")]
pub wallpaper: Option<Wallpaper>,
/// Determine what happens to a new window when the Floating workspace layer is active (default: Tile)
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
} }
impl From<&Monitor> for MonitorConfig { impl From<&Monitor> for MonitorConfig {
@@ -374,24 +303,20 @@ impl From<&Monitor> for MonitorConfig {
window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit()), window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit()),
container_padding, container_padding,
workspace_padding, workspace_padding,
wallpaper: value.wallpaper().clone(),
floating_layer_behaviour: value.floating_layer_behaviour(),
} }
} }
} }
#[serde_with::serde_as]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)] #[serde(untagged)]
pub enum AppSpecificConfigurationPath { pub enum AppSpecificConfigurationPath {
/// A single applications.json file /// A single applications.json file
Single(#[serde_as(as = "ResolvedPathBuf")] PathBuf), Single(PathBuf),
/// Multiple applications.json files /// Multiple applications.json files
Multiple(#[serde_as(as = "Vec<ResolvedPathBuf>")] Vec<PathBuf>), Multiple(Vec<PathBuf>),
} }
#[serde_with::serde_as]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// The `komorebi.json` static configuration file reference for `v0.1.36` /// The `komorebi.json` static configuration file reference for `v0.1.36`
@@ -441,7 +366,7 @@ pub struct StaticConfig {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(alias = "active_window_border_offset")] #[serde(alias = "active_window_border_offset")]
pub border_offset: Option<i32>, pub border_offset: Option<i32>,
/// Display an active window border (default: true) /// Display an active window border (default: false)
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde(alias = "active_window_border")] #[serde(alias = "active_window_border")]
pub border: Option<bool>, pub border: Option<bool>,
@@ -532,7 +457,6 @@ pub struct StaticConfig {
/// Komorebi status bar configuration files for multiple instances on different monitors /// Komorebi status bar configuration files for multiple instances on different monitors
// this option is a little special because it is only consumed by komorebic // this option is a little special because it is only consumed by komorebic
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[serde_as(as = "Option<Vec<ResolvedPathBuf>>")]
pub bar_configurations: Option<Vec<PathBuf>>, pub bar_configurations: Option<Vec<PathBuf>>,
/// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars /// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@@ -558,7 +482,7 @@ pub struct AnimationsConfig {
pub fps: Option<u64>, pub fps: Option<u64>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "palette")] #[serde(tag = "palette")]
pub enum KomorebiTheme { pub enum KomorebiTheme {
@@ -632,41 +556,6 @@ pub enum KomorebiTheme {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
bar_accent: Option<komorebi_themes::Base16Value>, bar_accent: Option<komorebi_themes::Base16Value>,
}, },
/// A custom Base16 theme
Custom {
/// Colours of the custom Base16 theme palette
colours: Box<komorebi_themes::Base16ColourPalette>,
/// Border colour when the container contains a single window (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
single_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container contains multiple windows (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
stack_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is in monocle mode (default: Base0F)
#[serde(skip_serializing_if = "Option::is_none")]
monocle_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the window is floating (default: Base09)
#[serde(skip_serializing_if = "Option::is_none")]
floating_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
unfocused_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused and locked (default: Base08)
#[serde(skip_serializing_if = "Option::is_none")]
unfocused_locked_border: Option<komorebi_themes::Base16Value>,
/// Stackbar focused tab text colour (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_focused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar unfocused tab text colour (default: Base05)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar tab background colour (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_background: Option<komorebi_themes::Base16Value>,
/// Komorebi status bar accent (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
bar_accent: Option<komorebi_themes::Base16Value>,
},
} }
impl StaticConfig { impl StaticConfig {
@@ -811,9 +700,6 @@ impl From<&WindowManager> for StaticConfig {
unfocused: Option::from(Colour::from( unfocused: Option::from(Colour::from(
border_manager::UNFOCUSED.load(Ordering::SeqCst), border_manager::UNFOCUSED.load(Ordering::SeqCst),
)), )),
unfocused_locked: Option::from(Colour::from(
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
)),
}) })
}; };
@@ -970,7 +856,10 @@ impl StaticConfig {
border_manager::BORDER_WIDTH.store(self.border_width.unwrap_or(8), Ordering::SeqCst); border_manager::BORDER_WIDTH.store(self.border_width.unwrap_or(8), Ordering::SeqCst);
border_manager::BORDER_OFFSET.store(self.border_offset.unwrap_or(-1), Ordering::SeqCst); border_manager::BORDER_OFFSET.store(self.border_offset.unwrap_or(-1), Ordering::SeqCst);
border_manager::BORDER_ENABLED.store(self.border.unwrap_or(true), Ordering::SeqCst);
if let Some(enabled) = &self.border {
border_manager::BORDER_ENABLED.store(*enabled, Ordering::SeqCst);
}
if let Some(colours) = &self.border_colours { if let Some(colours) = &self.border_colours {
if let Some(single) = colours.single { if let Some(single) = colours.single {
@@ -992,11 +881,6 @@ impl StaticConfig {
if let Some(unfocused) = colours.unfocused { if let Some(unfocused) = colours.unfocused {
border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst); border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst);
} }
if let Some(unfocused_locked) = colours.unfocused_locked {
border_manager::UNFOCUSED_LOCKED
.store(u32::from(unfocused_locked), Ordering::SeqCst);
}
} }
STYLE.store(self.border_style.unwrap_or_default()); STYLE.store(self.border_style.unwrap_or_default());
@@ -1137,7 +1021,7 @@ impl StaticConfig {
} }
if let Some(theme) = &self.theme { if let Some(theme) = &self.theme {
theme_manager::send_notification(theme.clone()); theme_manager::send_notification(*theme);
} }
if let Some(path) = &self.app_specific_configuration_path { if let Some(path) = &self.app_specific_configuration_path {
@@ -1182,7 +1066,44 @@ impl StaticConfig {
pub fn read(path: &PathBuf) -> Result<Self> { pub fn read(path: &PathBuf) -> Result<Self> {
let content = std::fs::read_to_string(path)?; let content = std::fs::read_to_string(path)?;
serde_json::from_str(&content).map_err(Into::into) let mut value: Self = serde_json::from_str(&content)?;
if let Some(path) = &mut value.app_specific_configuration_path {
match path {
AppSpecificConfigurationPath::Single(path) => {
*path = resolve_home_path(&*path)?;
}
AppSpecificConfigurationPath::Multiple(paths) => {
for path in paths {
*path = resolve_home_path(&*path)?;
}
}
}
}
if let Some(monitors) = &mut value.monitors {
for m in monitors {
for w in &mut m.workspaces {
if let Some(path) = &mut w.custom_layout {
*path = resolve_home_path(&*path)?;
}
if let Some(map) = &mut w.custom_layout_rules {
for path in map.values_mut() {
*path = resolve_home_path(&*path)?;
}
}
}
}
}
if let Some(bar_configurations) = &mut value.bar_configurations {
for path in bar_configurations {
*path = resolve_home_path(&*path)?;
}
}
Ok(value)
} }
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
@@ -1335,8 +1256,6 @@ impl StaticConfig {
); );
monitor.set_container_padding(monitor_config.container_padding); monitor.set_container_padding(monitor_config.container_padding);
monitor.set_workspace_padding(monitor_config.workspace_padding); monitor.set_workspace_padding(monitor_config.workspace_padding);
monitor.set_wallpaper(monitor_config.wallpaper.clone());
monitor.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
monitor.update_workspaces_globals(offset); monitor.update_workspaces_globals(offset);
for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() { for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() {
@@ -1422,7 +1341,6 @@ impl StaticConfig {
); );
m.set_container_padding(monitor_config.container_padding); m.set_container_padding(monitor_config.container_padding);
m.set_workspace_padding(monitor_config.workspace_padding); m.set_workspace_padding(monitor_config.workspace_padding);
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
m.update_workspaces_globals(offset); m.update_workspaces_globals(offset);
@@ -1509,8 +1427,6 @@ impl StaticConfig {
); );
monitor.set_container_padding(monitor_config.container_padding); monitor.set_container_padding(monitor_config.container_padding);
monitor.set_workspace_padding(monitor_config.workspace_padding); monitor.set_workspace_padding(monitor_config.workspace_padding);
monitor.set_wallpaper(monitor_config.wallpaper.clone());
monitor.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
monitor.update_workspaces_globals(offset); monitor.update_workspaces_globals(offset);
@@ -1597,7 +1513,6 @@ impl StaticConfig {
); );
m.set_container_padding(monitor_config.container_padding); m.set_container_padding(monitor_config.container_padding);
m.set_workspace_padding(monitor_config.workspace_padding); m.set_workspace_padding(monitor_config.workspace_padding);
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
m.update_workspaces_globals(offset); m.update_workspaces_globals(offset);
@@ -1662,8 +1577,6 @@ impl StaticConfig {
for i in 0..monitor_count { for i in 0..monitor_count {
wm.update_focused_workspace_by_monitor_idx(i)?; wm.update_focused_workspace_by_monitor_idx(i)?;
let ws_idx = wm.focused_workspace_idx_for_monitor_idx(i)?;
wm.apply_wallpaper_for_monitor_workspace(i, ws_idx)?;
} }
Ok(()) Ok(())
@@ -1752,6 +1665,7 @@ fn handle_asc_file(
Some(ext) => match ext.to_string_lossy().to_string().as_str() { Some(ext) => match ext.to_string_lossy().to_string().as_str() {
"yaml" => { "yaml" => {
tracing::info!("loading applications.yaml from: {}", path.display()); tracing::info!("loading applications.yaml from: {}", path.display());
let path = resolve_home_path(path)?;
let content = std::fs::read_to_string(path)?; let content = std::fs::read_to_string(path)?;
let asc = ApplicationConfigurationGenerator::load(&content)?; let asc = ApplicationConfigurationGenerator::load(&content)?;
@@ -1800,7 +1714,8 @@ fn handle_asc_file(
} }
"json" => { "json" => {
tracing::info!("loading applications.json from: {}", path.display()); tracing::info!("loading applications.json from: {}", path.display());
let mut asc = ApplicationSpecificConfiguration::load(path)?; let path = resolve_home_path(path)?;
let mut asc = ApplicationSpecificConfiguration::load(&path)?;
for entry in asc.values_mut() { for entry in asc.values_mut() {
match entry { match entry {
@@ -1862,10 +1777,7 @@ fn handle_asc_file(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::path::PathBuf;
use crate::StaticConfig; use crate::StaticConfig;
use crate::WorkspaceConfig;
#[test] #[test]
fn backwards_compat() { fn backwards_compat() {
@@ -1894,40 +1806,4 @@ mod tests {
StaticConfig::read_raw(&config).unwrap(); StaticConfig::read_raw(&config).unwrap();
} }
} }
#[test]
fn deserialize_custom_layout_rules() {
// set an environment variable for testing
std::env::set_var("VAR", "VALUE");
let config = r#"
{
"name": "Test",
"custom_layout_rules": {
"1": "path/to/dir",
"2": "path/to/%VAR%"
}
}
"#;
let config = serde_json::from_str::<WorkspaceConfig>(config).unwrap();
let custom_layout_rules = config.custom_layout_rules.unwrap();
assert_eq!(
custom_layout_rules.get(&1).unwrap(),
&PathBuf::from("path/to/dir")
);
assert_eq!(
custom_layout_rules.get(&2).unwrap(),
&PathBuf::from("path/to/VALUE")
);
let config = r#"
{
"name": "Test",
}
"#;
let config = serde_json::from_str::<WorkspaceConfig>(config).unwrap();
assert_eq!(config.custom_layout_rules, None);
}
} }
+11 -73
View File
@@ -5,12 +5,11 @@ use crate::stackbar_manager;
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR; use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR; use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR; use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
use crate::Colour;
use crate::KomorebiTheme; use crate::KomorebiTheme;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use crossbeam_utils::atomic::AtomicCell; use crossbeam_utils::atomic::AtomicCell;
use komorebi_themes::colour::Colour;
use komorebi_themes::Base16Wrapper;
use std::ops::Deref; use std::ops::Deref;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::OnceLock; use std::sync::OnceLock;
@@ -158,100 +157,39 @@ pub fn handle_notifications() -> color_eyre::Result<()> {
} => { } => {
let single_border = single_border let single_border = single_border
.unwrap_or(komorebi_themes::Base16Value::Base0D) .unwrap_or(komorebi_themes::Base16Value::Base0D)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let stack_border = stack_border let stack_border = stack_border
.unwrap_or(komorebi_themes::Base16Value::Base0B) .unwrap_or(komorebi_themes::Base16Value::Base0B)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let monocle_border = monocle_border let monocle_border = monocle_border
.unwrap_or(komorebi_themes::Base16Value::Base0F) .unwrap_or(komorebi_themes::Base16Value::Base0F)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let unfocused_border = unfocused_border let unfocused_border = unfocused_border
.unwrap_or(komorebi_themes::Base16Value::Base01) .unwrap_or(komorebi_themes::Base16Value::Base01)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let unfocused_locked_border = unfocused_locked_border let unfocused_locked_border = unfocused_locked_border
.unwrap_or(komorebi_themes::Base16Value::Base08) .unwrap_or(komorebi_themes::Base16Value::Base08)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let floating_border = floating_border let floating_border = floating_border
.unwrap_or(komorebi_themes::Base16Value::Base09) .unwrap_or(komorebi_themes::Base16Value::Base09)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let stackbar_focused_text = stackbar_focused_text let stackbar_focused_text = stackbar_focused_text
.unwrap_or(komorebi_themes::Base16Value::Base0B) .unwrap_or(komorebi_themes::Base16Value::Base0B)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let stackbar_unfocused_text = stackbar_unfocused_text let stackbar_unfocused_text = stackbar_unfocused_text
.unwrap_or(komorebi_themes::Base16Value::Base05) .unwrap_or(komorebi_themes::Base16Value::Base05)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
let stackbar_background = stackbar_background let stackbar_background = stackbar_background
.unwrap_or(komorebi_themes::Base16Value::Base01) .unwrap_or(komorebi_themes::Base16Value::Base01)
.color32(Base16Wrapper::Base16(*name)); .color32(*name);
(
single_border,
stack_border,
monocle_border,
floating_border,
unfocused_border,
unfocused_locked_border,
stackbar_focused_text,
stackbar_unfocused_text,
stackbar_background,
)
}
KomorebiTheme::Custom {
colours,
single_border,
stack_border,
monocle_border,
floating_border,
unfocused_border,
unfocused_locked_border,
stackbar_focused_text,
stackbar_unfocused_text,
stackbar_background,
..
} => {
let single_border = single_border
.unwrap_or(komorebi_themes::Base16Value::Base0D)
.color32(Base16Wrapper::Custom(colours.clone()));
let stack_border = stack_border
.unwrap_or(komorebi_themes::Base16Value::Base0B)
.color32(Base16Wrapper::Custom(colours.clone()));
let monocle_border = monocle_border
.unwrap_or(komorebi_themes::Base16Value::Base0F)
.color32(Base16Wrapper::Custom(colours.clone()));
let unfocused_border = unfocused_border
.unwrap_or(komorebi_themes::Base16Value::Base01)
.color32(Base16Wrapper::Custom(colours.clone()));
let unfocused_locked_border = unfocused_locked_border
.unwrap_or(komorebi_themes::Base16Value::Base08)
.color32(Base16Wrapper::Custom(colours.clone()));
let floating_border = floating_border
.unwrap_or(komorebi_themes::Base16Value::Base09)
.color32(Base16Wrapper::Custom(colours.clone()));
let stackbar_focused_text = stackbar_focused_text
.unwrap_or(komorebi_themes::Base16Value::Base0B)
.color32(Base16Wrapper::Custom(colours.clone()));
let stackbar_unfocused_text = stackbar_unfocused_text
.unwrap_or(komorebi_themes::Base16Value::Base05)
.color32(Base16Wrapper::Custom(colours.clone()));
let stackbar_background = stackbar_background
.unwrap_or(komorebi_themes::Base16Value::Base01)
.color32(Base16Wrapper::Custom(colours.clone()));
( (
single_border, single_border,
@@ -295,7 +233,7 @@ pub fn handle_notifications() -> color_eyre::Result<()> {
CURRENT_THEME.store(Some(notification.0)); CURRENT_THEME.store(Some(notification.0));
border_manager::send_force_update(); border_manager::send_notification(None);
stackbar_manager::send_notification(); stackbar_manager::send_notification();
} }
+6 -178
View File
@@ -248,9 +248,6 @@ impl Default for GlobalState {
unfocused: Option::from(Colour::Rgb(Rgb::from( unfocused: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED.load(Ordering::SeqCst), border_manager::UNFOCUSED.load(Ordering::SeqCst),
))), ))),
unfocused_locked: Option::from(Colour::Rgb(Rgb::from(
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
))),
}, },
border_style: STYLE.load(), border_style: STYLE.load(),
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst), border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
@@ -348,7 +345,6 @@ impl From<&WindowManager> for State {
floating_layer_behaviour: workspace.floating_layer_behaviour, floating_layer_behaviour: workspace.floating_layer_behaviour,
globals: workspace.globals, globals: workspace.globals,
locked_containers: workspace.locked_containers.clone(), locked_containers: workspace.locked_containers.clone(),
wallpaper: workspace.wallpaper.clone(),
workspace_config: None, workspace_config: None,
}) })
.collect::<VecDeque<_>>(); .collect::<VecDeque<_>>();
@@ -359,8 +355,6 @@ impl From<&WindowManager> for State {
workspace_names: monitor.workspace_names.clone(), workspace_names: monitor.workspace_names.clone(),
container_padding: monitor.container_padding, container_padding: monitor.container_padding,
workspace_padding: monitor.workspace_padding, workspace_padding: monitor.workspace_padding,
wallpaper: monitor.wallpaper.clone(),
floating_layer_behaviour: monitor.floating_layer_behaviour,
}) })
.collect::<VecDeque<_>>(); .collect::<VecDeque<_>>();
stripped_monitors.focus(wm.monitors.focused_idx()); stripped_monitors.focus(wm.monitors.focused_idx());
@@ -652,18 +646,14 @@ impl WindowManager {
self.window_management_behaviour.float_override self.window_management_behaviour.float_override
}; };
let floating_layer_behaviour =
if let Some(behaviour) = workspace.floating_layer_behaviour() {
behaviour
} else {
monitor.floating_layer_behaviour().unwrap_or_default()
};
// If the workspace layer is `Floating` and the floating layer behaviour is `Float`, // If the workspace layer is `Floating` and the floating layer behaviour is `Float`,
// then consider it as if it had float override so that new windows spawn as floating // then consider it as if it had float override so that new windows spawn as floating
float_override = float_override float_override = float_override
|| (matches!(workspace.layer, WorkspaceLayer::Floating) || (matches!(workspace.layer, WorkspaceLayer::Floating)
&& matches!(floating_layer_behaviour, FloatingLayerBehaviour::Float)); && matches!(
workspace.floating_layer_behaviour,
FloatingLayerBehaviour::Float
));
return WindowManagementBehaviour { return WindowManagementBehaviour {
current_behaviour, current_behaviour,
@@ -1020,8 +1010,6 @@ impl WindowManager {
let focused_workspace_idx = monitor.focused_workspace_idx(); let focused_workspace_idx = monitor.focused_workspace_idx();
monitor.update_workspace_globals(focused_workspace_idx, offset); monitor.update_workspace_globals(focused_workspace_idx, offset);
let hmonitor = monitor.id();
let monitor_wp = monitor.wallpaper.clone();
let workspace = monitor let workspace = monitor
.focused_workspace_mut() .focused_workspace_mut()
.ok_or_else(|| anyhow!("there is no workspace"))?; .ok_or_else(|| anyhow!("there is no workspace"))?;
@@ -1033,12 +1021,6 @@ impl WindowManager {
} }
} }
if workspace.wallpaper().is_some() || monitor_wp.is_some() {
if let Err(error) = workspace.apply_wallpaper(hmonitor, &monitor_wp) {
tracing::error!("failed to apply wallpaper: {}", error);
}
}
workspace.update()?; workspace.update()?;
} }
@@ -1722,30 +1704,6 @@ impl WindowManager {
Ok(()) Ok(())
} }
/// Check for an existing wallpaper definition on the workspace/monitor index pair and apply it
/// if it exists
#[tracing::instrument(skip(self))]
pub fn apply_wallpaper_for_monitor_workspace(
&mut self,
monitor_idx: usize,
workspace_idx: usize,
) -> Result<()> {
let monitor = self
.monitors_mut()
.get_mut(monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor"))?;
let hmonitor = monitor.id();
let monitor_wp = monitor.wallpaper.clone();
let workspace = monitor
.workspaces()
.get(workspace_idx)
.ok_or_else(|| anyhow!("there is no workspace"))?;
workspace.apply_wallpaper(hmonitor, &monitor_wp)
}
pub fn update_focused_workspace_by_monitor_idx(&mut self, idx: usize) -> Result<()> { pub fn update_focused_workspace_by_monitor_idx(&mut self, idx: usize) -> Result<()> {
let offset = self.work_area_offset; let offset = self.work_area_offset;
@@ -3099,7 +3057,7 @@ impl WindowManager {
} }
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn toggle_float(&mut self, force_float: bool) -> Result<()> { pub fn toggle_float(&mut self) -> Result<()> {
let hwnd = WindowsApi::foreground_window()?; let hwnd = WindowsApi::foreground_window()?;
let workspace = self.focused_workspace_mut()?; let workspace = self.focused_workspace_mut()?;
@@ -3111,7 +3069,7 @@ impl WindowManager {
} }
} }
if is_floating_window && !force_float { if is_floating_window {
workspace.set_layer(WorkspaceLayer::Tiling); workspace.set_layer(WorkspaceLayer::Tiling);
self.unfloat_window()?; self.unfloat_window()?;
} else { } else {
@@ -5022,134 +4980,4 @@ mod tests {
assert!(*workspace.tile()); assert!(*workspace.tile());
} }
} }
#[test]
fn test_toggle_lock() {
let (mut wm, _context) = setup_window_manager();
{
// Add monitor with default workspace to
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
let workspace = m.focused_workspace_mut().unwrap();
// Create containers to add to the workspace
for _ in 0..3 {
let container = Container::default();
workspace.add_container_to_back(container);
}
wm.monitors_mut().push_back(m);
}
{
// Ensure container 2 is not locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(!workspace.locked_containers().contains(&2));
}
// Toggle lock on focused container
wm.toggle_lock().unwrap();
{
// Ensure container 2 is locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(workspace.locked_containers().contains(&2));
}
// Toggle lock on focused container
wm.toggle_lock().unwrap();
{
// Ensure container 2 is not locked
let workspace = wm.focused_workspace_mut().unwrap();
assert!(!workspace.locked_containers().contains(&2));
}
}
#[test]
fn test_float_window() {
let (mut wm, _context) = setup_window_manager();
{
// Create a monitor
let mut m = monitor::new(
0,
Rect::default(),
Rect::default(),
"TestMonitor".to_string(),
"TestDevice".to_string(),
"TestDeviceID".to_string(),
Some("TestMonitorID".to_string()),
);
// Create a container
let mut container = Container::default();
// Add three windows to the container
for i in 0..3 {
container.windows_mut().push_back(Window::from(i));
}
// Should have 3 windows in the container
assert_eq!(container.windows().len(), 3);
// Add the container to the workspace
let workspace = m.focused_workspace_mut().unwrap();
workspace.add_container_to_back(container);
// Add monitor to the window manager
wm.monitors_mut().push_back(m);
}
// Add focused window to floating window list
wm.float_window().ok();
{
let workspace = wm.focused_workspace().unwrap();
let floating_windows = workspace.floating_windows();
let container = workspace.focused_container().unwrap();
// Hwnd 0 should be added to floating_windows
assert_eq!(floating_windows[0].hwnd, 0);
// Should have a length of 1
assert_eq!(floating_windows.len(), 1);
// Should have 2 windows in the container
assert_eq!(container.windows().len(), 2);
// Should be focused on window 1
assert_eq!(container.focused_window(), Some(&Window { hwnd: 1 }));
}
// Add focused window to floating window list
wm.float_window().ok();
{
let workspace = wm.focused_workspace().unwrap();
let floating_windows = workspace.floating_windows();
let container = workspace.focused_container().unwrap();
// Hwnd 1 should be added to floating_windows
assert_eq!(floating_windows[1].hwnd, 1);
// Should have a length of 2
assert_eq!(floating_windows.len(), 2);
// Should have 1 window in the container
assert_eq!(container.windows().len(), 1);
// Should be focused on window 2
assert_eq!(container.focused_window(), Some(&Window { hwnd: 2 }));
}
}
} }
+6 -65
View File
@@ -1,13 +1,13 @@
use color_eyre::eyre::anyhow;
use color_eyre::eyre::bail;
use color_eyre::eyre::Error;
use color_eyre::Result;
use core::ffi::c_void; use core::ffi::c_void;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::mem::size_of; use std::mem::size_of;
use std::path::Path;
use color_eyre::eyre::anyhow;
use color_eyre::eyre::bail;
use color_eyre::eyre::Error;
use color_eyre::Result;
use windows::core::Result as WindowsCrateResult; use windows::core::Result as WindowsCrateResult;
use windows::core::PCWSTR; use windows::core::PCWSTR;
use windows::core::PWSTR; use windows::core::PWSTR;
@@ -47,8 +47,6 @@ use windows::Win32::Graphics::Gdi::HMONITOR;
use windows::Win32::Graphics::Gdi::MONITORENUMPROC; use windows::Win32::Graphics::Gdi::MONITORENUMPROC;
use windows::Win32::Graphics::Gdi::MONITORINFOEXW; use windows::Win32::Graphics::Gdi::MONITORINFOEXW;
use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST; use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST;
use windows::Win32::System::Com::CoCreateInstance;
use windows::Win32::System::Com::CLSCTX_ALL;
use windows::Win32::System::LibraryLoader::GetModuleHandleW; use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::System::Power::RegisterPowerSettingNotification; use windows::Win32::System::Power::RegisterPowerSettingNotification;
use windows::Win32::System::Power::HPOWERNOTIFY; use windows::Win32::System::Power::HPOWERNOTIFY;
@@ -74,9 +72,6 @@ use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTUP;
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT; use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT;
use windows::Win32::UI::Input::KeyboardAndMouse::VK_LBUTTON; use windows::Win32::UI::Input::KeyboardAndMouse::VK_LBUTTON;
use windows::Win32::UI::Input::KeyboardAndMouse::VK_MENU; use windows::Win32::UI::Input::KeyboardAndMouse::VK_MENU;
use windows::Win32::UI::Shell::DesktopWallpaper;
use windows::Win32::UI::Shell::IDesktopWallpaper;
use windows::Win32::UI::Shell::DWPOS_FILL;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop; use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW; use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
@@ -146,7 +141,6 @@ use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOPMOST;
use windows::Win32::UI::WindowsAndMessaging::WS_POPUP; use windows::Win32::UI::WindowsAndMessaging::WS_POPUP;
use windows::Win32::UI::WindowsAndMessaging::WS_SYSMENU; use windows::Win32::UI::WindowsAndMessaging::WS_SYSMENU;
use windows_core::BOOL; use windows_core::BOOL;
use windows_core::HSTRING;
use crate::core::Rect; use crate::core::Rect;
@@ -939,7 +933,7 @@ impl WindowsApi {
pub fn exe(handle: HANDLE) -> Result<String> { pub fn exe(handle: HANDLE) -> Result<String> {
Ok(Self::exe_path(handle)? Ok(Self::exe_path(handle)?
.split('\\') .split('\\')
.next_back() .last()
.ok_or_else(|| anyhow!("there is no last element"))? .ok_or_else(|| anyhow!("there is no last element"))?
.to_string()) .to_string())
} }
@@ -1008,16 +1002,6 @@ impl WindowsApi {
Ok(ex_info) Ok(ex_info)
} }
pub fn monitor_device_path(hmonitor: isize) -> Option<String> {
for display in win32_display_data::connected_displays_all().flatten() {
if display.hmonitor == hmonitor {
return Some(display.device_path.clone());
}
}
None
}
pub fn monitor(hmonitor: isize) -> Result<Monitor> { pub fn monitor(hmonitor: isize) -> Result<Monitor> {
for mut display in win32_display_data::connected_displays_all().flatten() { for mut display in win32_display_data::connected_displays_all().flatten() {
if display.hmonitor == hmonitor { if display.hmonitor == hmonitor {
@@ -1361,47 +1345,4 @@ impl WindowsApi {
pub fn wts_register_session_notification(hwnd: isize) -> Result<()> { pub fn wts_register_session_notification(hwnd: isize) -> Result<()> {
unsafe { WTSRegisterSessionNotification(HWND(as_ptr!(hwnd)), 1) }.process() unsafe { WTSRegisterSessionNotification(HWND(as_ptr!(hwnd)), 1) }.process()
} }
pub fn set_wallpaper(path: &Path, hmonitor: isize) -> Result<()> {
let path = path.canonicalize()?;
let wallpaper: IDesktopWallpaper =
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL)? };
let wallpaper_path = HSTRING::from(path.to_str().unwrap_or_default());
unsafe {
wallpaper.SetPosition(DWPOS_FILL)?;
}
let monitor_id = if let Some(path) = Self::monitor_device_path(hmonitor) {
PCWSTR::from_raw(HSTRING::from(path).as_ptr())
} else {
PCWSTR::null()
};
// Set the wallpaper
unsafe {
wallpaper.SetWallpaper(monitor_id, PCWSTR::from_raw(wallpaper_path.as_ptr()))?;
}
Ok(())
}
pub fn get_wallpaper(hmonitor: isize) -> Result<String> {
let wallpaper: IDesktopWallpaper =
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL)? };
let monitor_id = if let Some(path) = Self::monitor_device_path(hmonitor) {
PCWSTR::from_raw(HSTRING::from(path).as_ptr())
} else {
PCWSTR::null()
};
// Set the wallpaper
unsafe {
wallpaper
.GetWallpaper(monitor_id)
.and_then(|pwstr| pwstr.to_string().map_err(|e| e.into()))
}
.process()
}
} }
+41 -218
View File
@@ -1,14 +1,20 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ffi::OsStr;
use std::fmt::Display; use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::io::Write;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use getset::CopyGetters;
use getset::Getters;
use getset::MutGetters;
use getset::Setters;
use serde::Deserialize;
use serde::Serialize;
use crate::border_manager; use crate::border_manager;
use crate::container::Container;
use crate::core::Axis; use crate::core::Axis;
use crate::core::CustomLayout; use crate::core::CustomLayout;
use crate::core::CycleDirection; use crate::core::CycleDirection;
@@ -16,6 +22,11 @@ use crate::core::DefaultLayout;
use crate::core::Layout; use crate::core::Layout;
use crate::core::OperationDirection; use crate::core::OperationDirection;
use crate::core::Rect; use crate::core::Rect;
use crate::FloatingLayerBehaviour;
use crate::border_manager::BORDER_OFFSET;
use crate::border_manager::BORDER_WIDTH;
use crate::container::Container;
use crate::locked_deque::LockedDeque; use crate::locked_deque::LockedDeque;
use crate::ring::Ring; use crate::ring::Ring;
use crate::should_act; use crate::should_act;
@@ -25,28 +36,13 @@ use crate::static_config::WorkspaceConfig;
use crate::window::Window; use crate::window::Window;
use crate::window::WindowDetails; use crate::window::WindowDetails;
use crate::windows_api::WindowsApi; use crate::windows_api::WindowsApi;
use crate::FloatingLayerBehaviour;
use crate::KomorebiTheme;
use crate::SocketMessage;
use crate::Wallpaper;
use crate::WindowContainerBehaviour; use crate::WindowContainerBehaviour;
use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING; use crate::DEFAULT_WORKSPACE_PADDING;
use crate::INITIAL_CONFIGURATION_LOADED; use crate::INITIAL_CONFIGURATION_LOADED;
use crate::NO_TITLEBAR; use crate::NO_TITLEBAR;
use crate::REGEX_IDENTIFIERS; use crate::REGEX_IDENTIFIERS;
use crate::REMOVE_TITLEBARS; use crate::REMOVE_TITLEBARS;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use getset::CopyGetters;
use getset::Getters;
use getset::MutGetters;
use getset::Setters;
use komorebi_themes::Base16ColourPalette;
use serde::Deserialize;
use serde::Serialize;
use uds_windows::UnixStream;
#[allow(clippy::struct_field_names)] #[allow(clippy::struct_field_names)]
#[derive( #[derive(
@@ -92,17 +88,14 @@ pub struct Workspace {
pub window_container_behaviour_rules: Option<Vec<(usize, WindowContainerBehaviour)>>, pub window_container_behaviour_rules: Option<Vec<(usize, WindowContainerBehaviour)>>,
#[getset(get = "pub", get_mut = "pub", set = "pub")] #[getset(get = "pub", get_mut = "pub", set = "pub")]
pub float_override: Option<bool>, pub float_override: Option<bool>,
#[serde(skip)]
#[getset(get = "pub", get_mut = "pub", set = "pub")] #[getset(get = "pub", get_mut = "pub", set = "pub")]
pub globals: WorkspaceGlobals, pub globals: WorkspaceGlobals,
#[getset(get = "pub", get_mut = "pub", set = "pub")] #[getset(get = "pub", get_mut = "pub", set = "pub")]
pub layer: WorkspaceLayer, pub layer: WorkspaceLayer,
#[getset(get_copy = "pub", get_mut = "pub", set = "pub")] #[getset(get = "pub", get_mut = "pub", set = "pub")]
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>, pub floating_layer_behaviour: FloatingLayerBehaviour,
#[getset(get = "pub", get_mut = "pub", set = "pub")] #[getset(get = "pub", get_mut = "pub", set = "pub")]
pub locked_containers: BTreeSet<usize>, pub locked_containers: BTreeSet<usize>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub wallpaper: Option<Wallpaper>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")] #[getset(get = "pub", set = "pub")]
pub workspace_config: Option<WorkspaceConfig>, pub workspace_config: Option<WorkspaceConfig>,
@@ -155,7 +148,6 @@ impl Default for Workspace {
globals: Default::default(), globals: Default::default(),
workspace_config: None, workspace_config: None,
locked_containers: Default::default(), locked_containers: Default::default(),
wallpaper: None,
} }
} }
} }
@@ -186,13 +178,10 @@ pub enum WorkspaceWindowLocation {
pub struct WorkspaceGlobals { pub struct WorkspaceGlobals {
pub container_padding: Option<i32>, pub container_padding: Option<i32>,
pub workspace_padding: Option<i32>, pub workspace_padding: Option<i32>,
pub border_width: i32,
pub border_offset: i32,
pub work_area: Rect, pub work_area: Rect,
pub work_area_offset: Option<Rect>, pub work_area_offset: Option<Rect>,
pub window_based_work_area_offset: Option<Rect>, pub window_based_work_area_offset: Option<Rect>,
pub window_based_work_area_offset_limit: isize, pub window_based_work_area_offset_limit: isize,
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
} }
impl Workspace { impl Workspace {
@@ -265,8 +254,7 @@ impl Workspace {
self.set_float_override(config.float_override); self.set_float_override(config.float_override);
self.set_layout_flip(config.layout_flip); self.set_layout_flip(config.layout_flip);
self.set_floating_layer_behaviour(config.floating_layer_behaviour); self.set_floating_layer_behaviour(config.floating_layer_behaviour.unwrap_or_default());
self.set_wallpaper(config.wallpaper.clone());
self.set_workspace_config(Some(config.clone())); self.set_workspace_config(Some(config.clone()));
@@ -303,133 +291,12 @@ impl Workspace {
} }
} }
pub fn apply_wallpaper(&self, hmonitor: isize, monitor_wp: &Option<Wallpaper>) -> Result<()> { pub fn restore(&mut self, mouse_follows_focus: bool) -> Result<()> {
if let Some(wallpaper) = self.wallpaper.as_ref().or(monitor_wp.as_ref()) {
if let Err(error) = WindowsApi::set_wallpaper(&wallpaper.path, hmonitor) {
tracing::error!("failed to set wallpaper: {error}");
}
if wallpaper.generate_theme.unwrap_or(true) {
let variant = wallpaper
.theme_options
.as_ref()
.and_then(|t| t.theme_variant)
.unwrap_or_default();
let cached_palette = DATA_DIR.join(format!(
"{}.base16.{variant}.json",
wallpaper
.path
.file_name()
.unwrap_or(OsStr::new("tmp"))
.to_string_lossy()
));
let mut base16_palette = None;
if cached_palette.is_file() {
tracing::info!(
"colour palette for wallpaper {} found in cache",
cached_palette.display()
);
// this code is VERY slow on debug builds - should only be a one-time issue when loading
// an uncached wallpaper
if let Ok(palette) = serde_json::from_str::<Base16ColourPalette>(
&std::fs::read_to_string(&cached_palette)?,
) {
base16_palette = Some(palette);
}
};
if base16_palette.is_none() {
base16_palette =
komorebi_themes::generate_base16_palette(&wallpaper.path, variant).ok();
std::fs::write(
&cached_palette,
serde_json::to_string_pretty(&base16_palette)?,
)?;
tracing::info!(
"colour palette for wallpaper {} cached",
cached_palette.display()
);
}
if let Some(palette) = base16_palette {
let komorebi_theme = KomorebiTheme::Custom {
colours: Box::new(palette),
single_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.single_border),
stack_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.stack_border),
monocle_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.monocle_border),
floating_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.floating_border),
unfocused_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.unfocused_border),
unfocused_locked_border: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.unfocused_locked_border),
stackbar_focused_text: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.stackbar_focused_text),
stackbar_unfocused_text: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.stackbar_unfocused_text),
stackbar_background: wallpaper
.theme_options
.as_ref()
.and_then(|o| o.stackbar_background),
bar_accent: wallpaper.theme_options.as_ref().and_then(|o| o.bar_accent),
};
let bytes = SocketMessage::Theme(Box::new(komorebi_theme)).as_bytes()?;
let socket = DATA_DIR.join("komorebi.sock");
match UnixStream::connect(socket) {
Ok(mut stream) => {
if let Err(error) = stream.write_all(&bytes) {
tracing::error!("failed to send theme update message: {error}")
}
}
Err(error) => {
tracing::error!("{error}")
}
}
}
}
}
Ok(())
}
pub fn restore(
&mut self,
mouse_follows_focus: bool,
hmonitor: isize,
monitor_wp: &Option<Wallpaper>,
) -> Result<()> {
if let Some(container) = self.monocle_container() { if let Some(container) = self.monocle_container() {
if let Some(window) = container.focused_window() { if let Some(window) = container.focused_window() {
container.restore(); container.restore();
window.focus(mouse_follows_focus)?; window.focus(mouse_follows_focus)?;
return self.apply_wallpaper(hmonitor, monitor_wp); return Ok(());
} }
} }
@@ -473,7 +340,7 @@ impl Workspace {
floating_window.focus(mouse_follows_focus)?; floating_window.focus(mouse_follows_focus)?;
} }
self.apply_wallpaper(hmonitor, monitor_wp) Ok(())
} }
pub fn update(&mut self) -> Result<()> { pub fn update(&mut self) -> Result<()> {
@@ -481,9 +348,6 @@ impl Workspace {
return Ok(()); return Ok(());
} }
// make sure we are never holding on to empty containers
self.containers_mut().retain(|c| !c.windows().is_empty());
let container_padding = self let container_padding = self
.container_padding() .container_padding()
.or(self.globals().container_padding) .or(self.globals().container_padding)
@@ -492,8 +356,6 @@ impl Workspace {
.workspace_padding() .workspace_padding()
.or(self.globals().workspace_padding) .or(self.globals().workspace_padding)
.unwrap_or_default(); .unwrap_or_default();
let border_width = self.globals().border_width;
let border_offset = self.globals().border_offset;
let work_area = self.globals().work_area; let work_area = self.globals().work_area;
let work_area_offset = self.globals().work_area_offset; let work_area_offset = self.globals().work_area_offset;
let window_based_work_area_offset = self.globals().window_based_work_area_offset; let window_based_work_area_offset = self.globals().window_based_work_area_offset;
@@ -566,8 +428,12 @@ impl Workspace {
if let Some(container) = self.monocle_container_mut() { if let Some(container) = self.monocle_container_mut() {
if let Some(window) = container.focused_window_mut() { if let Some(window) = container.focused_window_mut() {
adjusted_work_area.add_padding(container_padding); adjusted_work_area.add_padding(container_padding);
adjusted_work_area.add_padding(border_offset); {
adjusted_work_area.add_padding(border_width); let border_offset = BORDER_OFFSET.load(Ordering::SeqCst);
adjusted_work_area.add_padding(border_offset);
let width = BORDER_WIDTH.load(Ordering::SeqCst);
adjusted_work_area.add_padding(width);
}
window.set_position(&adjusted_work_area, true)?; window.set_position(&adjusted_work_area, true)?;
}; };
} else if let Some(window) = self.maximized_window_mut() { } else if let Some(window) = self.maximized_window_mut() {
@@ -595,8 +461,13 @@ impl Workspace {
let window_count = container.windows().len(); let window_count = container.windows().len();
if let Some(layout) = layouts.get_mut(i) { if let Some(layout) = layouts.get_mut(i) {
layout.add_padding(border_offset); {
layout.add_padding(border_width); let border_offset = BORDER_OFFSET.load(Ordering::SeqCst);
layout.add_padding(border_offset);
let width = BORDER_WIDTH.load(Ordering::SeqCst);
layout.add_padding(width);
}
if stackbar_manager::should_have_stackbar(window_count) { if stackbar_manager::should_have_stackbar(window_count) {
let tab_height = STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst); let tab_height = STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst);
@@ -688,13 +559,13 @@ impl Workspace {
for window in self.visible_windows().into_iter().flatten() { for window in self.visible_windows().into_iter().flatten() {
if !window.is_window() if !window.is_window()
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app // This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED // when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the // (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
// docs is closed // docs is closed
// //
// I hate every single person who worked on Microsoft Office 365, especially Word // I hate every single person who worked on Microsoft Office 365, especially Word
|| !window.is_visible() || !window.is_visible()
{ {
hwnds.push(window.hwnd); hwnds.push(window.hwnd);
} }
@@ -1776,6 +1647,7 @@ impl Workspace {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::container::Container; use crate::container::Container;
use crate::Window; use crate::Window;
use std::collections::BTreeSet; use std::collections::BTreeSet;
@@ -2488,53 +2360,4 @@ mod tests {
let floating_windows = workspace.floating_windows_mut(); let floating_windows = workspace.floating_windows_mut();
assert!(floating_windows.contains(&Window { hwnd: 0 })); assert!(floating_windows.contains(&Window { hwnd: 0 }));
} }
#[test]
fn test_visible_windows() {
let mut workspace = Workspace::default();
{
// Create and add a default Container with 2 windows
let mut container = Container::default();
container.windows_mut().push_back(Window::from(100));
container.windows_mut().push_back(Window::from(200));
workspace.add_container_to_back(container);
}
{
// visible_windows should return None and 100
let visible_windows = workspace.visible_windows();
assert_eq!(visible_windows.len(), 2);
assert!(visible_windows[0].is_none());
assert_eq!(visible_windows[1].unwrap().hwnd, 100);
}
{
// Create and add a default Container with 1 window
let mut container = Container::default();
container.windows_mut().push_back(Window::from(300));
workspace.add_container_to_back(container);
}
{
// visible_windows should return None, 100, and 300
let visible_windows = workspace.visible_windows();
assert_eq!(visible_windows.len(), 3);
assert!(visible_windows[0].is_none());
assert_eq!(visible_windows[1].unwrap().hwnd, 100);
assert_eq!(visible_windows[2].unwrap().hwnd, 300);
}
// Maximize window 200
workspace.set_maximized_window(Some(Window { hwnd: 200 }));
{
// visible_windows should return 200, 100, and 300
let visible_windows = workspace.visible_windows();
assert_eq!(visible_windows.len(), 3);
assert_eq!(visible_windows[0].unwrap().hwnd, 200);
assert_eq!(visible_windows[1].unwrap().hwnd, 100);
assert_eq!(visible_windows[2].unwrap().hwnd, 300);
}
}
} }
+69 -84
View File
@@ -2,13 +2,12 @@
#![allow(clippy::missing_errors_doc, clippy::doc_markdown)] #![allow(clippy::missing_errors_doc, clippy::doc_markdown)]
use chrono::Utc; use chrono::Utc;
use komorebi_client::replace_env_in_path;
use komorebi_client::PathExt;
use std::fs::File; use std::fs::File;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::BufRead; use std::io::BufRead;
use std::io::BufReader; use std::io::BufReader;
use std::io::Write; use std::io::Write;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
@@ -23,6 +22,7 @@ use color_eyre::eyre::bail;
use color_eyre::Result; use color_eyre::Result;
use dirs::data_local_dir; use dirs::data_local_dir;
use fs_tail::TailedFile; use fs_tail::TailedFile;
use komorebi_client::resolve_home_path;
use komorebi_client::send_message; use komorebi_client::send_message;
use komorebi_client::send_query; use komorebi_client::send_query;
use komorebi_client::AppSpecificConfigurationPath; use komorebi_client::AppSpecificConfigurationPath;
@@ -64,7 +64,8 @@ lazy_static! {
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else( std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|_| dirs::home_dir().expect("there is no home directory"), |_| dirs::home_dir().expect("there is no home directory"),
|home_path| { |home_path| {
let home = home_path.replace_env(); let home = PathBuf::from(&home_path);
if home.as_path().is_dir() { if home.as_path().is_dir() {
HAS_CUSTOM_CONFIG_HOME.store(true, Ordering::SeqCst); HAS_CUSTOM_CONFIG_HOME.store(true, Ordering::SeqCst);
home home
@@ -87,12 +88,12 @@ lazy_static! {
.join(".config") .join(".config")
}, },
|home_path| { |home_path| {
let whkd_config_home = home_path.replace_env(); let whkd_config_home = PathBuf::from(&home_path);
assert!( assert!(
whkd_config_home.is_dir(), whkd_config_home.as_path().is_dir(),
"$Env:WHKD_CONFIG_HOME is set to '{}', which is not a valid directory", "$Env:WHKD_CONFIG_HOME is set to '{}', which is not a valid directory",
home_path whkd_config_home.to_string_lossy()
); );
whkd_config_home whkd_config_home
@@ -298,7 +299,6 @@ pub struct WorkspaceCustomLayout {
workspace: usize, workspace: usize,
/// JSON or YAML file from which the custom layout definition should be loaded /// JSON or YAML file from which the custom layout definition should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -308,7 +308,6 @@ pub struct NamedWorkspaceCustomLayout {
workspace: String, workspace: String,
/// JSON or YAML file from which the custom layout definition should be loaded /// JSON or YAML file from which the custom layout definition should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -351,7 +350,6 @@ pub struct WorkspaceCustomLayoutRule {
at_container_count: usize, at_container_count: usize,
/// JSON or YAML file from which the custom layout definition should be loaded /// JSON or YAML file from which the custom layout definition should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -364,7 +362,6 @@ pub struct NamedWorkspaceCustomLayoutRule {
at_container_count: usize, at_container_count: usize,
/// JSON or YAML file from which the custom layout definition should be loaded /// JSON or YAML file from which the custom layout definition should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -773,7 +770,6 @@ struct Start {
ffm: bool, ffm: bool,
/// Path to a static configuration JSON file /// Path to a static configuration JSON file
#[clap(short, long)] #[clap(short, long)]
#[clap(value_parser = replace_env_in_path)]
config: Option<PathBuf>, config: Option<PathBuf>,
/// Wait for 'komorebic complete-configuration' to be sent before processing events /// Wait for 'komorebic complete-configuration' to be sent before processing events
#[clap(short, long)] #[clap(short, long)]
@@ -836,21 +832,18 @@ struct Kill {
#[derive(Parser)] #[derive(Parser)]
struct SaveResize { struct SaveResize {
/// File to which the resize layout dimensions should be saved /// File to which the resize layout dimensions should be saved
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
#[derive(Parser)] #[derive(Parser)]
struct LoadResize { struct LoadResize {
/// File from which the resize layout dimensions should be loaded /// File from which the resize layout dimensions should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
#[derive(Parser)] #[derive(Parser)]
struct LoadCustomLayout { struct LoadCustomLayout {
/// JSON or YAML file from which the custom layout definition should be loaded /// JSON or YAML file from which the custom layout definition should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -881,34 +874,28 @@ struct UnsubscribePipe {
#[derive(Parser)] #[derive(Parser)]
struct AhkAppSpecificConfiguration { struct AhkAppSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded /// YAML file from which the application-specific configurations should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
/// Optional YAML file of overrides to apply over the first file /// Optional YAML file of overrides to apply over the first file
#[clap(value_parser = replace_env_in_path)]
override_path: Option<PathBuf>, override_path: Option<PathBuf>,
} }
#[derive(Parser)] #[derive(Parser)]
struct PwshAppSpecificConfiguration { struct PwshAppSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded /// YAML file from which the application-specific configurations should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
/// Optional YAML file of overrides to apply over the first file /// Optional YAML file of overrides to apply over the first file
#[clap(value_parser = replace_env_in_path)]
override_path: Option<PathBuf>, override_path: Option<PathBuf>,
} }
#[derive(Parser)] #[derive(Parser)]
struct FormatAppSpecificConfiguration { struct FormatAppSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded /// YAML file from which the application-specific configurations should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
#[derive(Parser)] #[derive(Parser)]
struct ConvertAppSpecificConfiguration { struct ConvertAppSpecificConfiguration {
/// YAML file from which the application-specific configurations should be loaded /// YAML file from which the application-specific configurations should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -922,7 +909,6 @@ struct AltFocusHack {
struct EnableAutostart { struct EnableAutostart {
/// Path to a static configuration JSON file /// Path to a static configuration JSON file
#[clap(action, short, long)] #[clap(action, short, long)]
#[clap(value_parser = replace_env_in_path)]
config: Option<PathBuf>, config: Option<PathBuf>,
/// Enable komorebi's custom focus-follows-mouse implementation /// Enable komorebi's custom focus-follows-mouse implementation
#[clap(hide = true)] #[clap(hide = true)]
@@ -946,14 +932,12 @@ struct EnableAutostart {
struct Check { struct Check {
/// Path to a static configuration JSON file /// Path to a static configuration JSON file
#[clap(action, short, long)] #[clap(action, short, long)]
#[clap(value_parser = replace_env_in_path)]
komorebi_config: Option<PathBuf>, komorebi_config: Option<PathBuf>,
} }
#[derive(Parser)] #[derive(Parser)]
struct ReplaceConfiguration { struct ReplaceConfiguration {
/// Static configuration JSON file from which the configuration should be loaded /// Static configuration JSON file from which the configuration should be loaded
#[clap(value_parser = replace_env_in_path)]
path: PathBuf, path: PathBuf,
} }
@@ -994,9 +978,6 @@ enum SubCommand {
/// Show the path to whkdrc /// Show the path to whkdrc
#[clap(alias = "whkd")] #[clap(alias = "whkd")]
Whkdrc, Whkdrc,
/// Show the path to komorebi's data directory in %LOCALAPPDATA%
#[clap(alias = "datadir")]
DataDirectory,
/// Show a JSON representation of the current window manager state /// Show a JSON representation of the current window manager state
State, State,
/// Show a JSON representation of the current global state /// Show a JSON representation of the current global state
@@ -1339,12 +1320,6 @@ enum SubCommand {
/// Set the operation behaviour when the focused window is not managed /// Set the operation behaviour when the focused window is not managed
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour), UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour),
/// Add a rule to float the foreground window for the rest of this session
SessionFloatRule,
/// Show all session float rules
SessionFloatRules,
/// Clear all session float rules
ClearSessionFloatRules,
/// Add a rule to ignore the specified application /// Add a rule to ignore the specified application
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
#[clap(alias = "float-rule")] #[clap(alias = "float-rule")]
@@ -1693,7 +1668,7 @@ fn main() -> Result<()> {
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n"); println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
} }
Some(AppSpecificConfigurationPath::Single(path)) => { Some(AppSpecificConfigurationPath::Single(path)) => {
if !path.exists() { if !Path::exists(Path::new(&path)) {
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display()); println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
} }
} }
@@ -1706,7 +1681,8 @@ fn main() -> Result<()> {
// errors // errors
let _ = serde_json::from_str::<StaticConfig>(&config_source)?; let _ = serde_json::from_str::<StaticConfig>(&config_source)?;
let raw = std::fs::read_to_string(static_config)?; let path = resolve_home_path(static_config)?;
let raw = std::fs::read_to_string(path)?;
StaticConfig::aliases(&raw); StaticConfig::aliases(&raw);
StaticConfig::deprecated(&raw); StaticConfig::deprecated(&raw);
StaticConfig::end_of_life(&raw); StaticConfig::end_of_life(&raw);
@@ -1778,12 +1754,6 @@ fn main() -> Result<()> {
println!("{}", whkdrc.display()); println!("{}", whkdrc.display());
} }
} }
SubCommand::DataDirectory => {
let dir = &*DATA_DIR;
if dir.exists() {
println!("{}", dir.display());
}
}
SubCommand::Log => { SubCommand::Log => {
let timestamp = Utc::now().format("%Y-%m-%d").to_string(); let timestamp = Utc::now().format("%Y-%m-%d").to_string();
let color_log = std::env::temp_dir().join(format!("komorebi.log.{timestamp}")); let color_log = std::env::temp_dir().join(format!("komorebi.log.{timestamp}"));
@@ -2009,13 +1979,13 @@ fn main() -> Result<()> {
send_message(&SocketMessage::WorkspaceLayoutCustom( send_message(&SocketMessage::WorkspaceLayoutCustom(
arg.monitor, arg.monitor,
arg.workspace, arg.workspace,
arg.path, resolve_home_path(arg.path)?,
))?; ))?;
} }
SubCommand::NamedWorkspaceCustomLayout(arg) => { SubCommand::NamedWorkspaceCustomLayout(arg) => {
send_message(&SocketMessage::NamedWorkspaceLayoutCustom( send_message(&SocketMessage::NamedWorkspaceLayoutCustom(
arg.workspace, arg.workspace,
arg.path, resolve_home_path(arg.path)?,
))?; ))?;
} }
SubCommand::WorkspaceLayoutRule(arg) => { SubCommand::WorkspaceLayoutRule(arg) => {
@@ -2038,14 +2008,14 @@ fn main() -> Result<()> {
arg.monitor, arg.monitor,
arg.workspace, arg.workspace,
arg.at_container_count, arg.at_container_count,
arg.path, resolve_home_path(arg.path)?,
))?; ))?;
} }
SubCommand::NamedWorkspaceCustomLayoutRule(arg) => { SubCommand::NamedWorkspaceCustomLayoutRule(arg) => {
send_message(&SocketMessage::NamedWorkspaceLayoutCustomRule( send_message(&SocketMessage::NamedWorkspaceLayoutCustomRule(
arg.workspace, arg.workspace,
arg.at_container_count, arg.at_container_count,
arg.path, resolve_home_path(arg.path)?,
))?; ))?;
} }
SubCommand::ClearWorkspaceLayoutRules(arg) => { SubCommand::ClearWorkspaceLayoutRules(arg) => {
@@ -2118,12 +2088,13 @@ fn main() -> Result<()> {
let mut flags = vec![]; let mut flags = vec![];
if let Some(config) = &arg.config { if let Some(config) = &arg.config {
if !config.is_file() { let path = resolve_home_path(config)?;
bail!("could not find file: {}", config.display()); if !path.is_file() {
bail!("could not find file: {}", path.display());
} }
let config = dunce::simplified(config); // we don't need to replace UNC prefix here as `resolve_home_path` already did
flags.push(format!("'--config=\"{}\"'", config.display())); flags.push(format!("'--config=\"{}\"'", path.display()));
} }
if arg.ffm { if arg.ffm {
@@ -2142,12 +2113,17 @@ fn main() -> Result<()> {
flags.push("'--clean-state'".to_string()); flags.push("'--clean-state'".to_string());
} }
let exec = exec.unwrap_or("komorebi.exe");
let script = if flags.is_empty() { let script = if flags.is_empty() {
format!("Start-Process '{exec}' -WindowStyle hidden",) format!(
"Start-Process '{}' -WindowStyle hidden",
exec.unwrap_or("komorebi.exe")
)
} else { } else {
let argument_list = flags.join(","); let argument_list = flags.join(",");
format!("Start-Process '{exec}' -ArgumentList {argument_list} -WindowStyle hidden",) format!(
"Start-Process '{}' -ArgumentList {argument_list} -WindowStyle hidden",
exec.unwrap_or("komorebi.exe")
)
}; };
let mut system = sysinfo::System::new_all(); let mut system = sysinfo::System::new_all();
@@ -2190,8 +2166,9 @@ fn main() -> Result<()> {
if !running { if !running {
println!("\nRunning komorebi.exe directly for detailed error output\n"); println!("\nRunning komorebi.exe directly for detailed error output\n");
if let Some(config) = arg.config { if let Some(config) = arg.config {
let path = resolve_home_path(config)?;
if let Ok(output) = Command::new("komorebi.exe") if let Ok(output) = Command::new("komorebi.exe")
.arg(format!("'--config=\"{}\"'", config.display())) .arg(format!("'--config=\"{}\"'", path.display()))
.output() .output()
{ {
println!("{}", String::from_utf8(output.stderr)?); println!("{}", String::from_utf8(output.stderr)?);
@@ -2241,20 +2218,25 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue))
} }
} }
let static_config = arg.config.clone().or_else(|| { let static_config = arg.config.clone().map_or_else(
let komorebi_json = HOME_DIR.join("komorebi.json"); || {
komorebi_json.is_file().then_some(komorebi_json) let komorebi_json = HOME_DIR.join("komorebi.json");
}); if komorebi_json.is_file() {
Option::from(komorebi_json)
} else {
None
}
},
Option::from,
);
if arg.bar { if arg.bar {
if let Some(config) = &static_config { if let Some(config) = &static_config {
let mut config = StaticConfig::read(config)?; let mut config = StaticConfig::read(config)?;
if let Some(display_bar_configurations) = &mut config.bar_configurations { if let Some(display_bar_configurations) = &mut config.bar_configurations {
for config_file_path in &mut *display_bar_configurations { for config_file_path in &mut *display_bar_configurations {
let script = format!( let script = r#"Start-Process "komorebi-bar" '"--config" "CONFIGFILE"' -WindowStyle hidden"#
r#"Start-Process "komorebi-bar" '"--config" "{}"' -WindowStyle hidden"#, .replace("CONFIGFILE", &config_file_path.to_string_lossy());
config_file_path.to_string_lossy()
);
match powershell_script::run(&script) { match powershell_script::run(&script) {
Ok(_) => { Ok(_) => {
@@ -2316,13 +2298,21 @@ if (!(Get-Process masir -ErrorAction SilentlyContinue))
println!("\n# Documentation"); println!("\n# Documentation");
println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands"); println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands");
let bar_config = arg.config.or_else(|| { let bar_config = arg.config.map_or_else(
let bar_json = HOME_DIR.join("komorebi.bar.json"); || {
bar_json.is_file().then_some(bar_json) let bar_json = HOME_DIR.join("komorebi.bar.json");
}); if bar_json.is_file() {
Option::from(bar_json)
} else {
None
}
},
Option::from,
);
if let Some(config) = &static_config { if let Some(config) = &static_config {
let raw = std::fs::read_to_string(config)?; let path = resolve_home_path(config)?;
let raw = std::fs::read_to_string(path)?;
StaticConfig::aliases(&raw); StaticConfig::aliases(&raw);
StaticConfig::deprecated(&raw); StaticConfig::deprecated(&raw);
StaticConfig::end_of_life(&raw); StaticConfig::end_of_life(&raw);
@@ -2536,15 +2526,6 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
} }
} }
} }
SubCommand::SessionFloatRule => {
send_message(&SocketMessage::SessionFloatRule)?;
}
SubCommand::SessionFloatRules => {
print_query(&SocketMessage::SessionFloatRules);
}
SubCommand::ClearSessionFloatRules => {
send_message(&SocketMessage::ClearSessionFloatRules)?;
}
SubCommand::IgnoreRule(arg) => { SubCommand::IgnoreRule(arg) => {
send_message(&SocketMessage::IgnoreRule(arg.identifier, arg.id))?; send_message(&SocketMessage::IgnoreRule(arg.identifier, arg.id))?;
} }
@@ -2624,7 +2605,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
send_message(&SocketMessage::CycleLayout(arg.cycle_direction))?; send_message(&SocketMessage::CycleLayout(arg.cycle_direction))?;
} }
SubCommand::LoadCustomLayout(arg) => { SubCommand::LoadCustomLayout(arg) => {
send_message(&SocketMessage::ChangeLayoutCustom(arg.path))?; send_message(&SocketMessage::ChangeLayoutCustom(resolve_home_path(
arg.path,
)?))?;
} }
SubCommand::FlipLayout(arg) => { SubCommand::FlipLayout(arg) => {
send_message(&SocketMessage::FlipLayout(arg.axis))?; send_message(&SocketMessage::FlipLayout(arg.axis))?;
@@ -2801,10 +2784,10 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
send_message(&SocketMessage::QuickLoad)?; send_message(&SocketMessage::QuickLoad)?;
} }
SubCommand::SaveResize(arg) => { SubCommand::SaveResize(arg) => {
send_message(&SocketMessage::Save(arg.path))?; send_message(&SocketMessage::Save(resolve_home_path(arg.path)?))?;
} }
SubCommand::LoadResize(arg) => { SubCommand::LoadResize(arg) => {
send_message(&SocketMessage::Load(arg.path))?; send_message(&SocketMessage::Load(resolve_home_path(arg.path)?))?;
} }
SubCommand::SubscribeSocket(arg) => { SubCommand::SubscribeSocket(arg) => {
send_message(&SocketMessage::AddSubscriberSocket(arg.socket))?; send_message(&SocketMessage::AddSubscriberSocket(arg.socket))?;
@@ -2916,9 +2899,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
))?; ))?;
} }
SubCommand::AhkAppSpecificConfiguration(arg) => { SubCommand::AhkAppSpecificConfiguration(arg) => {
let content = std::fs::read_to_string(arg.path)?; let content = std::fs::read_to_string(resolve_home_path(arg.path)?)?;
let lines = if let Some(override_path) = arg.override_path { let lines = if let Some(override_path) = arg.override_path {
let override_content = std::fs::read_to_string(override_path)?; let override_content = std::fs::read_to_string(resolve_home_path(override_path)?)?;
ApplicationConfigurationGenerator::generate_ahk( ApplicationConfigurationGenerator::generate_ahk(
&content, &content,
@@ -2943,9 +2926,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
); );
} }
SubCommand::PwshAppSpecificConfiguration(arg) => { SubCommand::PwshAppSpecificConfiguration(arg) => {
let content = std::fs::read_to_string(arg.path)?; let content = std::fs::read_to_string(resolve_home_path(arg.path)?)?;
let lines = if let Some(override_path) = arg.override_path { let lines = if let Some(override_path) = arg.override_path {
let override_content = std::fs::read_to_string(override_path)?; let override_content = std::fs::read_to_string(resolve_home_path(override_path)?)?;
ApplicationConfigurationGenerator::generate_pwsh( ApplicationConfigurationGenerator::generate_pwsh(
&content, &content,
@@ -2970,21 +2953,23 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
); );
} }
SubCommand::ConvertAppSpecificConfiguration(arg) => { SubCommand::ConvertAppSpecificConfiguration(arg) => {
let content = std::fs::read_to_string(arg.path)?; let file_path = resolve_home_path(arg.path)?;
let content = std::fs::read_to_string(&file_path)?;
let mut asc = ApplicationConfigurationGenerator::load(&content)?; let mut asc = ApplicationConfigurationGenerator::load(&content)?;
asc.sort_by(|a, b| a.name.cmp(&b.name)); asc.sort_by(|a, b| a.name.cmp(&b.name));
let v2 = ApplicationSpecificConfiguration::from(asc); let v2 = ApplicationSpecificConfiguration::from(asc);
println!("{}", serde_json::to_string_pretty(&v2)?); println!("{}", serde_json::to_string_pretty(&v2)?);
} }
SubCommand::FormatAppSpecificConfiguration(arg) => { SubCommand::FormatAppSpecificConfiguration(arg) => {
let content = std::fs::read_to_string(&arg.path)?; let file_path = resolve_home_path(arg.path)?;
let content = std::fs::read_to_string(&file_path)?;
let formatted_content = ApplicationConfigurationGenerator::format(&content)?; let formatted_content = ApplicationConfigurationGenerator::format(&content)?;
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.write(true) .write(true)
.create(true) .create(true)
.truncate(true) .truncate(true)
.open(arg.path)?; .open(file_path)?;
file.write_all(formatted_content.as_bytes())?; file.write_all(formatted_content.as_bytes())?;
+31 -38
View File
@@ -49,40 +49,37 @@ plugins:
nav: nav:
- Komorebi: - Komorebi:
- About: - index.md
- index.md - Design: design.md
- design.md - Getting started:
- Getting started: - Installation: installation.md
- Installation: installation.md - Example configurations: example-configurations.md
- Example configurations: example-configurations.md - Troubleshooting: troubleshooting.md
- Troubleshooting: troubleshooting.md - Usage:
- Usage: - usage/focusing-windows.md
- usage/focusing-windows.md - usage/moving-windows.md
- usage/moving-windows.md - usage/stacking-windows.md
- usage/stacking-windows.md - usage/focusing-workspaces.md
- usage/focusing-workspaces.md - usage/moving-windows-across-workspaces.md
- usage/moving-windows-across-workspaces.md - Common workflows:
- Komorebi Configuration: - common-workflows/komorebi-config-home.md
- Schema: https://komorebi.lgug2z.com/schema - common-workflows/autostart.md
- Komorebi Bar Configuration: - common-workflows/animations.md
- Schema: https://komorebi-bar.lgug2z.com/schema - common-workflows/autohotkey.md
- Common workflows: - common-workflows/borders.md
- common-workflows/komorebi-config-home.md - common-workflows/stackbar.md
- common-workflows/autostart.md - common-workflows/remove-gaps.md
- common-workflows/animations.md - common-workflows/ignore-windows.md
- common-workflows/autohotkey.md - common-workflows/force-manage-windows.md
- common-workflows/borders.md - common-workflows/floating-applications.md
- common-workflows/stackbar.md - common-workflows/tray-and-multi-window-applications.md
- common-workflows/remove-gaps.md - common-workflows/mouse-follows-focus.md
- common-workflows/ignore-windows.md - common-workflows/dynamic-layout-switching.md
- common-workflows/force-manage-windows.md - common-workflows/set-display-index.md
- common-workflows/floating-applications.md - common-workflows/multiple-bar-instances.md
- common-workflows/tray-and-multi-window-applications.md - common-workflows/multi-monitor-setup.md
- common-workflows/mouse-follows-focus.md - Configuration reference: https://komorebi.lgug2z.com/schema
- common-workflows/dynamic-layout-switching.md - Bar reference: https://komorebi-bar.lgug2z.com/schema
- common-workflows/set-display-index.md
- common-workflows/multiple-bar-instances.md
- common-workflows/multi-monitor-setup.md
- CLI reference: - CLI reference:
- cli/quickstart.md - cli/quickstart.md
- cli/start.md - cli/start.md
@@ -92,7 +89,6 @@ nav:
- cli/configuration.md - cli/configuration.md
- cli/bar-configuration.md - cli/bar-configuration.md
- cli/whkdrc.md - cli/whkdrc.md
- cli/data-directory.md
- cli/state.md - cli/state.md
- cli/global-state.md - cli/global-state.md
- cli/gui.md - cli/gui.md
@@ -209,9 +205,6 @@ nav:
- cli/cross-monitor-move-behaviour.md - cli/cross-monitor-move-behaviour.md
- cli/toggle-cross-monitor-move-behaviour.md - cli/toggle-cross-monitor-move-behaviour.md
- cli/unmanaged-window-operation-behaviour.md - cli/unmanaged-window-operation-behaviour.md
- cli/session-float-rule.md
- cli/session-float-rules.md
- cli/clear-session-float-rules.md
- cli/ignore-rule.md - cli/ignore-rule.md
- cli/manage-rule.md - cli/manage-rule.md
- cli/initial-workspace-rule.md - cli/initial-workspace-rule.md
+54 -1220
View File
File diff suppressed because it is too large Load Diff
+1 -1410
View File
File diff suppressed because it is too large Load Diff