mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-02-13 08:47:41 +01:00
Compare commits
15 Commits
v0.1.38
...
feature/sc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a02b4e28c | ||
|
|
2ac1929117 | ||
|
|
e33a5f28f0 | ||
|
|
15d069f2bf | ||
|
|
3e9947c2e2 | ||
|
|
1c23439f95 | ||
|
|
6eb2905e00 | ||
|
|
52a745d0a3 | ||
|
|
80877cc449 | ||
|
|
160cb7202d | ||
|
|
8d085df1ba | ||
|
|
5d48a5c5b4 | ||
|
|
539aeec965 | ||
|
|
bcfb058bc3 | ||
|
|
e07b464b0d |
1
.github/workflows/windows.yaml
vendored
1
.github/workflows/windows.yaml
vendored
@@ -47,6 +47,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: rustup toolchain install stable --profile minimal
|
||||
- run: rustup component add --toolchain stable-x86_64-pc-windows-msvc clippy
|
||||
- run: rustup toolchain install nightly --allow-downgrade -c rustfmt
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
|
||||
1223
Cargo.lock
generated
1223
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
18
Cargo.toml
@@ -19,8 +19,8 @@ chrono = "0.4"
|
||||
crossbeam-channel = "0.5"
|
||||
crossbeam-utils = "0.8"
|
||||
color-eyre = "0.6"
|
||||
eframe = "0.31"
|
||||
egui_extras = "0.31"
|
||||
eframe = "0.32"
|
||||
egui_extras = "0.32"
|
||||
dirs = "6"
|
||||
dunce = "1"
|
||||
hotwatch = "0.5"
|
||||
@@ -35,24 +35,24 @@ tracing-appender = "0.2"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
parking_lot = "0.12"
|
||||
paste = "1"
|
||||
sysinfo = "0.34"
|
||||
sysinfo = "0.37"
|
||||
uds_windows = "1"
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "a28c6559a9de2f92c142a714947a9b081776caca" }
|
||||
windows-numerics = { version = "0.2" }
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "8c42d8db257d30fe95bc98c2e5cd8f75da861021" }
|
||||
windows-numerics = { version = "0.3" }
|
||||
windows-implement = { version = "0.60" }
|
||||
windows-interface = { version = "0.59" }
|
||||
windows-core = { version = "0.61" }
|
||||
windows-core = { version = "0.62" }
|
||||
shadow-rs = "1"
|
||||
which = "7"
|
||||
which = "8"
|
||||
|
||||
[workspace.dependencies.windows]
|
||||
version = "0.61"
|
||||
version = "0.62"
|
||||
features = [
|
||||
"Foundation_Numerics",
|
||||
"Win32_Devices",
|
||||
"Win32_Devices_Display",
|
||||
"Win32_System_Com",
|
||||
"Win32_UI_Shell_Common", # for IObjectArray
|
||||
"Win32_UI_Shell_Common", # for IObjectArray
|
||||
"Win32_Foundation",
|
||||
"Win32_Globalization",
|
||||
"Win32_Graphics_Dwm",
|
||||
|
||||
@@ -107,10 +107,10 @@ unknown-git = "deny"
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
allow-git = [
|
||||
"https://github.com/LGUG2Z/base16-egui-themes",
|
||||
"https://github.com/LGUG2Z/catppuccin-egui",
|
||||
"https://github.com/LGUG2Z/windows-icons",
|
||||
"https://github.com/LGUG2Z/win32-display-data",
|
||||
"https://github.com/LGUG2Z/flavours",
|
||||
"https://github.com/LGUG2Z/base16_color_scheme",
|
||||
"https://github.com/LGUG2Z/whkd",
|
||||
# "https://github.com/LGUG2Z/catppuccin-egui",
|
||||
]
|
||||
|
||||
@@ -5,34 +5,34 @@
|
||||
[
|
||||
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"adler2 2.0.1 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=8c42d8db257d30fe95bc98c2e5cd8f75da861021"
|
||||
]
|
||||
],
|
||||
[
|
||||
"Apache-2.0",
|
||||
[
|
||||
"ab_glyph 0.2.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ab_glyph 0.2.32 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ab_glyph_rasterizer 0.1.10 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_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 0.19.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit_consumer 0.28.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit_windows 0.27.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit_winit 0.27.0 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.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ahash 0.8.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstream 0.6.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle 1.0.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstream 0.6.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle 1.0.13 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-parse 0.2.7 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-query 1.1.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-wincon 3.0.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anyhow 1.0.99 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anyhow 1.0.100 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"approx 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"arboard 3.6.1 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",
|
||||
"autocfg 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"backtrace 0.3.75 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"backtrace 0.3.76 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",
|
||||
@@ -41,15 +41,15 @@
|
||||
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bitflags 2.9.4 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.23.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"cc 1.2.36 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck 1.24.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"cc 1.2.40 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.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"chrono 0.4.42 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"chrono-tz 0.10.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_builder 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap 4.5.48 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_builder 4.5.48 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_derive 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_lex 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"color-eyre 0.6.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -63,7 +63,7 @@
|
||||
"ctrlc 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"cursor-icon 1.2.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.5.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"deranged 0.5.4 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",
|
||||
@@ -74,28 +74,28 @@
|
||||
"dpi 0.1.2 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.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui 0.31.1 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_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ecolor 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"eframe 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui-phosphor 0.10.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui-winit 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_extras 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_glow 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"either 1.15.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.32.3 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-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",
|
||||
"epaint 0.31.1 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 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"epaint_default_fonts 0.32.3 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",
|
||||
"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",
|
||||
"filetime 0.2.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"find-msvc-tools 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"flate2 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"find-msvc-tools 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"flate2 1.1.4 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.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"futures 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -123,6 +123,7 @@
|
||||
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.14.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.15.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.16.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",
|
||||
@@ -130,17 +131,16 @@
|
||||
"http 1.3.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",
|
||||
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"iana-time-zone 0.1.64 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.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"idna_adapter 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"image 0.25.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"image-webp 0.2.4 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.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"imgref 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indenter 0.3.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 2.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"iri-string 0.7.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -152,12 +152,12 @@
|
||||
"jpeg-decoder 0.1.22 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",
|
||||
"libc 0.2.175 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libc 0.2.176 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libgit2-sys 0.18.2+1.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libz-sys 1.1.22 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.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"lock_api 0.4.13 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"lock_api 0.4.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"log 0.4.28 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",
|
||||
@@ -168,8 +168,8 @@
|
||||
"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.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"miow 0.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"moxcms 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"miow 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"moxcms 0.7.6 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",
|
||||
"nohash-hasher 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -189,8 +189,8 @@
|
||||
"owned_ttf_parser 0.25.1 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.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot_core 0.9.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot 0.12.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot_core 0.9.12 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.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"pin-project-lite 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -200,16 +200,14 @@
|
||||
"png 0.18.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",
|
||||
"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-macro2 1.0.101 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"profiling 1.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"profiling-procmacros 1.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"psm 0.1.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"pxfm 0.1.23 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"psm 0.1.27 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"pxfm 0.1.24 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",
|
||||
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"quote 1.0.41 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.9.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -223,8 +221,8 @@
|
||||
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rayon 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rayon-core 1.13.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex 1.11.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-automata 0.4.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex 1.11.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-automata 0.4.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-syntax 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"reqwest 0.12.23 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -232,18 +230,19 @@
|
||||
"rustls-pki-types 1.12.0 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",
|
||||
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde 1.0.228 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_core 1.0.228 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_derive 1.0.228 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.143 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_json 1.0.145 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_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with 3.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with_macros 3.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with 3.15.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with_macros 3.15.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",
|
||||
"shadow-rs 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"shadow-rs 1.4.0 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",
|
||||
@@ -253,7 +252,7 @@
|
||||
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"socket2 0.6.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",
|
||||
"stacker 0.1.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"stacker 0.1.22 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-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -261,27 +260,27 @@
|
||||
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"syn 2.0.106 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.21.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tempfile 3.23.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"terminal_size 0.4.3 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.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thiserror 2.0.17 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.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thiserror-impl 2.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thread_local 1.1.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time 0.3.43 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time 0.3.44 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time-core 0.1.6 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",
|
||||
"typenum 1.18.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"typenum 1.19.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tzdb 0.7.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tzdb_data 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-linebreak 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-segmentation 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.1.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-xid 0.2.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"uom 0.37.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"url 2.5.7 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -297,55 +296,63 @@
|
||||
"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.61.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows 0.62.2 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-collections 0.3.2 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.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-core 0.61.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-core 0.62.2 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.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-future 0.3.2 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.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-implement 0.60.2 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.59.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-interface 0.59.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.2.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-numerics 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-registry 0.5.3 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.3.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-result 0.4.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.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-strings 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-strings 0.5.1 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.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.60.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.61.2 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.53.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-targets 0.53.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-threading 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-threading 0.2.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_aarch64_msvc 0.53.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_i686_msvc 0.53.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_x86_64_msvc 0.53.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"winit 0.30.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"wmi 0.15.2 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.8.27 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zeroize 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zeroize 1.8.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-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zune-jpeg 0.4.21 registry+https://github.com/rust-lang/crates.io-index"
|
||||
@@ -378,8 +385,8 @@
|
||||
"encoding_rs 0.8.35 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"exr 1.73.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"lebe 0.5.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"moxcms 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"pxfm 0.1.23 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"moxcms 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"pxfm 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ravif 0.11.20 registry+https://github.com/rust-lang/crates.io-index"
|
||||
]
|
||||
],
|
||||
@@ -396,7 +403,7 @@
|
||||
[
|
||||
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"file-id 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"imgref 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"notify 6.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"notify-debouncer-full 0.1.0 registry+https://github.com/rust-lang/crates.io-index"
|
||||
]
|
||||
@@ -405,34 +412,34 @@
|
||||
"ISC",
|
||||
[
|
||||
"is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libloading 0.8.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libloading 0.8.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"starship-battery 0.10.2 registry+https://github.com/rust-lang/crates.io-index"
|
||||
]
|
||||
],
|
||||
[
|
||||
"MIT",
|
||||
[
|
||||
"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_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit 0.19.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit_consumer 0.28.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"accesskit_windows 0.27.0 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.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ahash 0.8.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"aligned-vec 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstream 0.6.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle 1.0.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstream 0.6.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle 1.0.13 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-parse 0.2.7 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-query 1.1.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anstyle-wincon 3.0.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anyhow 1.0.99 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"anyhow 1.0.100 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"arboard 3.6.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",
|
||||
"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",
|
||||
"autocfg 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"backtrace 0.3.75 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"backtrace 0.3.76 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",
|
||||
@@ -444,23 +451,23 @@
|
||||
"brotli 8.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"brotli-decompressor 5.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"built 0.7.7 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck 1.23.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck 1.24.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.2 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",
|
||||
"bytes 1.10.1 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",
|
||||
"cc 1.2.36 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"catppuccin-egui 5.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"cc 1.2.40 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.3 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.42 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"chrono-tz 0.10.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"chumsky 0.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_builder 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap 4.5.48 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_builder 4.5.48 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_derive 4.5.47 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"clap_lex 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"color-eyre 0.6.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -475,11 +482,11 @@
|
||||
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ctrlc 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"cursor-icon 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"darling 0.20.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",
|
||||
"darling 0.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"darling_core 0.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"darling_macro 0.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"deranged 0.5.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"deranged 0.5.4 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",
|
||||
@@ -489,21 +496,21 @@
|
||||
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"dpi 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"dyn-clone 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui 0.31.1 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_extras 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_glow 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ecolor 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"eframe 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui-phosphor 0.10.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui-winit 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_extras 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"egui_glow 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"either 1.15.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.32.3 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-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",
|
||||
"epaint 0.31.1 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 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"epaint_default_fonts 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"equator 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"equator-macro 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"equivalent 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -513,8 +520,8 @@
|
||||
"fax_derive 0.2.0 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.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"find-msvc-tools 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"flate2 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"find-msvc-tools 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"flate2 1.1.4 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",
|
||||
"font-loader 0.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -532,7 +539,6 @@
|
||||
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"getrandom 0.2.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"getrandom 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"getset 0.1.6 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.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"git2 0.20.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -544,6 +550,7 @@
|
||||
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.14.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.15.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hashbrown 0.16.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",
|
||||
@@ -554,18 +561,17 @@
|
||||
"httparse 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hyper 1.7.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.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"hyper-util 0.1.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"iana-time-zone 0.1.64 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.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"idna_adapter 1.2.1 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.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"image-webp 0.2.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"immutable-chunkmap 2.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indenter 0.3.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"indexmap 2.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"ipnet 2.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"iri-string 0.7.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"is_debug 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -576,12 +582,12 @@
|
||||
"jobserver 0.1.34 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"jpeg-decoder 0.1.22 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.175 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libc 0.2.176 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libgit2-sys 0.18.2+1.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"libz-sys 1.1.22 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.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"lock_api 0.4.13 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"lock_api 0.4.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"log 0.4.28 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",
|
||||
@@ -589,7 +595,7 @@
|
||||
"loop9 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"matchers 0.2.0 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.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"memchr 2.7.6 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_guess2 2.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -598,7 +604,7 @@
|
||||
"miniz_oxide 0.4.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"miniz_oxide 0.8.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"mio 1.0.4 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.1 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",
|
||||
"net2 0.2.39 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -622,11 +628,11 @@
|
||||
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"once_cell_polyfill 1.70.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"os_info 3.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"owo-colors 4.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"owo-colors 4.2.3 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.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot_core 0.9.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot 0.12.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"parking_lot_core 0.9.12 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.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"phf 0.11.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -645,15 +651,13 @@
|
||||
"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",
|
||||
"ppv-lite86 0.2.21 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-macro2 1.0.101 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"profiling 1.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"profiling-procmacros 1.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"psm 0.1.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"psm 0.1.27 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",
|
||||
"quote 1.0.40 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"quote 1.0.41 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.9.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -668,8 +672,8 @@
|
||||
"raw-window-handle 0.6.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rayon 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rayon-core 1.13.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex 1.11.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-automata 0.4.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex 1.11.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-automata 0.4.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"regex-syntax 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"reqwest 0.12.23 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rgb 0.8.52 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -677,23 +681,24 @@
|
||||
"rustc-demangle 0.1.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"rustls-pki-types 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"same-file 1.0.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"schannel 0.1.27 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"schannel 0.1.28 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",
|
||||
"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",
|
||||
"serde 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_derive 1.0.219 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde 1.0.228 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_core 1.0.228 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_derive 1.0.228 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.143 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_json 1.0.145 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_variant 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with 3.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with_macros 3.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with 3.15.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"serde_with_macros 3.15.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",
|
||||
"shadow-rs 1.3.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"shadow-rs 1.4.0 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",
|
||||
@@ -707,7 +712,7 @@
|
||||
"smol_str 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"socket2 0.6.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",
|
||||
"stacker 0.1.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"stacker 0.1.22 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",
|
||||
"strum 0.27.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -716,18 +721,18 @@
|
||||
"syn 2.0.106 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"synstructure 0.13.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"sysinfo 0.34.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tempfile 3.21.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"sysinfo 0.37.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tempfile 3.23.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"terminal_size 0.4.3 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 2.0.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thiserror 2.0.17 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.16 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thiserror-impl 2.0.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"thread_local 1.1.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tiff 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tiff 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time 0.3.43 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time 0.3.44 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"time-core 0.1.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tokio 1.47.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",
|
||||
@@ -746,15 +751,15 @@
|
||||
"tracing-subscriber 0.3.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"try-lock 0.2.5 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.19.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tz-rs 0.7.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tzdb_data 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"uds_windows 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicase 2.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-segmentation 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.1.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-width 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-xid 0.2.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unsafe-libyaml 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"uom 0.37.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -768,59 +773,67 @@
|
||||
"web-time 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"webbrowser 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"weezl 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"which 7.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"which 8.0.0 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.11 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.60.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows 0.61.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows 0.62.2 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-collections 0.3.2 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.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-core 0.61.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-core 0.62.2 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.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-future 0.3.2 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-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.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-implement 0.60.2 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.59.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-interface 0.59.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-link 0.2.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-numerics 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-registry 0.5.3 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.3.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-result 0.4.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.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-strings 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-strings 0.5.1 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.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.60.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-sys 0.61.2 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.53.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-targets 0.53.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-threading 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows-threading 0.2.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_aarch64_msvc 0.53.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_i686_msvc 0.53.1 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.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"windows_x86_64_msvc 0.53.1 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",
|
||||
"winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -828,7 +841,7 @@
|
||||
"xml-rs 0.8.27 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.8.27 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zeroize 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zeroize 1.8.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-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"zune-jpeg 0.4.21 registry+https://github.com/rust-lang/crates.io-index"
|
||||
@@ -851,13 +864,13 @@
|
||||
[
|
||||
"OFL-1.1",
|
||||
[
|
||||
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index"
|
||||
"epaint_default_fonts 0.32.3 registry+https://github.com/rust-lang/crates.io-index"
|
||||
]
|
||||
],
|
||||
[
|
||||
"Ubuntu-font-1.0",
|
||||
[
|
||||
"epaint_default_fonts 0.31.1 registry+https://github.com/rust-lang/crates.io-index"
|
||||
"epaint_default_fonts 0.32.3 registry+https://github.com/rust-lang/crates.io-index"
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -873,7 +886,7 @@
|
||||
"litemap 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"potential_utf 0.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"tinystr 0.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"unicode-ident 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"writeable 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"yoke 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"yoke-derive 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
@@ -890,7 +903,7 @@
|
||||
"aho-corasick 1.1.3 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",
|
||||
"memchr 2.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"memchr 2.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"same-file 1.0.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"walkdir 2.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"winapi-util 0.1.11 registry+https://github.com/rust-lang/crates.io-index"
|
||||
@@ -900,9 +913,9 @@
|
||||
"Zlib",
|
||||
[
|
||||
"adler32 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck 1.23.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck 1.24.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"bytemuck_derive 1.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"const_format 0.2.35 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.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||
"foldhash 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.38/schema.bar.json",
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.39/schema.bar.json",
|
||||
"monitor": 0,
|
||||
"font_family": "JetBrains Mono",
|
||||
"theme": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.38/schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.39/schema.json",
|
||||
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
|
||||
"window_hiding_behaviour": "Cloak",
|
||||
"cross_monitor_move_behaviour": "Insert",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "komorebi-bar"
|
||||
version = "0.1.38"
|
||||
edition = "2021"
|
||||
version = "0.1.39"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -17,7 +17,7 @@ crossbeam-channel = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
eframe = { workspace = true }
|
||||
egui-phosphor = "0.9"
|
||||
egui-phosphor = "0.10"
|
||||
font-loader = "0.11"
|
||||
hotwatch = { workspace = true }
|
||||
image = "0.25"
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
use crate::config::get_individual_spacing;
|
||||
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||
use crate::BAR_HEIGHT;
|
||||
use crate::DEFAULT_PADDING;
|
||||
use crate::KomorebiEvent;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_LEFT;
|
||||
use crate::MONITOR_RIGHT;
|
||||
use crate::MONITOR_TOP;
|
||||
use crate::config::KomobarConfig;
|
||||
use crate::config::KomobarTheme;
|
||||
use crate::config::MonitorConfigOrIndex;
|
||||
use crate::config::Position;
|
||||
use crate::config::PositionConfig;
|
||||
use crate::config::get_individual_spacing;
|
||||
use crate::process_hwnd;
|
||||
use crate::render::Color32Ext;
|
||||
use crate::render::Grouping;
|
||||
@@ -13,15 +22,7 @@ use crate::widgets::komorebi::Komorebi;
|
||||
use crate::widgets::komorebi::MonitorInfo;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use crate::widgets::widget::WidgetConfig;
|
||||
use crate::KomorebiEvent;
|
||||
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||
use crate::BAR_HEIGHT;
|
||||
use crate::DEFAULT_PADDING;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_LEFT;
|
||||
use crate::MONITOR_RIGHT;
|
||||
use crate::MONITOR_TOP;
|
||||
use color_eyre::eyre;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::TryRecvError;
|
||||
use eframe::egui::Align;
|
||||
@@ -52,16 +53,15 @@ use komorebi_client::NotificationEvent;
|
||||
use komorebi_client::PathExt;
|
||||
use komorebi_client::SocketMessage;
|
||||
use komorebi_client::VirtualDesktopNotification;
|
||||
use komorebi_themes::catppuccin_egui;
|
||||
use komorebi_themes::Base16Wrapper;
|
||||
use komorebi_themes::Catppuccin;
|
||||
use komorebi_themes::catppuccin_egui;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Error;
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Result;
|
||||
use std::io::Write;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
@@ -69,8 +69,8 @@ use std::process::ChildStdin;
|
||||
use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
|
||||
|
||||
@@ -78,7 +78,7 @@ lazy_static! {
|
||||
static ref SESSION_STDIN: Mutex<Option<ChildStdin>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
fn start_powershell() -> Result<()> {
|
||||
fn start_powershell() -> eyre::Result<()> {
|
||||
// found running session, do nothing
|
||||
if SESSION_STDIN.lock().as_mut().is_some() {
|
||||
tracing::debug!("PowerShell session already started");
|
||||
@@ -102,17 +102,17 @@ fn start_powershell() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_powershell() -> Result<()> {
|
||||
fn stop_powershell() -> eyre::Result<()> {
|
||||
tracing::debug!("Stopping PowerShell session");
|
||||
|
||||
if let Some(mut session_stdin) = SESSION_STDIN.lock().take() {
|
||||
if let Err(e) = session_stdin.write_all(b"exit\n") {
|
||||
tracing::error!(error = %e, "failed to write exit command to PowerShell stdin");
|
||||
return Err(e);
|
||||
return Err(e.into());
|
||||
}
|
||||
if let Err(e) = session_stdin.flush() {
|
||||
tracing::error!(error = %e, "failed to flush PowerShell stdin");
|
||||
return Err(e);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
tracing::debug!("PowerShell session stopped");
|
||||
@@ -123,25 +123,22 @@ fn stop_powershell() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exec_powershell(cmd: &str) -> Result<()> {
|
||||
pub fn exec_powershell(cmd: &str) -> eyre::Result<()> {
|
||||
if let Some(session_stdin) = SESSION_STDIN.lock().as_mut() {
|
||||
if let Err(e) = writeln!(session_stdin, "{cmd}") {
|
||||
tracing::error!(error = %e, cmd = cmd, "failed to write command to PowerShell stdin");
|
||||
return Err(e);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
if let Err(e) = session_stdin.flush() {
|
||||
tracing::error!(error = %e, "failed to flush PowerShell stdin");
|
||||
return Err(e);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(Error::new(
|
||||
ErrorKind::NotFound,
|
||||
"PowerShell session not started",
|
||||
))
|
||||
Err(Error::new(ErrorKind::NotFound, "PowerShell session not started").into())
|
||||
}
|
||||
|
||||
pub struct Komobar {
|
||||
@@ -322,16 +319,15 @@ pub fn apply_theme(
|
||||
// apply rounding to the widgets
|
||||
if let Some(Grouping::Bar(config) | Grouping::Alignment(config) | Grouping::Widget(config)) =
|
||||
&grouping
|
||||
&& let Some(rounding) = config.rounding
|
||||
{
|
||||
if let Some(rounding) = config.rounding {
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.widgets.noninteractive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.inactive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.hovered.corner_radius = rounding.into();
|
||||
style.visuals.widgets.active.corner_radius = rounding.into();
|
||||
style.visuals.widgets.open.corner_radius = rounding.into();
|
||||
});
|
||||
}
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.widgets.noninteractive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.inactive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.hovered.corner_radius = rounding.into();
|
||||
style.visuals.widgets.active.corner_radius = rounding.into();
|
||||
style.visuals.widgets.open.corner_radius = rounding.into();
|
||||
});
|
||||
}
|
||||
|
||||
// Update RenderConfig's background_color so that widgets will have the new color
|
||||
@@ -523,10 +519,14 @@ impl Komobar {
|
||||
}
|
||||
}
|
||||
} else if self.monitor_info.is_some() && !self.disabled {
|
||||
tracing::warn!("couldn't find the monitor index of this bar! Disabling the bar until the monitor connects...");
|
||||
tracing::warn!(
|
||||
"couldn't find the monitor index of this bar! Disabling the bar until the monitor connects..."
|
||||
);
|
||||
self.disabled = true;
|
||||
} else {
|
||||
tracing::warn!("couldn't find the monitor index of this bar, if the bar is starting up this is normal until it receives the first state from komorebi.");
|
||||
tracing::warn!(
|
||||
"couldn't find the monitor index of this bar, if the bar is starting up this is normal until it receives the first state from komorebi."
|
||||
);
|
||||
self.disabled = true;
|
||||
}
|
||||
|
||||
@@ -599,7 +599,9 @@ impl Komobar {
|
||||
end.x -= margin.left + margin.right;
|
||||
|
||||
if end.y == 0.0 {
|
||||
tracing::warn!("position.end.y is set to 0.0 which will make your bar invisible on a config reload - this is usually set to 50.0 by default")
|
||||
tracing::warn!(
|
||||
"position.end.y is set to 0.0 which will make your bar invisible on a config reload - this is usually set to 50.0 by default"
|
||||
)
|
||||
}
|
||||
|
||||
self.size_rect = komorebi_client::Rect {
|
||||
@@ -666,17 +668,16 @@ impl Komobar {
|
||||
| Grouping::Alignment(config)
|
||||
| Grouping::Widget(config),
|
||||
) = &bar_grouping
|
||||
&& let Some(rounding) = config.rounding
|
||||
{
|
||||
if let Some(rounding) = config.rounding {
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.widgets.noninteractive.corner_radius =
|
||||
rounding.into();
|
||||
style.visuals.widgets.inactive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.hovered.corner_radius = rounding.into();
|
||||
style.visuals.widgets.active.corner_radius = rounding.into();
|
||||
style.visuals.widgets.open.corner_radius = rounding.into();
|
||||
});
|
||||
}
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.widgets.noninteractive.corner_radius =
|
||||
rounding.into();
|
||||
style.visuals.widgets.inactive.corner_radius = rounding.into();
|
||||
style.visuals.widgets.hovered.corner_radius = rounding.into();
|
||||
style.visuals.widgets.active.corner_radius = rounding.into();
|
||||
style.visuals.widgets.open.corner_radius = rounding.into();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -937,9 +938,9 @@ impl eframe::App for Komobar {
|
||||
) {
|
||||
let monitor_index = self.monitor_index.expect("should have a monitor index");
|
||||
|
||||
let monitor_size = state.monitors.elements()[monitor_index].size();
|
||||
let monitor_size = state.monitors.elements()[monitor_index].size;
|
||||
|
||||
self.update_monitor_coordinates(monitor_size);
|
||||
self.update_monitor_coordinates(&monitor_size);
|
||||
|
||||
should_apply_config = true;
|
||||
}
|
||||
@@ -950,7 +951,7 @@ impl eframe::App for Komobar {
|
||||
|
||||
// Check if monitor coordinates/size has changed
|
||||
if let Some(monitor_index) = self.monitor_index {
|
||||
let monitor_size = state.monitors.elements()[monitor_index].size();
|
||||
let monitor_size = state.monitors.elements()[monitor_index].size;
|
||||
let top = MONITOR_TOP.load(Ordering::SeqCst);
|
||||
let left = MONITOR_LEFT.load(Ordering::SeqCst);
|
||||
let right = MONITOR_RIGHT.load(Ordering::SeqCst);
|
||||
@@ -960,13 +961,13 @@ impl eframe::App for Komobar {
|
||||
bottom: monitor_size.bottom,
|
||||
right,
|
||||
};
|
||||
if *monitor_size != rect {
|
||||
if monitor_size != rect {
|
||||
tracing::info!(
|
||||
"Monitor coordinates/size has changed, storing new coordinates: {:#?}",
|
||||
monitor_size
|
||||
);
|
||||
|
||||
self.update_monitor_coordinates(monitor_size);
|
||||
self.update_monitor_coordinates(&monitor_size);
|
||||
|
||||
should_apply_config = true;
|
||||
}
|
||||
@@ -1358,7 +1359,9 @@ fn handle_notification(
|
||||
"removed theme from updated komorebi.json and applied default theme"
|
||||
);
|
||||
} else {
|
||||
tracing::warn!("theme was removed from updated komorebi.json but there was no default theme to apply");
|
||||
tracing::warn!(
|
||||
"theme was removed from updated komorebi.json but there was no default theme to apply"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::DEFAULT_PADDING;
|
||||
use crate::bar::exec_powershell;
|
||||
use crate::render::Grouping;
|
||||
use crate::widgets::widget::WidgetConfig;
|
||||
use crate::DEFAULT_PADDING;
|
||||
use eframe::egui::Pos2;
|
||||
use eframe::egui::TextBuffer;
|
||||
use eframe::egui::Vec2;
|
||||
@@ -16,7 +16,7 @@ use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
/// The `komorebi.bar.json` configuration file reference for `v0.1.38`
|
||||
/// The `komorebi.bar.json` configuration file reference for `v0.1.39`
|
||||
pub struct KomobarConfig {
|
||||
/// Bar height (default: 50)
|
||||
pub height: Option<f32>,
|
||||
@@ -120,7 +120,9 @@ impl KomobarConfig {
|
||||
}
|
||||
|
||||
if display {
|
||||
println!("\nYour bar configuration file contains some options that have been renamed or deprecated:\n");
|
||||
println!(
|
||||
"\nYour bar configuration file contains some options that have been renamed or deprecated:\n"
|
||||
);
|
||||
for (canonical, aliases) in map {
|
||||
for alias in aliases {
|
||||
if raw.contains(alias) {
|
||||
@@ -453,7 +455,7 @@ impl MouseMessage {
|
||||
|
||||
tracing::debug!("Sending messages: {messages:?}");
|
||||
|
||||
if komorebi_client::send_batch(messages.into_iter()).is_err() {
|
||||
if komorebi_client::send_batch(messages).is_err() {
|
||||
tracing::error!("could not send commands");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ use eframe::egui::ViewportBuilder;
|
||||
use font_loader::system_fonts;
|
||||
use hotwatch::EventKind;
|
||||
use hotwatch::Hotwatch;
|
||||
use komorebi_client::replace_env_in_path;
|
||||
use komorebi_client::PathExt;
|
||||
use komorebi_client::SocketMessage;
|
||||
use komorebi_client::SubscribeOptions;
|
||||
use komorebi_client::replace_env_in_path;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
@@ -32,8 +32,8 @@ use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Foundation::LPARAM;
|
||||
use windows::Win32::System::Threading::GetCurrentProcessId;
|
||||
use windows::Win32::System::Threading::GetCurrentThreadId;
|
||||
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
|
||||
use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
|
||||
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EnumThreadWindows;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
|
||||
use windows_core::BOOL;
|
||||
@@ -114,14 +114,14 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
#[cfg(feature = "schemars")]
|
||||
if opts.schema {
|
||||
let settings = schemars::gen::SchemaSettings::default().with(|s| {
|
||||
let settings = schemars::r#gen::SchemaSettings::default().with(|s| {
|
||||
s.option_nullable = false;
|
||||
s.option_add_null_type = false;
|
||||
s.inline_subschemas = true;
|
||||
});
|
||||
|
||||
let gen = settings.into_generator();
|
||||
let socket_message = gen.into_root_schema_for::<KomobarConfig>();
|
||||
let generator = settings.into_generator();
|
||||
let socket_message = generator.into_root_schema_for::<KomobarConfig>();
|
||||
let schema = serde_json::to_string_pretty(&socket_message)?;
|
||||
|
||||
println!("{schema}");
|
||||
@@ -137,13 +137,17 @@ fn main() -> color_eyre::Result<()> {
|
||||
}
|
||||
|
||||
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
|
||||
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||
unsafe {
|
||||
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||
}
|
||||
}
|
||||
|
||||
color_eyre::install()?;
|
||||
|
||||
if std::env::var("RUST_LOG").is_err() {
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
unsafe {
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
}
|
||||
}
|
||||
|
||||
tracing::subscriber::set_global_default(
|
||||
@@ -230,17 +234,17 @@ fn main() -> color_eyre::Result<()> {
|
||||
.map_or(usr_monitor_index, |i| *i);
|
||||
|
||||
MONITOR_RIGHT.store(
|
||||
state.monitors.elements()[monitor_index].size().right,
|
||||
state.monitors.elements()[monitor_index].size.right,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
MONITOR_TOP.store(
|
||||
state.monitors.elements()[monitor_index].size().top,
|
||||
state.monitors.elements()[monitor_index].size.top,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
MONITOR_LEFT.store(
|
||||
state.monitors.elements()[monitor_index].size().left,
|
||||
state.monitors.elements()[monitor_index].size.left,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
@@ -250,11 +254,11 @@ fn main() -> color_eyre::Result<()> {
|
||||
None => {
|
||||
config.position = Some(PositionConfig {
|
||||
start: Some(Position {
|
||||
x: state.monitors.elements()[monitor_index].size().left as f32,
|
||||
y: state.monitors.elements()[monitor_index].size().top as f32,
|
||||
x: state.monitors.elements()[monitor_index].size.left as f32,
|
||||
y: state.monitors.elements()[monitor_index].size.top as f32,
|
||||
}),
|
||||
end: Some(Position {
|
||||
x: state.monitors.elements()[monitor_index].size().right as f32,
|
||||
x: state.monitors.elements()[monitor_index].size.right as f32,
|
||||
y: 50.0,
|
||||
}),
|
||||
})
|
||||
@@ -262,14 +266,14 @@ fn main() -> color_eyre::Result<()> {
|
||||
Some(ref mut position) => {
|
||||
if position.start.is_none() {
|
||||
position.start = Some(Position {
|
||||
x: state.monitors.elements()[monitor_index].size().left as f32,
|
||||
y: state.monitors.elements()[monitor_index].size().top as f32,
|
||||
x: state.monitors.elements()[monitor_index].size.left as f32,
|
||||
y: state.monitors.elements()[monitor_index].size.top as f32,
|
||||
});
|
||||
}
|
||||
|
||||
if position.end.is_none() {
|
||||
position.end = Some(Position {
|
||||
x: state.monitors.elements()[monitor_index].size().right as f32,
|
||||
x: state.monitors.elements()[monitor_index].size.right as f32,
|
||||
y: 50.0,
|
||||
})
|
||||
}
|
||||
@@ -354,7 +358,7 @@ fn main() -> color_eyre::Result<()> {
|
||||
while komorebi_client::send_message(
|
||||
&SocketMessage::AddSubscriberSocket(subscriber_name.clone()),
|
||||
)
|
||||
.is_err()
|
||||
.is_err()
|
||||
{
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
@@ -405,5 +409,5 @@ fn main() -> color_eyre::Result<()> {
|
||||
Ok(Box::new(Komobar::new(cc, rx_gui, rx_config, config)))
|
||||
}),
|
||||
)
|
||||
.map_err(|error| color_eyre::eyre::Error::msg(error.to_string()))
|
||||
.map_err(|error| color_eyre::eyre::Error::msg(error.to_string()))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||
use crate::bar::Alignment;
|
||||
use crate::config::KomobarConfig;
|
||||
use crate::config::MonitorConfigOrIndex;
|
||||
use crate::AUTO_SELECT_FILL_COLOUR;
|
||||
use crate::AUTO_SELECT_TEXT_COLOUR;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::CornerRadius;
|
||||
@@ -18,9 +18,9 @@ use komorebi_client::Rgb;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::num::NonZeroU32;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
static SHOW_KOMOREBI_LAYOUT_OPTIONS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ use super::ImageIcon;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::vec2;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::CornerRadius;
|
||||
@@ -17,6 +16,7 @@ use eframe::egui::Stroke;
|
||||
use eframe::egui::StrokeKind;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::vec2;
|
||||
use komorebi_client::PathExt;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -2,17 +2,17 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use starship_battery::units::ratio::percent;
|
||||
use starship_battery::Manager;
|
||||
use starship_battery::State;
|
||||
use starship_battery::units::ratio::percent;
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
@@ -87,41 +87,41 @@ impl Battery {
|
||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||
output = None;
|
||||
|
||||
if let Ok(mut batteries) = self.manager.batteries() {
|
||||
if let Some(Ok(first)) = batteries.nth(0) {
|
||||
let percentage = first.state_of_charge().get::<percent>().round() as u8;
|
||||
if let Ok(mut batteries) = self.manager.batteries()
|
||||
&& let Some(Ok(first)) = batteries.nth(0)
|
||||
{
|
||||
let percentage = first.state_of_charge().get::<percent>().round() as u8;
|
||||
|
||||
if percentage == 100 && self.hide_on_full_charge {
|
||||
output = None
|
||||
} else {
|
||||
match first.state() {
|
||||
State::Charging => self.state = BatteryState::Charging,
|
||||
State::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,
|
||||
}
|
||||
if percentage == 100 && self.hide_on_full_charge {
|
||||
output = None
|
||||
} else {
|
||||
match first.state() {
|
||||
State::Charging => self.state = BatteryState::Charging,
|
||||
State::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 = Some(BatteryOutput {
|
||||
label: match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("BAT: {percentage}%")
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => {
|
||||
format!("{percentage}%")
|
||||
}
|
||||
},
|
||||
selected,
|
||||
})
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let selected = self.auto_select_under.is_some_and(|u| percentage <= u);
|
||||
|
||||
output = Some(BatteryOutput {
|
||||
label: match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("BAT: {percentage}%")
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => {
|
||||
format!("{percentage}%")
|
||||
}
|
||||
},
|
||||
selected,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,13 +176,11 @@ impl BarWidget for Battery {
|
||||
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) = Command::new("cmd.exe")
|
||||
&& let Err(error) = Command::new("cmd.exe")
|
||||
.args(["/C", "start", "ms-settings:batterysaver"])
|
||||
.spawn()
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::process::Command;
|
||||
@@ -120,12 +120,10 @@ impl BarWidget for Cpu {
|
||||
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) =
|
||||
&& let Err(error) =
|
||||
Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn()
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,15 +4,16 @@ use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use chrono::Local;
|
||||
use chrono_tz::Tz;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::WidgetText;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -225,7 +226,7 @@ impl BarWidget for Date {
|
||||
if SelectableFrame::new(false)
|
||||
.show(ui, |ui| {
|
||||
ui.add(
|
||||
Label::new(WidgetText::LayoutJob(layout_job.clone()))
|
||||
Label::new(WidgetText::LayoutJob(Arc::from(layout_job.clone())))
|
||||
.selectable(false),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use color_eyre::eyre;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::WidgetText;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
use windows::Win32::Globalization::LCIDToLocaleName;
|
||||
@@ -80,7 +82,7 @@ pub struct Keyboard {
|
||||
/// - `Ok(String)`: The name of the active keyboard layout as a valid UTF-8 string.
|
||||
/// - `Err(())`: Indicates that the function failed to retrieve the locale name or encountered
|
||||
/// invalid UTF-16 characters during conversion.
|
||||
fn get_active_keyboard_layout() -> Result<String, ()> {
|
||||
fn get_active_keyboard_layout() -> eyre::Result<String, ()> {
|
||||
let foreground_window_tid = unsafe { GetWindowThreadProcessId(GetForegroundWindow(), None) };
|
||||
let lcid = unsafe { GetKeyboardLayout(foreground_window_tid) };
|
||||
|
||||
@@ -169,7 +171,10 @@ impl BarWidget for Keyboard {
|
||||
);
|
||||
|
||||
config.apply_on_widget(true, ui, |ui| {
|
||||
ui.add(Label::new(WidgetText::LayoutJob(layout_job.clone())).selectable(false))
|
||||
ui.add(
|
||||
Label::new(WidgetText::LayoutJob(Arc::from(layout_job.clone())))
|
||||
.selectable(false),
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use super::ImageIcon;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_INDEX;
|
||||
use crate::config::DisplayFormat;
|
||||
use crate::config::DisplayFormat::*;
|
||||
use crate::config::WorkspacesDisplayFormat;
|
||||
@@ -7,10 +9,6 @@ use crate::selected_frame::SelectableFrame;
|
||||
use crate::ui::CustomUi;
|
||||
use crate::widgets::komorebi_layout::KomorebiLayout;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_INDEX;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::vec2;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::Context;
|
||||
@@ -28,6 +26,8 @@ use eframe::egui::StrokeKind;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::vec2;
|
||||
use komorebi_client::Container;
|
||||
use komorebi_client::PathExt;
|
||||
use komorebi_client::Rect;
|
||||
@@ -271,14 +271,14 @@ impl Komorebi {
|
||||
}
|
||||
|
||||
fn render_layout(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||
if let Some(layout_config) = &self.layout {
|
||||
if layout_config.enable {
|
||||
let monitor_info = &mut *self.monitor_info.borrow_mut();
|
||||
let workspace_idx = monitor_info.focused_workspace_idx;
|
||||
monitor_info
|
||||
.layout
|
||||
.show(ctx, ui, config, layout_config, workspace_idx);
|
||||
}
|
||||
if let Some(layout_config) = &self.layout
|
||||
&& layout_config.enable
|
||||
{
|
||||
let monitor_info = &mut *self.monitor_info.borrow_mut();
|
||||
let workspace_idx = monitor_info.focused_workspace_idx;
|
||||
monitor_info
|
||||
.layout
|
||||
.show(ctx, ui, config, layout_config, workspace_idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,10 +558,8 @@ impl FocusedContainerBar {
|
||||
ui.add(img.fit_to_exact_size(self.icon_size));
|
||||
}
|
||||
});
|
||||
if HOVEL {
|
||||
if let Some(title) = &info.title {
|
||||
inner_response.response.on_hover_text(title);
|
||||
}
|
||||
if HOVEL && let Some(title) = &info.title {
|
||||
inner_response.response.on_hover_text(title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,7 +815,7 @@ impl MonitorInfo {
|
||||
self.mouse_follows_focus = state.mouse_follows_focus;
|
||||
|
||||
let monitor = &state.monitors.elements()[self.monitor_index];
|
||||
self.work_area_offset = monitor.work_area_offset();
|
||||
self.work_area_offset = monitor.work_area_offset;
|
||||
self.focused_workspace_idx = Some(monitor.focused_workspace_idx());
|
||||
|
||||
// Layout
|
||||
@@ -856,7 +854,7 @@ impl MonitorInfo {
|
||||
let containers = fn_containers_from(ws);
|
||||
WorkspaceInfo {
|
||||
name: ws
|
||||
.name()
|
||||
.name
|
||||
.to_owned()
|
||||
.unwrap_or_else(|| format!("{}", index + 1)),
|
||||
focused_container_idx: containers.iter().position(|c| c.is_focused),
|
||||
@@ -864,7 +862,7 @@ impl MonitorInfo {
|
||||
.iter()
|
||||
.any(|container| container.windows.iter().any(|window| window.icon.is_some())),
|
||||
containers,
|
||||
layer: *ws.layer(),
|
||||
layer: ws.layer,
|
||||
should_show: !hide_empty_ws || focused_ws_idx == Some(index) || !ws.is_empty(),
|
||||
is_selected: focused_ws_idx == Some(index),
|
||||
}
|
||||
@@ -873,15 +871,15 @@ impl MonitorInfo {
|
||||
|
||||
/// Determines the current layout of the focused workspace
|
||||
fn resolve_layout(focused_ws: &Workspace, is_paused: bool) -> KomorebiLayout {
|
||||
if focused_ws.monocle_container().is_some() {
|
||||
if focused_ws.monocle_container.is_some() {
|
||||
KomorebiLayout::Monocle
|
||||
} else if !focused_ws.tile() {
|
||||
} else if !focused_ws.tile {
|
||||
KomorebiLayout::Floating
|
||||
} else if is_paused {
|
||||
KomorebiLayout::Paused
|
||||
} else {
|
||||
match focused_ws.layout() {
|
||||
komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(*layout),
|
||||
match focused_ws.layout {
|
||||
komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(layout),
|
||||
komorebi_client::Layout::Custom(_) => KomorebiLayout::Custom,
|
||||
}
|
||||
}
|
||||
@@ -938,7 +936,7 @@ impl ContainerInfo {
|
||||
|
||||
// Monocle container first if present
|
||||
let monocle = ws
|
||||
.monocle_container()
|
||||
.monocle_container
|
||||
.as_ref()
|
||||
.map(|c| Self::from_container(c, !has_focused_float));
|
||||
|
||||
@@ -965,7 +963,7 @@ impl ContainerInfo {
|
||||
if let Some(window) = ws.floating_windows().iter().find(|w| w.is_focused()) {
|
||||
return Some(Self::from_window(window));
|
||||
}
|
||||
if let Some(container) = ws.monocle_container() {
|
||||
if let Some(container) = &ws.monocle_container {
|
||||
Some(Self::from_container(container, true))
|
||||
} else {
|
||||
ws.focused_container()
|
||||
@@ -979,7 +977,7 @@ impl ContainerInfo {
|
||||
windows: container.windows().iter().map(WindowInfo::from).collect(),
|
||||
focused_window_idx: container.focused_window_idx(),
|
||||
is_focused,
|
||||
is_locked: container.locked(),
|
||||
is_locked: container.locked,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::config::DisplayFormat;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::komorebi::KomorebiLayoutConfig;
|
||||
use eframe::egui::vec2;
|
||||
use color_eyre::eyre;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::CornerRadius;
|
||||
use eframe::egui::FontId;
|
||||
@@ -13,11 +13,12 @@ use eframe::egui::Stroke;
|
||||
use eframe::egui::StrokeKind;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::vec2;
|
||||
use komorebi_client::SocketMessage;
|
||||
use serde::de::Error;
|
||||
use serde::Deserialize;
|
||||
use serde::Deserializer;
|
||||
use serde::Serialize;
|
||||
use serde::de::Error;
|
||||
use serde_json::from_str;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
@@ -34,7 +35,7 @@ pub enum KomorebiLayout {
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for KomorebiLayout {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
fn deserialize<D>(deserializer: D) -> eyre::Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
@@ -91,16 +92,15 @@ impl KomorebiLayout {
|
||||
fn on_click_option(&mut self, monitor_idx: usize, workspace_idx: Option<usize>) {
|
||||
match self {
|
||||
KomorebiLayout::Default(option) => {
|
||||
if let Some(ws_idx) = workspace_idx {
|
||||
if komorebi_client::send_message(&SocketMessage::WorkspaceLayout(
|
||||
if let Some(ws_idx) = workspace_idx
|
||||
&& komorebi_client::send_message(&SocketMessage::WorkspaceLayout(
|
||||
monitor_idx,
|
||||
ws_idx,
|
||||
*option,
|
||||
))
|
||||
.is_err()
|
||||
{
|
||||
tracing::error!("could not send message to komorebi: WorkspaceLayout");
|
||||
}
|
||||
{
|
||||
tracing::error!("could not send message to komorebi: WorkspaceLayout");
|
||||
}
|
||||
}
|
||||
KomorebiLayout::Monocle => {
|
||||
@@ -269,57 +269,53 @@ impl KomorebiLayout {
|
||||
show_options = self.on_click(&show_options, monitor_idx, workspace_idx);
|
||||
}
|
||||
|
||||
if show_options {
|
||||
if let Some(workspace_idx) = workspace_idx {
|
||||
Frame::NONE.show(ui, |ui| {
|
||||
ui.add(
|
||||
Label::new(egui_phosphor::regular::ARROW_FAT_LINES_RIGHT.to_string())
|
||||
.selectable(false),
|
||||
);
|
||||
if show_options && let Some(workspace_idx) = workspace_idx {
|
||||
Frame::NONE.show(ui, |ui| {
|
||||
ui.add(
|
||||
Label::new(egui_phosphor::regular::ARROW_FAT_LINES_RIGHT.to_string())
|
||||
.selectable(false),
|
||||
);
|
||||
|
||||
let mut layout_options = layout_config.options.clone().unwrap_or(vec![
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::BSP),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Columns),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Rows),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::VerticalStack),
|
||||
KomorebiLayout::Default(
|
||||
komorebi_client::DefaultLayout::RightMainVerticalStack,
|
||||
),
|
||||
KomorebiLayout::Default(
|
||||
komorebi_client::DefaultLayout::HorizontalStack,
|
||||
),
|
||||
KomorebiLayout::Default(
|
||||
komorebi_client::DefaultLayout::UltrawideVerticalStack,
|
||||
),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Grid),
|
||||
//KomorebiLayout::Custom,
|
||||
KomorebiLayout::Monocle,
|
||||
KomorebiLayout::Floating,
|
||||
KomorebiLayout::Paused,
|
||||
]);
|
||||
let mut layout_options = layout_config.options.clone().unwrap_or(vec![
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::BSP),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Columns),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Rows),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::VerticalStack),
|
||||
KomorebiLayout::Default(
|
||||
komorebi_client::DefaultLayout::RightMainVerticalStack,
|
||||
),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::HorizontalStack),
|
||||
KomorebiLayout::Default(
|
||||
komorebi_client::DefaultLayout::UltrawideVerticalStack,
|
||||
),
|
||||
KomorebiLayout::Default(komorebi_client::DefaultLayout::Grid),
|
||||
//KomorebiLayout::Custom,
|
||||
KomorebiLayout::Monocle,
|
||||
KomorebiLayout::Floating,
|
||||
KomorebiLayout::Paused,
|
||||
]);
|
||||
|
||||
for layout_option in &mut layout_options {
|
||||
let is_selected = self == layout_option;
|
||||
for layout_option in &mut layout_options {
|
||||
let is_selected = self == layout_option;
|
||||
|
||||
if SelectableFrame::new(is_selected)
|
||||
.show(ui, |ui| {
|
||||
layout_option.show_icon(is_selected, font_id.clone(), ctx, ui)
|
||||
})
|
||||
.on_hover_text(match layout_option {
|
||||
KomorebiLayout::Default(layout) => layout.to_string(),
|
||||
KomorebiLayout::Monocle => "Toggle monocle".to_string(),
|
||||
KomorebiLayout::Floating => "Toggle tiling".to_string(),
|
||||
KomorebiLayout::Paused => "Toggle pause".to_string(),
|
||||
KomorebiLayout::Custom => "Custom".to_string(),
|
||||
})
|
||||
.clicked()
|
||||
{
|
||||
layout_option.on_click_option(monitor_idx, Some(workspace_idx));
|
||||
show_options = false;
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
if SelectableFrame::new(is_selected)
|
||||
.show(ui, |ui| {
|
||||
layout_option.show_icon(is_selected, font_id.clone(), ctx, ui)
|
||||
})
|
||||
.on_hover_text(match layout_option {
|
||||
KomorebiLayout::Default(layout) => layout.to_string(),
|
||||
KomorebiLayout::Monocle => "Toggle monocle".to_string(),
|
||||
KomorebiLayout::Floating => "Toggle tiling".to_string(),
|
||||
KomorebiLayout::Paused => "Toggle pause".to_string(),
|
||||
KomorebiLayout::Custom => "Custom".to_string(),
|
||||
})
|
||||
.clicked()
|
||||
{
|
||||
layout_option.on_click_option(monitor_idx, Some(workspace_idx));
|
||||
show_options = false;
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::ui::CustomUi;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -40,36 +40,34 @@ impl Media {
|
||||
enable,
|
||||
session_manager: GlobalSystemMediaTransportControlsSessionManager::RequestAsync()
|
||||
.unwrap()
|
||||
.get()
|
||||
.join()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&self) {
|
||||
if let Ok(session) = self.session_manager.GetCurrentSession() {
|
||||
if let Ok(op) = session.TryTogglePlayPauseAsync() {
|
||||
op.get().unwrap_or_default();
|
||||
}
|
||||
if let Ok(session) = self.session_manager.GetCurrentSession()
|
||||
&& let Ok(op) = session.TryTogglePlayPauseAsync()
|
||||
{
|
||||
op.join().unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
fn output(&mut self) -> String {
|
||||
if let Ok(session) = self.session_manager.GetCurrentSession() {
|
||||
if let Ok(operation) = session.TryGetMediaPropertiesAsync() {
|
||||
if let Ok(properties) = operation.get() {
|
||||
if let (Ok(artist), Ok(title)) = (properties.Artist(), properties.Title()) {
|
||||
if artist.is_empty() {
|
||||
return format!("{title}");
|
||||
}
|
||||
|
||||
if title.is_empty() {
|
||||
return format!("{artist}");
|
||||
}
|
||||
|
||||
return format!("{artist} - {title}");
|
||||
}
|
||||
}
|
||||
if let Ok(session) = self.session_manager.GetCurrentSession()
|
||||
&& let Ok(operation) = session.TryGetMediaPropertiesAsync()
|
||||
&& let Ok(properties) = operation.join()
|
||||
&& let (Ok(artist), Ok(title)) = (properties.Artist(), properties.Title())
|
||||
{
|
||||
if artist.is_empty() {
|
||||
return format!("{title}");
|
||||
}
|
||||
|
||||
if title.is_empty() {
|
||||
return format!("{artist}");
|
||||
}
|
||||
|
||||
return format!("{artist} - {title}");
|
||||
}
|
||||
|
||||
String::new()
|
||||
|
||||
@@ -2,12 +2,12 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::process::Command;
|
||||
@@ -124,12 +124,10 @@ impl BarWidget for Memory {
|
||||
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) =
|
||||
&& let Err(error) =
|
||||
Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn()
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use num_derive::FromPrimitive;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
@@ -58,6 +58,7 @@ pub struct NetworkSelectConfig {
|
||||
|
||||
impl From<NetworkConfig> for Network {
|
||||
fn from(value: NetworkConfig) -> Self {
|
||||
let default_refresh_interval = 10;
|
||||
let data_refresh_interval = value.data_refresh_interval.unwrap_or(10);
|
||||
|
||||
Self {
|
||||
@@ -67,10 +68,14 @@ impl From<NetworkConfig> for Network {
|
||||
show_default_interface: value.show_default_interface.unwrap_or(true),
|
||||
networks_network_activity: Networks::new_with_refreshed_list(),
|
||||
default_interface: String::new(),
|
||||
default_refresh_interval,
|
||||
data_refresh_interval,
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||
auto_select: value.auto_select,
|
||||
activity_left_padding: value.activity_left_padding.unwrap_or_default(),
|
||||
last_updated_default_interface: Instant::now()
|
||||
.checked_sub(Duration::from_secs(default_refresh_interval))
|
||||
.unwrap(),
|
||||
last_state_total_activity: vec![],
|
||||
last_state_activity: vec![],
|
||||
last_updated_network_activity: Instant::now()
|
||||
@@ -86,10 +91,12 @@ pub struct Network {
|
||||
pub show_activity: bool,
|
||||
pub show_default_interface: bool,
|
||||
networks_network_activity: Networks,
|
||||
default_refresh_interval: u64,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
auto_select: Option<NetworkSelectConfig>,
|
||||
default_interface: String,
|
||||
last_updated_default_interface: Instant,
|
||||
last_state_total_activity: Vec<NetworkReading>,
|
||||
last_state_activity: Vec<NetworkReading>,
|
||||
last_updated_network_activity: Instant,
|
||||
@@ -98,10 +105,18 @@ pub struct Network {
|
||||
|
||||
impl Network {
|
||||
fn default_interface(&mut self) {
|
||||
if let Ok(interface) = netdev::get_default_interface() {
|
||||
if let Some(friendly_name) = &interface.friendly_name {
|
||||
let now = Instant::now();
|
||||
|
||||
if now.duration_since(self.last_updated_default_interface)
|
||||
> Duration::from_secs(self.default_refresh_interval)
|
||||
{
|
||||
if let Ok(interface) = netdev::get_default_interface()
|
||||
&& let Some(friendly_name) = &interface.friendly_name
|
||||
{
|
||||
self.default_interface.clone_from(friendly_name);
|
||||
}
|
||||
|
||||
self.last_updated_default_interface = now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,43 +131,40 @@ impl Network {
|
||||
activity.clear();
|
||||
total_activity.clear();
|
||||
|
||||
if let Ok(interface) = netdev::get_default_interface() {
|
||||
if let Some(friendly_name) = &interface.friendly_name {
|
||||
self.default_interface.clone_from(friendly_name);
|
||||
if let Ok(interface) = netdev::get_default_interface()
|
||||
&& let Some(friendly_name) = &interface.friendly_name
|
||||
{
|
||||
self.default_interface.clone_from(friendly_name);
|
||||
|
||||
self.networks_network_activity.refresh(true);
|
||||
self.networks_network_activity.refresh(true);
|
||||
|
||||
for (interface_name, data) in &self.networks_network_activity {
|
||||
if friendly_name.eq(interface_name) {
|
||||
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,
|
||||
);
|
||||
for (interface_name, data) in &self.networks_network_activity {
|
||||
if friendly_name.eq(interface_name) {
|
||||
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(
|
||||
NetworkReadingFormat::Speed,
|
||||
ReadingValue::from(received),
|
||||
ReadingValue::from(transmitted),
|
||||
));
|
||||
}
|
||||
activity.push(NetworkReading::new(
|
||||
NetworkReadingFormat::Speed,
|
||||
ReadingValue::from(received),
|
||||
ReadingValue::from(transmitted),
|
||||
));
|
||||
}
|
||||
|
||||
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);
|
||||
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(
|
||||
NetworkReadingFormat::Total,
|
||||
ReadingValue::from(total_received),
|
||||
ReadingValue::from(total_transmitted),
|
||||
))
|
||||
}
|
||||
total_activity.push(NetworkReading::new(
|
||||
NetworkReadingFormat::Total,
|
||||
ReadingValue::from(total_received),
|
||||
ReadingValue::from(total_transmitted),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,10 +324,9 @@ impl Network {
|
||||
if SelectableFrame::new_auto(selected, auto_focus_fill)
|
||||
.show(ui, add_contents)
|
||||
.clicked()
|
||||
&& let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn()
|
||||
{
|
||||
if let Err(error) = Command::new("cmd.exe").args(["/C", "ncpa"]).spawn() {
|
||||
eprintln!("{error}");
|
||||
}
|
||||
eprintln!("{error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::process::Command;
|
||||
@@ -156,17 +156,15 @@ impl BarWidget for Storage {
|
||||
if SelectableFrame::new_auto(output.selected, auto_focus_fill)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) = Command::new("cmd.exe")
|
||||
&& let Err(error) = Command::new("cmd.exe")
|
||||
.args([
|
||||
"/C",
|
||||
"explorer.exe",
|
||||
output.label.split(' ').collect::<Vec<&str>>()[0],
|
||||
])
|
||||
.spawn()
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::widgets::widget::BarWidget;
|
||||
use chrono::Local;
|
||||
use chrono::NaiveTime;
|
||||
use chrono_tz::Tz;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::CornerRadius;
|
||||
@@ -16,6 +15,7 @@ use eframe::egui::Stroke;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::epaint::StrokeKind;
|
||||
use lazy_static::lazy_static;
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -2,12 +2,12 @@ use crate::config::LabelPrefix;
|
||||
use crate::render::RenderConfig;
|
||||
use crate::selected_frame::SelectableFrame;
|
||||
use crate::widgets::widget::BarWidget;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::Ui;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::process::Command;
|
||||
@@ -140,16 +140,14 @@ impl BarWidget for Update {
|
||||
if SelectableFrame::new(false)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) = Command::new("explorer.exe")
|
||||
&& let Err(error) = Command::new("explorer.exe")
|
||||
.args([format!(
|
||||
"https://github.com/LGUG2Z/komorebi/releases/v{}",
|
||||
self.latest_version
|
||||
)])
|
||||
.spawn()
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
{
|
||||
eprintln!("{error}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "komorebi-client"
|
||||
version = "0.1.38"
|
||||
edition = "2021"
|
||||
version = "0.1.39"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
pub use komorebi::animation::prefix::AnimationPrefix;
|
||||
pub use komorebi::AnimationsConfig;
|
||||
pub use komorebi::AppSpecificConfigurationPath;
|
||||
pub use komorebi::AspectRatio;
|
||||
pub use komorebi::BorderColours;
|
||||
pub use komorebi::Colour;
|
||||
pub use komorebi::CrossBoundaryBehaviour;
|
||||
pub use komorebi::GlobalState;
|
||||
pub use komorebi::KomorebiTheme;
|
||||
pub use komorebi::MonitorConfig;
|
||||
pub use komorebi::Notification;
|
||||
pub use komorebi::NotificationEvent;
|
||||
pub use komorebi::PredefinedAspectRatio;
|
||||
pub use komorebi::Rgb;
|
||||
pub use komorebi::RuleDebug;
|
||||
pub use komorebi::StackbarConfig;
|
||||
pub use komorebi::State;
|
||||
pub use komorebi::StaticConfig;
|
||||
pub use komorebi::SubscribeOptions;
|
||||
pub use komorebi::TabsConfig;
|
||||
pub use komorebi::VirtualDesktopNotification;
|
||||
pub use komorebi::WindowContainerBehaviour;
|
||||
pub use komorebi::WindowsApi;
|
||||
pub use komorebi::WorkspaceConfig;
|
||||
pub use komorebi::animation::PerAnimationPrefixConfig;
|
||||
pub use komorebi::animation::prefix::AnimationPrefix;
|
||||
pub use komorebi::asc::ApplicationSpecificConfiguration;
|
||||
pub use komorebi::border_manager::BorderInfo;
|
||||
pub use komorebi::config_generation::ApplicationConfiguration;
|
||||
@@ -11,8 +34,6 @@ pub use komorebi::config_generation::IdWithIdentifierAndComment;
|
||||
pub use komorebi::config_generation::MatchingRule;
|
||||
pub use komorebi::config_generation::MatchingStrategy;
|
||||
pub use komorebi::container::Container;
|
||||
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
|
||||
pub use komorebi::core::replace_env_in_path;
|
||||
pub use komorebi::core::AnimationStyle;
|
||||
pub use komorebi::core::ApplicationIdentifier;
|
||||
pub use komorebi::core::Arrangement;
|
||||
@@ -42,6 +63,8 @@ pub use komorebi::core::StackbarLabel;
|
||||
pub use komorebi::core::StackbarMode;
|
||||
pub use komorebi::core::StateQuery;
|
||||
pub use komorebi::core::WindowKind;
|
||||
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
|
||||
pub use komorebi::core::replace_env_in_path;
|
||||
pub use komorebi::monitor::Monitor;
|
||||
pub use komorebi::monitor_reconciliator::MonitorNotification;
|
||||
pub use komorebi::ring::Ring;
|
||||
@@ -51,29 +74,6 @@ pub use komorebi::window_manager_event::WindowManagerEvent;
|
||||
pub use komorebi::workspace::Workspace;
|
||||
pub use komorebi::workspace::WorkspaceGlobals;
|
||||
pub use komorebi::workspace::WorkspaceLayer;
|
||||
pub use komorebi::AnimationsConfig;
|
||||
pub use komorebi::AppSpecificConfigurationPath;
|
||||
pub use komorebi::AspectRatio;
|
||||
pub use komorebi::BorderColours;
|
||||
pub use komorebi::Colour;
|
||||
pub use komorebi::CrossBoundaryBehaviour;
|
||||
pub use komorebi::GlobalState;
|
||||
pub use komorebi::KomorebiTheme;
|
||||
pub use komorebi::MonitorConfig;
|
||||
pub use komorebi::Notification;
|
||||
pub use komorebi::NotificationEvent;
|
||||
pub use komorebi::PredefinedAspectRatio;
|
||||
pub use komorebi::Rgb;
|
||||
pub use komorebi::RuleDebug;
|
||||
pub use komorebi::StackbarConfig;
|
||||
pub use komorebi::State;
|
||||
pub use komorebi::StaticConfig;
|
||||
pub use komorebi::SubscribeOptions;
|
||||
pub use komorebi::TabsConfig;
|
||||
pub use komorebi::VirtualDesktopNotification;
|
||||
pub use komorebi::WindowContainerBehaviour;
|
||||
pub use komorebi::WindowsApi;
|
||||
pub use komorebi::WorkspaceConfig;
|
||||
|
||||
use komorebi::DATA_DIR;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "komorebi-gui"
|
||||
version = "0.1.38"
|
||||
edition = "2021"
|
||||
version = "0.1.39"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#![warn(clippy::all)]
|
||||
|
||||
use eframe::egui;
|
||||
use eframe::egui::color_picker::Alpha;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::ViewportBuilder;
|
||||
use eframe::egui::color_picker::Alpha;
|
||||
use komorebi_client::BorderStyle;
|
||||
use komorebi_client::Colour;
|
||||
use komorebi_client::DefaultLayout;
|
||||
@@ -78,8 +78,8 @@ impl From<&komorebi_client::Monitor> for MonitorConfig {
|
||||
}
|
||||
|
||||
Self {
|
||||
size: *value.size(),
|
||||
work_area_offset: value.work_area_offset().unwrap_or_default(),
|
||||
size: value.size,
|
||||
work_area_offset: value.work_area_offset.unwrap_or_default(),
|
||||
workspaces,
|
||||
}
|
||||
}
|
||||
@@ -95,22 +95,22 @@ struct WorkspaceConfig {
|
||||
|
||||
impl From<&komorebi_client::Workspace> for WorkspaceConfig {
|
||||
fn from(value: &komorebi_client::Workspace) -> Self {
|
||||
let layout = match value.layout() {
|
||||
Layout::Default(layout) => *layout,
|
||||
let layout = match value.layout {
|
||||
Layout::Default(layout) => layout,
|
||||
Layout::Custom(_) => DefaultLayout::BSP,
|
||||
};
|
||||
|
||||
let name = value
|
||||
.name()
|
||||
.name
|
||||
.to_owned()
|
||||
.unwrap_or_else(|| random_word::get(random_word::Lang::En).to_string());
|
||||
|
||||
Self {
|
||||
layout,
|
||||
name,
|
||||
tile: *value.tile(),
|
||||
workspace_padding: value.workspace_padding().unwrap_or(20),
|
||||
container_padding: value.container_padding().unwrap_or(20),
|
||||
tile: value.tile,
|
||||
workspace_padding: value.workspace_padding.unwrap_or(20),
|
||||
container_padding: value.container_padding.unwrap_or(20),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,7 +437,7 @@ impl eframe::App for KomorebiGui {
|
||||
BorderStyle::Square,
|
||||
] {
|
||||
if ui
|
||||
.add(egui::SelectableLabel::new(
|
||||
.add(egui::Button::selectable(
|
||||
self.border_config.border_style == option,
|
||||
option.to_string(),
|
||||
))
|
||||
@@ -494,7 +494,7 @@ impl eframe::App for KomorebiGui {
|
||||
StackbarMode::Always,
|
||||
] {
|
||||
if ui
|
||||
.add(egui::SelectableLabel::new(
|
||||
.add(egui::Button::selectable(
|
||||
self.stackbar_config.mode == option,
|
||||
option.to_string(),
|
||||
))
|
||||
@@ -513,7 +513,7 @@ impl eframe::App for KomorebiGui {
|
||||
ui.collapsing("Label", |ui| {
|
||||
for option in [StackbarLabel::Process, StackbarLabel::Title] {
|
||||
if ui
|
||||
.add(egui::SelectableLabel::new(
|
||||
.add(egui::Button::selectable(
|
||||
self.stackbar_config.label == option,
|
||||
option.to_string(),
|
||||
))
|
||||
@@ -772,7 +772,7 @@ impl eframe::App for KomorebiGui {
|
||||
DefaultLayout::Grid,
|
||||
] {
|
||||
if ui
|
||||
.add(egui::SelectableLabel::new(
|
||||
.add(egui::Button::selectable(
|
||||
workspace.layout == option,
|
||||
option.to_string(),
|
||||
))
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
[package]
|
||||
name = "komorebi-themes"
|
||||
version = "0.1.38"
|
||||
edition = "2021"
|
||||
version = "0.1.39"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "96f26c88d83781f234d42222293ec73d23a39ad8" }
|
||||
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"] }
|
||||
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "c9008bd5cfa288c926e9ea3aa18c92073f9281bd" }
|
||||
catppuccin-egui = { version = "5", default-features = false, features = ["egui32"] }
|
||||
eframe = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use hex_color::HexColor;
|
||||
#[cfg(feature = "schemars")]
|
||||
use schemars::gen::SchemaGenerator;
|
||||
use schemars::SchemaGenerator;
|
||||
#[cfg(feature = "schemars")]
|
||||
use schemars::schema::InstanceType;
|
||||
#[cfg(feature = "schemars")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::Base16ColourPalette;
|
||||
use crate::colour::Colour;
|
||||
use crate::colour::Hex;
|
||||
use crate::Base16ColourPalette;
|
||||
use hex_color::HexColor;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Display;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
pub mod colour;
|
||||
mod generator;
|
||||
|
||||
pub use generator::generate_base16_palette;
|
||||
pub use generator::ThemeVariant;
|
||||
pub use generator::generate_base16_palette;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
@@ -16,14 +16,14 @@ use strum::IntoEnumIterator;
|
||||
use crate::colour::Colour;
|
||||
pub use base16_egui_themes::Base16;
|
||||
pub use catppuccin_egui;
|
||||
use eframe::egui::style::Selection;
|
||||
use eframe::egui::style::WidgetVisuals;
|
||||
use eframe::egui::style::Widgets;
|
||||
pub use eframe::egui::Color32;
|
||||
use eframe::egui::Shadow;
|
||||
use eframe::egui::Stroke;
|
||||
use eframe::egui::Style;
|
||||
use eframe::egui::Visuals;
|
||||
use eframe::egui::style::Selection;
|
||||
use eframe::egui::style::WidgetVisuals;
|
||||
use eframe::egui::style::Widgets;
|
||||
use serde_variant::to_variant_name;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "komorebi"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
description = "A tiling window manager for Windows"
|
||||
repository = "https://github.com/LGUG2Z/komorebi"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -17,7 +17,6 @@ crossbeam-channel = { workspace = true }
|
||||
crossbeam-utils = { workspace = true }
|
||||
ctrlc = { version = "3", features = ["termination"] }
|
||||
dirs = { workspace = true }
|
||||
getset = "0.1"
|
||||
hotwatch = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
miow = "0.6"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use super::prefix::AnimationPrefix;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
@@ -6,10 +6,10 @@ use std::sync::atomic::Ordering;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use super::RenderDispatcher;
|
||||
use super::ANIMATION_DURATION_GLOBAL;
|
||||
use super::ANIMATION_FPS;
|
||||
use super::ANIMATION_MANAGER;
|
||||
use super::RenderDispatcher;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
@@ -55,9 +55,9 @@ impl AnimationEngine {
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
pub fn animate(
|
||||
render_dispatcher: (impl RenderDispatcher + Send + 'static),
|
||||
render_dispatcher: impl RenderDispatcher + Send + 'static,
|
||||
duration: Duration,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
std::thread::spawn(move || {
|
||||
let animation_key = render_dispatcher.get_animation_key();
|
||||
if ANIMATION_MANAGER.lock().in_progress(animation_key.as_str()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::core::Rect;
|
||||
use crate::AnimationStyle;
|
||||
use crate::core::Rect;
|
||||
|
||||
use super::style::apply_ease_func;
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::core::animation::AnimationStyle;
|
||||
use lazy_static::lazy_static;
|
||||
use prefix::AnimationPrefix;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
|
||||
pub trait RenderDispatcher {
|
||||
fn get_animation_key(&self) -> String;
|
||||
fn pre_render(&self) -> Result<()>;
|
||||
fn render(&self, delta: f64) -> Result<()>;
|
||||
fn post_render(&self) -> Result<()>;
|
||||
fn pre_render(&self) -> eyre::Result<()>;
|
||||
fn render(&self, delta: f64) -> eyre::Result<()>;
|
||||
fn post_render(&self) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
use crate::border_manager::window_kind_colour;
|
||||
use crate::border_manager::RenderTarget;
|
||||
use crate::border_manager::WindowKind;
|
||||
use crate::WINDOWS_11;
|
||||
use crate::WindowsApi;
|
||||
use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::border_manager::RenderTarget;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::border_manager::WindowKind;
|
||||
use crate::border_manager::window_kind_colour;
|
||||
use crate::core::BorderStyle;
|
||||
use crate::core::Rect;
|
||||
use crate::windows_api;
|
||||
use crate::WindowsApi;
|
||||
use crate::WINDOWS_11;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::LazyLock;
|
||||
use windows::Win32::Foundation::FALSE;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Foundation::LPARAM;
|
||||
use windows::Win32::Foundation::LRESULT;
|
||||
use windows::Win32::Foundation::TRUE;
|
||||
use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D_RECT_F;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D_SIZE_U;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D1_ALPHA_MODE_PREMULTIPLIED;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D1_COLOR_F;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D1_PIXEL_FORMAT;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D_RECT_F;
|
||||
use windows::Win32::Graphics::Direct2D::Common::D2D_SIZE_U;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1CreateFactory;
|
||||
use windows::Win32::Graphics::Direct2D::ID2D1Factory;
|
||||
use windows::Win32::Graphics::Direct2D::ID2D1SolidColorBrush;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_BRUSH_PROPERTIES;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_FACTORY_TYPE_MULTI_THREADED;
|
||||
@@ -36,31 +33,34 @@ use windows::Win32::Graphics::Direct2D::D2D1_PRESENT_OPTIONS_IMMEDIATELY;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_RENDER_TARGET_PROPERTIES;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_RENDER_TARGET_TYPE_DEFAULT;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1_ROUNDED_RECT;
|
||||
use windows::Win32::Graphics::Dwm::DwmEnableBlurBehindWindow;
|
||||
use windows::Win32::Graphics::Direct2D::D2D1CreateFactory;
|
||||
use windows::Win32::Graphics::Direct2D::ID2D1Factory;
|
||||
use windows::Win32::Graphics::Direct2D::ID2D1SolidColorBrush;
|
||||
use windows::Win32::Graphics::Dwm::DWM_BB_BLURREGION;
|
||||
use windows::Win32::Graphics::Dwm::DWM_BB_ENABLE;
|
||||
use windows::Win32::Graphics::Dwm::DWM_BLURBEHIND;
|
||||
use windows::Win32::Graphics::Dwm::DwmEnableBlurBehindWindow;
|
||||
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
|
||||
use windows::Win32::Graphics::Gdi::CreateRectRgn;
|
||||
use windows::Win32::Graphics::Gdi::InvalidateRect;
|
||||
use windows::Win32::Graphics::Gdi::ValidateRect;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CREATESTRUCTW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetSystemMetrics;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LoadCursorW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetCursor;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CREATESTRUCTW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EVENT_OBJECT_DESTROY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EVENT_OBJECT_LOCATIONCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWLP_USERDATA;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetSystemMetrics;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IDC_ARROW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LoadCursorW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MSG;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SM_CXVIRTUALSCREEN;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetCursor;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_CREATE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_PAINT;
|
||||
@@ -102,10 +102,10 @@ pub extern "system" fn border_hwnds(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
let hwnds = unsafe { &mut *(lparam.0 as *mut Vec<isize>) };
|
||||
let hwnd = hwnd.0 as isize;
|
||||
|
||||
if let Ok(class) = WindowsApi::real_window_class_w(hwnd) {
|
||||
if class.starts_with("komoborder") {
|
||||
hwnds.push(hwnd);
|
||||
}
|
||||
if let Ok(class) = WindowsApi::real_window_class_w(hwnd)
|
||||
&& class.starts_with("komoborder")
|
||||
{
|
||||
hwnds.push(hwnd);
|
||||
}
|
||||
|
||||
true.into()
|
||||
@@ -392,63 +392,63 @@ impl Border {
|
||||
tracing::error!("failed to update border position {error}");
|
||||
}
|
||||
|
||||
if !rect.is_same_size_as(&old_rect) || !rect.has_same_position_as(&old_rect) {
|
||||
if let Some(render_target) = (*border_pointer).render_target.as_ref() {
|
||||
let border_width = (*border_pointer).width;
|
||||
let border_offset = (*border_pointer).offset;
|
||||
if (!rect.is_same_size_as(&old_rect) || !rect.has_same_position_as(&old_rect))
|
||||
&& let Some(render_target) = (*border_pointer).render_target.as_ref()
|
||||
{
|
||||
let border_width = (*border_pointer).width;
|
||||
let border_offset = (*border_pointer).offset;
|
||||
|
||||
(*border_pointer).rounded_rect.rect = D2D_RECT_F {
|
||||
left: (border_width / 2 - border_offset) as f32,
|
||||
top: (border_width / 2 - border_offset) as f32,
|
||||
right: (rect.right - border_width / 2 + border_offset) as f32,
|
||||
bottom: (rect.bottom - border_width / 2 + border_offset) as f32,
|
||||
(*border_pointer).rounded_rect.rect = D2D_RECT_F {
|
||||
left: (border_width / 2 - border_offset) as f32,
|
||||
top: (border_width / 2 - border_offset) as f32,
|
||||
right: (rect.right - border_width / 2 + border_offset) as f32,
|
||||
bottom: (rect.bottom - border_width / 2 + border_offset) as f32,
|
||||
};
|
||||
|
||||
let _ = render_target.Resize(&D2D_SIZE_U {
|
||||
width: rect.right as u32,
|
||||
height: rect.bottom as u32,
|
||||
});
|
||||
|
||||
let window_kind = (*border_pointer).window_kind;
|
||||
if let Some(brush) = (*border_pointer).brushes.get(&window_kind) {
|
||||
render_target.BeginDraw();
|
||||
render_target.Clear(None);
|
||||
|
||||
// Calculate border radius based on style
|
||||
let style = match (*border_pointer).style {
|
||||
BorderStyle::System => {
|
||||
if *WINDOWS_11 {
|
||||
BorderStyle::Rounded
|
||||
} else {
|
||||
BorderStyle::Square
|
||||
}
|
||||
}
|
||||
BorderStyle::Rounded => BorderStyle::Rounded,
|
||||
BorderStyle::Square => BorderStyle::Square,
|
||||
};
|
||||
|
||||
let _ = render_target.Resize(&D2D_SIZE_U {
|
||||
width: rect.right as u32,
|
||||
height: rect.bottom as u32,
|
||||
});
|
||||
|
||||
let window_kind = (*border_pointer).window_kind;
|
||||
if let Some(brush) = (*border_pointer).brushes.get(&window_kind) {
|
||||
render_target.BeginDraw();
|
||||
render_target.Clear(None);
|
||||
|
||||
// Calculate border radius based on style
|
||||
let style = match (*border_pointer).style {
|
||||
BorderStyle::System => {
|
||||
if *WINDOWS_11 {
|
||||
BorderStyle::Rounded
|
||||
} else {
|
||||
BorderStyle::Square
|
||||
}
|
||||
}
|
||||
BorderStyle::Rounded => BorderStyle::Rounded,
|
||||
BorderStyle::Square => BorderStyle::Square,
|
||||
};
|
||||
|
||||
match style {
|
||||
BorderStyle::Rounded => {
|
||||
render_target.DrawRoundedRectangle(
|
||||
&(*border_pointer).rounded_rect,
|
||||
brush,
|
||||
border_width as f32,
|
||||
None,
|
||||
);
|
||||
}
|
||||
BorderStyle::Square => {
|
||||
render_target.DrawRectangle(
|
||||
&(*border_pointer).rounded_rect.rect,
|
||||
brush,
|
||||
border_width as f32,
|
||||
None,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
match style {
|
||||
BorderStyle::Rounded => {
|
||||
render_target.DrawRoundedRectangle(
|
||||
&(*border_pointer).rounded_rect,
|
||||
brush,
|
||||
border_width as f32,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = render_target.EndDraw(None, None);
|
||||
BorderStyle::Square => {
|
||||
render_target.DrawRectangle(
|
||||
&(*border_pointer).rounded_rect.rect,
|
||||
brush,
|
||||
border_width as f32,
|
||||
None,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let _ = render_target.EndDraw(None, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
mod border;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::core::BorderImplementation;
|
||||
use crate::core::BorderStyle;
|
||||
use crate::core::WindowKind;
|
||||
@@ -8,10 +10,8 @@ use crate::ring::Ring;
|
||||
use crate::windows_api;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use border::border_hwnds;
|
||||
pub use border::Border;
|
||||
use border::border_hwnds;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -22,15 +22,15 @@ use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use strum::Display;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Graphics::Direct2D::ID2D1HwndRenderTarget;
|
||||
@@ -170,13 +170,15 @@ fn window_kind_colour(focus_kind: WindowKind) -> u32 {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -209,9 +211,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
.iter()
|
||||
.map(|w| w.hwnd)
|
||||
.collect::<Vec<_>>();
|
||||
let workspace_layer = *state.monitors.elements()[focused_monitor_idx].workspaces()
|
||||
let workspace_layer = state.monitors.elements()[focused_monitor_idx].workspaces()
|
||||
[focused_workspace_idx]
|
||||
.layer();
|
||||
.layer;
|
||||
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
|
||||
let layer_changed = previous_layer != workspace_layer;
|
||||
let forced_update = matches!(notification, Notification::ForceUpdate);
|
||||
@@ -224,7 +226,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
// Only operate on the focused workspace of each monitor
|
||||
if let Some(ws) = m.focused_workspace() {
|
||||
// Handle the monocle container separately
|
||||
if let Some(monocle) = ws.monocle_container() {
|
||||
if let Some(monocle) = &ws.monocle_container {
|
||||
let window_kind = if monitor_idx != focused_monitor_idx {
|
||||
WindowKind::Unfocused
|
||||
} else {
|
||||
@@ -237,7 +239,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
.unwrap_or_default()
|
||||
.set_accent(window_kind_colour(window_kind))?;
|
||||
|
||||
if ws.layer() == &WorkspaceLayer::Floating {
|
||||
if ws.layer == WorkspaceLayer::Floating {
|
||||
for window in ws.floating_windows() {
|
||||
let mut window_kind = WindowKind::Unfocused;
|
||||
|
||||
@@ -255,7 +257,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let window_kind = if idx != ws.focused_container_idx()
|
||||
|| monitor_idx != focused_monitor_idx
|
||||
{
|
||||
if c.locked() {
|
||||
if c.locked {
|
||||
WindowKind::UnfocusedLocked
|
||||
} else {
|
||||
WindowKind::Unfocused
|
||||
@@ -339,15 +341,11 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
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;
|
||||
}
|
||||
}
|
||||
if !should_process_notification
|
||||
&& let Some(Notification::Update(ref previous)) = previous_notification
|
||||
&& previous.unwrap_or_default() != notification_hwnd.unwrap_or_default()
|
||||
{
|
||||
should_process_notification = true;
|
||||
}
|
||||
|
||||
should_process_notification
|
||||
@@ -383,7 +381,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
// Only operate on the focused workspace of each monitor
|
||||
if let Some(ws) = m.focused_workspace() {
|
||||
// Workspaces with tiling disabled don't have borders
|
||||
if !ws.tile() {
|
||||
if !ws.tile {
|
||||
// Remove all borders on this monitor
|
||||
remove_borders(
|
||||
&mut borders,
|
||||
@@ -396,16 +394,16 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
}
|
||||
|
||||
// Handle the monocle container separately
|
||||
if let Some(monocle) = ws.monocle_container() {
|
||||
if let Some(monocle) = &ws.monocle_container {
|
||||
let mut new_border = false;
|
||||
let focused_window_hwnd =
|
||||
monocle.focused_window().map(|w| w.hwnd).unwrap_or_default();
|
||||
let id = monocle.id().clone();
|
||||
let id = monocle.id.clone();
|
||||
let border = match borders.entry(id.clone()) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(border) = Border::create(
|
||||
monocle.id(),
|
||||
&monocle.id,
|
||||
focused_window_hwnd,
|
||||
monitor_idx,
|
||||
) {
|
||||
@@ -463,7 +461,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
|
||||
let border_hwnd = border.hwnd;
|
||||
|
||||
if ws.layer() == &WorkspaceLayer::Floating {
|
||||
if ws.layer == WorkspaceLayer::Floating {
|
||||
handle_floating_borders(
|
||||
&mut borders,
|
||||
&mut windows_borders,
|
||||
@@ -502,8 +500,8 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let foreground_hwnd = WindowsApi::foreground_window().unwrap_or_default();
|
||||
let foreground_monitor_id =
|
||||
WindowsApi::monitor_from_window(foreground_hwnd);
|
||||
let is_maximized = foreground_monitor_id == m.id()
|
||||
&& WindowsApi::is_zoomed(foreground_hwnd);
|
||||
let is_maximized =
|
||||
foreground_monitor_id == m.id && WindowsApi::is_zoomed(foreground_hwnd);
|
||||
|
||||
if is_maximized {
|
||||
// Remove all borders on this monitor
|
||||
@@ -521,7 +519,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let mut container_and_floating_window_ids = ws
|
||||
.containers()
|
||||
.iter()
|
||||
.map(|c| c.id().clone())
|
||||
.map(|c| c.id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for w in ws.floating_windows() {
|
||||
@@ -539,7 +537,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
'containers: for (idx, c) in ws.containers().iter().enumerate() {
|
||||
let focused_window_hwnd =
|
||||
c.focused_window().map(|w| w.hwnd).unwrap_or_default();
|
||||
let id = c.id().clone();
|
||||
let id = c.id.clone();
|
||||
|
||||
// Get the border entry for this container from the map or create one
|
||||
let mut new_border = false;
|
||||
@@ -547,7 +545,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(border) =
|
||||
Border::create(c.id(), focused_window_hwnd, monitor_idx)
|
||||
Border::create(&c.id, focused_window_hwnd, monitor_idx)
|
||||
{
|
||||
new_border = true;
|
||||
entry.insert(border)
|
||||
@@ -563,7 +561,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
|| monitor_idx != focused_monitor_idx
|
||||
|| focused_window_hwnd != foreground_window
|
||||
{
|
||||
if c.locked() {
|
||||
if c.locked {
|
||||
WindowKind::UnfocusedLocked
|
||||
} else {
|
||||
WindowKind::Unfocused
|
||||
@@ -603,7 +601,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let rect = match WindowsApi::window_rect(focused_window_hwnd) {
|
||||
Ok(rect) => rect,
|
||||
Err(_) => {
|
||||
remove_border(c.id(), &mut borders, &mut windows_borders)?;
|
||||
remove_border(&c.id, &mut borders, &mut windows_borders)?;
|
||||
continue 'containers;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::ops::Deref;
|
||||
use windows::core::IUnknown;
|
||||
use windows::core::IUnknown_Vtbl;
|
||||
use windows::core::GUID;
|
||||
use windows::core::HRESULT;
|
||||
use windows::core::HSTRING;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::core::PWSTR;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Foundation::RECT;
|
||||
use windows::Win32::Foundation::SIZE;
|
||||
use windows::Win32::UI::Shell::Common::IObjectArray;
|
||||
use windows::core::GUID;
|
||||
use windows::core::HRESULT;
|
||||
use windows::core::HSTRING;
|
||||
use windows::core::IUnknown;
|
||||
use windows::core::IUnknown_Vtbl;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::core::PWSTR;
|
||||
use windows_core::BOOL;
|
||||
|
||||
type DesktopID = GUID;
|
||||
@@ -129,7 +129,7 @@ pub unsafe trait IApplicationView: IUnknown {
|
||||
pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17
|
||||
pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT;
|
||||
pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT)
|
||||
-> HRESULT;
|
||||
-> HRESULT;
|
||||
|
||||
/*** IApplicationView methods ***/
|
||||
pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20
|
||||
|
||||
@@ -11,11 +11,11 @@ use interfaces::IServiceProvider;
|
||||
use std::ffi::c_void;
|
||||
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::System::Com::CLSCTX_ALL;
|
||||
use windows::Win32::System::Com::COINIT_MULTITHREADED;
|
||||
use windows::Win32::System::Com::CoCreateInstance;
|
||||
use windows::Win32::System::Com::CoInitializeEx;
|
||||
use windows::Win32::System::Com::CoUninitialize;
|
||||
use windows::Win32::System::Com::CLSCTX_ALL;
|
||||
use windows::Win32::System::Com::COINIT_MULTITHREADED;
|
||||
use windows_core::Interface;
|
||||
|
||||
struct ComInit();
|
||||
@@ -64,7 +64,7 @@ fn get_iapplication_view_collection(provider: &IServiceProvider) -> IApplication
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn SetCloak(hwnd: HWND, cloak_type: u32, flags: i32) {
|
||||
COM_INIT.with(|_| {
|
||||
let provider = get_iservice_provider();
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use getset::CopyGetters;
|
||||
use getset::Getters;
|
||||
use getset::Setters;
|
||||
use nanoid::nanoid;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::Lockable;
|
||||
use crate::ring::Ring;
|
||||
use crate::window::Window;
|
||||
use crate::Lockable;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters, CopyGetters, Setters)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Container {
|
||||
#[getset(get = "pub")]
|
||||
id: String,
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
locked: bool,
|
||||
pub locked: bool,
|
||||
windows: Ring<Window>,
|
||||
}
|
||||
|
||||
@@ -50,12 +45,11 @@ impl Container {
|
||||
for window in self.windows().iter().rev() {
|
||||
let mut should_hide = omit.is_none();
|
||||
|
||||
if !should_hide {
|
||||
if let Some(omit) = omit {
|
||||
if omit != window.hwnd {
|
||||
should_hide = true
|
||||
}
|
||||
}
|
||||
if !should_hide
|
||||
&& let Some(omit) = omit
|
||||
&& omit != window.hwnd
|
||||
{
|
||||
should_hide = true
|
||||
}
|
||||
|
||||
if should_hide {
|
||||
@@ -87,10 +81,10 @@ impl Container {
|
||||
|
||||
pub fn hwnd_from_exe(&self, exe: &str) -> Option<isize> {
|
||||
for window in self.windows() {
|
||||
if let Ok(window_exe) = window.exe() {
|
||||
if exe == window_exe {
|
||||
return Option::from(window.hwnd);
|
||||
}
|
||||
if let Ok(window_exe) = window.exe()
|
||||
&& exe == window_exe
|
||||
{
|
||||
return Option::from(window.hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,10 +93,10 @@ impl Container {
|
||||
|
||||
pub fn idx_from_exe(&self, exe: &str) -> Option<usize> {
|
||||
for (idx, window) in self.windows().iter().enumerate() {
|
||||
if let Ok(window_exe) = window.exe() {
|
||||
if exe == window_exe {
|
||||
return Option::from(idx);
|
||||
}
|
||||
if let Ok(window_exe) = window.exe()
|
||||
&& exe == window_exe
|
||||
{
|
||||
return Option::from(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +272,8 @@ mod tests {
|
||||
}"#;
|
||||
let container: Container = serde_json::from_str(json).expect("Should deserialize");
|
||||
|
||||
assert!(!container.locked());
|
||||
assert_eq!(container.id(), "test-1");
|
||||
assert!(!container.locked);
|
||||
assert_eq!(container.id, "test-1");
|
||||
assert!(container.windows().is_empty());
|
||||
|
||||
let json = r#"{
|
||||
@@ -287,8 +281,8 @@ mod tests {
|
||||
"windows": { "elements": [ { "hwnd": 5 }, { "hwnd": 9 } ], "focused": 1 }
|
||||
}"#;
|
||||
let container: Container = serde_json::from_str(json).unwrap();
|
||||
assert_eq!(container.id(), "test-2");
|
||||
assert!(!container.locked());
|
||||
assert_eq!(container.id, "test-2");
|
||||
assert!(!container.locked);
|
||||
assert_eq!(container.windows(), &[Window::from(5), Window::from(9)]);
|
||||
assert_eq!(container.focused_window_idx(), 1);
|
||||
}
|
||||
@@ -302,7 +296,7 @@ mod tests {
|
||||
let deserialized: Container =
|
||||
serde_json::from_str(&serialized).expect("Should deserialize");
|
||||
|
||||
assert!(deserialized.locked());
|
||||
assert_eq!(deserialized.id(), container.id());
|
||||
assert!(deserialized.locked);
|
||||
assert_eq!(deserialized.id, container.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use clap::ValueEnum;
|
||||
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde::ser::SerializeSeq;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
use super::custom_layout::Column;
|
||||
use super::custom_layout::ColumnSplit;
|
||||
use super::custom_layout::ColumnSplitWithCapacity;
|
||||
use super::CustomLayout;
|
||||
use super::DefaultLayout;
|
||||
use super::Rect;
|
||||
use super::custom_layout::Column;
|
||||
use super::custom_layout::ColumnSplit;
|
||||
use super::custom_layout::ColumnSplitWithCapacity;
|
||||
use crate::default_layout::LayoutOptions;
|
||||
|
||||
pub trait Arrangement {
|
||||
@@ -52,94 +52,83 @@ impl Arrangement for DefaultLayout {
|
||||
let column_width = area.right / column_count as i32;
|
||||
let mut layouts = Vec::with_capacity(len);
|
||||
|
||||
match len {
|
||||
// treat < 3 windows the same as the columns layout
|
||||
len if len < 3 => {
|
||||
layouts = columns(area, len);
|
||||
let visible_columns = area.right / column_width;
|
||||
let keep_centered = layout_options
|
||||
.and_then(|o| {
|
||||
o.scrolling
|
||||
.map(|s| s.center_focused_column.unwrap_or_default())
|
||||
})
|
||||
.unwrap_or(false);
|
||||
|
||||
let adjustment = calculate_columns_adjustment(resize_dimensions);
|
||||
layouts.iter_mut().zip(adjustment.iter()).for_each(
|
||||
|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
},
|
||||
);
|
||||
let first_visible: isize = if focused_idx == 0 {
|
||||
// if focused idx is 0, we are at the beginning of the scrolling strip
|
||||
0
|
||||
} else {
|
||||
let previous_first_visible = if latest_layout.is_empty() {
|
||||
0
|
||||
} else {
|
||||
// previous first_visible based on the left position of the first visible window
|
||||
let left_edge = area.left;
|
||||
latest_layout
|
||||
.iter()
|
||||
.position(|rect| rect.left >= left_edge)
|
||||
.unwrap_or(0) as isize
|
||||
};
|
||||
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
columns_reverse(&mut layouts);
|
||||
}
|
||||
}
|
||||
}
|
||||
// treat >= column_count as scrolling
|
||||
len => {
|
||||
let visible_columns = area.right / column_width;
|
||||
let first_visible: isize = if focused_idx == 0 {
|
||||
// if focused idx is 0, we are at the beginning of the scrolling strip
|
||||
0
|
||||
let focused_idx = focused_idx as isize;
|
||||
|
||||
// if center_focused_column is enabled, and we have an odd number of visible columns,
|
||||
// center the focused window column
|
||||
if keep_centered && visible_columns % 2 == 1 {
|
||||
let center_offset = visible_columns as isize / 2;
|
||||
(focused_idx - center_offset).max(0).min(
|
||||
(len as isize)
|
||||
.saturating_sub(visible_columns as isize)
|
||||
.max(0),
|
||||
)
|
||||
} else {
|
||||
if focused_idx < previous_first_visible {
|
||||
// focused window is off the left edge, we need to scroll left
|
||||
focused_idx
|
||||
} else if focused_idx >= previous_first_visible + visible_columns as isize {
|
||||
// focused window is off the right edge, we need to scroll right
|
||||
// and make sure it's the last visible window
|
||||
(focused_idx + 1 - visible_columns as isize).max(0)
|
||||
} else {
|
||||
let previous_first_visible = if latest_layout.is_empty() {
|
||||
0
|
||||
} else {
|
||||
// previous first_visible based on the left position of the first visible window
|
||||
let left_edge = area.left;
|
||||
latest_layout
|
||||
.iter()
|
||||
.position(|rect| rect.left >= left_edge)
|
||||
.unwrap_or(0) as isize
|
||||
};
|
||||
|
||||
let focused_idx = focused_idx as isize;
|
||||
|
||||
if focused_idx < previous_first_visible {
|
||||
// focused window is off the left edge, we need to scroll left
|
||||
focused_idx
|
||||
} else if focused_idx
|
||||
>= previous_first_visible + visible_columns as isize
|
||||
{
|
||||
// focused window is off the right edge, we need to scroll right
|
||||
// and make sure it's the last visible window
|
||||
(focused_idx + 1 - visible_columns as isize).max(0)
|
||||
} else {
|
||||
// focused window is already visible, we don't need to scroll
|
||||
previous_first_visible
|
||||
}
|
||||
.min(
|
||||
(len as isize)
|
||||
.saturating_sub(visible_columns as isize)
|
||||
.max(0),
|
||||
)
|
||||
};
|
||||
|
||||
for i in 0..len {
|
||||
let position = (i as isize) - first_visible;
|
||||
let left = area.left + (position as i32 * column_width);
|
||||
|
||||
layouts.push(Rect {
|
||||
left,
|
||||
top: area.top,
|
||||
right: column_width,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
// focused window is already visible, we don't need to scroll
|
||||
previous_first_visible
|
||||
}
|
||||
|
||||
let adjustment = calculate_scrolling_adjustment(resize_dimensions);
|
||||
layouts.iter_mut().zip(adjustment.iter()).for_each(
|
||||
|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
},
|
||||
);
|
||||
.min(
|
||||
(len as isize)
|
||||
.saturating_sub(visible_columns as isize)
|
||||
.max(0),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..len {
|
||||
let position = (i as isize) - first_visible;
|
||||
let left = area.left + (position as i32 * column_width);
|
||||
|
||||
layouts.push(Rect {
|
||||
left,
|
||||
top: area.top,
|
||||
right: column_width,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
}
|
||||
|
||||
let adjustment = calculate_scrolling_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::BSP => recursive_fibonacci(
|
||||
@@ -166,10 +155,9 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
columns_reverse(&mut layouts);
|
||||
}
|
||||
) && let 2.. = len
|
||||
{
|
||||
columns_reverse(&mut layouts);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -191,10 +179,9 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
rows_reverse(&mut layouts);
|
||||
}
|
||||
) && let 2.. = len
|
||||
{
|
||||
rows_reverse(&mut layouts);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -245,25 +232,23 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
) && let 2.. = len
|
||||
{
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left;
|
||||
}
|
||||
primary.left = rest[0].left + rest[0].right;
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left;
|
||||
}
|
||||
primary.left = rest[0].left + rest[0].right;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 3.. = len {
|
||||
rows_reverse(&mut layouts[1..]);
|
||||
}
|
||||
) && let 3.. = len
|
||||
{
|
||||
rows_reverse(&mut layouts[1..]);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -317,25 +302,23 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
) && let 2.. = len
|
||||
{
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
primary.left = rest[0].left;
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left + primary.right;
|
||||
}
|
||||
primary.left = rest[0].left;
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left + primary.right;
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 3.. = len {
|
||||
rows_reverse(&mut layouts[1..]);
|
||||
}
|
||||
) && let 3.. = len
|
||||
{
|
||||
rows_reverse(&mut layouts[1..]);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -386,25 +369,23 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 2.. = len {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
) && let 2.. = len
|
||||
{
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
for rect in rest.iter_mut() {
|
||||
rect.top = primary.top;
|
||||
}
|
||||
primary.top = rest[0].top + rest[0].bottom;
|
||||
for rect in rest.iter_mut() {
|
||||
rect.top = primary.top;
|
||||
}
|
||||
primary.top = rest[0].top + rest[0].bottom;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 3.. = len {
|
||||
columns_reverse(&mut layouts[1..]);
|
||||
}
|
||||
) && let 3.. = len
|
||||
{
|
||||
columns_reverse(&mut layouts[1..]);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -513,10 +494,9 @@ impl Arrangement for DefaultLayout {
|
||||
if matches!(
|
||||
layout_flip,
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical)
|
||||
) {
|
||||
if let 4.. = len {
|
||||
rows_reverse(&mut layouts[2..]);
|
||||
}
|
||||
) && let 4.. = len
|
||||
{
|
||||
rows_reverse(&mut layouts[2..]);
|
||||
}
|
||||
|
||||
layouts
|
||||
@@ -782,67 +762,67 @@ fn calculate_resize_adjustments(resize_dimensions: &[Option<Rect>]) -> Vec<Optio
|
||||
|
||||
// This needs to be aware of layout flips
|
||||
for (i, opt) in resize_dimensions.iter().enumerate() {
|
||||
if let Some(resize_ref) = opt {
|
||||
if i > 0 {
|
||||
if resize_ref.left != 0 {
|
||||
#[allow(clippy::if_not_else)]
|
||||
let range = if i == 1 {
|
||||
0..1
|
||||
} else if i & 1 != 0 {
|
||||
i - 1..i
|
||||
} else {
|
||||
i - 2..i
|
||||
};
|
||||
if let Some(resize_ref) = opt
|
||||
&& i > 0
|
||||
{
|
||||
if resize_ref.left != 0 {
|
||||
#[allow(clippy::if_not_else)]
|
||||
let range = if i == 1 {
|
||||
0..1
|
||||
} else if i & 1 != 0 {
|
||||
i - 1..i
|
||||
} else {
|
||||
i - 2..i
|
||||
};
|
||||
|
||||
for n in range {
|
||||
let should_adjust = n % 2 == 0;
|
||||
if should_adjust {
|
||||
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
||||
adjacent_resize.right += resize_ref.left;
|
||||
} else {
|
||||
resize_adjustments[n] = Option::from(Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: resize_ref.left,
|
||||
bottom: 0,
|
||||
});
|
||||
}
|
||||
for n in range {
|
||||
let should_adjust = n % 2 == 0;
|
||||
if should_adjust {
|
||||
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
||||
adjacent_resize.right += resize_ref.left;
|
||||
} else {
|
||||
resize_adjustments[n] = Option::from(Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: resize_ref.left,
|
||||
bottom: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(rr) = resize_adjustments[i].as_mut() {
|
||||
rr.left = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if resize_ref.top != 0 {
|
||||
let range = if i == 1 {
|
||||
0..1
|
||||
} else if i & 1 == 0 {
|
||||
i - 1..i
|
||||
} else {
|
||||
i - 2..i
|
||||
};
|
||||
if let Some(rr) = resize_adjustments[i].as_mut() {
|
||||
rr.left = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for n in range {
|
||||
let should_adjust = n % 2 != 0;
|
||||
if should_adjust {
|
||||
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
||||
adjacent_resize.bottom += resize_ref.top;
|
||||
} else {
|
||||
resize_adjustments[n] = Option::from(Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: resize_ref.top,
|
||||
});
|
||||
}
|
||||
if resize_ref.top != 0 {
|
||||
let range = if i == 1 {
|
||||
0..1
|
||||
} else if i & 1 == 0 {
|
||||
i - 1..i
|
||||
} else {
|
||||
i - 2..i
|
||||
};
|
||||
|
||||
for n in range {
|
||||
let should_adjust = n % 2 != 0;
|
||||
if should_adjust {
|
||||
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
||||
adjacent_resize.bottom += resize_ref.top;
|
||||
} else {
|
||||
resize_adjustments[n] = Option::from(Rect {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: resize_ref.top,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Some(resize)) = resize_adjustments.get_mut(i) {
|
||||
resize.top = 0;
|
||||
}
|
||||
if let Some(Some(resize)) = resize_adjustments.get_mut(i) {
|
||||
resize.top = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -927,7 +907,7 @@ fn recursive_fibonacci(
|
||||
right: resized.right,
|
||||
bottom: resized.bottom,
|
||||
}]
|
||||
} else if idx % 2 != 0 {
|
||||
} else if !idx.is_multiple_of(2) {
|
||||
let mut res = vec![Rect {
|
||||
left: resized.left,
|
||||
top: main_y,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::config_generation::ApplicationConfiguration;
|
||||
use crate::config_generation::ApplicationOptions;
|
||||
use crate::config_generation::MatchingRule;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -36,12 +36,12 @@ impl DerefMut for ApplicationSpecificConfiguration {
|
||||
}
|
||||
|
||||
impl ApplicationSpecificConfiguration {
|
||||
pub fn load(pathbuf: &PathBuf) -> Result<Self> {
|
||||
pub fn load(pathbuf: &PathBuf) -> eyre::Result<Self> {
|
||||
let content = std::fs::read_to_string(pathbuf)?;
|
||||
Ok(serde_json::from_str(&content)?)
|
||||
}
|
||||
|
||||
pub fn format(pathbuf: &PathBuf) -> Result<String> {
|
||||
pub fn format(pathbuf: &PathBuf) -> eyre::Result<String> {
|
||||
Ok(serde_json::to_string_pretty(&Self::load(pathbuf)?)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use clap::ValueEnum;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use strum::Display;
|
||||
@@ -142,11 +142,11 @@ impl ApplicationConfiguration {
|
||||
pub struct ApplicationConfigurationGenerator;
|
||||
|
||||
impl ApplicationConfigurationGenerator {
|
||||
pub fn load(content: &str) -> Result<Vec<ApplicationConfiguration>> {
|
||||
pub fn load(content: &str) -> eyre::Result<Vec<ApplicationConfiguration>> {
|
||||
Ok(serde_yaml::from_str(content)?)
|
||||
}
|
||||
|
||||
pub fn format(content: &str) -> Result<String> {
|
||||
pub fn format(content: &str) -> eyre::Result<String> {
|
||||
let mut cfgen = Self::load(content)?;
|
||||
for cfg in &mut cfgen {
|
||||
cfg.populate_default_matching_strategies();
|
||||
@@ -156,7 +156,10 @@ impl ApplicationConfigurationGenerator {
|
||||
Ok(serde_yaml::to_string(&cfgen)?)
|
||||
}
|
||||
|
||||
fn merge(base_content: &str, override_content: &str) -> Result<Vec<ApplicationConfiguration>> {
|
||||
fn merge(
|
||||
base_content: &str,
|
||||
override_content: &str,
|
||||
) -> eyre::Result<Vec<ApplicationConfiguration>> {
|
||||
let base_cfgen = Self::load(base_content)?;
|
||||
let override_cfgen = Self::load(override_content)?;
|
||||
|
||||
@@ -182,7 +185,7 @@ impl ApplicationConfigurationGenerator {
|
||||
pub fn generate_pwsh(
|
||||
base_content: &str,
|
||||
override_content: Option<&str>,
|
||||
) -> Result<Vec<String>> {
|
||||
) -> eyre::Result<Vec<String>> {
|
||||
let mut cfgen = if let Some(override_content) = override_content {
|
||||
Self::merge(base_content, override_content)?
|
||||
} else {
|
||||
@@ -233,7 +236,10 @@ impl ApplicationConfigurationGenerator {
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
pub fn generate_ahk(base_content: &str, override_content: Option<&str>) -> Result<Vec<String>> {
|
||||
pub fn generate_ahk(
|
||||
base_content: &str,
|
||||
override_content: Option<&str>,
|
||||
) -> eyre::Result<Vec<String>> {
|
||||
let mut cfgen = if let Some(override_content) = override_content {
|
||||
Self::merge(base_content, override_content)?
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::bail;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
@@ -5,12 +9,6 @@ use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
use std::path::Path;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::Rect;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
@@ -32,7 +30,7 @@ impl DerefMut for CustomLayout {
|
||||
}
|
||||
|
||||
impl CustomLayout {
|
||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||
pub fn from_path<P: AsRef<Path>>(path: P) -> eyre::Result<Self> {
|
||||
let path = path.as_ref();
|
||||
let layout: Self = match path.extension() {
|
||||
Some(extension) if extension == "yaml" || extension == "yml" => {
|
||||
@@ -41,7 +39,7 @@ impl CustomLayout {
|
||||
Some(extension) if extension == "json" => {
|
||||
serde_json::from_reader(BufReader::new(File::open(path)?))?
|
||||
}
|
||||
_ => return Err(anyhow!("custom layouts must be json or yaml files")),
|
||||
_ => bail!("custom layouts must be json or yaml files"),
|
||||
};
|
||||
|
||||
if !layout.is_valid() {
|
||||
|
||||
@@ -37,6 +37,8 @@ pub struct LayoutOptions {
|
||||
pub struct ScrollingLayoutOptions {
|
||||
/// Desired number of visible columns (default: 3)
|
||||
pub columns: usize,
|
||||
/// With an odd number of visible columns, keep the focused window column centered
|
||||
pub center_focused_column: Option<bool>,
|
||||
}
|
||||
|
||||
impl DefaultLayout {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::DefaultLayout;
|
||||
use super::OperationDirection;
|
||||
use super::custom_layout::Column;
|
||||
use super::custom_layout::ColumnSplit;
|
||||
use super::custom_layout::ColumnSplitWithCapacity;
|
||||
use super::custom_layout::CustomLayout;
|
||||
use super::DefaultLayout;
|
||||
use super::OperationDirection;
|
||||
|
||||
pub trait Direction {
|
||||
fn index_in_direction(
|
||||
@@ -105,7 +105,7 @@ impl Direction for DefaultLayout {
|
||||
Self::Scrolling => false,
|
||||
},
|
||||
OperationDirection::Down => match self {
|
||||
Self::BSP => idx != count - 1 && idx % 2 != 0,
|
||||
Self::BSP => idx != count - 1 && !idx.is_multiple_of(2),
|
||||
Self::Columns => false,
|
||||
Self::Rows => idx != count - 1,
|
||||
Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != count - 1,
|
||||
@@ -125,7 +125,7 @@ impl Direction for DefaultLayout {
|
||||
Self::Scrolling => idx != 0,
|
||||
},
|
||||
OperationDirection::Right => match self {
|
||||
Self::BSP => idx % 2 == 0 && idx != count - 1,
|
||||
Self::BSP => idx.is_multiple_of(2) && idx != count - 1,
|
||||
Self::Columns => idx != count - 1,
|
||||
Self::Rows => false,
|
||||
Self::VerticalStack => idx == 0,
|
||||
@@ -149,7 +149,7 @@ impl Direction for DefaultLayout {
|
||||
) -> usize {
|
||||
match self {
|
||||
Self::BSP => {
|
||||
if idx % 2 == 0 {
|
||||
if idx.is_multiple_of(2) {
|
||||
idx - 1
|
||||
} else {
|
||||
idx - 2
|
||||
@@ -193,7 +193,7 @@ impl Direction for DefaultLayout {
|
||||
) -> usize {
|
||||
match self {
|
||||
Self::BSP => {
|
||||
if idx % 2 == 0 {
|
||||
if idx.is_multiple_of(2) {
|
||||
idx - 2
|
||||
} else {
|
||||
idx - 1
|
||||
|
||||
@@ -6,14 +6,14 @@ use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::ValueEnum;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
use crate::animation::prefix::AnimationPrefix;
|
||||
use crate::KomorebiTheme;
|
||||
use crate::animation::prefix::AnimationPrefix;
|
||||
pub use animation::AnimationStyle;
|
||||
pub use arrangement::Arrangement;
|
||||
pub use arrangement::Axis;
|
||||
@@ -27,10 +27,10 @@ pub use default_layout::DefaultLayout;
|
||||
pub use direction::Direction;
|
||||
pub use layout::Layout;
|
||||
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::ResolvedPathBuf;
|
||||
pub use pathext::replace_env_in_path;
|
||||
pub use pathext::resolve_option_hashmap_usize_path;
|
||||
pub use rect::Rect;
|
||||
|
||||
pub mod animation;
|
||||
@@ -248,7 +248,7 @@ pub enum SocketMessage {
|
||||
}
|
||||
|
||||
impl SocketMessage {
|
||||
pub fn as_bytes(&self) -> Result<Vec<u8>> {
|
||||
pub fn as_bytes(&self) -> eyre::Result<Vec<u8>> {
|
||||
Ok(serde_json::to_string(self)?.as_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
@@ -256,7 +256,7 @@ impl SocketMessage {
|
||||
impl FromStr for SocketMessage {
|
||||
type Err = serde_json::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> eyre::Result<Self, Self::Err> {
|
||||
serde_json::from_str(s)
|
||||
}
|
||||
}
|
||||
@@ -550,7 +550,9 @@ mod tests {
|
||||
#[test]
|
||||
fn deserializes() {
|
||||
// Set a variable for testing
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
unsafe {
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
}
|
||||
|
||||
let json = r#"{"type":"WorkspaceLayoutCustomRule","content":[0,0,0,"/path/%VAR%/d"]}"#;
|
||||
let message: SocketMessage = serde_json::from_str(json).unwrap();
|
||||
|
||||
@@ -6,8 +6,8 @@ use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
use super::direction::Direction;
|
||||
use super::Axis;
|
||||
use super::direction::Direction;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
@@ -58,7 +57,7 @@ impl<P: AsRef<Path>> PathExt for P {
|
||||
// if component is a variable, get the value from the environment
|
||||
if let Some(var) = var {
|
||||
let var = unsafe { OsStr::from_encoded_bytes_unchecked(var) };
|
||||
if let Some(value) = env::var_os(var) {
|
||||
if let Some(value) = std::env::var_os(var) {
|
||||
out.push(value);
|
||||
continue;
|
||||
}
|
||||
@@ -127,8 +126,8 @@ impl serde_with::schemars_0_8::JsonSchemaAs<PathBuf> for ResolvedPathBuf {
|
||||
"PathBuf".to_owned()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
<PathBuf as schemars::JsonSchema>::json_schema(gen)
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::schema::Schema {
|
||||
<PathBuf as schemars::JsonSchema>::json_schema(generator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +164,9 @@ mod tests {
|
||||
#[test]
|
||||
fn resolves_env_vars() {
|
||||
// Set a variable for testing
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
unsafe {
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
}
|
||||
|
||||
// %VAR% format
|
||||
assert_eq!(resolve("/path/%VAR%/d"), expected("/path/VALUE/d"));
|
||||
@@ -183,7 +184,9 @@ mod tests {
|
||||
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");
|
||||
unsafe {
|
||||
std::env::set_var("USERPROFILE", "C:\\Users\\user");
|
||||
}
|
||||
|
||||
// ~ and $HOME should be replaced with $Env:USERPROFILE
|
||||
assert_eq!(resolve("~"), expected("C:\\Users\\user"));
|
||||
|
||||
@@ -44,13 +44,15 @@ pub fn send_notification(hwnd: isize) {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,12 +39,12 @@ use std::io::Write;
|
||||
use std::net::TcpStream;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use core::*;
|
||||
pub use komorebi_themes::colour::*;
|
||||
@@ -62,7 +62,7 @@ use crate::core::config_generation::IdWithIdentifier;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
use crate::core::config_generation::WorkspaceMatchingRule;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use os_info::Version;
|
||||
use parking_lot::Mutex;
|
||||
@@ -72,8 +72,8 @@ use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use uds_windows::UnixStream;
|
||||
use which::which;
|
||||
use winreg::enums::HKEY_CURRENT_USER;
|
||||
use winreg::RegKey;
|
||||
use winreg::enums::HKEY_CURRENT_USER;
|
||||
|
||||
lazy_static! {
|
||||
static ref HIDDEN_HWNDS: Arc<Mutex<Vec<isize>>> = Arc::new(Mutex::new(vec![]));
|
||||
@@ -211,11 +211,10 @@ lazy_static! {
|
||||
pub static ref AHK_EXE: String = {
|
||||
let mut ahk: String = String::from("autohotkey.exe");
|
||||
|
||||
if let Ok(komorebi_ahk_exe) = std::env::var("KOMOREBI_AHK_EXE") {
|
||||
if which(&komorebi_ahk_exe).is_ok() {
|
||||
if let Ok(komorebi_ahk_exe) = std::env::var("KOMOREBI_AHK_EXE")
|
||||
&& which(&komorebi_ahk_exe).is_ok() {
|
||||
ahk = komorebi_ahk_exe;
|
||||
}
|
||||
}
|
||||
|
||||
ahk
|
||||
};
|
||||
@@ -330,7 +329,10 @@ pub struct Notification {
|
||||
pub state: State,
|
||||
}
|
||||
|
||||
pub fn notify_subscribers(notification: Notification, state_has_been_modified: bool) -> Result<()> {
|
||||
pub fn notify_subscribers(
|
||||
notification: Notification,
|
||||
state_has_been_modified: bool,
|
||||
) -> eyre::Result<()> {
|
||||
let is_override_event = matches!(
|
||||
notification.event,
|
||||
NotificationEvent::Socket(SocketMessage::AddSubscriberSocket(_))
|
||||
@@ -411,7 +413,7 @@ pub fn notify_subscribers(notification: Notification, state_has_been_modified: b
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_configuration() -> Result<()> {
|
||||
pub fn load_configuration() -> eyre::Result<()> {
|
||||
let config_pwsh = HOME_DIR.join("komorebi.ps1");
|
||||
let config_ahk = HOME_DIR.join("komorebi.ahk");
|
||||
|
||||
|
||||
@@ -10,31 +10,36 @@
|
||||
use std::env::temp_dir;
|
||||
use std::net::Shutdown;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::Parser;
|
||||
use clap::ValueEnum;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::bail;
|
||||
use crossbeam_utils::Backoff;
|
||||
use komorebi::animation::AnimationEngine;
|
||||
use komorebi::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
use komorebi::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
||||
use komorebi::animation::AnimationEngine;
|
||||
use komorebi::replace_env_in_path;
|
||||
use parking_lot::Mutex;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
use parking_lot::deadlock;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use sysinfo::Process;
|
||||
use sysinfo::ProcessesToUpdate;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
use komorebi::CUSTOM_FFM;
|
||||
use komorebi::DATA_DIR;
|
||||
use komorebi::HOME_DIR;
|
||||
use komorebi::INITIAL_CONFIGURATION_LOADED;
|
||||
use komorebi::SESSION_ID;
|
||||
use komorebi::border_manager;
|
||||
use komorebi::focus_manager;
|
||||
use komorebi::load_configuration;
|
||||
@@ -52,30 +57,29 @@ use komorebi::window_manager::State;
|
||||
use komorebi::window_manager::WindowManager;
|
||||
use komorebi::windows_api::WindowsApi;
|
||||
use komorebi::winevent_listener;
|
||||
use komorebi::CUSTOM_FFM;
|
||||
use komorebi::DATA_DIR;
|
||||
use komorebi::HOME_DIR;
|
||||
use komorebi::INITIAL_CONFIGURATION_LOADED;
|
||||
use komorebi::SESSION_ID;
|
||||
|
||||
fn setup(log_level: LogLevel) -> Result<(WorkerGuard, WorkerGuard)> {
|
||||
fn setup(log_level: LogLevel) -> eyre::Result<(WorkerGuard, WorkerGuard)> {
|
||||
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
|
||||
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||
unsafe {
|
||||
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||
}
|
||||
}
|
||||
|
||||
color_eyre::install()?;
|
||||
|
||||
if std::env::var("RUST_LOG").is_err() {
|
||||
std::env::set_var(
|
||||
"RUST_LOG",
|
||||
match log_level {
|
||||
LogLevel::Error => "error",
|
||||
LogLevel::Warn => "warn",
|
||||
LogLevel::Info => "info",
|
||||
LogLevel::Debug => "debug",
|
||||
LogLevel::Trace => "trace",
|
||||
},
|
||||
);
|
||||
unsafe {
|
||||
std::env::set_var(
|
||||
"RUST_LOG",
|
||||
match log_level {
|
||||
LogLevel::Error => "error",
|
||||
LogLevel::Warn => "warn",
|
||||
LogLevel::Info => "info",
|
||||
LogLevel::Debug => "debug",
|
||||
LogLevel::Trace => "trace",
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let appender = tracing_appender::rolling::daily(std::env::temp_dir(), "komorebi_plaintext.log");
|
||||
@@ -134,20 +138,22 @@ fn setup(log_level: LogLevel) -> Result<(WorkerGuard, WorkerGuard)> {
|
||||
#[tracing::instrument]
|
||||
fn detect_deadlocks() {
|
||||
// Create a background thread which checks for deadlocks every 10s
|
||||
std::thread::spawn(move || loop {
|
||||
tracing::info!("running deadlock detector");
|
||||
std::thread::sleep(Duration::from_secs(5));
|
||||
let deadlocks = deadlock::check_deadlock();
|
||||
if deadlocks.is_empty() {
|
||||
continue;
|
||||
}
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
tracing::info!("running deadlock detector");
|
||||
std::thread::sleep(Duration::from_secs(5));
|
||||
let deadlocks = deadlock::check_deadlock();
|
||||
if deadlocks.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
tracing::error!("{} deadlocks detected", deadlocks.len());
|
||||
for (i, threads) in deadlocks.iter().enumerate() {
|
||||
tracing::error!("deadlock #{}", i);
|
||||
for t in threads {
|
||||
tracing::error!("thread id: {:#?}", t.thread_id());
|
||||
tracing::error!("{:#?}", t.backtrace());
|
||||
tracing::error!("{} deadlocks detected", deadlocks.len());
|
||||
for (i, threads) in deadlocks.iter().enumerate() {
|
||||
tracing::error!("deadlock #{}", i);
|
||||
for t in threads {
|
||||
tracing::error!("thread id: {:#?}", t.thread_id());
|
||||
tracing::error!("{:#?}", t.backtrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -190,7 +196,7 @@ struct Opts {
|
||||
|
||||
#[tracing::instrument]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn main() -> Result<()> {
|
||||
fn main() -> eyre::Result<()> {
|
||||
let opts: Opts = Opts::parse();
|
||||
CUSTOM_FFM.store(opts.focus_follows_mouse, Ordering::SeqCst);
|
||||
|
||||
@@ -210,9 +216,7 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
if set_foreground_window_retries == 0 {
|
||||
return Err(anyhow!(
|
||||
"failed call to AllowSetForegroundWindow after 5 retries"
|
||||
));
|
||||
bail!("failed call to AllowSetForegroundWindow after 5 retries");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,15 +233,17 @@ fn main() -> Result<()> {
|
||||
if matched_procs.len() > 1 {
|
||||
let mut len = matched_procs.len();
|
||||
for proc in matched_procs {
|
||||
if let Some(executable_path) = proc.exe() {
|
||||
if executable_path.to_string_lossy().contains("shims") {
|
||||
len -= 1;
|
||||
}
|
||||
if let Some(executable_path) = proc.exe()
|
||||
&& executable_path.to_string_lossy().contains("shims")
|
||||
{
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if len > 1 {
|
||||
tracing::error!("komorebi.exe is already running, please exit the existing process before starting a new one");
|
||||
tracing::error!(
|
||||
"komorebi.exe is already running, please exit the existing process before starting a new one"
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,9 @@ use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::OptionExt;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use getset::CopyGetters;
|
||||
use getset::Getters;
|
||||
use getset::MutGetters;
|
||||
use getset::Setters;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -17,58 +13,40 @@ use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::core::Rect;
|
||||
|
||||
use crate::container::Container;
|
||||
use crate::ring::Ring;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::workspace::WorkspaceGlobals;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::DefaultLayout;
|
||||
use crate::FloatingLayerBehaviour;
|
||||
use crate::Layout;
|
||||
use crate::OperationDirection;
|
||||
use crate::Wallpaper;
|
||||
use crate::WindowsApi;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::container::Container;
|
||||
use crate::ring::Ring;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::workspace::WorkspaceGlobals;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Getters, CopyGetters, MutGetters, Setters, PartialEq,
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Monitor {
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub id: isize,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub name: String,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub device: String,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub device_id: String,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub serial_number_id: Option<String>,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub size: Rect,
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub work_area_size: Rect,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub work_area_offset: Option<Rect>,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub window_based_work_area_offset: Option<Rect>,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub window_based_work_area_offset_limit: isize,
|
||||
pub workspaces: Ring<Workspace>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub last_focused_workspace: Option<usize>,
|
||||
#[getset(get_mut = "pub")]
|
||||
pub workspace_names: HashMap<usize, String>,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub container_padding: Option<i32>,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
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>,
|
||||
}
|
||||
|
||||
@@ -175,23 +153,23 @@ impl Monitor {
|
||||
|
||||
pub fn focused_workspace_name(&self) -> Option<String> {
|
||||
self.focused_workspace()
|
||||
.map(|w| w.name().clone())
|
||||
.map(|w| w.name.clone())
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
pub fn focused_workspace_layout(&self) -> Option<Layout> {
|
||||
self.focused_workspace().and_then(|workspace| {
|
||||
if *workspace.tile() {
|
||||
Some(workspace.layout().clone())
|
||||
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) -> eyre::Result<()> {
|
||||
let focused_idx = self.focused_workspace_idx();
|
||||
let hmonitor = self.id();
|
||||
let hmonitor = self.id;
|
||||
let monitor_wp = self.wallpaper.clone();
|
||||
for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() {
|
||||
if i == focused_idx {
|
||||
@@ -207,10 +185,10 @@ impl Monitor {
|
||||
/// Updates the `globals` field of all workspaces
|
||||
pub fn update_workspaces_globals(&mut self, offset: Option<Rect>) {
|
||||
let container_padding = self
|
||||
.container_padding()
|
||||
.container_padding
|
||||
.or(Some(DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst)));
|
||||
let workspace_padding = self
|
||||
.workspace_padding()
|
||||
.workspace_padding
|
||||
.or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst)));
|
||||
let (border_width, border_offset) = {
|
||||
let border_enabled = BORDER_ENABLED.load(Ordering::SeqCst);
|
||||
@@ -222,11 +200,11 @@ impl Monitor {
|
||||
(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 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 floating_layer_behaviour = self.floating_layer_behaviour();
|
||||
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 floating_layer_behaviour = self.floating_layer_behaviour;
|
||||
|
||||
for workspace in self.workspaces_mut() {
|
||||
workspace.globals = WorkspaceGlobals {
|
||||
@@ -246,10 +224,10 @@ impl Monitor {
|
||||
/// Updates the `globals` field of workspace with index `workspace_idx`
|
||||
pub fn update_workspace_globals(&mut self, workspace_idx: usize, offset: Option<Rect>) {
|
||||
let container_padding = self
|
||||
.container_padding()
|
||||
.container_padding
|
||||
.or(Some(DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst)));
|
||||
let workspace_padding = self
|
||||
.workspace_padding()
|
||||
.workspace_padding
|
||||
.or(Some(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst)));
|
||||
let (border_width, border_offset) = {
|
||||
let border_enabled = BORDER_ENABLED.load(Ordering::SeqCst);
|
||||
@@ -261,11 +239,11 @@ impl Monitor {
|
||||
(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 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 floating_layer_behaviour = self.floating_layer_behaviour();
|
||||
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 floating_layer_behaviour = self.floating_layer_behaviour;
|
||||
|
||||
if let Some(workspace) = self.workspaces_mut().get_mut(workspace_idx) {
|
||||
workspace.globals = WorkspaceGlobals {
|
||||
@@ -286,14 +264,14 @@ impl Monitor {
|
||||
&mut self,
|
||||
container: Container,
|
||||
workspace_idx: Option<usize>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
let workspace = if let Some(idx) = workspace_idx {
|
||||
self.workspaces_mut()
|
||||
.get_mut(idx)
|
||||
.ok_or_else(|| anyhow!("there is no workspace at index {}", idx))?
|
||||
.ok_or_eyre(format!("there is no workspace at index {idx}"))?
|
||||
} else {
|
||||
self.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?
|
||||
.ok_or_eyre("there is no workspace")?
|
||||
};
|
||||
|
||||
workspace.add_container_to_back(container);
|
||||
@@ -310,21 +288,21 @@ impl Monitor {
|
||||
container: Container,
|
||||
workspace_idx: Option<usize>,
|
||||
direction: OperationDirection,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
let workspace = if let Some(idx) = workspace_idx {
|
||||
self.workspaces_mut()
|
||||
.get_mut(idx)
|
||||
.ok_or_else(|| anyhow!("there is no workspace at index {}", idx))?
|
||||
.ok_or_eyre(format!("there is no workspace at index {idx}"))?
|
||||
} else {
|
||||
self.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?
|
||||
.ok_or_eyre("there is no workspace")?
|
||||
};
|
||||
|
||||
match direction {
|
||||
OperationDirection::Left => {
|
||||
// insert the container into the workspace on the monitor at the back (or rightmost position)
|
||||
// if we are moving across a boundary to the left (back = right side of the target)
|
||||
match workspace.layout() {
|
||||
match workspace.layout {
|
||||
Layout::Default(layout) => match layout {
|
||||
DefaultLayout::RightMainVerticalStack => {
|
||||
workspace.add_container_to_front(container);
|
||||
@@ -348,7 +326,7 @@ impl Monitor {
|
||||
OperationDirection::Right => {
|
||||
// insert the container into the workspace on the monitor at the front (or leftmost position)
|
||||
// if we are moving across a boundary to the right (front = left side of the target)
|
||||
match workspace.layout() {
|
||||
match workspace.layout {
|
||||
Layout::Default(layout) => {
|
||||
let target_index = layout.leftmost_index(workspace.containers().len());
|
||||
|
||||
@@ -412,12 +390,12 @@ impl Monitor {
|
||||
target_workspace_idx: usize,
|
||||
follow: bool,
|
||||
direction: Option<OperationDirection>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
let workspace = self
|
||||
.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
.ok_or_eyre("there is no workspace")?;
|
||||
|
||||
if workspace.maximized_window().is_some() {
|
||||
if workspace.maximized_window.is_some() {
|
||||
bail!("cannot move native maximized window to another monitor or workspace");
|
||||
}
|
||||
|
||||
@@ -440,12 +418,12 @@ impl Monitor {
|
||||
};
|
||||
|
||||
target_workspace.floating_windows_mut().push_back(window);
|
||||
target_workspace.set_layer(WorkspaceLayer::Floating);
|
||||
target_workspace.layer = WorkspaceLayer::Floating;
|
||||
}
|
||||
} else {
|
||||
let container = workspace
|
||||
.remove_focused_container()
|
||||
.ok_or_else(|| anyhow!("there is no container"))?;
|
||||
.ok_or_eyre("there is no container")?;
|
||||
|
||||
let workspaces = self.workspaces_mut();
|
||||
|
||||
@@ -458,7 +436,7 @@ impl Monitor {
|
||||
Some(workspace) => workspace,
|
||||
};
|
||||
|
||||
if target_workspace.monocle_container().is_some() {
|
||||
if target_workspace.monocle_container.is_some() {
|
||||
for container in target_workspace.containers_mut() {
|
||||
container.restore();
|
||||
}
|
||||
@@ -470,7 +448,7 @@ impl Monitor {
|
||||
target_workspace.reintegrate_monocle_container()?;
|
||||
}
|
||||
|
||||
target_workspace.set_layer(WorkspaceLayer::Tiling);
|
||||
target_workspace.layer = WorkspaceLayer::Tiling;
|
||||
|
||||
if let Some(direction) = direction {
|
||||
self.add_container_with_direction(
|
||||
@@ -491,7 +469,7 @@ impl Monitor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn focus_workspace(&mut self, idx: usize) -> Result<()> {
|
||||
pub fn focus_workspace(&mut self, idx: usize) -> eyre::Result<()> {
|
||||
tracing::info!("focusing workspace");
|
||||
|
||||
{
|
||||
@@ -500,7 +478,7 @@ impl Monitor {
|
||||
if workspaces.get(idx).is_none() {
|
||||
workspaces.resize(idx + 1, Workspace::default());
|
||||
}
|
||||
self.set_last_focused_workspace(Some(self.workspaces.focused_idx()));
|
||||
self.last_focused_workspace = Some(self.workspaces.focused_idx());
|
||||
self.workspaces.focus(idx);
|
||||
}
|
||||
|
||||
@@ -510,8 +488,8 @@ impl Monitor {
|
||||
if name.is_some() {
|
||||
self.workspaces_mut()
|
||||
.get_mut(idx)
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?
|
||||
.set_name(name);
|
||||
.ok_or_eyre("there is no workspace")?
|
||||
.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,9 +500,9 @@ impl Monitor {
|
||||
self.workspaces().len()
|
||||
}
|
||||
|
||||
pub fn update_focused_workspace(&mut self, offset: Option<Rect>) -> Result<()> {
|
||||
let offset = if self.work_area_offset().is_some() {
|
||||
self.work_area_offset()
|
||||
pub fn update_focused_workspace(&mut self, offset: Option<Rect>) -> eyre::Result<()> {
|
||||
let offset = if self.work_area_offset.is_some() {
|
||||
self.work_area_offset
|
||||
} else {
|
||||
offset
|
||||
};
|
||||
@@ -532,7 +510,7 @@ impl Monitor {
|
||||
let focused_workspace_idx = self.focused_workspace_idx();
|
||||
self.update_workspace_globals(focused_workspace_idx, offset);
|
||||
self.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?
|
||||
.ok_or_eyre("there is no workspace")?
|
||||
.update()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
use windows::core::PCWSTR;
|
||||
use windows::Win32::Devices::Display::GUID_DEVINTERFACE_DISPLAY_ADAPTER;
|
||||
use windows::Win32::Devices::Display::GUID_DEVINTERFACE_MONITOR;
|
||||
use windows::Win32::Devices::Display::GUID_DEVINTERFACE_VIDEO_OUTPUT_ARRIVAL;
|
||||
@@ -11,10 +10,6 @@ use windows::Win32::Foundation::LRESULT;
|
||||
use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::System::Power::POWERBROADCAST_SETTING;
|
||||
use windows::Win32::System::SystemServices::GUID_LIDSWITCH_STATE_CHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DBT_CONFIGCHANGED;
|
||||
@@ -23,6 +18,9 @@ use windows::Win32::UI::WindowsAndMessaging::DBT_DEVICEREMOVECOMPLETE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DBT_DEVNODES_CHANGED;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DBT_DEVTYP_DEVICEINTERFACE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DEV_BROADCAST_DEVICEINTERFACE_W;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MSG;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PBT_APMRESUMEAUTOMATIC;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PBT_APMRESUMESUSPEND;
|
||||
@@ -30,6 +28,7 @@ use windows::Win32::UI::WindowsAndMessaging::PBT_APMSUSPEND;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PBT_POWERSETTINGCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::REGISTER_NOTIFICATION_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETWORKAREA;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_DEVICECHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_DISPLAYCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_POWERBROADCAST;
|
||||
@@ -38,10 +37,11 @@ use windows::Win32::UI::WindowsAndMessaging::WM_WTSSESSION_CHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WTS_SESSION_LOCK;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WTS_SESSION_UNLOCK;
|
||||
use windows::core::PCWSTR;
|
||||
|
||||
use crate::WindowsApi;
|
||||
use crate::monitor_reconciliator;
|
||||
use crate::windows_api;
|
||||
use crate::WindowsApi;
|
||||
|
||||
// This is a hidden window specifically spawned to listen to system-wide events related to monitors
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -224,14 +224,18 @@ impl Hidden {
|
||||
WM_WTSSESSION_CHANGE => {
|
||||
match wparam.0 as u32 {
|
||||
WTS_SESSION_LOCK => {
|
||||
tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_LOCK - screen locked");
|
||||
tracing::debug!(
|
||||
"WM_WTSSESSION_CHANGE event received with WTS_SESSION_LOCK - screen locked"
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::MonitorNotification::SessionLocked,
|
||||
);
|
||||
}
|
||||
WTS_SESSION_UNLOCK => {
|
||||
tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_UNLOCK - screen unlocked");
|
||||
tracing::debug!(
|
||||
"WM_WTSSESSION_CHANGE event received with WTS_SESSION_UNLOCK - screen unlocked"
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::MonitorNotification::SessionUnlocked,
|
||||
@@ -251,7 +255,8 @@ impl Hidden {
|
||||
// and resolution changes here
|
||||
WM_DISPLAYCHANGE => {
|
||||
tracing::debug!(
|
||||
"WM_DISPLAYCHANGE event received with wparam: {}- work area or display resolution changed", wparam.0
|
||||
"WM_DISPLAYCHANGE event received with wparam: {}- work area or display resolution changed",
|
||||
wparam.0
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
@@ -265,8 +270,8 @@ impl Hidden {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
if wparam.0 as u32 == SPI_SETWORKAREA.0 {
|
||||
tracing::debug!(
|
||||
"WM_SETTINGCHANGE event received with SPI_SETWORKAREA - work area changed (probably butterytaskbar or something similar)"
|
||||
);
|
||||
"WM_SETTINGCHANGE event received with SPI_SETWORKAREA - work area changed (probably butterytaskbar or something similar)"
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::MonitorNotification::WorkAreaChanged,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::State;
|
||||
use crate::WORKSPACE_MATCHING_RULES;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::border_manager;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::core::Rect;
|
||||
@@ -7,14 +15,6 @@ use crate::monitor;
|
||||
use crate::monitor::Monitor;
|
||||
use crate::monitor_reconciliator::hidden::Hidden;
|
||||
use crate::notify_subscribers;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::State;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
|
||||
use crate::WORKSPACE_MATCHING_RULES;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
@@ -22,10 +22,10 @@ use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub mod hidden;
|
||||
|
||||
@@ -70,10 +70,10 @@ pub fn send_notification(notification: MonitorNotification) {
|
||||
pub fn insert_in_monitor_cache(serial_or_device_id: &str, monitor: Monitor) {
|
||||
let dip = DISPLAY_INDEX_PREFERENCES.read();
|
||||
let mut dip_ids = dip.values();
|
||||
let preferred_id = if dip_ids.any(|id| id == monitor.device_id()) {
|
||||
monitor.device_id().clone()
|
||||
} else if dip_ids.any(|id| Some(id) == monitor.serial_number_id().as_ref()) {
|
||||
monitor.serial_number_id().clone().unwrap_or_default()
|
||||
let preferred_id = if dip_ids.any(|id| id.eq(&monitor.device_id)) {
|
||||
monitor.device_id.clone()
|
||||
} else if dip_ids.any(|id| Some(id) == monitor.serial_number_id.as_ref()) {
|
||||
monitor.serial_number_id.clone().unwrap_or_default()
|
||||
} else {
|
||||
serial_or_device_id.to_string()
|
||||
};
|
||||
@@ -100,12 +100,12 @@ where
|
||||
}
|
||||
|
||||
for d in &all_displays {
|
||||
if let Some(id) = &d.serial_number_id {
|
||||
if serial_id_map.get(id).copied().unwrap_or_default() > 1 {
|
||||
let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.write();
|
||||
if !dupes.contains(id) {
|
||||
(*dupes).push(id.clone());
|
||||
}
|
||||
if let Some(id) = &d.serial_number_id
|
||||
&& serial_id_map.get(id).copied().unwrap_or_default() > 1
|
||||
{
|
||||
let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.write();
|
||||
if !dupes.contains(id) {
|
||||
(*dupes).push(id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,16 +155,18 @@ pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Re
|
||||
|
||||
tracing::info!("created hidden window to listen for monitor-related events");
|
||||
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone(), win32_display_data::connected_displays_all) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
tracing::error!("restarting failed thread: {:?}", error)
|
||||
} else {
|
||||
tracing::error!("restarting failed thread: {}", error)
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone(), win32_display_data::connected_displays_all) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
tracing::error!("restarting failed thread: {:?}", error)
|
||||
} else {
|
||||
tracing::error!("restarting failed thread: {}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,27 +221,27 @@ where
|
||||
let mut should_update = false;
|
||||
|
||||
// Update work areas as necessary
|
||||
if let Ok(reference) = WindowsApi::monitor(monitor.id()) {
|
||||
if reference.work_area_size() != monitor.work_area_size() {
|
||||
monitor.set_work_area_size(Rect {
|
||||
left: reference.work_area_size().left,
|
||||
top: reference.work_area_size().top,
|
||||
right: reference.work_area_size().right,
|
||||
bottom: reference.work_area_size().bottom,
|
||||
});
|
||||
if let Ok(reference) = WindowsApi::monitor(monitor.id)
|
||||
&& reference.work_area_size != monitor.work_area_size
|
||||
{
|
||||
monitor.work_area_size = Rect {
|
||||
left: reference.work_area_size.left,
|
||||
top: reference.work_area_size.top,
|
||||
right: reference.work_area_size.right,
|
||||
bottom: reference.work_area_size.bottom,
|
||||
};
|
||||
|
||||
should_update = true;
|
||||
}
|
||||
should_update = true;
|
||||
}
|
||||
|
||||
if should_update {
|
||||
tracing::info!("updated work area for {}", monitor.device_id());
|
||||
tracing::info!("updated work area for {}", monitor.device_id);
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
border_manager::send_notification(None);
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"work areas match, reconciliation not required for {}",
|
||||
monitor.device_id()
|
||||
monitor.device_id
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -251,25 +253,25 @@ where
|
||||
let mut should_update = false;
|
||||
|
||||
// Update sizes and work areas as necessary
|
||||
if let Ok(reference) = WindowsApi::monitor(monitor.id()) {
|
||||
if reference.work_area_size() != monitor.work_area_size() {
|
||||
monitor.set_work_area_size(Rect {
|
||||
left: reference.work_area_size().left,
|
||||
top: reference.work_area_size().top,
|
||||
right: reference.work_area_size().right,
|
||||
bottom: reference.work_area_size().bottom,
|
||||
});
|
||||
if let Ok(reference) = WindowsApi::monitor(monitor.id) {
|
||||
if reference.work_area_size != monitor.work_area_size {
|
||||
monitor.work_area_size = Rect {
|
||||
left: reference.work_area_size.left,
|
||||
top: reference.work_area_size.top,
|
||||
right: reference.work_area_size.right,
|
||||
bottom: reference.work_area_size.bottom,
|
||||
};
|
||||
|
||||
should_update = true;
|
||||
}
|
||||
|
||||
if reference.size() != monitor.size() {
|
||||
monitor.set_size(Rect {
|
||||
left: reference.size().left,
|
||||
top: reference.size().top,
|
||||
right: reference.size().right,
|
||||
bottom: reference.size().bottom,
|
||||
});
|
||||
if reference.size != monitor.size {
|
||||
monitor.size = Rect {
|
||||
left: reference.size.left,
|
||||
top: reference.size.top,
|
||||
right: reference.size.right,
|
||||
bottom: reference.size.bottom,
|
||||
};
|
||||
|
||||
should_update = true;
|
||||
}
|
||||
@@ -278,7 +280,7 @@ where
|
||||
if should_update {
|
||||
tracing::info!(
|
||||
"updated monitor resolution/scaling for {}",
|
||||
monitor.device_id()
|
||||
monitor.device_id
|
||||
);
|
||||
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
@@ -286,7 +288,7 @@ where
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"resolutions match, reconciliation not required for {}",
|
||||
monitor.device_id()
|
||||
monitor.device_id
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -311,21 +313,21 @@ where
|
||||
for monitor in wm.monitors_mut() {
|
||||
for attached in &attached_devices {
|
||||
let serial_number_ids_match = if let (Some(attached_snid), Some(m_snid)) =
|
||||
(attached.serial_number_id(), monitor.serial_number_id())
|
||||
(&attached.serial_number_id, &monitor.serial_number_id)
|
||||
{
|
||||
attached_snid.eq(m_snid)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if serial_number_ids_match || attached.device_id().eq(monitor.device_id()) {
|
||||
monitor.set_id(attached.id());
|
||||
monitor.set_device(attached.device().clone());
|
||||
monitor.set_device_id(attached.device_id().clone());
|
||||
monitor.set_serial_number_id(attached.serial_number_id().clone());
|
||||
monitor.set_name(attached.name().clone());
|
||||
monitor.set_size(*attached.size());
|
||||
monitor.set_work_area_size(*attached.work_area_size());
|
||||
if serial_number_ids_match || attached.device_id.eq(&monitor.device_id) {
|
||||
monitor.id = attached.id;
|
||||
monitor.device = attached.device.clone();
|
||||
monitor.device_id = attached.device_id.clone();
|
||||
monitor.serial_number_id = attached.serial_number_id.clone();
|
||||
monitor.name = attached.name.clone();
|
||||
monitor.size = attached.size;
|
||||
monitor.work_area_size = attached.work_area_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,13 +361,13 @@ where
|
||||
|
||||
for (m_idx, m) in wm.monitors().iter().enumerate() {
|
||||
if !attached_devices.iter().any(|attached| {
|
||||
attached.serial_number_id().eq(m.serial_number_id())
|
||||
|| attached.device_id().eq(m.device_id())
|
||||
attached.serial_number_id.eq(&m.serial_number_id)
|
||||
|| attached.device_id.eq(&m.device_id)
|
||||
}) {
|
||||
let id = m
|
||||
.serial_number_id()
|
||||
.serial_number_id
|
||||
.as_ref()
|
||||
.map_or(m.device_id().clone(), |sn| sn.clone());
|
||||
.map_or(m.device_id.clone(), |sn| sn.clone());
|
||||
|
||||
newly_removed_displays.push(id.clone());
|
||||
|
||||
@@ -392,7 +394,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(maximized) = workspace.maximized_window() {
|
||||
if let Some(maximized) = &workspace.maximized_window {
|
||||
windows_to_remove.push(maximized.hwnd);
|
||||
// Minimize the focused window since Windows might try
|
||||
// to move it to another monitor if it was focused.
|
||||
@@ -401,7 +403,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(container) = workspace.monocle_container() {
|
||||
if let Some(container) = &workspace.monocle_container {
|
||||
for window in container.windows() {
|
||||
windows_to_remove.push(window.hwnd);
|
||||
}
|
||||
@@ -440,10 +442,10 @@ where
|
||||
// the user set as preference as the id.
|
||||
let dip = DISPLAY_INDEX_PREFERENCES.read();
|
||||
let mut dip_ids = dip.values();
|
||||
let preferred_id = if dip_ids.any(|id| id == m.device_id()) {
|
||||
m.device_id().clone()
|
||||
} else if dip_ids.any(|id| Some(id) == m.serial_number_id().as_ref()) {
|
||||
m.serial_number_id().clone().unwrap_or_default()
|
||||
let preferred_id = if dip_ids.any(|id| id.eq(&m.device_id)) {
|
||||
m.device_id.clone()
|
||||
} else if dip_ids.any(|id| Some(id) == m.serial_number_id.as_ref()) {
|
||||
m.serial_number_id.clone().unwrap_or_default()
|
||||
} else {
|
||||
id
|
||||
};
|
||||
@@ -458,8 +460,8 @@ where
|
||||
// After we have cached them, remove them from our state
|
||||
wm.monitors_mut().retain(|m| {
|
||||
!newly_removed_displays.iter().any(|id| {
|
||||
m.serial_number_id().as_ref().is_some_and(|sn| sn == id)
|
||||
|| m.device_id() == id
|
||||
m.serial_number_id.as_ref().is_some_and(|sn| sn == id)
|
||||
|| m.device_id.eq(id)
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -490,7 +492,7 @@ where
|
||||
let post_removal_device_ids = wm
|
||||
.monitors()
|
||||
.iter()
|
||||
.map(Monitor::device_id)
|
||||
.map(|m| &m.device_id)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -513,21 +515,23 @@ where
|
||||
|
||||
// Look in the updated state for new monitors
|
||||
for (i, m) in wm.monitors_mut().iter_mut().enumerate() {
|
||||
let device_id = m.device_id();
|
||||
let device_id = &m.device_id;
|
||||
// We identify a new monitor when we encounter a new device id
|
||||
if !post_removal_device_ids.contains(device_id) {
|
||||
let mut cache_hit = false;
|
||||
let mut cached_id = String::new();
|
||||
// Check if that device id exists in the cache for this session
|
||||
if let Some((id, cached)) = monitor_cache.get_key_value(device_id).or(m
|
||||
.serial_number_id()
|
||||
.serial_number_id
|
||||
.as_ref()
|
||||
.and_then(|sn| monitor_cache.get_key_value(sn)))
|
||||
{
|
||||
cache_hit = true;
|
||||
cached_id = id.clone();
|
||||
|
||||
tracing::info!("found monitor and workspace configuration for {id} in the monitor cache, applying");
|
||||
tracing::info!(
|
||||
"found monitor and workspace configuration for {id} in the monitor cache, applying"
|
||||
);
|
||||
|
||||
// If it does, update the cached monitor info with the new one and
|
||||
// load the cached monitor removing any window that has since been
|
||||
@@ -608,24 +612,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(window) = workspace.maximized_window() {
|
||||
if let Some(window) = &workspace.maximized_window {
|
||||
if window.exe().is_err()
|
||||
|| known_hwnds.contains_key(&window.hwnd)
|
||||
{
|
||||
workspace.set_maximized_window(None);
|
||||
workspace.maximized_window = None;
|
||||
} else if is_focused_workspace {
|
||||
WindowsApi::restore_window(window.hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(container) = workspace.monocle_container_mut() {
|
||||
if let Some(container) = &mut workspace.monocle_container {
|
||||
container.windows_mut().retain(|window| {
|
||||
window.exe().is_ok()
|
||||
&& !known_hwnds.contains_key(&window.hwnd)
|
||||
});
|
||||
|
||||
if container.windows().is_empty() {
|
||||
workspace.set_monocle_container(None);
|
||||
workspace.monocle_container = None;
|
||||
} else if is_focused_workspace {
|
||||
if let Some(window) = container.focused_window() {
|
||||
WindowsApi::restore_window(window.hwnd);
|
||||
@@ -657,7 +661,7 @@ where
|
||||
let mut workspace_matching_rules =
|
||||
WORKSPACE_MATCHING_RULES.lock();
|
||||
if let Some(rules) = workspace
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.workspace_rules.as_ref())
|
||||
{
|
||||
@@ -672,7 +676,7 @@ where
|
||||
}
|
||||
|
||||
if let Some(rules) = workspace
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.initial_workspace_rules.as_ref())
|
||||
{
|
||||
@@ -734,8 +738,8 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crossbeam_channel::bounded;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_channel::bounded;
|
||||
use std::path::PathBuf;
|
||||
use uuid::Uuid;
|
||||
use windows::Win32::Devices::Display::DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY;
|
||||
@@ -1006,18 +1010,18 @@ mod tests {
|
||||
assert_eq!(monitors.len(), 1, "Expected one monitor");
|
||||
|
||||
// hmonitor
|
||||
assert_eq!(monitors[0].id(), 1);
|
||||
assert_eq!(monitors[0].id, 1);
|
||||
|
||||
// device name
|
||||
assert_eq!(monitors[0].name(), &String::from("DISPLAY1"));
|
||||
assert_eq!(monitors[0].name, String::from("DISPLAY1"));
|
||||
|
||||
// Device
|
||||
assert_eq!(monitors[0].device(), &String::from("ABC123"));
|
||||
assert_eq!(monitors[0].device, String::from("ABC123"));
|
||||
|
||||
// Device ID
|
||||
assert_eq!(
|
||||
monitors[0].device_id(),
|
||||
&String::from("ABC123-4&123456&0&UID0")
|
||||
monitors[0].device_id,
|
||||
String::from("ABC123-4&123456&0&UID0")
|
||||
);
|
||||
|
||||
// Check monitor serial number id
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::OptionExt;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
@@ -11,6 +11,18 @@ use crate::core::Rect;
|
||||
use crate::core::Sizing;
|
||||
use crate::core::WindowContainerBehaviour;
|
||||
|
||||
use crate::CURRENT_VIRTUAL_DESKTOP;
|
||||
use crate::DefaultLayout;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::HIDDEN_HWNDS;
|
||||
use crate::Layout;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::State;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::VirtualDesktopNotification;
|
||||
use crate::Window;
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
@@ -18,25 +30,13 @@ use crate::current_virtual_desktop;
|
||||
use crate::notify_subscribers;
|
||||
use crate::stackbar_manager;
|
||||
use crate::transparency_manager;
|
||||
use crate::window::should_act;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window::should_act;
|
||||
use crate::window_manager::WindowManager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
use crate::DefaultLayout;
|
||||
use crate::Layout;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::State;
|
||||
use crate::VirtualDesktopNotification;
|
||||
use crate::Window;
|
||||
use crate::CURRENT_VIRTUAL_DESKTOP;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::HIDDEN_HWNDS;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
@@ -65,7 +65,7 @@ pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
impl WindowManager {
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
#[tracing::instrument(skip(self, event), fields(event = event.title(), winevent = event.winevent(), hwnd = event.hwnd()))]
|
||||
pub fn process_event(&mut self, event: WindowManagerEvent) -> Result<()> {
|
||||
pub fn process_event(&mut self, event: WindowManagerEvent) -> eyre::Result<()> {
|
||||
if self.is_paused {
|
||||
tracing::trace!("ignoring while paused");
|
||||
return Ok(());
|
||||
@@ -145,7 +145,9 @@ impl WindowManager {
|
||||
// to be consumed by integrating gui applications like bars to know
|
||||
// when to hide visual components which don't make sense when not on
|
||||
// komorebi's associated virtual desktop
|
||||
tracing::debug!("notifying subscribers that we have left komorebi's associated virtual desktop");
|
||||
tracing::debug!(
|
||||
"notifying subscribers that we have left komorebi's associated virtual desktop"
|
||||
);
|
||||
notify_subscribers(
|
||||
Notification {
|
||||
event: NotificationEvent::VirtualDesktop(
|
||||
@@ -165,7 +167,9 @@ impl WindowManager {
|
||||
// to be consumed by integrating gui applications like bars to know
|
||||
// when to show visual components associated with komorebi's virtual
|
||||
// desktop
|
||||
tracing::debug!("notifying subscribers that we are back on komorebi's associated virtual desktop");
|
||||
tracing::debug!(
|
||||
"notifying subscribers that we are back on komorebi's associated virtual desktop"
|
||||
);
|
||||
notify_subscribers(
|
||||
Notification {
|
||||
event: NotificationEvent::VirtualDesktop(
|
||||
@@ -203,12 +207,11 @@ impl WindowManager {
|
||||
//
|
||||
// This check ensures that we only update the focused monitor when the window
|
||||
// triggering monitor reconciliation is known to not be tied to a specific monitor.
|
||||
if let Ok(class) = window.class() {
|
||||
if class != "OleMainThreadWndClass"
|
||||
&& self.focused_monitor_idx() != monitor_idx
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
if let Ok(class) = window.class()
|
||||
&& class != "OleMainThreadWndClass"
|
||||
&& self.focused_monitor_idx() != monitor_idx
|
||||
{
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,7 +307,7 @@ impl WindowManager {
|
||||
// containers - this makes floating windows on empty workspaces go into very
|
||||
// annoying focus change loops which prevents users from interacting with them
|
||||
if !matches!(
|
||||
self.focused_workspace()?.layout(),
|
||||
self.focused_workspace()?.layout,
|
||||
Layout::Default(DefaultLayout::Scrolling)
|
||||
) && !self.focused_workspace()?.containers().is_empty()
|
||||
{
|
||||
@@ -319,13 +322,13 @@ impl WindowManager {
|
||||
|
||||
match floating_window_idx {
|
||||
None => {
|
||||
if let Some(w) = workspace.maximized_window() {
|
||||
if w.hwnd == window.hwnd {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(w) = &workspace.maximized_window
|
||||
&& w.hwnd == window.hwnd
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(monocle) = workspace.monocle_container() {
|
||||
if let Some(monocle) = &workspace.monocle_container {
|
||||
if let Some(window) = monocle.focused_window() {
|
||||
window.focus(false)?;
|
||||
}
|
||||
@@ -333,10 +336,10 @@ impl WindowManager {
|
||||
workspace.focus_container_by_window(window.hwnd)?;
|
||||
}
|
||||
|
||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||
workspace.layer = WorkspaceLayer::Tiling;
|
||||
|
||||
if matches!(
|
||||
self.focused_workspace()?.layout(),
|
||||
self.focused_workspace()?.layout,
|
||||
Layout::Default(DefaultLayout::Scrolling)
|
||||
) && !self.focused_workspace()?.containers().is_empty()
|
||||
{
|
||||
@@ -345,7 +348,7 @@ impl WindowManager {
|
||||
}
|
||||
Some(idx) => {
|
||||
if let Some(_window) = workspace.floating_windows().get(idx) {
|
||||
workspace.set_layer(WorkspaceLayer::Floating);
|
||||
workspace.layer = WorkspaceLayer::Floating;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,23 +392,20 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((m_idx, w_idx)) = self.known_hwnds.get(&window.hwnd) {
|
||||
if let Some(focused_workspace_idx) = self
|
||||
if let Some((m_idx, w_idx)) = self.known_hwnds.get(&window.hwnd)
|
||||
&& let Some(focused_workspace_idx) = self
|
||||
.monitors()
|
||||
.get(*m_idx)
|
||||
.map(|m| m.focused_workspace_idx())
|
||||
{
|
||||
if *m_idx != self.focused_monitor_idx()
|
||||
&& *w_idx != focused_workspace_idx
|
||||
{
|
||||
tracing::debug!(
|
||||
"ignoring show event for window already associated with another workspace"
|
||||
);
|
||||
&& *m_idx != self.focused_monitor_idx()
|
||||
&& *w_idx != focused_workspace_idx
|
||||
{
|
||||
tracing::debug!(
|
||||
"ignoring show event for window already associated with another workspace"
|
||||
);
|
||||
|
||||
window.hide();
|
||||
proceed = false;
|
||||
}
|
||||
}
|
||||
window.hide();
|
||||
proceed = false;
|
||||
}
|
||||
|
||||
if proceed {
|
||||
@@ -415,7 +415,7 @@ impl WindowManager {
|
||||
);
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
let workspace_contains_window = workspace.contains_window(window.hwnd);
|
||||
let monocle_container = workspace.monocle_container().clone();
|
||||
let monocle_container = workspace.monocle_container.clone();
|
||||
|
||||
if !workspace_contains_window && needs_reconciliation.is_none() {
|
||||
let floating_applications = FLOATING_APPLICATIONS.lock();
|
||||
@@ -458,11 +458,11 @@ impl WindowManager {
|
||||
let center_spawned_floats =
|
||||
placement.should_center() && workspace.tile;
|
||||
workspace.floating_windows_mut().push_back(window);
|
||||
workspace.set_layer(WorkspaceLayer::Floating);
|
||||
workspace.layer = WorkspaceLayer::Floating;
|
||||
if center_spawned_floats {
|
||||
let mut floating_window = window;
|
||||
floating_window.center(
|
||||
&workspace.globals().work_area,
|
||||
&workspace.globals.work_area,
|
||||
placement.should_resize(),
|
||||
)?;
|
||||
}
|
||||
@@ -471,17 +471,15 @@ impl WindowManager {
|
||||
match behaviour.current_behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
workspace.new_container_for_window(window);
|
||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||
workspace.layer = WorkspaceLayer::Tiling;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
WindowContainerBehaviour::Append => {
|
||||
workspace
|
||||
.focused_container_mut()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("there is no focused container")
|
||||
})?
|
||||
.ok_or_eyre("there is no focused container")?
|
||||
.add_window(window);
|
||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||
workspace.layer = WorkspaceLayer::Tiling;
|
||||
self.update_focused_workspace(true, false)?;
|
||||
stackbar_manager::send_notification();
|
||||
}
|
||||
@@ -506,17 +504,15 @@ impl WindowManager {
|
||||
|
||||
if workspace_contains_window {
|
||||
let mut monocle_window_event = false;
|
||||
if let Some(ref monocle) = monocle_container {
|
||||
if let Some(monocle_window) = monocle.focused_window() {
|
||||
if monocle_window.hwnd == window.hwnd {
|
||||
monocle_window_event = true;
|
||||
}
|
||||
}
|
||||
if let Some(ref monocle) = monocle_container
|
||||
&& let Some(monocle_window) = monocle.focused_window()
|
||||
&& monocle_window.hwnd == window.hwnd
|
||||
{
|
||||
monocle_window_event = true;
|
||||
}
|
||||
|
||||
let workspace = self.focused_workspace()?;
|
||||
if !(monocle_window_event
|
||||
|| workspace.layer() != &WorkspaceLayer::Tiling)
|
||||
if !(monocle_window_event || workspace.layer != WorkspaceLayer::Tiling)
|
||||
&& monocle_container.is_some()
|
||||
{
|
||||
window.hide();
|
||||
@@ -529,7 +525,7 @@ impl WindowManager {
|
||||
let monitor_idx = self.focused_monitor_idx();
|
||||
let workspace_idx = self
|
||||
.focused_monitor()
|
||||
.ok_or_else(|| anyhow!("there is no monitor with this idx"))?
|
||||
.ok_or_eyre("there is no monitor with this idx")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
WindowsApi::bring_window_to_top(window.hwnd)?;
|
||||
@@ -547,19 +543,19 @@ impl WindowManager {
|
||||
|
||||
// If the window handles don't match then something went wrong and the pending move
|
||||
// is not related to this current move, if so abort this operation.
|
||||
if let Some((_, _, w_hwnd)) = pending {
|
||||
if w_hwnd != window.hwnd {
|
||||
color_eyre::eyre::bail!(
|
||||
"window handles for move operation don't match: {} != {}",
|
||||
w_hwnd,
|
||||
window.hwnd
|
||||
);
|
||||
}
|
||||
if let Some((_, _, w_hwnd)) = pending
|
||||
&& w_hwnd != window.hwnd
|
||||
{
|
||||
color_eyre::eyre::bail!(
|
||||
"window handles for move operation don't match: {} != {}",
|
||||
w_hwnd,
|
||||
window.hwnd
|
||||
);
|
||||
}
|
||||
|
||||
let target_monitor_idx = self
|
||||
.monitor_idx_from_current_pos()
|
||||
.ok_or_else(|| anyhow!("cannot get monitor idx from current position"))?;
|
||||
.ok_or_eyre("cannot get monitor idx from current position")?;
|
||||
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
let focused_workspace_idx = self.focused_workspace_idx().unwrap_or_default();
|
||||
@@ -570,7 +566,7 @@ impl WindowManager {
|
||||
let focused_container_idx = workspace.focused_container_idx();
|
||||
let new_position = WindowsApi::window_rect(window.hwnd)?;
|
||||
let old_position = *workspace
|
||||
.latest_layout()
|
||||
.latest_layout
|
||||
.get(focused_container_idx)
|
||||
// If the move was to another monitor with an empty workspace, the
|
||||
// workspace here will refer to that empty workspace, which won't
|
||||
@@ -582,10 +578,10 @@ impl WindowManager {
|
||||
// This will be true if we have moved to another monitor
|
||||
let mut moved_across_monitors = false;
|
||||
|
||||
if let Some((m_idx, _)) = self.known_hwnds.get(&window.hwnd) {
|
||||
if *m_idx != target_monitor_idx {
|
||||
moved_across_monitors = true;
|
||||
}
|
||||
if let Some((m_idx, _)) = self.known_hwnds.get(&window.hwnd)
|
||||
&& *m_idx != target_monitor_idx
|
||||
{
|
||||
moved_across_monitors = true;
|
||||
}
|
||||
|
||||
if let Some((origin_monitor_idx, origin_workspace_idx, _)) = pending {
|
||||
@@ -603,10 +599,10 @@ impl WindowManager {
|
||||
let origin_workspace = self
|
||||
.monitors()
|
||||
.get(origin_monitor_idx)
|
||||
.ok_or_else(|| anyhow!("cannot get monitor idx"))?
|
||||
.ok_or_eyre("cannot get monitor idx")?
|
||||
.workspaces()
|
||||
.get(origin_workspace_idx)
|
||||
.ok_or_else(|| anyhow!("cannot get workspace idx"))?;
|
||||
.ok_or_eyre("cannot get workspace idx")?;
|
||||
|
||||
let managed_window = origin_workspace.contains_window(window.hwnd);
|
||||
|
||||
@@ -618,7 +614,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
if (*workspace.tile() && workspace.contains_managed_window(window.hwnd))
|
||||
if (workspace.tile && workspace.contains_managed_window(window.hwnd))
|
||||
|| moved_across_monitors
|
||||
{
|
||||
let resize = Rect {
|
||||
@@ -646,17 +642,15 @@ impl WindowManager {
|
||||
let target_workspace_idx = self
|
||||
.monitors()
|
||||
.get(target_monitor_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
|
||||
.ok_or_eyre("there is no monitor at this idx")?
|
||||
.focused_workspace_idx();
|
||||
|
||||
let target_container_idx = self
|
||||
.monitors()
|
||||
.get(target_monitor_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
|
||||
.ok_or_eyre("there is no monitor at this idx")?
|
||||
.focused_workspace()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("there is no focused workspace for this monitor")
|
||||
})?
|
||||
.ok_or_eyre("there is no focused workspace for this monitor")?
|
||||
.container_idx_from_current_point()
|
||||
// Default to 0 in the case of an empty workspace
|
||||
.unwrap_or(0);
|
||||
@@ -676,7 +670,7 @@ impl WindowManager {
|
||||
let origin_monitor = self
|
||||
.monitors_mut()
|
||||
.get_mut(origin_monitor_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?;
|
||||
.ok_or_eyre("there is no monitor at this idx")?;
|
||||
origin_monitor.focus_workspace(origin_workspace_idx)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
|
||||
@@ -684,7 +678,7 @@ impl WindowManager {
|
||||
let target_monitor = self
|
||||
.monitors_mut()
|
||||
.get_mut(target_monitor_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?;
|
||||
.ok_or_eyre("there is no monitor at this idx")?;
|
||||
target_monitor.focus_workspace(target_workspace_idx)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
|
||||
@@ -836,7 +830,7 @@ impl WindowManager {
|
||||
.and_then(|m| m.workspaces().get(*ws_idx))
|
||||
{
|
||||
if let Some(monocle_with_window) = target_workspace
|
||||
.monocle_container()
|
||||
.monocle_container
|
||||
.as_ref()
|
||||
.and_then(|m| m.contains_window(window.hwnd).then_some(m))
|
||||
{
|
||||
@@ -849,13 +843,12 @@ impl WindowManager {
|
||||
|
||||
if let Some(target_container) =
|
||||
c_idx.and_then(|c_idx| target_workspace.containers().get(c_idx))
|
||||
&& target_container.focused_window() != Some(&window)
|
||||
{
|
||||
if target_container.focused_window() != Some(&window) {
|
||||
tracing::debug!(
|
||||
"Needs reconciliation within a stack on the focused workspace"
|
||||
);
|
||||
needs_reconciliation = Some((*m_idx, *ws_idx));
|
||||
}
|
||||
tracing::debug!(
|
||||
"Needs reconciliation within a stack on the focused workspace"
|
||||
);
|
||||
needs_reconciliation = Some((*m_idx, *ws_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -886,13 +879,13 @@ impl WindowManager {
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
if ws_idx != monitor.focused_workspace_idx() {
|
||||
let previous_idx = monitor.focused_workspace_idx();
|
||||
monitor.set_last_focused_workspace(Option::from(previous_idx));
|
||||
monitor.last_focused_workspace = Option::from(previous_idx);
|
||||
monitor.focus_workspace(ws_idx)?;
|
||||
}
|
||||
if let Some(workspace) = monitor.focused_workspace_mut() {
|
||||
let mut layer = WorkspaceLayer::Tiling;
|
||||
if let Some((monocle, idx)) = workspace
|
||||
.monocle_container_mut()
|
||||
.monocle_container
|
||||
.as_mut()
|
||||
.and_then(|m| m.idx_for_window(window.hwnd).map(|i| (m, i)))
|
||||
{
|
||||
@@ -903,14 +896,14 @@ impl WindowManager {
|
||||
.any(|w| w.hwnd == window.hwnd)
|
||||
{
|
||||
layer = WorkspaceLayer::Floating;
|
||||
} else if !workspace
|
||||
.maximized_window()
|
||||
.is_some_and(|w| w.hwnd == window.hwnd)
|
||||
} else if workspace
|
||||
.maximized_window
|
||||
.is_none_or(|w| w.hwnd != window.hwnd)
|
||||
{
|
||||
// If the window is the maximized window do nothing, else we
|
||||
// reintegrate the monocle if it exists and then focus the
|
||||
// container
|
||||
if workspace.monocle_container().is_some() {
|
||||
if workspace.monocle_container.is_some() {
|
||||
tracing::info!("disabling monocle");
|
||||
for container in workspace.containers_mut() {
|
||||
container.restore();
|
||||
@@ -922,7 +915,7 @@ impl WindowManager {
|
||||
}
|
||||
workspace.focus_container_by_window(window.hwnd)?;
|
||||
}
|
||||
workspace.set_layer(layer);
|
||||
workspace.layer = layer;
|
||||
}
|
||||
monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use winput::Action;
|
||||
use winput::message_loop;
|
||||
use winput::message_loop::Event;
|
||||
use winput::Action;
|
||||
|
||||
use crate::core::FocusFollowsMouseImplementation;
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use crate::border_manager;
|
||||
use crate::notify_subscribers;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::DATA_DIR;
|
||||
use crate::HIDING_BEHAVIOUR;
|
||||
use crate::HidingBehaviour;
|
||||
use crate::NotificationEvent;
|
||||
use crate::Window;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowManagerEvent;
|
||||
use crate::DATA_DIR;
|
||||
use crate::HIDING_BEHAVIOUR;
|
||||
use crate::border_manager;
|
||||
use crate::notify_subscribers;
|
||||
use crate::winevent::WinEvent;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
@@ -55,13 +55,15 @@ pub fn listen_for_notifications(
|
||||
) {
|
||||
watch_for_orphans(known_hwnds);
|
||||
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -150,16 +152,18 @@ fn watch_for_orphans(known_hwnds: HashMap<isize, (usize, usize)>) {
|
||||
*cache = known_hwnds;
|
||||
}
|
||||
|
||||
std::thread::spawn(move || loop {
|
||||
match find_orphans() {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
tracing::error!("restarting failed thread: {:?}", error)
|
||||
} else {
|
||||
tracing::error!("restarting failed thread: {}", error)
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match find_orphans() {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
tracing::error!("restarting failed thread: {:?}", error)
|
||||
} else {
|
||||
tracing::error!("restarting failed thread: {}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
mod stackbar;
|
||||
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::container::Container;
|
||||
use crate::core::StackbarLabel;
|
||||
use crate::core::StackbarMode;
|
||||
use crate::stackbar_manager::stackbar::Stackbar;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
pub static STACKBAR_FONT_SIZE: AtomicI32 = AtomicI32::new(0); // 0 will produce the system default
|
||||
pub static STACKBAR_FOCUSED_TEXT_COLOUR: AtomicU32 = AtomicU32::new(16777215); // white
|
||||
@@ -71,13 +71,15 @@ pub fn should_have_stackbar(window_count: usize) -> bool {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -111,7 +113,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
// Only operate on the focused workspace of each monitor
|
||||
if let Some(ws) = m.focused_workspace_mut() {
|
||||
// Workspaces with tiling disabled don't have stackbars
|
||||
if !ws.tile() {
|
||||
if !ws.tile {
|
||||
let mut to_remove = vec![];
|
||||
for (id, border) in stackbars.iter() {
|
||||
if stackbars_monitors.get(id).copied().unwrap_or_default() == monitor_idx {
|
||||
@@ -131,7 +133,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
WindowsApi::is_zoomed(WindowsApi::foreground_window().unwrap_or_default());
|
||||
|
||||
// Handle the monocle container separately
|
||||
if ws.monocle_container().is_some() || is_maximized {
|
||||
if ws.monocle_container.is_some() || is_maximized {
|
||||
// Destroy any stackbars associated with the focused workspace
|
||||
let mut to_remove = vec![];
|
||||
for (id, stackbar) in stackbars.iter() {
|
||||
@@ -152,7 +154,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
let container_ids = ws
|
||||
.containers()
|
||||
.iter()
|
||||
.map(|c| c.id().clone())
|
||||
.map(|c| c.id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut to_remove = vec![];
|
||||
@@ -170,7 +172,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
}
|
||||
|
||||
let container_padding = ws
|
||||
.container_padding()
|
||||
.container_padding
|
||||
.unwrap_or_else(|| DEFAULT_CONTAINER_PADDING.load_consume());
|
||||
|
||||
'containers: for container in ws.containers_mut() {
|
||||
@@ -181,20 +183,20 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
};
|
||||
|
||||
if !should_add_stackbar {
|
||||
if let Some(stackbar) = stackbars.get(container.id()) {
|
||||
if let Some(stackbar) = stackbars.get(&container.id) {
|
||||
stackbar.destroy()?
|
||||
}
|
||||
|
||||
stackbars.remove(container.id());
|
||||
stackbars_monitors.remove(container.id());
|
||||
stackbars.remove(&container.id);
|
||||
stackbars_monitors.remove(&container.id);
|
||||
continue 'containers;
|
||||
}
|
||||
|
||||
// Get the stackbar entry for this container from the map or create one
|
||||
let stackbar = match stackbars.entry(container.id().clone()) {
|
||||
let stackbar = match stackbars.entry(container.id.clone()) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
if let Ok(stackbar) = Stackbar::create(container.id()) {
|
||||
if let Ok(stackbar) = Stackbar::create(&container.id) {
|
||||
entry.insert(stackbar)
|
||||
} else {
|
||||
continue 'receiver;
|
||||
@@ -202,7 +204,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
}
|
||||
};
|
||||
|
||||
stackbars_monitors.insert(container.id().clone(), monitor_idx);
|
||||
stackbars_monitors.insert(container.id.clone(), monitor_idx);
|
||||
|
||||
let rect = WindowsApi::window_rect(
|
||||
container.focused_window().copied().unwrap_or_default().hwnd,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::WINDOWS_11;
|
||||
use crate::WindowsApi;
|
||||
use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::border_manager::STYLE;
|
||||
@@ -5,7 +8,6 @@ use crate::container::Container;
|
||||
use crate::core::BorderStyle;
|
||||
use crate::core::Rect;
|
||||
use crate::core::StackbarLabel;
|
||||
use crate::stackbar_manager::STACKBARS_CONTAINERS;
|
||||
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_FONT_FAMILY;
|
||||
use crate::stackbar_manager::STACKBAR_FONT_SIZE;
|
||||
@@ -14,16 +16,13 @@ use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_WIDTH;
|
||||
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::stackbar_manager::STACKBARS_CONTAINERS;
|
||||
use crate::windows_api;
|
||||
use crate::WindowsApi;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::WINDOWS_11;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::Win32::Foundation::COLORREF;
|
||||
use windows::Win32::Foundation::HINSTANCE;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
@@ -33,41 +32,41 @@ use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::Graphics::Gdi::CreateFontIndirectW;
|
||||
use windows::Win32::Graphics::Gdi::CreatePen;
|
||||
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
|
||||
use windows::Win32::Graphics::Gdi::DT_CENTER;
|
||||
use windows::Win32::Graphics::Gdi::DT_END_ELLIPSIS;
|
||||
use windows::Win32::Graphics::Gdi::DT_SINGLELINE;
|
||||
use windows::Win32::Graphics::Gdi::DT_VCENTER;
|
||||
use windows::Win32::Graphics::Gdi::DeleteObject;
|
||||
use windows::Win32::Graphics::Gdi::DrawTextW;
|
||||
use windows::Win32::Graphics::Gdi::FONT_QUALITY;
|
||||
use windows::Win32::Graphics::Gdi::FW_BOLD;
|
||||
use windows::Win32::Graphics::Gdi::GetDC;
|
||||
use windows::Win32::Graphics::Gdi::GetDeviceCaps;
|
||||
use windows::Win32::Graphics::Gdi::LOGFONTW;
|
||||
use windows::Win32::Graphics::Gdi::LOGPIXELSY;
|
||||
use windows::Win32::Graphics::Gdi::PROOF_QUALITY;
|
||||
use windows::Win32::Graphics::Gdi::PS_SOLID;
|
||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||
use windows::Win32::Graphics::Gdi::ReleaseDC;
|
||||
use windows::Win32::Graphics::Gdi::RoundRect;
|
||||
use windows::Win32::Graphics::Gdi::SelectObject;
|
||||
use windows::Win32::Graphics::Gdi::SetBkColor;
|
||||
use windows::Win32::Graphics::Gdi::SetTextColor;
|
||||
use windows::Win32::Graphics::Gdi::DT_CENTER;
|
||||
use windows::Win32::Graphics::Gdi::DT_END_ELLIPSIS;
|
||||
use windows::Win32::Graphics::Gdi::DT_SINGLELINE;
|
||||
use windows::Win32::Graphics::Gdi::DT_VCENTER;
|
||||
use windows::Win32::Graphics::Gdi::FONT_QUALITY;
|
||||
use windows::Win32::Graphics::Gdi::FW_BOLD;
|
||||
use windows::Win32::Graphics::Gdi::LOGFONTW;
|
||||
use windows::Win32::Graphics::Gdi::LOGPIXELSY;
|
||||
use windows::Win32::Graphics::Gdi::PROOF_QUALITY;
|
||||
use windows::Win32::Graphics::Gdi::PS_SOLID;
|
||||
use windows::Win32::System::WindowsProgramming::MulDiv;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IDC_ARROW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LoadCursorW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MSG;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetCursor;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IDC_ARROW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MSG;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_LBUTTONDOWN;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_SETCURSOR;
|
||||
@@ -76,6 +75,7 @@ use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOOLWINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_POPUP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_VISIBLE;
|
||||
use windows::core::PCWSTR;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stackbar {
|
||||
@@ -353,16 +353,15 @@ impl Stackbar {
|
||||
// stackbar, make sure we update its location so that it doesn't render
|
||||
// on top of other tiles before eventually ending up in the correct
|
||||
// tile
|
||||
if index != focused_window_idx {
|
||||
if let Err(err) =
|
||||
if index != focused_window_idx
|
||||
&& let Err(err) =
|
||||
window.set_position(&focused_window_rect, false)
|
||||
{
|
||||
tracing::error!(
|
||||
{
|
||||
tracing::error!(
|
||||
"stackbar WM_LBUTTONDOWN repositioning error: hwnd {} ({})",
|
||||
*window,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the window corresponding to the tab we have clicked
|
||||
|
||||
@@ -1,4 +1,33 @@
|
||||
use crate::animation::PerAnimationPrefixConfig;
|
||||
use crate::AspectRatio;
|
||||
use crate::Axis;
|
||||
use crate::CrossBoundaryBehaviour;
|
||||
use crate::DATA_DIR;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO;
|
||||
use crate::FloatingLayerBehaviour;
|
||||
use crate::HIDING_BEHAVIOUR;
|
||||
use crate::IGNORE_IDENTIFIERS;
|
||||
use crate::LAYERED_WHITELIST;
|
||||
use crate::MANAGE_IDENTIFIERS;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::NO_TITLEBAR;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST;
|
||||
use crate::Placement;
|
||||
use crate::PredefinedAspectRatio;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::ResolvedPathBuf;
|
||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||
use crate::SLOW_APPLICATION_IDENTIFIERS;
|
||||
use crate::TRANSPARENCY_BLACKLIST;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WINDOW_HANDLING_BEHAVIOUR;
|
||||
use crate::WINDOWS_11;
|
||||
use crate::WORKSPACE_MATCHING_RULES;
|
||||
use crate::WindowHandlingBehaviour;
|
||||
use crate::animation::ANIMATION_DURATION_GLOBAL;
|
||||
use crate::animation::ANIMATION_DURATION_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
@@ -7,18 +36,14 @@ use crate::animation::ANIMATION_FPS;
|
||||
use crate::animation::ANIMATION_STYLE_GLOBAL;
|
||||
use crate::animation::ANIMATION_STYLE_PER_ANIMATION;
|
||||
use crate::animation::DEFAULT_ANIMATION_FPS;
|
||||
use crate::animation::PerAnimationPrefixConfig;
|
||||
use crate::asc::ApplicationSpecificConfiguration;
|
||||
use crate::asc::AscApplicationRulesOrSchema;
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::ZOrder;
|
||||
use crate::border_manager::IMPLEMENTATION;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::border_manager::ZOrder;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::core::config_generation::ApplicationConfiguration;
|
||||
use crate::core::config_generation::ApplicationConfigurationGenerator;
|
||||
use crate::core::config_generation::ApplicationOptions;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
use crate::core::AnimationStyle;
|
||||
use crate::core::BorderImplementation;
|
||||
use crate::core::BorderStyle;
|
||||
@@ -34,6 +59,11 @@ use crate::core::StackbarLabel;
|
||||
use crate::core::StackbarMode;
|
||||
use crate::core::WindowContainerBehaviour;
|
||||
use crate::core::WindowManagementBehaviour;
|
||||
use crate::core::config_generation::ApplicationConfiguration;
|
||||
use crate::core::config_generation::ApplicationConfigurationGenerator;
|
||||
use crate::core::config_generation::ApplicationOptions;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
use crate::current_virtual_desktop;
|
||||
use crate::default_layout::LayoutOptions;
|
||||
use crate::monitor;
|
||||
@@ -57,37 +87,7 @@ use crate::window_manager::WindowManager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::AspectRatio;
|
||||
use crate::Axis;
|
||||
use crate::CrossBoundaryBehaviour;
|
||||
use crate::FloatingLayerBehaviour;
|
||||
use crate::Placement;
|
||||
use crate::PredefinedAspectRatio;
|
||||
use crate::ResolvedPathBuf;
|
||||
use crate::WindowHandlingBehaviour;
|
||||
use crate::DATA_DIR;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO;
|
||||
use crate::HIDING_BEHAVIOUR;
|
||||
use crate::IGNORE_IDENTIFIERS;
|
||||
use crate::LAYERED_WHITELIST;
|
||||
use crate::MANAGE_IDENTIFIERS;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::NO_TITLEBAR;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||
use crate::SLOW_APPLICATION_IDENTIFIERS;
|
||||
use crate::TRANSPARENCY_BLACKLIST;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WINDOWS_11;
|
||||
use crate::WINDOW_HANDLING_BEHAVIOUR;
|
||||
use crate::WORKSPACE_MATCHING_RULES;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre;
|
||||
use crossbeam_channel::Receiver;
|
||||
use hotwatch::EventKind;
|
||||
use hotwatch::Hotwatch;
|
||||
@@ -101,8 +101,8 @@ use std::collections::HashSet;
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use uds_windows::UnixListener;
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
@@ -250,7 +250,7 @@ pub struct WorkspaceConfig {
|
||||
impl From<&Workspace> for WorkspaceConfig {
|
||||
fn from(value: &Workspace) -> Self {
|
||||
let mut layout_rules = HashMap::new();
|
||||
for (threshold, layout) in value.layout_rules() {
|
||||
for (threshold, layout) in &value.layout_rules {
|
||||
match layout {
|
||||
Layout::Default(value) => {
|
||||
layout_rules.insert(*threshold, *value);
|
||||
@@ -261,14 +261,14 @@ impl From<&Workspace> for WorkspaceConfig {
|
||||
let layout_rules = (!layout_rules.is_empty()).then_some(layout_rules);
|
||||
|
||||
let mut window_container_behaviour_rules = HashMap::new();
|
||||
for (threshold, behaviour) in value.window_container_behaviour_rules().iter().flatten() {
|
||||
for (threshold, behaviour) in value.window_container_behaviour_rules.iter().flatten() {
|
||||
window_container_behaviour_rules.insert(*threshold, *behaviour);
|
||||
}
|
||||
|
||||
let default_container_padding = DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst);
|
||||
let default_workspace_padding = DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst);
|
||||
|
||||
let container_padding = value.container_padding().and_then(|container_padding| {
|
||||
let container_padding = value.container_padding.and_then(|container_padding| {
|
||||
if container_padding == default_container_padding {
|
||||
None
|
||||
} else {
|
||||
@@ -276,7 +276,7 @@ impl From<&Workspace> for WorkspaceConfig {
|
||||
}
|
||||
});
|
||||
|
||||
let workspace_padding = value.workspace_padding().and_then(|workspace_padding| {
|
||||
let workspace_padding = value.workspace_padding.and_then(|workspace_padding| {
|
||||
if workspace_padding == default_workspace_padding {
|
||||
None
|
||||
} else {
|
||||
@@ -284,48 +284,48 @@ impl From<&Workspace> for WorkspaceConfig {
|
||||
}
|
||||
});
|
||||
|
||||
let tile = if *value.tile() { None } else { Some(false) };
|
||||
let tile = if value.tile { None } else { Some(false) };
|
||||
|
||||
Self {
|
||||
name: value
|
||||
.name()
|
||||
.name
|
||||
.clone()
|
||||
.unwrap_or_else(|| String::from("unnamed")),
|
||||
layout: value
|
||||
.tile()
|
||||
.then_some(match value.layout() {
|
||||
Layout::Default(layout) => Option::from(*layout),
|
||||
.tile
|
||||
.then_some(match value.layout {
|
||||
Layout::Default(layout) => Option::from(layout),
|
||||
Layout::Custom(_) => None,
|
||||
})
|
||||
.flatten(),
|
||||
layout_options: value.layout_options(),
|
||||
layout_options: value.layout_options,
|
||||
custom_layout: value
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.custom_layout.clone()),
|
||||
layout_rules,
|
||||
custom_layout_rules: value
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.custom_layout_rules.clone()),
|
||||
container_padding,
|
||||
workspace_padding,
|
||||
initial_workspace_rules: value
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.initial_workspace_rules.clone()),
|
||||
workspace_rules: value
|
||||
.workspace_config()
|
||||
.workspace_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.workspace_rules.clone()),
|
||||
work_area_offset: value.work_area_offset(),
|
||||
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()),
|
||||
window_container_behaviour: *value.window_container_behaviour(),
|
||||
work_area_offset: value.work_area_offset,
|
||||
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset),
|
||||
window_container_behaviour: value.window_container_behaviour,
|
||||
window_container_behaviour_rules: Option::from(window_container_behaviour_rules),
|
||||
float_override: *value.float_override(),
|
||||
float_override: value.float_override,
|
||||
tile,
|
||||
layout_flip: value.layout_flip(),
|
||||
floating_layer_behaviour: value.floating_layer_behaviour(),
|
||||
layout_flip: value.layout_flip,
|
||||
floating_layer_behaviour: value.floating_layer_behaviour,
|
||||
wallpaper: None,
|
||||
}
|
||||
}
|
||||
@@ -369,7 +369,7 @@ impl From<&Monitor> for MonitorConfig {
|
||||
let default_container_padding = DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst);
|
||||
let default_workspace_padding = DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst);
|
||||
|
||||
let container_padding = value.container_padding().and_then(|container_padding| {
|
||||
let container_padding = value.container_padding.and_then(|container_padding| {
|
||||
if container_padding == default_container_padding {
|
||||
None
|
||||
} else {
|
||||
@@ -377,7 +377,7 @@ impl From<&Monitor> for MonitorConfig {
|
||||
}
|
||||
});
|
||||
|
||||
let workspace_padding = value.workspace_padding().and_then(|workspace_padding| {
|
||||
let workspace_padding = value.workspace_padding.and_then(|workspace_padding| {
|
||||
if workspace_padding == default_workspace_padding {
|
||||
None
|
||||
} else {
|
||||
@@ -387,13 +387,13 @@ impl From<&Monitor> for MonitorConfig {
|
||||
|
||||
Self {
|
||||
workspaces,
|
||||
work_area_offset: value.work_area_offset(),
|
||||
window_based_work_area_offset: value.window_based_work_area_offset(),
|
||||
window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit()),
|
||||
work_area_offset: value.work_area_offset,
|
||||
window_based_work_area_offset: value.window_based_work_area_offset,
|
||||
window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit),
|
||||
container_padding,
|
||||
workspace_padding,
|
||||
wallpaper: value.wallpaper().clone(),
|
||||
floating_layer_behaviour: value.floating_layer_behaviour(),
|
||||
wallpaper: value.wallpaper.clone(),
|
||||
floating_layer_behaviour: value.floating_layer_behaviour,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,7 +412,7 @@ pub enum AppSpecificConfigurationPath {
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.38`
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.39`
|
||||
pub struct StaticConfig {
|
||||
/// DEPRECATED from v0.1.22: no longer required
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
@@ -731,7 +731,9 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
if display {
|
||||
println!("\nEnd-of-life features will not receive any further bug fixes or updates; they should not be used\n")
|
||||
println!(
|
||||
"\nEnd-of-life features will not receive any further bug fixes or updates; they should not be used\n"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +758,9 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
if display {
|
||||
println!("\nYour configuration file contains some options that have been renamed or deprecated:\n");
|
||||
println!(
|
||||
"\nYour configuration file contains some options that have been renamed or deprecated:\n"
|
||||
);
|
||||
for (canonical, aliases) in map {
|
||||
for alias in aliases {
|
||||
if raw.contains(alias) {
|
||||
@@ -948,7 +952,7 @@ impl From<&WindowManager> for StaticConfig {
|
||||
|
||||
impl StaticConfig {
|
||||
#[allow(clippy::cognitive_complexity, clippy::too_many_lines)]
|
||||
fn apply_globals(&mut self) -> Result<()> {
|
||||
fn apply_globals(&mut self) -> eyre::Result<()> {
|
||||
*FLOATING_WINDOW_TOGGLE_ASPECT_RATIO.lock() = self
|
||||
.floating_window_aspect_ratio
|
||||
.unwrap_or(AspectRatio::Predefined(PredefinedAspectRatio::Standard));
|
||||
@@ -1236,11 +1240,11 @@ impl StaticConfig {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_raw(raw: &str) -> Result<Self> {
|
||||
pub fn read_raw(raw: &str) -> eyre::Result<Self> {
|
||||
Ok(serde_json::from_str(raw)?)
|
||||
}
|
||||
|
||||
pub fn read(path: &PathBuf) -> Result<Self> {
|
||||
pub fn read(path: &PathBuf) -> eyre::Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
serde_json::from_str(&content).map_err(Into::into)
|
||||
}
|
||||
@@ -1250,7 +1254,7 @@ impl StaticConfig {
|
||||
path: &PathBuf,
|
||||
incoming: Receiver<WindowManagerEvent>,
|
||||
unix_listener: Option<UnixListener>,
|
||||
) -> Result<WindowManager> {
|
||||
) -> eyre::Result<WindowManager> {
|
||||
let mut value = Self::read(path)?;
|
||||
value.apply_globals()?;
|
||||
|
||||
@@ -1345,7 +1349,7 @@ impl StaticConfig {
|
||||
Ok(wm)
|
||||
}
|
||||
|
||||
pub fn postload(path: &PathBuf, wm: &Arc<Mutex<WindowManager>>) -> Result<()> {
|
||||
pub fn postload(path: &PathBuf, wm: &Arc<Mutex<WindowManager>>) -> eyre::Result<()> {
|
||||
let mut value = Self::read(path)?;
|
||||
let mut wm = wm.lock();
|
||||
|
||||
@@ -1363,15 +1367,12 @@ impl StaticConfig {
|
||||
for (i, monitor) in wm.monitors_mut().iter_mut().enumerate() {
|
||||
let preferred_config_idx = {
|
||||
let display_index_preferences = DISPLAY_INDEX_PREFERENCES.read();
|
||||
let c_idx = display_index_preferences.iter().find_map(|(c_idx, id)| {
|
||||
(monitor
|
||||
.serial_number_id()
|
||||
.as_ref()
|
||||
.is_some_and(|sn| sn == id)
|
||||
|| monitor.device_id() == id)
|
||||
.then_some(*c_idx)
|
||||
});
|
||||
c_idx
|
||||
|
||||
display_index_preferences.iter().find_map(|(c_idx, id)| {
|
||||
(monitor.serial_number_id.as_ref().is_some_and(|sn| sn == id)
|
||||
|| monitor.device_id.eq(id))
|
||||
.then_some(*c_idx)
|
||||
})
|
||||
};
|
||||
let idx = preferred_config_idx.or({
|
||||
// Monitor without preferred config idx.
|
||||
@@ -1396,19 +1397,16 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
monitor.ensure_workspace_count(monitor_config.workspaces.len());
|
||||
monitor.set_work_area_offset(monitor_config.work_area_offset);
|
||||
monitor.set_window_based_work_area_offset(
|
||||
monitor_config.window_based_work_area_offset,
|
||||
);
|
||||
monitor.set_window_based_work_area_offset_limit(
|
||||
monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1),
|
||||
);
|
||||
monitor.set_container_padding(monitor_config.container_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.work_area_offset = monitor_config.work_area_offset;
|
||||
monitor.window_based_work_area_offset =
|
||||
monitor_config.window_based_work_area_offset;
|
||||
monitor.window_based_work_area_offset_limit = monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1);
|
||||
monitor.container_padding = monitor_config.container_padding;
|
||||
monitor.workspace_padding = monitor_config.workspace_padding;
|
||||
monitor.wallpaper = monitor_config.wallpaper.clone();
|
||||
monitor.floating_layer_behaviour = monitor_config.floating_layer_behaviour;
|
||||
|
||||
monitor.update_workspaces_globals(offset);
|
||||
for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() {
|
||||
@@ -1416,7 +1414,9 @@ impl StaticConfig {
|
||||
if monitor_count > 1
|
||||
&& matches!(workspace_config.layout, Some(DefaultLayout::Scrolling))
|
||||
{
|
||||
tracing::warn!("scrolling layout is only supported for a single monitor; falling back to columns layout");
|
||||
tracing::warn!(
|
||||
"scrolling layout is only supported for a single monitor; falling back to columns layout"
|
||||
);
|
||||
workspace_config.layout = Some(DefaultLayout::Columns);
|
||||
}
|
||||
|
||||
@@ -1428,9 +1428,9 @@ impl StaticConfig {
|
||||
// a copy of the monitor itself on the monitor cache if it is.
|
||||
if idx == preferred_config_idx {
|
||||
let id = monitor
|
||||
.serial_number_id()
|
||||
.serial_number_id
|
||||
.as_ref()
|
||||
.map_or(monitor.device_id(), |sn| sn);
|
||||
.map_or(&monitor.device_id, |sn| sn);
|
||||
monitor_reconciliator::insert_in_monitor_cache(id, monitor.clone());
|
||||
}
|
||||
|
||||
@@ -1490,18 +1490,14 @@ impl StaticConfig {
|
||||
);
|
||||
|
||||
m.ensure_workspace_count(monitor_config.workspaces.len());
|
||||
m.set_work_area_offset(monitor_config.work_area_offset);
|
||||
m.set_window_based_work_area_offset(
|
||||
monitor_config.window_based_work_area_offset,
|
||||
);
|
||||
m.set_window_based_work_area_offset_limit(
|
||||
monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1),
|
||||
);
|
||||
m.set_container_padding(monitor_config.container_padding);
|
||||
m.set_workspace_padding(monitor_config.workspace_padding);
|
||||
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
|
||||
m.work_area_offset = monitor_config.work_area_offset;
|
||||
m.window_based_work_area_offset = monitor_config.window_based_work_area_offset;
|
||||
m.window_based_work_area_offset_limit = monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1);
|
||||
m.container_padding = monitor_config.container_padding;
|
||||
m.workspace_padding = monitor_config.workspace_padding;
|
||||
m.floating_layer_behaviour = monitor_config.floating_layer_behaviour;
|
||||
|
||||
m.update_workspaces_globals(offset);
|
||||
|
||||
@@ -1525,7 +1521,7 @@ impl StaticConfig {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> Result<()> {
|
||||
pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> eyre::Result<()> {
|
||||
let mut value = Self::read(path)?;
|
||||
|
||||
value.apply_globals()?;
|
||||
@@ -1542,15 +1538,12 @@ impl StaticConfig {
|
||||
for (i, monitor) in wm.monitors_mut().iter_mut().enumerate() {
|
||||
let preferred_config_idx = {
|
||||
let display_index_preferences = DISPLAY_INDEX_PREFERENCES.read();
|
||||
let c_idx = display_index_preferences.iter().find_map(|(c_idx, id)| {
|
||||
(monitor
|
||||
.serial_number_id()
|
||||
.as_ref()
|
||||
.is_some_and(|sn| sn == id)
|
||||
|| monitor.device_id() == id)
|
||||
.then_some(*c_idx)
|
||||
});
|
||||
c_idx
|
||||
|
||||
display_index_preferences.iter().find_map(|(c_idx, id)| {
|
||||
(monitor.serial_number_id.as_ref().is_some_and(|sn| sn == id)
|
||||
|| monitor.device_id.eq(id))
|
||||
.then_some(*c_idx)
|
||||
})
|
||||
};
|
||||
let idx = preferred_config_idx.or({
|
||||
// Monitor without preferred config idx.
|
||||
@@ -1575,21 +1568,18 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
monitor.ensure_workspace_count(monitor_config.workspaces.len());
|
||||
if monitor.work_area_offset().is_none() {
|
||||
monitor.set_work_area_offset(monitor_config.work_area_offset);
|
||||
if monitor.work_area_offset.is_none() {
|
||||
monitor.work_area_offset = monitor_config.work_area_offset;
|
||||
}
|
||||
monitor.set_window_based_work_area_offset(
|
||||
monitor_config.window_based_work_area_offset,
|
||||
);
|
||||
monitor.set_window_based_work_area_offset_limit(
|
||||
monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1),
|
||||
);
|
||||
monitor.set_container_padding(monitor_config.container_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.window_based_work_area_offset =
|
||||
monitor_config.window_based_work_area_offset;
|
||||
monitor.window_based_work_area_offset_limit = monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1);
|
||||
monitor.container_padding = monitor_config.container_padding;
|
||||
monitor.workspace_padding = monitor_config.workspace_padding;
|
||||
monitor.wallpaper = monitor_config.wallpaper.clone();
|
||||
monitor.floating_layer_behaviour = monitor_config.floating_layer_behaviour;
|
||||
|
||||
monitor.update_workspaces_globals(offset);
|
||||
|
||||
@@ -1603,9 +1593,9 @@ impl StaticConfig {
|
||||
// a copy of the monitor itself on the monitor cache if it is.
|
||||
if idx == preferred_config_idx {
|
||||
let id = monitor
|
||||
.serial_number_id()
|
||||
.serial_number_id
|
||||
.as_ref()
|
||||
.map_or(monitor.device_id(), |sn| sn);
|
||||
.map_or(&monitor.device_id, |sn| sn);
|
||||
monitor_reconciliator::insert_in_monitor_cache(id, monitor.clone());
|
||||
}
|
||||
|
||||
@@ -1665,18 +1655,14 @@ impl StaticConfig {
|
||||
);
|
||||
|
||||
m.ensure_workspace_count(monitor_config.workspaces.len());
|
||||
m.set_work_area_offset(monitor_config.work_area_offset);
|
||||
m.set_window_based_work_area_offset(
|
||||
monitor_config.window_based_work_area_offset,
|
||||
);
|
||||
m.set_window_based_work_area_offset_limit(
|
||||
monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1),
|
||||
);
|
||||
m.set_container_padding(monitor_config.container_padding);
|
||||
m.set_workspace_padding(monitor_config.workspace_padding);
|
||||
m.set_floating_layer_behaviour(monitor_config.floating_layer_behaviour);
|
||||
m.work_area_offset = monitor_config.work_area_offset;
|
||||
m.window_based_work_area_offset = monitor_config.window_based_work_area_offset;
|
||||
m.window_based_work_area_offset_limit = monitor_config
|
||||
.window_based_work_area_offset_limit
|
||||
.unwrap_or(1);
|
||||
m.container_padding = monitor_config.container_padding;
|
||||
m.workspace_padding = monitor_config.workspace_padding;
|
||||
m.floating_layer_behaviour = monitor_config.floating_layer_behaviour;
|
||||
|
||||
m.update_workspaces_globals(offset);
|
||||
|
||||
@@ -1742,7 +1728,7 @@ fn populate_option(
|
||||
entry: &mut ApplicationConfiguration,
|
||||
identifiers: &mut Vec<MatchingRule>,
|
||||
regex_identifiers: &mut HashMap<String, Regex>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
if entry.identifier.matching_strategy.is_none() {
|
||||
entry.identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
||||
}
|
||||
@@ -1768,7 +1754,7 @@ fn populate_rules(
|
||||
matching_rules: &mut Vec<MatchingRule>,
|
||||
identifiers: &mut Vec<MatchingRule>,
|
||||
regex_identifiers: &mut HashMap<String, Regex>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
for matching_rule in matching_rules {
|
||||
if !identifiers.contains(matching_rule) {
|
||||
match matching_rule {
|
||||
@@ -1814,7 +1800,7 @@ fn handle_asc_file(
|
||||
transparency_blacklist: &mut Vec<MatchingRule>,
|
||||
slow_application_identifiers: &mut Vec<MatchingRule>,
|
||||
regex_identifiers: &mut HashMap<String, Regex>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
match path.extension() {
|
||||
None => {}
|
||||
Some(ext) => match ext.to_string_lossy().to_string().as_str() {
|
||||
@@ -1968,7 +1954,9 @@ mod tests {
|
||||
#[test]
|
||||
fn deserialize_custom_layout_rules() {
|
||||
// set an environment variable for testing
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
unsafe {
|
||||
std::env::set_var("VAR", "VALUE");
|
||||
}
|
||||
|
||||
let config = r#"
|
||||
{
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use crate::KomorebiTheme;
|
||||
use crate::border_manager;
|
||||
use crate::stackbar_manager;
|
||||
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::KomorebiTheme;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use komorebi_themes::colour::Colour;
|
||||
use komorebi_themes::Base16Wrapper;
|
||||
use komorebi_themes::colour::Colour;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub struct Notification(KomorebiTheme);
|
||||
|
||||
@@ -51,13 +51,15 @@ pub fn send_notification(theme: KomorebiTheme) {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications() {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications() {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications() {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,17 +4,17 @@ use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU8;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU8;
|
||||
|
||||
use crate::should_act;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::TRANSPARENCY_BLACKLIST;
|
||||
use crate::Window;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::TRANSPARENCY_BLACKLIST;
|
||||
use crate::should_act;
|
||||
|
||||
pub static TRANSPARENCY_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
pub static TRANSPARENCY_ALPHA: AtomicU8 = AtomicU8::new(200);
|
||||
@@ -49,13 +49,15 @@ pub fn send_notification() {
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -92,7 +94,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
'workspaces: for (workspace_idx, ws) in m.workspaces().iter().enumerate() {
|
||||
// Only operate on the focused workspace of each monitor
|
||||
// Workspaces with tiling disabled don't have transparent windows
|
||||
if !ws.tile() || workspace_idx != focused_workspace_idx {
|
||||
if !ws.tile || workspace_idx != focused_workspace_idx {
|
||||
for window in ws.visible_windows().iter().flatten() {
|
||||
if let Err(error) = window.opaque() {
|
||||
let hwnd = window.hwnd;
|
||||
@@ -104,7 +106,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
}
|
||||
|
||||
// Monocle container is never transparent
|
||||
if let Some(monocle) = ws.monocle_container() {
|
||||
if let Some(monocle) = &ws.monocle_container {
|
||||
if let Some(window) = monocle.focused_window() {
|
||||
if monitor_idx == focused_monitor_idx {
|
||||
if let Err(error) = window.opaque() {
|
||||
@@ -150,32 +152,34 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
for (window_idx, window) in c.windows().iter().enumerate() {
|
||||
if window_idx == focused_window_idx {
|
||||
let mut should_make_transparent = true;
|
||||
if !transparency_blacklist.is_empty() {
|
||||
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) = (
|
||||
if !transparency_blacklist.is_empty()
|
||||
&& let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) = (
|
||||
window.title(),
|
||||
window.exe(),
|
||||
window.class(),
|
||||
window.path(),
|
||||
) {
|
||||
let is_blacklisted = should_act(
|
||||
&title,
|
||||
&exe_name,
|
||||
&class,
|
||||
&path,
|
||||
&transparency_blacklist,
|
||||
®ex_identifiers,
|
||||
)
|
||||
.is_some();
|
||||
)
|
||||
{
|
||||
let is_blacklisted = should_act(
|
||||
&title,
|
||||
&exe_name,
|
||||
&class,
|
||||
&path,
|
||||
&transparency_blacklist,
|
||||
®ex_identifiers,
|
||||
)
|
||||
.is_some();
|
||||
|
||||
should_make_transparent = !is_blacklisted;
|
||||
}
|
||||
should_make_transparent = !is_blacklisted;
|
||||
}
|
||||
|
||||
if should_make_transparent {
|
||||
match window.transparent() {
|
||||
Err(error) => {
|
||||
let hwnd = foreground_hwnd;
|
||||
tracing::error!("failed to make unfocused window {hwnd} transparent: {error}" )
|
||||
tracing::error!(
|
||||
"failed to make unfocused window {hwnd} transparent: {error}"
|
||||
)
|
||||
}
|
||||
Ok(..) => {
|
||||
known_hwnds.lock().push(window.hwnd);
|
||||
|
||||
@@ -1,31 +1,3 @@
|
||||
use crate::animation::lerp::Lerp;
|
||||
use crate::animation::prefix::new_animation_key;
|
||||
use crate::animation::prefix::AnimationPrefix;
|
||||
use crate::animation::AnimationEngine;
|
||||
use crate::animation::RenderDispatcher;
|
||||
use crate::animation::ANIMATION_DURATION_GLOBAL;
|
||||
use crate::animation::ANIMATION_DURATION_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
use crate::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_MANAGER;
|
||||
use crate::animation::ANIMATION_STYLE_GLOBAL;
|
||||
use crate::animation::ANIMATION_STYLE_PER_ANIMATION;
|
||||
use crate::border_manager;
|
||||
use crate::com::SetCloak;
|
||||
use crate::core::config_generation::IdWithIdentifier;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
use crate::core::ApplicationIdentifier;
|
||||
use crate::core::HidingBehaviour;
|
||||
use crate::core::Rect;
|
||||
use crate::focus_manager;
|
||||
use crate::stackbar_manager;
|
||||
use crate::styles::ExtendedWindowStyle;
|
||||
use crate::styles::WindowStyle;
|
||||
use crate::transparency_manager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::AnimationStyle;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::FLOATING_WINDOW_TOGGLE_ASPECT_RATIO;
|
||||
@@ -40,14 +12,41 @@ use crate::REGEX_IDENTIFIERS;
|
||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||
use crate::SLOW_APPLICATION_IDENTIFIERS;
|
||||
use crate::WSL2_UI_PROCESSES;
|
||||
use crate::animation::ANIMATION_DURATION_GLOBAL;
|
||||
use crate::animation::ANIMATION_DURATION_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
use crate::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_MANAGER;
|
||||
use crate::animation::ANIMATION_STYLE_GLOBAL;
|
||||
use crate::animation::ANIMATION_STYLE_PER_ANIMATION;
|
||||
use crate::animation::AnimationEngine;
|
||||
use crate::animation::RenderDispatcher;
|
||||
use crate::animation::lerp::Lerp;
|
||||
use crate::animation::prefix::AnimationPrefix;
|
||||
use crate::animation::prefix::new_animation_key;
|
||||
use crate::border_manager;
|
||||
use crate::com::SetCloak;
|
||||
use crate::core::ApplicationIdentifier;
|
||||
use crate::core::HidingBehaviour;
|
||||
use crate::core::Rect;
|
||||
use crate::core::config_generation::IdWithIdentifier;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
use crate::focus_manager;
|
||||
use crate::stackbar_manager;
|
||||
use crate::styles::ExtendedWindowStyle;
|
||||
use crate::styles::WindowStyle;
|
||||
use crate::transparency_manager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use regex::Regex;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde::Serializer;
|
||||
use serde::ser::SerializeStruct;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Display;
|
||||
@@ -128,7 +127,7 @@ impl Display for Window {
|
||||
}
|
||||
|
||||
impl Serialize for Window {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
fn serialize<S>(&self, serializer: S) -> eyre::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
@@ -193,14 +192,14 @@ impl RenderDispatcher for MovementRenderDispatcher {
|
||||
new_animation_key(MovementRenderDispatcher::PREFIX, self.hwnd.to_string())
|
||||
}
|
||||
|
||||
fn pre_render(&self) -> Result<()> {
|
||||
fn pre_render(&self) -> eyre::Result<()> {
|
||||
stackbar_manager::STACKBAR_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst);
|
||||
stackbar_manager::send_notification();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(&self, progress: f64) -> Result<()> {
|
||||
fn render(&self, progress: f64) -> eyre::Result<()> {
|
||||
let new_rect = self.start_rect.lerp(self.target_rect, progress, self.style);
|
||||
|
||||
// we don't check WINDOW_HANDLING_BEHAVIOUR here because animations
|
||||
@@ -211,7 +210,7 @@ impl RenderDispatcher for MovementRenderDispatcher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_render(&self) -> Result<()> {
|
||||
fn post_render(&self) -> eyre::Result<()> {
|
||||
// we don't add the async_window_pos flag here because animations
|
||||
// are always run on a separate thread
|
||||
WindowsApi::position_window(self.hwnd, &self.target_rect, self.top, false)?;
|
||||
@@ -267,7 +266,7 @@ impl RenderDispatcher for TransparencyRenderDispatcher {
|
||||
new_animation_key(TransparencyRenderDispatcher::PREFIX, self.hwnd.to_string())
|
||||
}
|
||||
|
||||
fn pre_render(&self) -> Result<()> {
|
||||
fn pre_render(&self) -> eyre::Result<()> {
|
||||
//transparent
|
||||
if !self.is_opaque {
|
||||
let window = Window::from(self.hwnd);
|
||||
@@ -279,7 +278,7 @@ impl RenderDispatcher for TransparencyRenderDispatcher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(&self, progress: f64) -> Result<()> {
|
||||
fn render(&self, progress: f64) -> eyre::Result<()> {
|
||||
WindowsApi::set_transparent(
|
||||
self.hwnd,
|
||||
self.start_opacity
|
||||
@@ -287,7 +286,7 @@ impl RenderDispatcher for TransparencyRenderDispatcher {
|
||||
)
|
||||
}
|
||||
|
||||
fn post_render(&self) -> Result<()> {
|
||||
fn post_render(&self) -> eyre::Result<()> {
|
||||
//opaque
|
||||
if self.is_opaque {
|
||||
let window = Window::from(self.hwnd);
|
||||
@@ -346,7 +345,7 @@ impl Window {
|
||||
HWND(windows_api::as_ptr!(self.hwnd))
|
||||
}
|
||||
|
||||
pub fn move_to_area(&mut self, current_area: &Rect, target_area: &Rect) -> Result<()> {
|
||||
pub fn move_to_area(&mut self, current_area: &Rect, target_area: &Rect) -> eyre::Result<()> {
|
||||
let current_rect = WindowsApi::window_rect(self.hwnd)?;
|
||||
let x_diff = target_area.left - current_area.left;
|
||||
let y_diff = target_area.top - current_area.top;
|
||||
@@ -413,7 +412,7 @@ impl Window {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn center(&mut self, work_area: &Rect, resize: bool) -> Result<()> {
|
||||
pub fn center(&mut self, work_area: &Rect, resize: bool) -> eyre::Result<()> {
|
||||
let (target_width, target_height) = if resize {
|
||||
let (aspect_ratio_width, aspect_ratio_height) = FLOATING_WINDOW_TOGGLE_ASPECT_RATIO
|
||||
.lock()
|
||||
@@ -440,7 +439,7 @@ impl Window {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_position(&self, layout: &Rect, top: bool) -> Result<()> {
|
||||
pub fn set_position(&self, layout: &Rect, top: bool) -> eyre::Result<()> {
|
||||
let window_rect = WindowsApi::window_rect(self.hwnd)?;
|
||||
|
||||
if window_rect.eq(layout) {
|
||||
@@ -538,7 +537,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(self) -> Result<()> {
|
||||
pub fn close(self) -> eyre::Result<()> {
|
||||
WindowsApi::close_window(self.hwnd)
|
||||
}
|
||||
|
||||
@@ -566,17 +565,17 @@ impl Window {
|
||||
WindowsApi::unmaximize_window(self.hwnd);
|
||||
}
|
||||
|
||||
pub fn focus(self, mouse_follows_focus: bool) -> Result<()> {
|
||||
pub fn focus(self, mouse_follows_focus: bool) -> eyre::Result<()> {
|
||||
// If the target window is already focused, do nothing.
|
||||
if let Ok(ihwnd) = WindowsApi::foreground_window() {
|
||||
if ihwnd == self.hwnd {
|
||||
// Center cursor in Window
|
||||
if mouse_follows_focus {
|
||||
WindowsApi::center_cursor_in_rect(&WindowsApi::window_rect(self.hwnd)?)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
if let Ok(ihwnd) = WindowsApi::foreground_window()
|
||||
&& ihwnd == self.hwnd
|
||||
{
|
||||
// Center cursor in Window
|
||||
if mouse_follows_focus {
|
||||
WindowsApi::center_cursor_in_rect(&WindowsApi::window_rect(self.hwnd)?)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
WindowsApi::raise_and_focus_window(self.hwnd)?;
|
||||
@@ -593,7 +592,7 @@ impl Window {
|
||||
WindowsApi::foreground_window().unwrap_or_default() == self.hwnd
|
||||
}
|
||||
|
||||
pub fn transparent(self) -> Result<()> {
|
||||
pub fn transparent(self) -> eyre::Result<()> {
|
||||
let animation_enabled = ANIMATION_ENABLED_PER_ANIMATION.lock();
|
||||
let transparent_enabled = animation_enabled.get(&TransparencyRenderDispatcher::PREFIX);
|
||||
|
||||
@@ -631,7 +630,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opaque(self) -> Result<()> {
|
||||
pub fn opaque(self) -> eyre::Result<()> {
|
||||
let animation_enabled = ANIMATION_ENABLED_PER_ANIMATION.lock();
|
||||
let transparent_enabled = animation_enabled.get(&TransparencyRenderDispatcher::PREFIX);
|
||||
|
||||
@@ -666,49 +665,49 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_accent(self, colour: u32) -> Result<()> {
|
||||
pub fn set_accent(self, colour: u32) -> eyre::Result<()> {
|
||||
WindowsApi::set_window_accent(self.hwnd, Some(colour))
|
||||
}
|
||||
|
||||
pub fn remove_accent(self) -> Result<()> {
|
||||
pub fn remove_accent(self) -> eyre::Result<()> {
|
||||
WindowsApi::set_window_accent(self.hwnd, None)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn update_style(self, style: &WindowStyle) -> Result<()> {
|
||||
pub fn update_style(self, style: &WindowStyle) -> eyre::Result<()> {
|
||||
WindowsApi::update_style(self.hwnd, isize::try_from(style.bits())?)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn update_style(self, style: &WindowStyle) -> Result<()> {
|
||||
pub fn update_style(self, style: &WindowStyle) -> eyre::Result<()> {
|
||||
WindowsApi::update_style(self.hwnd, i32::try_from(style.bits())?)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn update_ex_style(self, style: &ExtendedWindowStyle) -> Result<()> {
|
||||
pub fn update_ex_style(self, style: &ExtendedWindowStyle) -> eyre::Result<()> {
|
||||
WindowsApi::update_ex_style(self.hwnd, isize::try_from(style.bits())?)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn update_ex_style(self, style: &ExtendedWindowStyle) -> Result<()> {
|
||||
pub fn update_ex_style(self, style: &ExtendedWindowStyle) -> eyre::Result<()> {
|
||||
WindowsApi::update_ex_style(self.hwnd, i32::try_from(style.bits())?)
|
||||
}
|
||||
|
||||
pub fn style(self) -> Result<WindowStyle> {
|
||||
pub fn style(self) -> eyre::Result<WindowStyle> {
|
||||
let bits = u32::try_from(WindowsApi::gwl_style(self.hwnd)?)?;
|
||||
Ok(WindowStyle::from_bits_truncate(bits))
|
||||
}
|
||||
|
||||
pub fn ex_style(self) -> Result<ExtendedWindowStyle> {
|
||||
pub fn ex_style(self) -> eyre::Result<ExtendedWindowStyle> {
|
||||
let bits = u32::try_from(WindowsApi::gwl_ex_style(self.hwnd)?)?;
|
||||
Ok(ExtendedWindowStyle::from_bits_truncate(bits))
|
||||
}
|
||||
|
||||
pub fn title(self) -> Result<String> {
|
||||
pub fn title(self) -> eyre::Result<String> {
|
||||
WindowsApi::window_text_w(self.hwnd)
|
||||
}
|
||||
|
||||
pub fn path(self) -> Result<String> {
|
||||
pub fn path(self) -> eyre::Result<String> {
|
||||
let (process_id, _) = WindowsApi::window_thread_process_id(self.hwnd);
|
||||
let handle = WindowsApi::process_handle(process_id)?;
|
||||
let path = WindowsApi::exe_path(handle);
|
||||
@@ -716,7 +715,7 @@ impl Window {
|
||||
path
|
||||
}
|
||||
|
||||
pub fn exe(self) -> Result<String> {
|
||||
pub fn exe(self) -> eyre::Result<String> {
|
||||
let (process_id, _) = WindowsApi::window_thread_process_id(self.hwnd);
|
||||
let handle = WindowsApi::process_handle(process_id)?;
|
||||
let exe = WindowsApi::exe(handle);
|
||||
@@ -729,11 +728,11 @@ impl Window {
|
||||
process_id
|
||||
}
|
||||
|
||||
pub fn class(self) -> Result<String> {
|
||||
pub fn class(self) -> eyre::Result<String> {
|
||||
WindowsApi::real_window_class_w(self.hwnd)
|
||||
}
|
||||
|
||||
pub fn is_cloaked(self) -> Result<bool> {
|
||||
pub fn is_cloaked(self) -> eyre::Result<bool> {
|
||||
WindowsApi::is_window_cloaked(self.hwnd)
|
||||
}
|
||||
|
||||
@@ -741,14 +740,14 @@ impl Window {
|
||||
WindowsApi::is_window(self.hwnd)
|
||||
}
|
||||
|
||||
pub fn remove_title_bar(self) -> Result<()> {
|
||||
pub fn remove_title_bar(self) -> eyre::Result<()> {
|
||||
let mut style = self.style()?;
|
||||
style.remove(WindowStyle::CAPTION);
|
||||
style.remove(WindowStyle::THICKFRAME);
|
||||
self.update_style(&style)
|
||||
}
|
||||
|
||||
pub fn add_title_bar(self) -> Result<()> {
|
||||
pub fn add_title_bar(self) -> eyre::Result<()> {
|
||||
let mut style = self.style()?;
|
||||
style.insert(WindowStyle::CAPTION);
|
||||
style.insert(WindowStyle::THICKFRAME);
|
||||
@@ -759,7 +758,7 @@ impl Window {
|
||||
/// it. Use raise_and_focus_window to activate and focus a window.
|
||||
/// It also checks if there is a border attached to this window and if it is
|
||||
/// it raises it as well.
|
||||
pub fn raise(self) -> Result<()> {
|
||||
pub fn raise(self) -> eyre::Result<()> {
|
||||
WindowsApi::raise_window(self.hwnd)?;
|
||||
if let Some(border_info) = crate::border_manager::window_border(self.hwnd) {
|
||||
WindowsApi::raise_window(border_info.border_hwnd)?;
|
||||
@@ -771,7 +770,7 @@ impl Window {
|
||||
/// it.
|
||||
/// It also checks if there is a border attached to this window and if it is
|
||||
/// it lowers it as well.
|
||||
pub fn lower(self) -> Result<()> {
|
||||
pub fn lower(self) -> eyre::Result<()> {
|
||||
WindowsApi::lower_window(self.hwnd)?;
|
||||
if let Some(border_info) = crate::border_manager::window_border(self.hwnd) {
|
||||
WindowsApi::lower_window(border_info.border_hwnd)?;
|
||||
@@ -784,7 +783,7 @@ impl Window {
|
||||
self,
|
||||
event: Option<WindowManagerEvent>,
|
||||
debug: &mut RuleDebug,
|
||||
) -> Result<bool> {
|
||||
) -> eyre::Result<bool> {
|
||||
if !self.is_window() {
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -817,13 +816,13 @@ impl Window {
|
||||
|
||||
let mut allow_cloaked = false;
|
||||
|
||||
if let Some(event) = event {
|
||||
if matches!(
|
||||
if let Some(event) = event
|
||||
&& matches!(
|
||||
event,
|
||||
WindowManagerEvent::Hide(_, _) | WindowManagerEvent::Cloak(_, _)
|
||||
) {
|
||||
allow_cloaked = true;
|
||||
}
|
||||
)
|
||||
{
|
||||
allow_cloaked = true;
|
||||
}
|
||||
|
||||
debug.allow_cloaked = allow_cloaked;
|
||||
@@ -1302,31 +1301,31 @@ pub fn should_act_individual(
|
||||
},
|
||||
Some(MatchingStrategy::Regex) => match identifier.kind {
|
||||
ApplicationIdentifier::Title => {
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
||||
if re.is_match(title) {
|
||||
should_act = true;
|
||||
}
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id)
|
||||
&& re.is_match(title)
|
||||
{
|
||||
should_act = true;
|
||||
}
|
||||
}
|
||||
ApplicationIdentifier::Class => {
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
||||
if re.is_match(class) {
|
||||
should_act = true;
|
||||
}
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id)
|
||||
&& re.is_match(class)
|
||||
{
|
||||
should_act = true;
|
||||
}
|
||||
}
|
||||
ApplicationIdentifier::Exe => {
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
||||
if re.is_match(exe_name) {
|
||||
should_act = true;
|
||||
}
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id)
|
||||
&& re.is_match(exe_name)
|
||||
{
|
||||
should_act = true;
|
||||
}
|
||||
}
|
||||
ApplicationIdentifier::Path => {
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
||||
if re.is_match(path) {
|
||||
should_act = true;
|
||||
}
|
||||
if let Some(re) = regex_identifiers.get(&identifier.id)
|
||||
&& re.is_match(path)
|
||||
{
|
||||
should_act = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,12 @@ use std::fmt::Formatter;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::window::should_act;
|
||||
use crate::window::Window;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::window::Window;
|
||||
use crate::window::should_act;
|
||||
use crate::winevent::WinEvent;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::Error;
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre::OptionExt;
|
||||
use color_eyre::eyre::bail;
|
||||
use core::ffi::c_void;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::mem::size_of;
|
||||
use std::path::Path;
|
||||
use windows::core::Result as WindowsCrateResult;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::core::PWSTR;
|
||||
use windows::Win32::Foundation::CloseHandle;
|
||||
use windows::Win32::Foundation::COLORREF;
|
||||
use windows::Win32::Foundation::CloseHandle;
|
||||
use windows::Win32::Foundation::HANDLE;
|
||||
use windows::Win32::Foundation::HINSTANCE;
|
||||
use windows::Win32::Foundation::HMODULE;
|
||||
@@ -21,8 +18,9 @@ use windows::Win32::Foundation::LPARAM;
|
||||
use windows::Win32::Foundation::POINT;
|
||||
use windows::Win32::Foundation::RECT;
|
||||
use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::Graphics::Dwm::DwmGetWindowAttribute;
|
||||
use windows::Win32::Graphics::Dwm::DwmSetWindowAttribute;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
|
||||
use windows::Win32::Graphics::Dwm::DWMWA_BORDER_COLOR;
|
||||
use windows::Win32::Graphics::Dwm::DWMWA_CLOAKED;
|
||||
use windows::Win32::Graphics::Dwm::DWMWA_COLOR_NONE;
|
||||
@@ -30,57 +28,61 @@ use windows::Win32::Graphics::Dwm::DWMWA_EXTENDED_FRAME_BOUNDS;
|
||||
use windows::Win32::Graphics::Dwm::DWMWA_WINDOW_CORNER_PREFERENCE;
|
||||
use windows::Win32::Graphics::Dwm::DWMWCP_ROUND;
|
||||
use windows::Win32::Graphics::Dwm::DWMWINDOWATTRIBUTE;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED;
|
||||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
|
||||
use windows::Win32::Graphics::Dwm::DwmGetWindowAttribute;
|
||||
use windows::Win32::Graphics::Dwm::DwmSetWindowAttribute;
|
||||
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
|
||||
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
|
||||
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
|
||||
use windows::Win32::Graphics::Gdi::HBRUSH;
|
||||
use windows::Win32::Graphics::Gdi::HDC;
|
||||
use windows::Win32::Graphics::Gdi::HMONITOR;
|
||||
use windows::Win32::Graphics::Gdi::InvalidateRect;
|
||||
use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST;
|
||||
use windows::Win32::Graphics::Gdi::MONITORENUMPROC;
|
||||
use windows::Win32::Graphics::Gdi::MONITORINFOEXW;
|
||||
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
|
||||
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
|
||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||
use windows::Win32::Graphics::Gdi::RoundRect;
|
||||
use windows::Win32::Graphics::Gdi::HBRUSH;
|
||||
use windows::Win32::Graphics::Gdi::HDC;
|
||||
use windows::Win32::Graphics::Gdi::HMONITOR;
|
||||
use windows::Win32::Graphics::Gdi::MONITORENUMPROC;
|
||||
use windows::Win32::Graphics::Gdi::MONITORINFOEXW;
|
||||
use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST;
|
||||
use windows::Win32::System::Com::CoCreateInstance;
|
||||
use windows::Win32::System::Com::CLSCTX_ALL;
|
||||
use windows::Win32::System::Com::CoCreateInstance;
|
||||
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
|
||||
use windows::Win32::System::Power::RegisterPowerSettingNotification;
|
||||
use windows::Win32::System::Power::HPOWERNOTIFY;
|
||||
use windows::Win32::System::Power::RegisterPowerSettingNotification;
|
||||
use windows::Win32::System::RemoteDesktop::ProcessIdToSessionId;
|
||||
use windows::Win32::System::RemoteDesktop::WTSRegisterSessionNotification;
|
||||
use windows::Win32::System::Threading::GetCurrentProcessId;
|
||||
use windows::Win32::System::Threading::OpenProcess;
|
||||
use windows::Win32::System::Threading::QueryFullProcessImageNameW;
|
||||
use windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS;
|
||||
use windows::Win32::System::Threading::PROCESS_NAME_WIN32;
|
||||
use windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION;
|
||||
use windows::Win32::UI::HiDpi::GetDpiForMonitor;
|
||||
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
|
||||
use windows::Win32::System::Threading::QueryFullProcessImageNameW;
|
||||
use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
|
||||
use windows::Win32::UI::HiDpi::GetDpiForMonitor;
|
||||
use windows::Win32::UI::HiDpi::MDT_EFFECTIVE_DPI;
|
||||
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::GetKeyState;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::SendInput;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_0;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_MOUSE;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTDOWN;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTUP;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::SendInput;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::VK_LBUTTON;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::VK_MENU;
|
||||
use windows::Win32::UI::Shell::DWPOS_FILL;
|
||||
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::BringWindowToTop;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DEV_BROADCAST_DEVICEINTERFACE_W;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow;
|
||||
@@ -91,15 +93,38 @@ use windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowRect;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowTextW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HDEVNOTIFY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsIconic;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsZoomed;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MoveWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::REGISTER_NOTIFICATION_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::RegisterClassW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::RegisterDeviceNotificationW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPIF_SENDCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MINIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_NORMAL;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNOACTIVATE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_ASYNCWINDOWPOS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetCursorPos;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
|
||||
@@ -108,35 +133,6 @@ use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
|
||||
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::ShowWindowAsync;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DEV_BROADCAST_DEVICEINTERFACE_W;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HDEVNOTIFY;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
|
||||
use windows::Win32::UI::WindowsAndMessaging::REGISTER_NOTIFICATION_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPIF_SENDCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_ASYNCWINDOWPOS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MINIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_NORMAL;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNOACTIVATE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
||||
@@ -147,24 +143,28 @@ use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOOLWINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOPMOST;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_POPUP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_SYSMENU;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::core::PWSTR;
|
||||
use windows::core::Result as WindowsCrateResult;
|
||||
use windows_core::BOOL;
|
||||
use windows_core::HSTRING;
|
||||
|
||||
use crate::core::Rect;
|
||||
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::WINDOW_HANDLING_BEHAVIOUR;
|
||||
use crate::Window;
|
||||
use crate::WindowHandlingBehaviour;
|
||||
use crate::WindowManager;
|
||||
use crate::container::Container;
|
||||
use crate::monitor;
|
||||
use crate::monitor::Monitor;
|
||||
use crate::ring::Ring;
|
||||
use crate::set_window_position::SetWindowPosition;
|
||||
use crate::windows_callbacks;
|
||||
use crate::Window;
|
||||
use crate::WindowHandlingBehaviour;
|
||||
use crate::WindowManager;
|
||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::DUPLICATE_MONITOR_SERIAL_IDS;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::WINDOW_HANDLING_BEHAVIOUR;
|
||||
|
||||
macro_rules! as_ptr {
|
||||
($value:expr) => {
|
||||
@@ -207,7 +207,7 @@ impl<T, E> From<WindowsResult<T, E>> for Result<T, E> {
|
||||
}
|
||||
|
||||
pub trait ProcessWindowsCrateResult<T> {
|
||||
fn process(self) -> Result<T>;
|
||||
fn process(self) -> eyre::Result<T>;
|
||||
}
|
||||
|
||||
macro_rules! impl_process_windows_crate_integer_wrapper_result {
|
||||
@@ -215,7 +215,7 @@ macro_rules! impl_process_windows_crate_integer_wrapper_result {
|
||||
paste::paste! {
|
||||
$(
|
||||
impl ProcessWindowsCrateResult<$deref> for $input {
|
||||
fn process(self) -> Result<$deref> {
|
||||
fn process(self) -> eyre::Result<$deref> {
|
||||
if self == $input(std::ptr::null_mut()) {
|
||||
Err(std::io::Error::last_os_error().into())
|
||||
} else {
|
||||
@@ -233,7 +233,7 @@ impl_process_windows_crate_integer_wrapper_result!(
|
||||
);
|
||||
|
||||
impl<T> ProcessWindowsCrateResult<T> for WindowsCrateResult<T> {
|
||||
fn process(self) -> Result<T> {
|
||||
fn process(self) -> eyre::Result<T> {
|
||||
match self {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => Err(error.into()),
|
||||
@@ -247,13 +247,13 @@ impl WindowsApi {
|
||||
pub fn enum_display_monitors(
|
||||
callback: MONITORENUMPROC,
|
||||
callback_data_address: isize,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
unsafe { EnumDisplayMonitors(None, None, callback, LPARAM(callback_data_address)) }
|
||||
.ok()
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn valid_hmonitors() -> Result<Vec<(String, isize)>> {
|
||||
pub fn valid_hmonitors() -> eyre::Result<Vec<(String, isize)>> {
|
||||
Ok(win32_display_data::connected_displays_all()
|
||||
.flatten()
|
||||
.map(|d| {
|
||||
@@ -265,7 +265,7 @@ impl WindowsApi {
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn load_monitor_information(wm: &mut WindowManager) -> Result<()> {
|
||||
pub fn load_monitor_information(wm: &mut WindowManager) -> eyre::Result<()> {
|
||||
let monitors = &mut wm.monitors;
|
||||
let monitor_usr_idx_map = &mut wm.monitor_usr_idx_map;
|
||||
|
||||
@@ -282,12 +282,12 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
for d in &all_displays {
|
||||
if let Some(id) = &d.serial_number_id {
|
||||
if serial_id_map.get(id).copied().unwrap_or_default() > 1 {
|
||||
let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.write();
|
||||
if !dupes.contains(id) {
|
||||
(*dupes).push(id.clone());
|
||||
}
|
||||
if let Some(id) = &d.serial_number_id
|
||||
&& serial_id_map.get(id).copied().unwrap_or_default() > 1
|
||||
{
|
||||
let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.write();
|
||||
if !dupes.contains(id) {
|
||||
(*dupes).push(id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,7 +310,7 @@ impl WindowsApi {
|
||||
let name = name.split('\\').collect::<Vec<_>>()[0].to_string();
|
||||
|
||||
for monitor in monitors.elements() {
|
||||
if device_id.eq(monitor.device_id()) {
|
||||
if device_id.eq(&monitor.device_id) {
|
||||
continue 'read;
|
||||
}
|
||||
}
|
||||
@@ -335,15 +335,14 @@ impl WindowsApi {
|
||||
let mut index_preference = None;
|
||||
let monitor_index_preferences = MONITOR_INDEX_PREFERENCES.lock();
|
||||
for (index, monitor_size) in &*monitor_index_preferences {
|
||||
if m.size() == monitor_size {
|
||||
if m.size == *monitor_size {
|
||||
index_preference = Option::from(index);
|
||||
}
|
||||
}
|
||||
|
||||
let display_index_preferences = DISPLAY_INDEX_PREFERENCES.read();
|
||||
for (index, id) in &*display_index_preferences {
|
||||
if m.serial_number_id().as_ref().is_some_and(|sn| sn == id) || id.eq(m.device_id())
|
||||
{
|
||||
if m.serial_number_id.as_ref().is_some_and(|sn| sn == id) || id.eq(&m.device_id) {
|
||||
index_preference = Option::from(index);
|
||||
}
|
||||
}
|
||||
@@ -356,7 +355,7 @@ impl WindowsApi {
|
||||
let current_name = monitors
|
||||
.elements_mut()
|
||||
.get(*preference)
|
||||
.map_or("", |m| m.name());
|
||||
.map_or("", |m| &m.name);
|
||||
if current_name == "PLACEHOLDER" {
|
||||
let _ = monitors.elements_mut().remove(*preference);
|
||||
monitors.elements_mut().insert(*preference, m);
|
||||
@@ -368,16 +367,14 @@ impl WindowsApi {
|
||||
}
|
||||
}
|
||||
|
||||
monitors
|
||||
.elements_mut()
|
||||
.retain(|m| m.name().ne("PLACEHOLDER"));
|
||||
monitors.elements_mut().retain(|m| m.name.ne("PLACEHOLDER"));
|
||||
|
||||
// Rebuild monitor index map
|
||||
*monitor_usr_idx_map = HashMap::new();
|
||||
let mut added_monitor_idxs = Vec::new();
|
||||
for (index, id) in &*DISPLAY_INDEX_PREFERENCES.read() {
|
||||
if let Some(m_idx) = monitors.elements().iter().position(|m| {
|
||||
m.serial_number_id().as_ref().is_some_and(|sn| sn == id) || m.device_id() == id
|
||||
m.serial_number_id.as_ref().is_some_and(|sn| sn == id) || m.device_id.eq(id)
|
||||
}) {
|
||||
monitor_usr_idx_map.insert(*index, m_idx);
|
||||
added_monitor_idxs.push(m_idx);
|
||||
@@ -409,13 +406,13 @@ impl WindowsApi {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enum_windows(callback: WNDENUMPROC, callback_data_address: isize) -> Result<()> {
|
||||
pub fn enum_windows(callback: WNDENUMPROC, callback_data_address: isize) -> eyre::Result<()> {
|
||||
unsafe { EnumWindows(callback, LPARAM(callback_data_address)) }.process()
|
||||
}
|
||||
|
||||
pub fn load_workspace_information(monitors: &mut Ring<Monitor>) -> Result<()> {
|
||||
pub fn load_workspace_information(monitors: &mut Ring<Monitor>) -> eyre::Result<()> {
|
||||
for monitor in monitors.elements_mut() {
|
||||
let monitor_name = monitor.name().clone();
|
||||
let monitor_name = monitor.name.clone();
|
||||
if let Some(workspace) = monitor.workspaces_mut().front_mut() {
|
||||
// EnumWindows will enumerate through windows on all monitors
|
||||
Self::enum_windows(
|
||||
@@ -426,7 +423,7 @@ impl WindowsApi {
|
||||
// Ensure that the resize_dimensions Vec length matches the number of containers for
|
||||
// the potential later calls to workspace.remove_window later in this fn
|
||||
let len = workspace.containers().len();
|
||||
workspace.resize_dimensions_mut().resize(len, None);
|
||||
workspace.resize_dimensions.resize(len, None);
|
||||
|
||||
// We have to prune each monitor's primary workspace of undesired windows here
|
||||
let mut windows_on_other_monitors = vec![];
|
||||
@@ -448,7 +445,7 @@ impl WindowsApi {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn allow_set_foreground_window(process_id: u32) -> Result<()> {
|
||||
pub fn allow_set_foreground_window(process_id: u32) -> eyre::Result<()> {
|
||||
unsafe { AllowSetForegroundWindow(process_id) }.process()
|
||||
}
|
||||
|
||||
@@ -458,13 +455,13 @@ impl WindowsApi {
|
||||
unsafe { MonitorFromWindow(HWND(as_ptr!(hwnd)), MONITOR_DEFAULTTONEAREST) }.0 as isize
|
||||
}
|
||||
|
||||
pub fn monitor_name_from_window(hwnd: isize) -> Result<String> {
|
||||
pub fn monitor_name_from_window(hwnd: isize) -> eyre::Result<String> {
|
||||
// MONITOR_DEFAULTTONEAREST ensures that the return value will never be NULL
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow
|
||||
Ok(Self::monitor(
|
||||
unsafe { MonitorFromWindow(HWND(as_ptr!(hwnd)), MONITOR_DEFAULTTONEAREST) }.0 as isize,
|
||||
)?
|
||||
.name()
|
||||
.name
|
||||
.to_string())
|
||||
}
|
||||
|
||||
@@ -482,7 +479,7 @@ impl WindowsApi {
|
||||
layout: &Rect,
|
||||
top: bool,
|
||||
with_async_window_pos: bool,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
let hwnd = HWND(as_ptr!(hwnd));
|
||||
|
||||
let mut flags = SetWindowPosition::NO_ACTIVATE
|
||||
@@ -533,13 +530,13 @@ impl WindowsApi {
|
||||
Self::set_window_pos(hwnd, &rect, HWND_TOP, flags.bits())
|
||||
}
|
||||
|
||||
pub fn bring_window_to_top(hwnd: isize) -> Result<()> {
|
||||
pub fn bring_window_to_top(hwnd: isize) -> eyre::Result<()> {
|
||||
unsafe { BringWindowToTop(HWND(as_ptr!(hwnd))) }.process()
|
||||
}
|
||||
|
||||
/// Raise the window to the top of the Z order, but do not activate or focus
|
||||
/// it. Use raise_and_focus_window to activate and focus a window.
|
||||
pub fn raise_window(hwnd: isize) -> Result<()> {
|
||||
pub fn raise_window(hwnd: isize) -> eyre::Result<()> {
|
||||
let mut flags = SetWindowPosition::NO_MOVE
|
||||
| SetWindowPosition::NO_SIZE
|
||||
| SetWindowPosition::NO_ACTIVATE
|
||||
@@ -563,7 +560,7 @@ impl WindowsApi {
|
||||
|
||||
/// Lower the window to the bottom of the Z order, but do not activate or focus
|
||||
/// it.
|
||||
pub fn lower_window(hwnd: isize) -> Result<()> {
|
||||
pub fn lower_window(hwnd: isize) -> eyre::Result<()> {
|
||||
let mut flags = SetWindowPosition::NO_MOVE
|
||||
| SetWindowPosition::NO_SIZE
|
||||
| SetWindowPosition::NO_ACTIVATE
|
||||
@@ -585,7 +582,7 @@ impl WindowsApi {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> Result<()> {
|
||||
pub fn set_border_pos(hwnd: isize, layout: &Rect, position: isize) -> eyre::Result<()> {
|
||||
let mut flags = SetWindowPosition::NO_SEND_CHANGING
|
||||
| SetWindowPosition::NO_ACTIVATE
|
||||
| SetWindowPosition::NO_REDRAW
|
||||
@@ -607,7 +604,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
/// set_window_pos calls SetWindowPos without any accounting for Window decorations.
|
||||
fn set_window_pos(hwnd: HWND, layout: &Rect, position: HWND, flags: u32) -> Result<()> {
|
||||
fn set_window_pos(hwnd: HWND, layout: &Rect, position: HWND, flags: u32) -> eyre::Result<()> {
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
hwnd,
|
||||
@@ -623,7 +620,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
/// move_windows calls MoveWindow, but cannot be called with async window pos, so it might hang
|
||||
pub fn move_window(hwnd: isize, layout: &Rect, repaint: bool) -> Result<()> {
|
||||
pub fn move_window(hwnd: isize, layout: &Rect, repaint: bool) -> eyre::Result<()> {
|
||||
let hwnd = HWND(as_ptr!(hwnd));
|
||||
|
||||
let shadow_rect = Self::shadow_rect(hwnd).unwrap_or_default();
|
||||
@@ -658,15 +655,16 @@ impl WindowsApi {
|
||||
Self::show_window(hwnd, SW_MINIMIZE);
|
||||
}
|
||||
|
||||
fn post_message(hwnd: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> Result<()> {
|
||||
fn post_message(hwnd: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> eyre::Result<()> {
|
||||
unsafe { PostMessageW(Option::from(hwnd), message, wparam, lparam) }.process()
|
||||
}
|
||||
|
||||
pub fn close_window(hwnd: isize) -> Result<()> {
|
||||
match Self::post_message(HWND(as_ptr!(hwnd)), WM_CLOSE, WPARAM(0), LPARAM(0)) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(anyhow!("could not close window")),
|
||||
pub fn close_window(hwnd: isize) -> eyre::Result<()> {
|
||||
if Self::post_message(HWND(as_ptr!(hwnd)), WM_CLOSE, WPARAM(0), LPARAM(0)).is_err() {
|
||||
bail!("could not close window");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hide_window(hwnd: isize) {
|
||||
@@ -685,11 +683,11 @@ impl WindowsApi {
|
||||
Self::show_window(hwnd, SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
pub fn foreground_window() -> Result<isize> {
|
||||
pub fn foreground_window() -> eyre::Result<isize> {
|
||||
unsafe { GetForegroundWindow() }.process()
|
||||
}
|
||||
|
||||
pub fn raise_and_focus_window(hwnd: isize) -> Result<()> {
|
||||
pub fn raise_and_focus_window(hwnd: isize) -> eyre::Result<()> {
|
||||
let event = [INPUT {
|
||||
r#type: INPUT_MOUSE,
|
||||
..Default::default()
|
||||
@@ -717,20 +715,20 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn top_window() -> Result<isize> {
|
||||
pub fn top_window() -> eyre::Result<isize> {
|
||||
unsafe { GetTopWindow(None)? }.process()
|
||||
}
|
||||
|
||||
pub fn desktop_window() -> Result<isize> {
|
||||
pub fn desktop_window() -> eyre::Result<isize> {
|
||||
unsafe { GetDesktopWindow() }.process()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn next_window(hwnd: isize) -> Result<isize> {
|
||||
pub fn next_window(hwnd: isize) -> eyre::Result<isize> {
|
||||
unsafe { GetWindow(HWND(as_ptr!(hwnd)), GW_HWNDNEXT)? }.process()
|
||||
}
|
||||
|
||||
pub fn alt_tab_windows() -> Result<Vec<Window>> {
|
||||
pub fn alt_tab_windows() -> eyre::Result<Vec<Window>> {
|
||||
let mut hwnds = vec![];
|
||||
Self::enum_windows(
|
||||
Some(windows_callbacks::alt_tab_windows),
|
||||
@@ -741,7 +739,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn top_visible_window() -> Result<isize> {
|
||||
pub fn top_visible_window() -> eyre::Result<isize> {
|
||||
let hwnd = Self::top_window()?;
|
||||
let mut next_hwnd = hwnd;
|
||||
|
||||
@@ -753,10 +751,10 @@ impl WindowsApi {
|
||||
next_hwnd = Self::next_window(next_hwnd)?;
|
||||
}
|
||||
|
||||
Err(anyhow!("could not find next window"))
|
||||
bail!("could not find next window")
|
||||
}
|
||||
|
||||
pub fn window_rect(hwnd: isize) -> Result<Rect> {
|
||||
pub fn window_rect(hwnd: isize) -> eyre::Result<Rect> {
|
||||
let mut rect = unsafe { std::mem::zeroed() };
|
||||
|
||||
if Self::dwm_get_window_attribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &mut rect).is_ok() {
|
||||
@@ -775,7 +773,7 @@ impl WindowsApi {
|
||||
/// the window painted region. The four values in the returned Rect can be
|
||||
/// added to a position rect to compute a size for set_window_pos that will
|
||||
/// fill the target area, ignoring shadows.
|
||||
fn shadow_rect(hwnd: HWND) -> Result<Rect> {
|
||||
fn shadow_rect(hwnd: HWND) -> eyre::Result<Rect> {
|
||||
let window_rect = Self::window_rect(hwnd.0 as isize)?;
|
||||
|
||||
let mut srect = Default::default();
|
||||
@@ -810,26 +808,26 @@ impl WindowsApi {
|
||||
let _ = Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
}
|
||||
fn set_cursor_pos(x: i32, y: i32) -> Result<()> {
|
||||
fn set_cursor_pos(x: i32, y: i32) -> eyre::Result<()> {
|
||||
unsafe { SetCursorPos(x, y) }.process()
|
||||
}
|
||||
|
||||
pub fn cursor_pos() -> Result<POINT> {
|
||||
pub fn cursor_pos() -> eyre::Result<POINT> {
|
||||
let mut cursor_pos = POINT::default();
|
||||
unsafe { GetCursorPos(&mut cursor_pos) }.process()?;
|
||||
|
||||
Ok(cursor_pos)
|
||||
}
|
||||
|
||||
pub fn window_from_point(point: POINT) -> Result<isize> {
|
||||
pub fn window_from_point(point: POINT) -> eyre::Result<isize> {
|
||||
unsafe { WindowFromPoint(point) }.process()
|
||||
}
|
||||
|
||||
pub fn window_at_cursor_pos() -> Result<isize> {
|
||||
pub fn window_at_cursor_pos() -> eyre::Result<isize> {
|
||||
Self::window_from_point(Self::cursor_pos()?)
|
||||
}
|
||||
|
||||
pub fn center_cursor_in_rect(rect: &Rect) -> Result<()> {
|
||||
pub fn center_cursor_in_rect(rect: &Rect) -> eyre::Result<()> {
|
||||
Self::set_cursor_pos(rect.left + (rect.right / 2), rect.top + (rect.bottom / 2))
|
||||
}
|
||||
|
||||
@@ -852,17 +850,17 @@ impl WindowsApi {
|
||||
unsafe { GetCurrentProcessId() }
|
||||
}
|
||||
|
||||
pub fn process_id_to_session_id() -> Result<u32> {
|
||||
pub fn process_id_to_session_id() -> eyre::Result<u32> {
|
||||
let process_id = Self::current_process_id();
|
||||
let mut session_id = 0;
|
||||
|
||||
unsafe {
|
||||
if ProcessIdToSessionId(process_id, &mut session_id).is_ok() {
|
||||
Ok(session_id)
|
||||
} else {
|
||||
Err(anyhow!("could not determine current session id"))
|
||||
if ProcessIdToSessionId(process_id, &mut session_id).is_err() {
|
||||
bail!("could not determine current session id")
|
||||
}
|
||||
}
|
||||
|
||||
Ok(session_id)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
@@ -870,7 +868,7 @@ impl WindowsApi {
|
||||
hwnd: HWND,
|
||||
index: WINDOW_LONG_PTR_INDEX,
|
||||
new_value: isize,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
Result::from(WindowsResult::from(unsafe {
|
||||
SetWindowLongPtrW(hwnd, index, new_value)
|
||||
}))
|
||||
@@ -882,7 +880,7 @@ impl WindowsApi {
|
||||
hwnd: HWND,
|
||||
index: WINDOW_LONG_PTR_INDEX,
|
||||
new_value: i32,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
Result::from(WindowsResult::from(unsafe {
|
||||
SetWindowLongPtrW(hwnd, index, new_value)
|
||||
}))
|
||||
@@ -890,27 +888,27 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn gwl_style(hwnd: isize) -> Result<isize> {
|
||||
pub fn gwl_style(hwnd: isize) -> eyre::Result<isize> {
|
||||
Self::window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_STYLE)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn gwl_style(hwnd: isize) -> Result<i32> {
|
||||
pub fn gwl_style(hwnd: isize) -> eyre::Result<i32> {
|
||||
Self::window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_STYLE)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn gwl_ex_style(hwnd: isize) -> Result<isize> {
|
||||
pub fn gwl_ex_style(hwnd: isize) -> eyre::Result<isize> {
|
||||
Self::window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_EXSTYLE)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn gwl_ex_style(hwnd: isize) -> Result<i32> {
|
||||
pub fn gwl_ex_style(hwnd: isize) -> eyre::Result<i32> {
|
||||
Self::window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_EXSTYLE)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn window_long_ptr_w(hwnd: HWND, index: WINDOW_LONG_PTR_INDEX) -> Result<isize> {
|
||||
fn window_long_ptr_w(hwnd: HWND, index: WINDOW_LONG_PTR_INDEX) -> eyre::Result<isize> {
|
||||
// Can return 0, which does not always mean that an error has occurred
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptrw
|
||||
Result::from(WindowsResult::from(unsafe {
|
||||
@@ -919,7 +917,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn window_long_ptr_w(hwnd: HWND, index: WINDOW_LONG_PTR_INDEX) -> Result<i32> {
|
||||
fn window_long_ptr_w(hwnd: HWND, index: WINDOW_LONG_PTR_INDEX) -> eyre::Result<i32> {
|
||||
// Can return 0, which does not always mean that an error has occurred
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptrw
|
||||
Result::from(WindowsResult::from(unsafe {
|
||||
@@ -928,26 +926,26 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn update_style(hwnd: isize, new_value: isize) -> Result<()> {
|
||||
pub fn update_style(hwnd: isize, new_value: isize) -> eyre::Result<()> {
|
||||
Self::set_window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_STYLE, new_value)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn update_style(hwnd: isize, new_value: i32) -> Result<()> {
|
||||
pub fn update_style(hwnd: isize, new_value: i32) -> eyre::Result<()> {
|
||||
Self::set_window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_STYLE, new_value)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn update_ex_style(hwnd: isize, new_value: isize) -> Result<()> {
|
||||
pub fn update_ex_style(hwnd: isize, new_value: isize) -> eyre::Result<()> {
|
||||
Self::set_window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_EXSTYLE, new_value)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn update_ex_style(hwnd: isize, new_value: i32) -> Result<()> {
|
||||
pub fn update_ex_style(hwnd: isize, new_value: i32) -> eyre::Result<()> {
|
||||
Self::set_window_long_ptr_w(HWND(as_ptr!(hwnd)), GWL_EXSTYLE, new_value)
|
||||
}
|
||||
|
||||
pub fn window_text_w(hwnd: isize) -> Result<String> {
|
||||
pub fn window_text_w(hwnd: isize) -> eyre::Result<String> {
|
||||
let mut text: [u16; 512] = [0; 512];
|
||||
match WindowsResult::from(unsafe { GetWindowTextW(HWND(as_ptr!(hwnd)), &mut text) }) {
|
||||
WindowsResult::Ok(len) => {
|
||||
@@ -962,19 +960,19 @@ impl WindowsApi {
|
||||
access_rights: PROCESS_ACCESS_RIGHTS,
|
||||
inherit_handle: bool,
|
||||
process_id: u32,
|
||||
) -> Result<HANDLE> {
|
||||
) -> eyre::Result<HANDLE> {
|
||||
unsafe { OpenProcess(access_rights, inherit_handle, process_id) }.process()
|
||||
}
|
||||
|
||||
pub fn close_process(handle: HANDLE) -> Result<()> {
|
||||
pub fn close_process(handle: HANDLE) -> eyre::Result<()> {
|
||||
unsafe { CloseHandle(handle) }.process()
|
||||
}
|
||||
|
||||
pub fn process_handle(process_id: u32) -> Result<HANDLE> {
|
||||
pub fn process_handle(process_id: u32) -> eyre::Result<HANDLE> {
|
||||
Self::open_process(PROCESS_QUERY_INFORMATION, false, process_id)
|
||||
}
|
||||
|
||||
pub fn exe_path(handle: HANDLE) -> Result<String> {
|
||||
pub fn exe_path(handle: HANDLE) -> eyre::Result<String> {
|
||||
let mut len = 260_u32;
|
||||
let mut path: Vec<u16> = vec![0; len as usize];
|
||||
let text_ptr = path.as_mut_ptr();
|
||||
@@ -987,15 +985,15 @@ impl WindowsApi {
|
||||
Ok(String::from_utf16(&path[..len as usize])?)
|
||||
}
|
||||
|
||||
pub fn exe(handle: HANDLE) -> Result<String> {
|
||||
pub fn exe(handle: HANDLE) -> eyre::Result<String> {
|
||||
Ok(Self::exe_path(handle)?
|
||||
.split('\\')
|
||||
.next_back()
|
||||
.ok_or_else(|| anyhow!("there is no last element"))?
|
||||
.ok_or_eyre("there is no last element")?
|
||||
.to_string())
|
||||
}
|
||||
|
||||
pub fn real_window_class_w(hwnd: isize) -> Result<String> {
|
||||
pub fn real_window_class_w(hwnd: isize) -> eyre::Result<String> {
|
||||
const BUF_SIZE: usize = 512;
|
||||
let mut class: [u16; BUF_SIZE] = [0; BUF_SIZE];
|
||||
|
||||
@@ -1010,7 +1008,7 @@ impl WindowsApi {
|
||||
hwnd: isize,
|
||||
attribute: DWMWINDOWATTRIBUTE,
|
||||
value: &mut T,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
unsafe {
|
||||
DwmGetWindowAttribute(
|
||||
HWND(as_ptr!(hwnd)),
|
||||
@@ -1023,7 +1021,7 @@ impl WindowsApi {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_window_cloaked(hwnd: isize) -> Result<bool> {
|
||||
pub fn is_window_cloaked(hwnd: isize) -> eyre::Result<bool> {
|
||||
let mut cloaked: u32 = 0;
|
||||
Self::dwm_get_window_attribute(hwnd, DWMWA_CLOAKED, &mut cloaked)?;
|
||||
|
||||
@@ -1049,7 +1047,7 @@ impl WindowsApi {
|
||||
unsafe { IsZoomed(HWND(as_ptr!(hwnd))) }.into()
|
||||
}
|
||||
|
||||
pub fn monitor_info_w(hmonitor: HMONITOR) -> Result<MONITORINFOEXW> {
|
||||
pub fn monitor_info_w(hmonitor: HMONITOR) -> eyre::Result<MONITORINFOEXW> {
|
||||
let mut ex_info = MONITORINFOEXW::default();
|
||||
ex_info.monitorInfo.cbSize = u32::try_from(std::mem::size_of::<MONITORINFOEXW>())?;
|
||||
unsafe { GetMonitorInfoW(hmonitor, &mut ex_info.monitorInfo) }
|
||||
@@ -1069,7 +1067,7 @@ impl WindowsApi {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
|
||||
pub fn monitor(hmonitor: isize) -> eyre::Result<Monitor> {
|
||||
for mut display in win32_display_data::connected_displays_all().flatten() {
|
||||
if display.hmonitor == hmonitor {
|
||||
let path = display.device_path;
|
||||
@@ -1112,7 +1110,7 @@ impl WindowsApi {
|
||||
bail!("could not find device_id for hmonitor: {hmonitor}");
|
||||
}
|
||||
|
||||
pub fn set_process_dpi_awareness_context() -> Result<()> {
|
||||
pub fn set_process_dpi_awareness_context() -> eyre::Result<()> {
|
||||
unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) }
|
||||
.process()
|
||||
}
|
||||
@@ -1123,13 +1121,13 @@ impl WindowsApi {
|
||||
ui_param: u32,
|
||||
pv_param: *mut c_void,
|
||||
update_flags: SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
unsafe { SystemParametersInfoW(action, ui_param, Option::from(pv_param), update_flags) }
|
||||
.process()
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn foreground_lock_timeout() -> Result<()> {
|
||||
pub fn foreground_lock_timeout() -> eyre::Result<()> {
|
||||
let mut value: u32 = 0;
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
@@ -1142,7 +1140,9 @@ impl WindowsApi {
|
||||
tracing::info!("current value of ForegroundLockTimeout is {value}");
|
||||
|
||||
if value != 0 {
|
||||
tracing::info!("updating value of ForegroundLockTimeout to {value} in order to enable keyboard-driven focus updating");
|
||||
tracing::info!(
|
||||
"updating value of ForegroundLockTimeout to {value} in order to enable keyboard-driven focus updating"
|
||||
);
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
SPI_SETFOREGROUNDLOCKTIMEOUT,
|
||||
@@ -1165,7 +1165,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn focus_follows_mouse() -> Result<bool> {
|
||||
pub fn focus_follows_mouse() -> eyre::Result<bool> {
|
||||
let mut is_enabled: BOOL = unsafe { std::mem::zeroed() };
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
@@ -1179,7 +1179,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn enable_focus_follows_mouse() -> Result<()> {
|
||||
pub fn enable_focus_follows_mouse() -> eyre::Result<()> {
|
||||
#[allow(clippy::manual_dangling_ptr)]
|
||||
Self::system_parameters_info_w(
|
||||
SPI_SETACTIVEWINDOWTRACKING,
|
||||
@@ -1190,7 +1190,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn disable_focus_follows_mouse() -> Result<()> {
|
||||
pub fn disable_focus_follows_mouse() -> eyre::Result<()> {
|
||||
Self::system_parameters_info_w(
|
||||
SPI_SETACTIVEWINDOWTRACKING,
|
||||
0,
|
||||
@@ -1199,7 +1199,7 @@ impl WindowsApi {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn module_handle_w() -> Result<HMODULE> {
|
||||
pub fn module_handle_w() -> eyre::Result<HMODULE> {
|
||||
unsafe { GetModuleHandleW(None) }.process()
|
||||
}
|
||||
|
||||
@@ -1207,11 +1207,11 @@ impl WindowsApi {
|
||||
unsafe { CreateSolidBrush(COLORREF(colour)) }
|
||||
}
|
||||
|
||||
pub fn register_class_w(window_class: &WNDCLASSW) -> Result<u16> {
|
||||
pub fn register_class_w(window_class: &WNDCLASSW) -> eyre::Result<u16> {
|
||||
Result::from(WindowsResult::from(unsafe { RegisterClassW(window_class) }))
|
||||
}
|
||||
|
||||
pub fn dpi_for_monitor(hmonitor: isize) -> Result<f32> {
|
||||
pub fn dpi_for_monitor(hmonitor: isize) -> eyre::Result<f32> {
|
||||
let mut dpi_x = u32::default();
|
||||
let mut dpi_y = u32::default();
|
||||
|
||||
@@ -1229,14 +1229,14 @@ impl WindowsApi {
|
||||
Ok(dpi_y as f32 / 96.0)
|
||||
}
|
||||
|
||||
pub fn monitors_have_same_dpi(hmonitor_a: isize, hmonitor_b: isize) -> Result<bool> {
|
||||
pub fn monitors_have_same_dpi(hmonitor_a: isize, hmonitor_b: isize) -> eyre::Result<bool> {
|
||||
let dpi_a = Self::dpi_for_monitor(hmonitor_a)?;
|
||||
let dpi_b = Self::dpi_for_monitor(hmonitor_b)?;
|
||||
|
||||
Ok((dpi_a - dpi_b).abs() < f32::EPSILON)
|
||||
}
|
||||
|
||||
pub fn round_corners(hwnd: isize) -> Result<()> {
|
||||
pub fn round_corners(hwnd: isize) -> eyre::Result<()> {
|
||||
let round = DWMWCP_ROUND;
|
||||
|
||||
unsafe {
|
||||
@@ -1250,7 +1250,7 @@ impl WindowsApi {
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn set_window_accent(hwnd: isize, color: Option<u32>) -> Result<()> {
|
||||
pub fn set_window_accent(hwnd: isize, color: Option<u32>) -> eyre::Result<()> {
|
||||
let col_ref = COLORREF(color.unwrap_or(DWMWA_COLOR_NONE));
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
@@ -1267,7 +1267,7 @@ impl WindowsApi {
|
||||
name: PCWSTR,
|
||||
instance: isize,
|
||||
border: *mut Border,
|
||||
) -> Result<isize> {
|
||||
) -> eyre::Result<isize> {
|
||||
unsafe {
|
||||
CreateWindowExW(
|
||||
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE,
|
||||
@@ -1287,7 +1287,7 @@ impl WindowsApi {
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn set_transparent(hwnd: isize, alpha: u8) -> Result<()> {
|
||||
pub fn set_transparent(hwnd: isize, alpha: u8) -> eyre::Result<()> {
|
||||
unsafe {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
SetLayeredWindowAttributes(
|
||||
@@ -1301,7 +1301,7 @@ impl WindowsApi {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_transparent(hwnd: isize) -> Result<u8> {
|
||||
pub fn get_transparent(hwnd: isize) -> eyre::Result<u8> {
|
||||
unsafe {
|
||||
let mut alpha: u8 = u8::default();
|
||||
let mut color_ref = COLORREF(-1i32 as u32);
|
||||
@@ -1316,7 +1316,7 @@ impl WindowsApi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_hidden_window(name: PCWSTR, instance: isize) -> Result<isize> {
|
||||
pub fn create_hidden_window(name: PCWSTR, instance: isize) -> eyre::Result<isize> {
|
||||
unsafe {
|
||||
CreateWindowExW(
|
||||
WS_EX_NOACTIVATE,
|
||||
@@ -1410,11 +1410,11 @@ impl WindowsApi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wts_register_session_notification(hwnd: isize) -> Result<()> {
|
||||
pub fn wts_register_session_notification(hwnd: isize) -> eyre::Result<()> {
|
||||
unsafe { WTSRegisterSessionNotification(HWND(as_ptr!(hwnd)), 1) }.process()
|
||||
}
|
||||
|
||||
pub fn set_wallpaper(path: &Path, hmonitor: isize) -> Result<()> {
|
||||
pub fn set_wallpaper(path: &Path, hmonitor: isize) -> eyre::Result<()> {
|
||||
let path = path.canonicalize()?;
|
||||
|
||||
let wallpaper: IDesktopWallpaper =
|
||||
@@ -1438,7 +1438,7 @@ impl WindowsApi {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_wallpaper(hmonitor: isize) -> Result<String> {
|
||||
pub fn get_wallpaper(hmonitor: isize) -> eyre::Result<String> {
|
||||
let wallpaper: IDesktopWallpaper =
|
||||
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL)? };
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Foundation::LPARAM;
|
||||
use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::UI::Accessibility::HWINEVENTHOOK;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowLongW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SendNotifyMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowLongW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::OBJID_WINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SendNotifyMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_CHILD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_EX_NOACTIVATE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOOLWINDOW;
|
||||
@@ -33,16 +33,16 @@ pub extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window::from(hwnd);
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default()) {
|
||||
if should_manage {
|
||||
if is_maximized {
|
||||
WindowsApi::restore_window(window.hwnd);
|
||||
}
|
||||
|
||||
let mut container = Container::default();
|
||||
container.windows_mut().push_back(window);
|
||||
containers.push_back(container);
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default())
|
||||
&& should_manage
|
||||
{
|
||||
if is_maximized {
|
||||
WindowsApi::restore_window(window.hwnd);
|
||||
}
|
||||
|
||||
let mut container = Container::default();
|
||||
container.windows_mut().push_back(window);
|
||||
containers.push_back(container);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +59,10 @@ pub extern "system" fn alt_tab_windows(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window::from(hwnd);
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default()) {
|
||||
if should_manage {
|
||||
windows.push(window);
|
||||
}
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default())
|
||||
&& should_manage
|
||||
{
|
||||
windows.push(window);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use windows::Win32::UI::Accessibility::SetWinEventHook;
|
||||
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EVENT_MAX;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EVENT_MIN;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MSG;
|
||||
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WINEVENT_OUTOFCONTEXT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WINEVENT_SKIPOWNPROCESS;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
description = "The command-line interface (without a console) for Komorebi, a tiling window manager for Windows"
|
||||
repository = "https://github.com/LGUG2Z/komorebi"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "komorebic"
|
||||
version = "0.1.38"
|
||||
version = "0.1.39"
|
||||
description = "The command-line interface for Komorebi, a tiling window manager for Windows"
|
||||
repository = "https://github.com/LGUG2Z/komorebi"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#![allow(clippy::missing_errors_doc, clippy::doc_markdown)]
|
||||
|
||||
use chrono::Utc;
|
||||
use komorebi_client::replace_env_in_path;
|
||||
use komorebi_client::PathExt;
|
||||
use komorebi_client::replace_env_in_path;
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io;
|
||||
@@ -20,15 +20,15 @@ use std::time::Duration;
|
||||
use clap::CommandFactory;
|
||||
use clap::Parser;
|
||||
use clap::ValueEnum;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::OptionExt;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use dirs::data_local_dir;
|
||||
use fs_tail::TailedFile;
|
||||
use komorebi_client::send_message;
|
||||
use komorebi_client::send_query;
|
||||
use komorebi_client::AppSpecificConfigurationPath;
|
||||
use komorebi_client::ApplicationSpecificConfiguration;
|
||||
use komorebi_client::send_message;
|
||||
use komorebi_client::send_query;
|
||||
use lazy_static::lazy_static;
|
||||
use miette::NamedSource;
|
||||
use miette::Report;
|
||||
@@ -39,9 +39,9 @@ use serde::Deserialize;
|
||||
use sysinfo::ProcessesToUpdate;
|
||||
use which::which;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_RESTORE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
||||
|
||||
use komorebi_client::ApplicationConfigurationGenerator;
|
||||
use komorebi_client::ApplicationIdentifier;
|
||||
@@ -1527,7 +1527,7 @@ fn print_query(message: &SocketMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
fn startup_dir() -> Result<PathBuf> {
|
||||
fn startup_dir() -> eyre::Result<PathBuf> {
|
||||
let startup = dirs::home_dir()
|
||||
.expect("unable to obtain user's home folder")
|
||||
.join("AppData")
|
||||
@@ -1546,7 +1546,7 @@ fn startup_dir() -> Result<PathBuf> {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
fn main() -> Result<()> {
|
||||
fn main() -> eyre::Result<()> {
|
||||
let opts: Opts = Opts::parse();
|
||||
|
||||
match opts.subcmd {
|
||||
@@ -1585,7 +1585,7 @@ fn main() -> Result<()> {
|
||||
path: &PathBuf,
|
||||
content: &str,
|
||||
created_files: &mut Vec<String>,
|
||||
) -> Result<()> {
|
||||
) -> eyre::Result<()> {
|
||||
if path.exists() {
|
||||
print!(
|
||||
"{} will be overwritten, do you want to continue? (y/N): ",
|
||||
@@ -1691,8 +1691,12 @@ fn main() -> Result<()> {
|
||||
.env("TARGET_ARGS", arguments)
|
||||
.output()?;
|
||||
|
||||
println!("NOTE: If your komorebi.json file contains a reference to $Env:KOMOREBI_CONFIG_HOME,");
|
||||
println!("you need to add this to System Properties > Environment Variables > User Variables");
|
||||
println!(
|
||||
"NOTE: If your komorebi.json file contains a reference to $Env:KOMOREBI_CONFIG_HOME,"
|
||||
);
|
||||
println!(
|
||||
"you need to add this to System Properties > Environment Variables > User Variables"
|
||||
);
|
||||
println!("in order for the autostart command to work properly");
|
||||
}
|
||||
SubCommand::DisableAutostart => {
|
||||
@@ -1756,16 +1760,23 @@ fn main() -> Result<()> {
|
||||
println!("{:?}", Report::new(diagnostic));
|
||||
}
|
||||
|
||||
println!("Found komorebi.json; this file can be passed to the start command with the --config flag\n");
|
||||
println!(
|
||||
"Found komorebi.json; this file can be passed to the start command with the --config flag\n"
|
||||
);
|
||||
|
||||
if let Ok(config) = StaticConfig::read(&static_config) {
|
||||
match config.app_specific_configuration_path {
|
||||
None => {
|
||||
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)) => {
|
||||
if !path.exists() {
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -1783,9 +1794,14 @@ fn main() -> Result<()> {
|
||||
StaticConfig::end_of_life(&raw);
|
||||
|
||||
if config_whkd.exists() {
|
||||
println!("Found {}; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n", config_whkd.to_string_lossy());
|
||||
println!(
|
||||
"Found {}; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n",
|
||||
config_whkd.to_string_lossy()
|
||||
);
|
||||
} else {
|
||||
println!("No ~/.config/whkdrc found; you may not be able to control komorebi with your keyboard\n");
|
||||
println!(
|
||||
"No ~/.config/whkdrc found; you may not be able to control komorebi with your keyboard\n"
|
||||
);
|
||||
}
|
||||
} else if config_pwsh.exists() {
|
||||
println!("Found komorebi.ps1; this file will be autoloaded by komorebi\n");
|
||||
@@ -1795,13 +1811,17 @@ fn main() -> Result<()> {
|
||||
config_whkd.to_string_lossy()
|
||||
);
|
||||
} else {
|
||||
println!("No ~/.config/whkdrc found; you may not be able to control komorebi with your keyboard\n");
|
||||
println!(
|
||||
"No ~/.config/whkdrc found; you may not be able to control komorebi with your keyboard\n"
|
||||
);
|
||||
}
|
||||
} else if config_ahk.exists() {
|
||||
println!("Found komorebi.ahk; this file will be autoloaded by komorebi\n");
|
||||
} else {
|
||||
println!("No komorebi configuration found in {home_display}\n");
|
||||
println!("If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration\n");
|
||||
println!(
|
||||
"If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration\n"
|
||||
);
|
||||
}
|
||||
|
||||
let client = reqwest::blocking::Client::new();
|
||||
@@ -1823,7 +1843,9 @@ fn main() -> Result<()> {
|
||||
{
|
||||
let trimmed = release.tag_name.trim_start_matches("v");
|
||||
if trimmed > version {
|
||||
println!("An updated version of komorebi is available! https://github.com/LGUG2Z/komorebi/releases/v{trimmed}");
|
||||
println!(
|
||||
"An updated version of komorebi is available! https://github.com/LGUG2Z/komorebi/releases/v{trimmed}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2160,46 +2182,53 @@ fn main() -> Result<()> {
|
||||
SubCommand::Start(arg) => {
|
||||
let mut ahk: String = String::from("autohotkey.exe");
|
||||
|
||||
if let Ok(komorebi_ahk_exe) = std::env::var("KOMOREBI_AHK_EXE") {
|
||||
if which(&komorebi_ahk_exe).is_ok() {
|
||||
ahk = komorebi_ahk_exe;
|
||||
}
|
||||
if let Ok(komorebi_ahk_exe) = std::env::var("KOMOREBI_AHK_EXE")
|
||||
&& which(&komorebi_ahk_exe).is_ok()
|
||||
{
|
||||
ahk = komorebi_ahk_exe;
|
||||
}
|
||||
|
||||
if arg.whkd && which("whkd").is_err() {
|
||||
bail!("could not find whkd, please make sure it is installed before using the --whkd flag");
|
||||
bail!(
|
||||
"could not find whkd, please make sure it is installed before using the --whkd flag"
|
||||
);
|
||||
}
|
||||
|
||||
if arg.masir && which("masir").is_err() {
|
||||
bail!("could not find masir, please make sure it is installed before using the --masir flag");
|
||||
bail!(
|
||||
"could not find masir, please make sure it is installed before using the --masir flag"
|
||||
);
|
||||
}
|
||||
|
||||
if arg.ahk && which(&ahk).is_err() {
|
||||
bail!("could not find autohotkey, please make sure it is installed before using the --ahk flag");
|
||||
bail!(
|
||||
"could not find autohotkey, please make sure it is installed before using the --ahk flag"
|
||||
);
|
||||
}
|
||||
|
||||
let mut buf: PathBuf;
|
||||
|
||||
// The komorebi.ps1 shim will only exist in the Path if installed by Scoop
|
||||
let exec = if let Ok(output) = Command::new("where.exe").arg("komorebi.ps1").output() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
match stdout.trim() {
|
||||
"" => None,
|
||||
// It's possible that a komorebi.ps1 config will be in %USERPROFILE% - ignore this
|
||||
stdout if !stdout.contains("scoop") => None,
|
||||
stdout => {
|
||||
buf = PathBuf::from(stdout);
|
||||
buf.pop(); // %USERPROFILE%\scoop\shims
|
||||
buf.pop(); // %USERPROFILE%\scoop
|
||||
buf.push("apps\\komorebi\\current\\komorebi.exe"); //%USERPROFILE%\scoop\komorebi\current\komorebi.exe
|
||||
Some(buf.to_str().ok_or_else(|| {
|
||||
anyhow!("cannot create a string from the scoop komorebi path")
|
||||
})?)
|
||||
let exec =
|
||||
if let Ok(output) = Command::new("where.exe").arg("komorebi.ps1").output() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
match stdout.trim() {
|
||||
"" => None,
|
||||
// It's possible that a komorebi.ps1 config will be in %USERPROFILE% - ignore this
|
||||
stdout if !stdout.contains("scoop") => None,
|
||||
stdout => {
|
||||
buf = PathBuf::from(stdout);
|
||||
buf.pop(); // %USERPROFILE%\scoop\shims
|
||||
buf.pop(); // %USERPROFILE%\scoop
|
||||
buf.push("apps\\komorebi\\current\\komorebi.exe"); //%USERPROFILE%\scoop\komorebi\current\komorebi.exe
|
||||
Some(buf.to_str().ok_or_eyre(
|
||||
"cannot create a string from the scoop komorebi path",
|
||||
)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut flags = vec![];
|
||||
if let Some(config) = &arg.config {
|
||||
@@ -2331,33 +2360,18 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue))
|
||||
komorebi_json.is_file().then_some(komorebi_json)
|
||||
});
|
||||
|
||||
if arg.bar {
|
||||
if let Some(config) = &static_config {
|
||||
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 = format!(
|
||||
r#"Start-Process "komorebi-bar" '"--config" "{}"' -WindowStyle hidden"#,
|
||||
config_file_path.to_string_lossy()
|
||||
);
|
||||
if arg.bar
|
||||
&& let Some(config) = &static_config
|
||||
{
|
||||
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 = format!(
|
||||
r#"Start-Process "komorebi-bar" '"--config" "{}"' -WindowStyle hidden"#,
|
||||
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) {
|
||||
match powershell_script::run(&script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
}
|
||||
@@ -2366,6 +2380,21 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2388,18 +2417,28 @@ if (!(Get-Process masir -ErrorAction SilentlyContinue))
|
||||
|
||||
println!("\nThank you for using komorebi!\n");
|
||||
println!("# Commercial Use License");
|
||||
println!("* View licensing options https://lgug2z.com/software/komorebi - A commercial use license is required to use komorebi at work");
|
||||
println!(
|
||||
"* View licensing options https://lgug2z.com/software/komorebi - A commercial use license is required to use komorebi at work"
|
||||
);
|
||||
println!("\n# Personal Use Sponsorship");
|
||||
println!("* Become a sponsor https://github.com/sponsors/LGUG2Z - $5/month makes a big difference");
|
||||
println!(
|
||||
"* Become a sponsor https://github.com/sponsors/LGUG2Z - $5/month makes a big difference"
|
||||
);
|
||||
println!("* Leave a tip https://ko-fi.com/lgug2z - An alternative to GitHub Sponsors");
|
||||
println!("\n# Community");
|
||||
println!("* Join the Discord https://discord.gg/mGkn66PHkx - Chat, ask questions, share your desktops");
|
||||
println!(
|
||||
"* Join the Discord https://discord.gg/mGkn66PHkx - Chat, ask questions, share your desktops"
|
||||
);
|
||||
println!(
|
||||
"* Subscribe to https://youtube.com/@LGUG2Z - Development videos, feature previews and release overviews"
|
||||
);
|
||||
println!("* Explore the Awesome Komorebi list https://github.com/LGUG2Z/awesome-komorebi - Projects in the komorebi ecosystem");
|
||||
println!(
|
||||
"* Explore the Awesome Komorebi list https://github.com/LGUG2Z/awesome-komorebi - Projects in the komorebi ecosystem"
|
||||
);
|
||||
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_json = HOME_DIR.join("komorebi.bar.json");
|
||||
@@ -2438,7 +2477,9 @@ if (!(Get-Process masir -ErrorAction SilentlyContinue))
|
||||
{
|
||||
let trimmed = release.tag_name.trim_start_matches("v");
|
||||
if trimmed > version {
|
||||
println!("An updated version of komorebi is available! https://github.com/LGUG2Z/komorebi/releases/v{trimmed}");
|
||||
println!(
|
||||
"An updated version of komorebi is available! https://github.com/LGUG2Z/komorebi/releases/v{trimmed}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3085,7 +3126,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
||||
|
||||
file.write_all(formatted_content.as_bytes())?;
|
||||
|
||||
println!("File successfully formatted for PRs to https://github.com/LGUG2Z/komorebi-application-specific-configuration");
|
||||
println!(
|
||||
"File successfully formatted for PRs to https://github.com/LGUG2Z/komorebi-application-specific-configuration"
|
||||
);
|
||||
}
|
||||
SubCommand::FetchAppSpecificConfiguration => {
|
||||
let content = reqwest::blocking::get("https://raw.githubusercontent.com/LGUG2Z/komorebi-application-specific-configuration/master/applications.json")?
|
||||
@@ -3101,10 +3144,12 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
||||
|
||||
file.write_all(content.as_bytes())?;
|
||||
|
||||
println!("Latest version of applications.json from https://github.com/LGUG2Z/komorebi-application-specific-configuration downloaded\n");
|
||||
println!(
|
||||
"You can add this to your komorebi.json static configuration file like this: \n\n\"app_specific_configuration_path\": \"{}\"",
|
||||
output_file.display().to_string().replace("\\", "/")
|
||||
"Latest version of applications.json from https://github.com/LGUG2Z/komorebi-application-specific-configuration downloaded\n"
|
||||
);
|
||||
println!(
|
||||
"You can add this to your komorebi.json static configuration file like this: \n\n\"app_specific_configuration_path\": \"{}\"",
|
||||
output_file.display().to_string().replace("\\", "/")
|
||||
);
|
||||
}
|
||||
SubCommand::ApplicationSpecificConfigurationSchema => {
|
||||
@@ -3134,14 +3179,14 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
||||
SubCommand::StaticConfigSchema => {
|
||||
#[cfg(feature = "schemars")]
|
||||
{
|
||||
let settings = schemars::gen::SchemaSettings::default().with(|s| {
|
||||
let settings = schemars::r#gen::SchemaSettings::default().with(|s| {
|
||||
s.option_nullable = false;
|
||||
s.option_add_null_type = false;
|
||||
s.inline_subschemas = true;
|
||||
});
|
||||
|
||||
let gen = settings.into_generator();
|
||||
let socket_message = gen.into_root_schema_for::<StaticConfig>();
|
||||
let generator = settings.into_generator();
|
||||
let socket_message = generator.into_root_schema_for::<StaticConfig>();
|
||||
let schema = serde_json::to_string_pretty(&socket_message)?;
|
||||
println!("{schema}");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "KomobarConfig",
|
||||
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.38`",
|
||||
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.39`",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"left_widgets",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "StaticConfig",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.38`",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.39`",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"animation": {
|
||||
@@ -1814,6 +1814,10 @@
|
||||
"columns"
|
||||
],
|
||||
"properties": {
|
||||
"center_focused_column": {
|
||||
"description": "With an odd number of visible columns, keep the focused window column centered",
|
||||
"type": "boolean"
|
||||
},
|
||||
"columns": {
|
||||
"description": "Desired number of visible columns (default: 3)",
|
||||
"type": "integer",
|
||||
|
||||
Reference in New Issue
Block a user