mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-05-16 16:57:02 +02:00
Compare commits
1 Commits
v0.1.37
...
feature/fl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3281c61113 |
748
Cargo.lock
generated
748
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,6 @@ strum = { version = "0.27", features = ["derive"] }
|
|||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-appender = "0.2"
|
tracing-appender = "0.2"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
parking_lot = "0.12"
|
|
||||||
paste = "1"
|
paste = "1"
|
||||||
sysinfo = "0.34"
|
sysinfo = "0.34"
|
||||||
uds_windows = "1"
|
uds_windows = "1"
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
|
|||||||
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
|
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.37"}
|
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.36"}
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use komorebi_client::Notification;
|
use komorebi_client::Notification;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index",
|
"accesskit_winit 0.23.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ahash 0.8.12 registry+https://github.com/rust-lang/crates.io-index",
|
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"allocator-api2 0.2.21 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.18 registry+https://github.com/rust-lang/crates.io-index",
|
"anstream 0.6.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index",
|
"anstyle 1.0.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -32,36 +32,36 @@
|
|||||||
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"backtrace 0.3.75 registry+https://github.com/rust-lang/crates.io-index",
|
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
|
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
|
||||||
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
|
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitflags 2.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck 1.23.0 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cc 1.2.23 registry+https://github.com/rust-lang/crates.io-index",
|
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
|
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono 0.4.41 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap 4.5.38 registry+https://github.com/rust-lang/crates.io-index",
|
"clap 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_builder 4.5.38 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_builder 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color-eyre 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
|
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color-spantrace 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
"crc32fast 1.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-channel 0.5.15 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ctrlc 3.4.7 registry+https://github.com/rust-lang/crates.io-index",
|
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
"deflate 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"deranged 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
|
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"dpi 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"dpi 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
"dunce 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -108,21 +108,21 @@
|
|||||||
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
|
"getrandom 0.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.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"getrandom 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
|
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"git2 0.20.2 registry+https://github.com/rust-lang/crates.io-index",
|
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
"gl_generator 0.14.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
|
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glutin 0.32.3 registry+https://github.com/rust-lang/crates.io-index",
|
"glutin 0.32.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
|
"glutin_egl_sys 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
"glutin_wgl_sys 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
"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.14.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hashbrown 0.15.3 registry+https://github.com/rust-lang/crates.io-index",
|
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
|
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
|
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"idna_adapter 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
|
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
"imgref 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
|
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustls-pki-types 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"scopeguard 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -256,9 +256,9 @@
|
|||||||
"supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"supports-hyperlinks 3.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"supports-unicode 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
|
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"syn 2.0.101 registry+https://github.com/rust-lang/crates.io-index",
|
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
"sync_wrapper 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tempfile 3.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
|
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
|
"thiserror 2.0.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -282,6 +282,7 @@
|
|||||||
"unicode-xid 0.2.6 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.36.0 registry+https://github.com/rust-lang/crates.io-index",
|
"uom 0.36.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"url 2.5.4 registry+https://github.com/rust-lang/crates.io-index",
|
"url 2.5.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"utf16_iter 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
|
"utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -299,9 +300,9 @@
|
|||||||
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-future 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-implement 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-implement 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -315,17 +316,16 @@
|
|||||||
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-threading 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
|
||||||
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -335,11 +335,12 @@
|
|||||||
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_x86_64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_x86_64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_x86_64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"winit 0.30.10 registry+https://github.com/rust-lang/crates.io-index",
|
"winit 0.30.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
|
"yaml-rust 0.4.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerocopy 0.8.25 registry+https://github.com/rust-lang/crates.io-index",
|
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zeroize 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
|
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
|
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
@@ -358,7 +359,8 @@
|
|||||||
"av1-grain 0.2.3 registry+https://github.com/rust-lang/crates.io-index",
|
"av1-grain 0.2.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
|
"rav1e 0.7.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index",
|
"v_frame 0.3.8 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerocopy 0.8.25 registry+https://github.com/rust-lang/crates.io-index"
|
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -379,7 +381,7 @@
|
|||||||
"BSL-1.0",
|
"BSL-1.0",
|
||||||
[
|
[
|
||||||
"clipboard-win 5.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"clipboard-win 5.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"error-code 3.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
"error-code 3.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index"
|
"ryu 1.0.20 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -397,7 +399,7 @@
|
|||||||
"ISC",
|
"ISC",
|
||||||
[
|
[
|
||||||
"is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"is_ci 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"libloading 0.8.7 registry+https://github.com/rust-lang/crates.io-index",
|
"libloading 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"starship-battery 0.10.1 registry+https://github.com/rust-lang/crates.io-index"
|
"starship-battery 0.10.1 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
]
|
]
|
||||||
@@ -410,7 +412,7 @@
|
|||||||
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
|
"accesskit_windows 0.24.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
"adler 1.0.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"adler2 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ahash 0.8.12 registry+https://github.com/rust-lang/crates.io-index",
|
"ahash 0.8.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
"aho-corasick 1.1.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"aligned-vec 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"aligned-vec 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
|
"allocator-api2 0.2.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -425,19 +427,19 @@
|
|||||||
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
"arrayvec 0.7.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"atomic-waker 1.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"autocfg 1.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"backtrace 0.3.75 registry+https://github.com/rust-lang/crates.io-index",
|
"backtrace 0.3.71 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"backtrace-ext 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
|
"base16_color_scheme 0.3.2 git+https://github.com/LGUG2Z/base16_color_scheme",
|
||||||
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
|
"base64 0.22.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
"beef 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
"bit_field 0.10.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
"bitflags 1.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitflags 2.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
"bitflags 2.9.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
"bitstream-io 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"brotli 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"brotli 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
"brotli-decompressor 2.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"built 0.7.7 registry+https://github.com/rust-lang/crates.io-index",
|
"built 0.7.7 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck 1.23.0 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"byteorder 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"byteorder-lite 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -445,20 +447,20 @@
|
|||||||
"calm_io 0.1.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",
|
"calmio_filters 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f",
|
"catppuccin-egui 5.3.1 git+https://github.com/LGUG2Z/catppuccin-egui?rev=bdaff30959512c4f7ee7304117076a48633d777f",
|
||||||
"cc 1.2.23 registry+https://github.com/rust-lang/crates.io-index",
|
"cc 1.2.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
|
"cfg-if 0.1.10 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"cfg-if 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"cfg_aliases 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono 0.4.41 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono 0.4.40 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono-tz 0.10.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
"chrono-tz-build 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"chumsky 0.9.3 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.38 registry+https://github.com/rust-lang/crates.io-index",
|
"clap 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_builder 4.5.38 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_builder 4.5.37 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_derive 4.5.32 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
"clap_lex 0.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color-eyre 0.6.4 registry+https://github.com/rust-lang/crates.io-index",
|
"color-eyre 0.6.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color-spantrace 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"color-spantrace 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color-thief 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"color-thief 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"color_quant 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
"colorchoice 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -467,7 +469,7 @@
|
|||||||
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-deque 0.8.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
|
"crossbeam-utils 0.8.21 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ctrlc 3.4.7 registry+https://github.com/rust-lang/crates.io-index",
|
"ctrlc 3.4.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"cursor-icon 1.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"darling 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
|
"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_core 0.20.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -481,7 +483,6 @@
|
|||||||
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"dirs-sys 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
|
"displaydoc 0.2.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
"document-features 0.2.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"dpi 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
|
||||||
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
"dyn-clone 1.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
"ecolor 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
"eframe 0.31.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -519,20 +520,20 @@
|
|||||||
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
"futures-task 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
"futures-util 0.3.31 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"getrandom 0.1.16 registry+https://github.com/rust-lang/crates.io-index",
|
"getrandom 0.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.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"getrandom 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
"getrandom 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
|
"getset 0.1.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
"gif 0.11.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
|
"gif 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"git2 0.20.2 registry+https://github.com/rust-lang/crates.io-index",
|
"git2 0.20.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
"glob 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
|
"glow 0.16.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"glutin-winit 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"h2 0.4.10 registry+https://github.com/rust-lang/crates.io-index",
|
"h2 0.4.9 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
"half 2.6.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hashbrown 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
"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.14.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hashbrown 0.15.3 registry+https://github.com/rust-lang/crates.io-index",
|
"hashbrown 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"heck 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
|
"hex 0.4.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"hex_color 3.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -547,7 +548,7 @@
|
|||||||
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
"iana-time-zone 0.1.63 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
|
"ident_case 1.0.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
"idna 1.0.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"idna_adapter 1.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"idna_adapter 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"image 0.23.14 registry+https://github.com/rust-lang/crates.io-index",
|
"image 0.23.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
|
"image 0.25.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"image-webp 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -581,7 +582,7 @@
|
|||||||
"memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
"memchr 2.7.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
"memoffset 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
|
"mime 0.3.17 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"mime_guess2 2.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
"mime_guess2 2.3.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"minimal-lexical 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"miniz_oxide 0.3.7 registry+https://github.com/rust-lang/crates.io-index",
|
"miniz_oxide 0.3.7 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.4.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -609,9 +610,10 @@
|
|||||||
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
"num-rational 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
|
"num-traits 0.2.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
"once_cell 1.21.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"os_info 3.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
"os_info 3.10.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
"overload 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"owo-colors 4.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"owo-colors 3.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"owo-colors 4.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"palette 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
"palette 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",
|
"palette_derive 0.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
"parking_lot 0.12.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -665,7 +667,7 @@
|
|||||||
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
"roxmltree 0.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
|
"rustc-demangle 0.1.24 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"rustls-pemfile 2.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustls-pki-types 1.12.0 registry+https://github.com/rust-lang/crates.io-index",
|
"rustls-pki-types 1.11.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
"rustversion 1.0.20 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"same-file 1.0.6 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.27 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -704,11 +706,11 @@
|
|||||||
"strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
|
"strum 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
|
"strum_macros 0.27.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
|
"syn 1.0.109 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"syn 2.0.101 registry+https://github.com/rust-lang/crates.io-index",
|
"syn 2.0.100 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"synstructure 0.13.2 registry+https://github.com/rust-lang/crates.io-index",
|
"synstructure 0.13.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index",
|
"sysinfo 0.33.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"sysinfo 0.34.2 registry+https://github.com/rust-lang/crates.io-index",
|
"sysinfo 0.34.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tempfile 3.20.0 registry+https://github.com/rust-lang/crates.io-index",
|
"tempfile 3.19.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
"terminal_size 0.4.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index",
|
"textwrap 0.16.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
|
"thiserror 1.0.69 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -720,9 +722,9 @@
|
|||||||
"tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
"tiff 0.9.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index",
|
"time 0.3.41 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
|
"time-core 0.1.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tokio 1.45.0 registry+https://github.com/rust-lang/crates.io-index",
|
"tokio 1.44.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
"tokio-native-tls 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tokio-util 0.7.15 registry+https://github.com/rust-lang/crates.io-index",
|
"tokio-util 0.7.14 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
|
"toml 0.5.11 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
"tower 0.5.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
"tower-layer 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -749,6 +751,7 @@
|
|||||||
"unsafe-libyaml 0.2.11 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.36.0 registry+https://github.com/rust-lang/crates.io-index",
|
"uom 0.36.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"url 2.5.4 registry+https://github.com/rust-lang/crates.io-index",
|
"url 2.5.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"utf16_iter 1.0.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
|
"utf8_iter 1.0.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"utf8parse 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
"vcpkg 0.2.15 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -770,9 +773,9 @@
|
|||||||
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.58.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.60.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-core 0.61.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-core 0.61.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-future 0.1.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-future 0.2.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-future 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354",
|
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=0c9d7ee1b807347c507d3a9862dd007b4d3f4354",
|
||||||
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5",
|
"windows-icons 0.1.0 git+https://github.com/LGUG2Z/windows-icons?rev=d67cc9920aa9b4883393e411fb4fa2ddd4c498b5",
|
||||||
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-implement 0.57.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -788,17 +791,16 @@
|
|||||||
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-registry 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-result 0.3.3 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-result 0.3.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.3.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-strings 0.4.1 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-strings 0.4.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.48.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.52.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-sys 0.59.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows-targets 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows-threading 0.1.0 registry+https://github.com/rust-lang/crates.io-index",
|
|
||||||
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.48.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.52.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
"windows_aarch64_msvc 0.53.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
@@ -812,10 +814,11 @@
|
|||||||
"winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index",
|
"winreg 0.55.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
"winsafe 0.0.19 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
"wmi 0.15.2 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"write16 1.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"xml-rs 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
|
"xml-rs 0.8.26 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"yaml-rust 0.4.5 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.25 registry+https://github.com/rust-lang/crates.io-index",
|
"zerocopy 0.7.35 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zeroize 1.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
"zerocopy 0.8.24 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
|
"zune-core 0.4.12 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
"zune-inflate 0.2.54 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
|
"zune-jpeg 0.4.14 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
@@ -850,25 +853,26 @@
|
|||||||
[
|
[
|
||||||
"Unicode-3.0",
|
"Unicode-3.0",
|
||||||
[
|
[
|
||||||
"icu_collections 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_collections 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_locale_core 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_locid 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_normalizer 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_locid_transform 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_normalizer_data 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_locid_transform_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_properties 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_normalizer 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_properties_data 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_normalizer_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"icu_provider 2.0.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_properties 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"litemap 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_properties_data 1.5.1 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"potential_utf 0.1.2 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_provider 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"tinystr 0.8.1 registry+https://github.com/rust-lang/crates.io-index",
|
"icu_provider_macros 1.5.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"litemap 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
"tinystr 0.7.6 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.18 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"writeable 0.6.1 registry+https://github.com/rust-lang/crates.io-index",
|
"writeable 0.5.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"yoke 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
"yoke 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"yoke-derive 0.8.0 registry+https://github.com/rust-lang/crates.io-index",
|
"yoke-derive 0.7.5 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerofrom 0.1.6 registry+https://github.com/rust-lang/crates.io-index",
|
"zerofrom 0.1.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerofrom-derive 0.1.6 registry+https://github.com/rust-lang/crates.io-index",
|
"zerofrom-derive 0.1.6 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerotrie 0.2.2 registry+https://github.com/rust-lang/crates.io-index",
|
"zerovec 0.10.4 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"zerovec 0.11.2 registry+https://github.com/rust-lang/crates.io-index",
|
"zerovec-derive 0.10.3 registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"zerovec-derive 0.11.1 registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -888,7 +892,7 @@
|
|||||||
"Zlib",
|
"Zlib",
|
||||||
[
|
[
|
||||||
"adler32 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
"adler32 1.2.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck 1.23.0 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck 1.22.0 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
"bytemuck_derive 1.9.3 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
|
"const_format 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
"const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
|
"const_format_proc_macros 0.2.34 registry+https://github.com/rust-lang/crates.io-index",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Usage: komorebic.exe query <STATE_QUERY>
|
|||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
<STATE_QUERY>
|
<STATE_QUERY>
|
||||||
[possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name, focused-workspace-layout, focused-container-kind, version]
|
[possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name, focused-workspace-layout, version]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help
|
-h, --help
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# toggle-shortcuts
|
|
||||||
|
|
||||||
```
|
|
||||||
Toggle the komorebi-shortcuts helper
|
|
||||||
|
|
||||||
Usage: komorebic.exe toggle-shortcuts
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h, --help
|
|
||||||
Print help
|
|
||||||
|
|
||||||
```
|
|
||||||
@@ -8,7 +8,7 @@ Usage: komorebic.exe window-hiding-behaviour <HIDING_BEHAVIOUR>
|
|||||||
Arguments:
|
Arguments:
|
||||||
<HIDING_BEHAVIOUR>
|
<HIDING_BEHAVIOUR>
|
||||||
Possible values:
|
Possible values:
|
||||||
- hide: END OF LIFE FEATURE: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
|
- hide: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
|
||||||
- minimize: Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)
|
- minimize: Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)
|
||||||
- cloak: Use the undocumented SetCloak Win32 function to hide windows when switching workspaces
|
- cloak: Use the undocumented SetCloak Win32 function to hide windows when switching workspaces
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ defined in the `komorebi.json` configuration file.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"animation": {
|
"animation": {
|
||||||
"enabled": true,
|
"enabled": true
|
||||||
"duration": 250,
|
|
||||||
"fps": 60,
|
|
||||||
"style": "EaseOutSine"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ how to map the indices and would use default behaviour which would result in a m
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# Multiple monitors on different machines
|
# Multiple Monitors on different machines
|
||||||
|
|
||||||
You can use the same `komorebi.json` to configure two different setups and then synchronize your config across machines.
|
You can use the same `komorebi.json` to configure two different setups and then synchronize your config across machines.
|
||||||
However, if you do this it is important to be aware of a few things.
|
However, if you do this it is important to be aware of a few things.
|
||||||
@@ -393,13 +393,6 @@ This is because komorebi will apply the appropriate config to the loaded monitor
|
|||||||
index (the index defined in the user config) to the actual monitor index, and the bar will use that map to know if it
|
index (the index defined in the user config) to the actual monitor index, and the bar will use that map to know if it
|
||||||
should be enabled, and where it should be drawn.
|
should be enabled, and where it should be drawn.
|
||||||
|
|
||||||
# Windows Display Settings
|
|
||||||
|
|
||||||
In `Settings > System > Display > Multiple Displays`:
|
|
||||||
|
|
||||||
- Disable "Remember windows locations on monitor connection"
|
|
||||||
- Enable "Minimize windows when a monitor is disconnected"
|
|
||||||
|
|
||||||
### Things to keep in mind
|
### Things to keep in mind
|
||||||
|
|
||||||
* If you are using a laptop connected to one monitor at work and a different one at home, the work monitor and the home
|
* If you are using a laptop connected to one monitor at work and a different one at home, the work monitor and the home
|
||||||
|
|||||||
17
docs/common-workflows/set-display-index.md
Normal file
17
docs/common-workflows/set-display-index.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Setting a Given Display to a Specific Index
|
||||||
|
|
||||||
|
If you would like `komorebi` to remember monitor index positions, you will need to set the `display_index_preferences`
|
||||||
|
configuration option in the static configuration file.
|
||||||
|
|
||||||
|
Display IDs can be found using `komorebic monitor-information`.
|
||||||
|
|
||||||
|
Then, in `komorebi.json`, you simply need to specify the preferred index position for each display ID:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"display_index_preferences": {
|
||||||
|
"0": "DEL4310-5&1a6c0954&0&UID209155",
|
||||||
|
"1": "<another-display_id>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -186,9 +186,6 @@ limitations on hotkey bindings that include the `win` key. However, you will sti
|
|||||||
to [modify the registry](https://superuser.com/questions/1059511/how-to-disable-winl-in-windows-10) to prevent
|
to [modify the registry](https://superuser.com/questions/1059511/how-to-disable-winl-in-windows-10) to prevent
|
||||||
`win + l` from locking the operating system.
|
`win + l` from locking the operating system.
|
||||||
|
|
||||||
You can toggle an overlay of the current `whkdrc` shortcuts related to `komorebi` at any time when using the example
|
|
||||||
configuration with `alt + i`.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
{% include "./whkdrc.sample" %}
|
{% include "./whkdrc.sample" %}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ cargo +stable install --path komorebic --locked
|
|||||||
cargo +stable install --path komorebic-no-console --locked
|
cargo +stable install --path komorebic-no-console --locked
|
||||||
cargo +stable install --path komorebi-gui --locked
|
cargo +stable install --path komorebi-gui --locked
|
||||||
cargo +stable install --path komorebi-bar --locked
|
cargo +stable install --path komorebi-bar --locked
|
||||||
cargo +stable install --path komorebi-shortcuts --locked
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If the binaries have been built and added to your `$PATH` correctly, you should
|
If the binaries have been built and added to your `$PATH` correctly, you should
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.37/schema.bar.json",
|
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.bar.json",
|
||||||
"monitor": 0,
|
"monitor": 0,
|
||||||
"font_family": "JetBrains Mono",
|
"font_family": "JetBrains Mono",
|
||||||
"theme": {
|
"theme": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.37/schema.json",
|
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.36/schema.json",
|
||||||
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
|
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
|
||||||
"window_hiding_behaviour": "Cloak",
|
"window_hiding_behaviour": "Cloak",
|
||||||
"cross_monitor_move_behaviour": "Insert",
|
"cross_monitor_move_behaviour": "Insert",
|
||||||
|
|||||||
@@ -138,14 +138,13 @@ running `komorebic stop` and `komorebic start`.
|
|||||||
Users with Nvidia GPUs may have issues with transparency on the Komorebi Bar.
|
Users with Nvidia GPUs may have issues with transparency on the Komorebi Bar.
|
||||||
|
|
||||||
To solve this the user can do the following:
|
To solve this the user can do the following:
|
||||||
|
1. Open the Nvidia Control Panel
|
||||||
- Open the Nvidia Control Panel
|
2. On the left menu tree, under "3D Settings", select "Manage 3D Settings"
|
||||||
- On the left menu tree, under "3D Settings", select "Manage 3D Settings"
|
3. Select the "Program Settings" tab
|
||||||
- Select the "Program Settings" tab
|
4. Press the "Add" button and select "komorebi-bar"
|
||||||
- Press the "Add" button and select "komorebi-bar"
|
5. Under "3. Specify the settings for this program:", find the feature labelled, "OpenGL GDI compatibility"
|
||||||
- Under "3. Specify the settings for this program:", find the feature labelled, "OpenGL GDI compatibility"
|
6. Change the setting to "Prefer compatibility"
|
||||||
- Change the setting to "Prefer compatibility"
|
7. At the bottom of the window select "Apply"
|
||||||
- At the bottom of the window select "Apply"
|
8. Restart the Komorebi Bar with "komorebic stop --bar; komorebic start --bar"
|
||||||
- Restart the Komorebi Bar with "komorebic stop --bar; komorebic start --bar"
|
|
||||||
|
|
||||||
This should resolve the issue and your Komorebi Bar should render with the proper transparency.
|
This should resolve the issue and your Komorebi Bar should render with the proper transparency.
|
||||||
|
|||||||
4
justfile
4
justfile
@@ -28,7 +28,7 @@ install-target-with-jsonschema target:
|
|||||||
cargo +stable install --path {{ target }} --locked
|
cargo +stable install --path {{ target }} --locked
|
||||||
|
|
||||||
install:
|
install:
|
||||||
just install-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
|
just install-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
|
||||||
|
|
||||||
install-with-jsonschema:
|
install-with-jsonschema:
|
||||||
just install-targets-with-jsonschema komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
|
just install-targets-with-jsonschema komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
|
||||||
@@ -52,7 +52,7 @@ wpm target:
|
|||||||
just build-target {{ target }} && wpmctl stop {{ target }}; just copy-target {{ target }} && wpmctl start {{ target }}
|
just build-target {{ target }} && wpmctl stop {{ target }}; just copy-target {{ target }} && wpmctl start {{ target }}
|
||||||
|
|
||||||
copy:
|
copy:
|
||||||
just copy-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui komorebi-shortcuts
|
just copy-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
|
||||||
|
|
||||||
run target:
|
run target:
|
||||||
cargo +stable run --bin {{ target }} --locked --no-default-features
|
cargo +stable run --bin {{ target }} --locked --no-default-features
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
komorebi-client = { path = "../komorebi-client", default-features = false }
|
komorebi-client = { path = "../komorebi-client" }
|
||||||
komorebi-themes = { path = "../komorebi-themes", default-features = false }
|
komorebi-themes = { path = "../komorebi-themes" }
|
||||||
|
|
||||||
chrono-tz = { workspace = true }
|
chrono-tz = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
@@ -26,7 +26,6 @@ netdev = "0.34"
|
|||||||
num = "0.4"
|
num = "0.4"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
parking_lot = { workspace = true }
|
|
||||||
random_word = { version = "0.5", features = ["en"] }
|
random_word = { version = "0.5", features = ["en"] }
|
||||||
reqwest = { version = "0.12", features = ["blocking"] }
|
reqwest = { version = "0.12", features = ["blocking"] }
|
||||||
schemars = { workspace = true, optional = true }
|
schemars = { workspace = true, optional = true }
|
||||||
@@ -44,4 +43,4 @@ windows-icons-fallback = { package = "windows-icons", git = "https://github.com/
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["schemars"]
|
default = ["schemars"]
|
||||||
schemars = ["dep:schemars", "komorebi-client/default", "komorebi-themes/default"]
|
schemars = ["dep:schemars", "komorebi-client/schemars", "komorebi-themes/schemars"]
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ use eframe::egui::Frame;
|
|||||||
use eframe::egui::Id;
|
use eframe::egui::Id;
|
||||||
use eframe::egui::Layout;
|
use eframe::egui::Layout;
|
||||||
use eframe::egui::Margin;
|
use eframe::egui::Margin;
|
||||||
use eframe::egui::PointerButton;
|
|
||||||
use eframe::egui::Rgba;
|
use eframe::egui::Rgba;
|
||||||
use eframe::egui::Style;
|
use eframe::egui::Style;
|
||||||
use eframe::egui::TextStyle;
|
use eframe::egui::TextStyle;
|
||||||
@@ -58,95 +57,13 @@ use komorebi_themes::Base16Value;
|
|||||||
use komorebi_themes::Base16Wrapper;
|
use komorebi_themes::Base16Wrapper;
|
||||||
use komorebi_themes::Catppuccin;
|
use komorebi_themes::Catppuccin;
|
||||||
use komorebi_themes::CatppuccinValue;
|
use komorebi_themes::CatppuccinValue;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
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;
|
use std::path::PathBuf;
|
||||||
use std::process::ChildStdin;
|
|
||||||
use std::process::Command;
|
|
||||||
use std::process::Stdio;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref SESSION_STDIN: Mutex<Option<ChildStdin>> = Mutex::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_powershell() -> Result<()> {
|
|
||||||
// found running session, do nothing
|
|
||||||
if SESSION_STDIN.lock().as_mut().is_some() {
|
|
||||||
tracing::debug!("PowerShell session already started");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::debug!("Starting PowerShell session");
|
|
||||||
|
|
||||||
let mut child = Command::new("powershell.exe")
|
|
||||||
.args(["-NoLogo", "-NoProfile", "-Command", "-"])
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.creation_flags(CREATE_NO_WINDOW)
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
let stdin = child.stdin.take().expect("stdin piped");
|
|
||||||
|
|
||||||
// Store stdin for later commands
|
|
||||||
let mut session_stdin = SESSION_STDIN.lock();
|
|
||||||
*session_stdin = Option::from(stdin);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop_powershell() -> 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);
|
|
||||||
}
|
|
||||||
if let Err(e) = session_stdin.flush() {
|
|
||||||
tracing::error!(error = %e, "failed to flush PowerShell stdin");
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::debug!("PowerShell session stopped");
|
|
||||||
} else {
|
|
||||||
tracing::debug!("PowerShell session already stopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exec_powershell(cmd: &str) -> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = session_stdin.flush() {
|
|
||||||
tracing::error!(error = %e, "failed to flush PowerShell stdin");
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(
|
|
||||||
ErrorKind::NotFound,
|
|
||||||
"PowerShell session not started",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Komobar {
|
pub struct Komobar {
|
||||||
pub hwnd: Option<isize>,
|
pub hwnd: Option<isize>,
|
||||||
pub monitor_index: Option<usize>,
|
pub monitor_index: Option<usize>,
|
||||||
@@ -165,18 +82,6 @@ pub struct Komobar {
|
|||||||
pub size_rect: komorebi_client::Rect,
|
pub size_rect: komorebi_client::Rect,
|
||||||
pub work_area_offset: komorebi_client::Rect,
|
pub work_area_offset: komorebi_client::Rect,
|
||||||
applied_theme_on_first_frame: bool,
|
applied_theme_on_first_frame: bool,
|
||||||
mouse_follows_focus: bool,
|
|
||||||
input_config: InputConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InputConfig {
|
|
||||||
accumulated_scroll_delta: Vec2,
|
|
||||||
act_on_vertical_scroll: bool,
|
|
||||||
act_on_horizontal_scroll: bool,
|
|
||||||
vertical_scroll_threshold: f32,
|
|
||||||
horizontal_scroll_threshold: f32,
|
|
||||||
vertical_scroll_max_threshold: f32,
|
|
||||||
horizontal_scroll_max_threshold: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_theme(
|
pub fn apply_theme(
|
||||||
@@ -463,19 +368,15 @@ impl Komobar {
|
|||||||
}
|
}
|
||||||
MonitorConfigOrIndex::Index(idx) => (*idx, None),
|
MonitorConfigOrIndex::Index(idx) => (*idx, None),
|
||||||
};
|
};
|
||||||
|
let monitor_index = self.komorebi_notification_state.as_ref().and_then(|state| {
|
||||||
let mapped_state = self.komorebi_notification_state.as_ref().map(|state| {
|
state
|
||||||
let state = state.borrow();
|
.borrow()
|
||||||
(
|
.monitor_usr_idx_map
|
||||||
state.monitor_usr_idx_map.get(&usr_monitor_index).copied(),
|
.get(&usr_monitor_index)
|
||||||
state.mouse_follows_focus,
|
.copied()
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(state) = mapped_state {
|
self.monitor_index = monitor_index;
|
||||||
self.monitor_index = state.0;
|
|
||||||
self.mouse_follows_focus = state.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(monitor_index) = self.monitor_index {
|
if let Some(monitor_index) = self.monitor_index {
|
||||||
if let (prev_rect, Some(new_rect)) = (&self.work_area_offset, &config_work_area_offset)
|
if let (prev_rect, Some(new_rect)) = (&self.work_area_offset, &config_work_area_offset)
|
||||||
@@ -534,36 +435,6 @@ impl Komobar {
|
|||||||
self.disabled = true;
|
self.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mouse) = &self.config.mouse {
|
|
||||||
self.input_config.act_on_vertical_scroll =
|
|
||||||
mouse.on_scroll_up.is_some() || mouse.on_scroll_down.is_some();
|
|
||||||
self.input_config.act_on_horizontal_scroll =
|
|
||||||
mouse.on_scroll_left.is_some() || mouse.on_scroll_right.is_some();
|
|
||||||
self.input_config.vertical_scroll_threshold = mouse
|
|
||||||
.vertical_scroll_threshold
|
|
||||||
.unwrap_or(30.0)
|
|
||||||
.clamp(10.0, 300.0);
|
|
||||||
self.input_config.horizontal_scroll_threshold = mouse
|
|
||||||
.horizontal_scroll_threshold
|
|
||||||
.unwrap_or(30.0)
|
|
||||||
.clamp(10.0, 300.0);
|
|
||||||
// limit how many "ticks" can be accumulated
|
|
||||||
self.input_config.vertical_scroll_max_threshold =
|
|
||||||
self.input_config.vertical_scroll_threshold * 3.0;
|
|
||||||
self.input_config.horizontal_scroll_max_threshold =
|
|
||||||
self.input_config.horizontal_scroll_threshold * 3.0;
|
|
||||||
|
|
||||||
if mouse.has_command() {
|
|
||||||
start_powershell().unwrap_or_else(|_| {
|
|
||||||
tracing::error!("failed to start powershell session");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
stop_powershell().unwrap_or_else(|_| {
|
|
||||||
tracing::error!("failed to stop powershell session");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!("widget configuration options applied");
|
tracing::info!("widget configuration options applied");
|
||||||
|
|
||||||
self.komorebi_notification_state = komorebi_notification_state;
|
self.komorebi_notification_state = komorebi_notification_state;
|
||||||
@@ -737,16 +608,6 @@ impl Komobar {
|
|||||||
size_rect: komorebi_client::Rect::default(),
|
size_rect: komorebi_client::Rect::default(),
|
||||||
work_area_offset: komorebi_client::Rect::default(),
|
work_area_offset: komorebi_client::Rect::default(),
|
||||||
applied_theme_on_first_frame: false,
|
applied_theme_on_first_frame: false,
|
||||||
mouse_follows_focus: false,
|
|
||||||
input_config: InputConfig {
|
|
||||||
accumulated_scroll_delta: Vec2::new(0.0, 0.0),
|
|
||||||
act_on_vertical_scroll: false,
|
|
||||||
act_on_horizontal_scroll: false,
|
|
||||||
vertical_scroll_threshold: 0.0,
|
|
||||||
horizontal_scroll_threshold: 0.0,
|
|
||||||
vertical_scroll_max_threshold: 0.0,
|
|
||||||
horizontal_scroll_max_threshold: 0.0,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
komobar.apply_config(&cc.egui_ctx, None);
|
komobar.apply_config(&cc.egui_ctx, None);
|
||||||
@@ -1100,111 +961,6 @@ impl eframe::App for Komobar {
|
|||||||
let frame = render_config.change_frame_on_bar(frame, &ctx.style());
|
let frame = render_config.change_frame_on_bar(frame, &ctx.style());
|
||||||
|
|
||||||
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
||||||
if let Some(mouse_config) = &self.config.mouse {
|
|
||||||
let command = if ui
|
|
||||||
.input(|i| i.pointer.button_double_clicked(PointerButton::Primary))
|
|
||||||
{
|
|
||||||
tracing::debug!("Input: primary button double clicked");
|
|
||||||
&mouse_config.on_primary_double_click
|
|
||||||
} else if ui.input(|i| i.pointer.button_clicked(PointerButton::Secondary)) {
|
|
||||||
tracing::debug!("Input: secondary button clicked");
|
|
||||||
&mouse_config.on_secondary_click
|
|
||||||
} else if ui.input(|i| i.pointer.button_clicked(PointerButton::Middle)) {
|
|
||||||
tracing::debug!("Input: middle button clicked");
|
|
||||||
&mouse_config.on_middle_click
|
|
||||||
} else if ui.input(|i| i.pointer.button_clicked(PointerButton::Extra1)) {
|
|
||||||
tracing::debug!("Input: extra1 button clicked");
|
|
||||||
&mouse_config.on_extra1_click
|
|
||||||
} else if ui.input(|i| i.pointer.button_clicked(PointerButton::Extra2)) {
|
|
||||||
tracing::debug!("Input: extra2 button clicked");
|
|
||||||
&mouse_config.on_extra2_click
|
|
||||||
} else if self.input_config.act_on_vertical_scroll
|
|
||||||
|| self.input_config.act_on_horizontal_scroll
|
|
||||||
{
|
|
||||||
let scroll_delta = ui.input(|input| input.smooth_scroll_delta);
|
|
||||||
|
|
||||||
self.input_config.accumulated_scroll_delta += scroll_delta;
|
|
||||||
|
|
||||||
if scroll_delta.y != 0.0 && self.input_config.act_on_vertical_scroll {
|
|
||||||
// Do not store more than the max threshold
|
|
||||||
self.input_config.accumulated_scroll_delta.y =
|
|
||||||
self.input_config.accumulated_scroll_delta.y.clamp(
|
|
||||||
-self.input_config.vertical_scroll_max_threshold,
|
|
||||||
self.input_config.vertical_scroll_max_threshold,
|
|
||||||
);
|
|
||||||
|
|
||||||
// When the accumulated scroll passes the threshold, trigger a tick.
|
|
||||||
if self.input_config.accumulated_scroll_delta.y.abs()
|
|
||||||
>= self.input_config.vertical_scroll_threshold
|
|
||||||
{
|
|
||||||
let direction_command =
|
|
||||||
if self.input_config.accumulated_scroll_delta.y > 0.0 {
|
|
||||||
&mouse_config.on_scroll_up
|
|
||||||
} else {
|
|
||||||
&mouse_config.on_scroll_down
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove one tick's worth of scroll from the accumulator, preserving any excess.
|
|
||||||
self.input_config.accumulated_scroll_delta.y -=
|
|
||||||
self.input_config.vertical_scroll_threshold
|
|
||||||
* self.input_config.accumulated_scroll_delta.y.signum();
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"Input: vertical scroll ticked. excess: {} | threshold: {}",
|
|
||||||
self.input_config.accumulated_scroll_delta.y,
|
|
||||||
self.input_config.vertical_scroll_threshold
|
|
||||||
);
|
|
||||||
|
|
||||||
direction_command
|
|
||||||
} else {
|
|
||||||
&None
|
|
||||||
}
|
|
||||||
} else if scroll_delta.x != 0.0 && self.input_config.act_on_horizontal_scroll {
|
|
||||||
// Do not store more than the max threshold
|
|
||||||
self.input_config.accumulated_scroll_delta.x =
|
|
||||||
self.input_config.accumulated_scroll_delta.x.clamp(
|
|
||||||
-self.input_config.horizontal_scroll_max_threshold,
|
|
||||||
self.input_config.horizontal_scroll_max_threshold,
|
|
||||||
);
|
|
||||||
|
|
||||||
// When the accumulated scroll passes the threshold, trigger a tick.
|
|
||||||
if self.input_config.accumulated_scroll_delta.x.abs()
|
|
||||||
>= self.input_config.horizontal_scroll_threshold
|
|
||||||
{
|
|
||||||
let direction_command =
|
|
||||||
if self.input_config.accumulated_scroll_delta.x > 0.0 {
|
|
||||||
&mouse_config.on_scroll_left
|
|
||||||
} else {
|
|
||||||
&mouse_config.on_scroll_right
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove one tick's worth of scroll from the accumulator, preserving any excess.
|
|
||||||
self.input_config.accumulated_scroll_delta.x -=
|
|
||||||
self.input_config.horizontal_scroll_threshold
|
|
||||||
* self.input_config.accumulated_scroll_delta.x.signum();
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"Input: horizontal scroll ticked. excess: {} | threshold: {}",
|
|
||||||
self.input_config.accumulated_scroll_delta.x,
|
|
||||||
self.input_config.horizontal_scroll_threshold
|
|
||||||
);
|
|
||||||
|
|
||||||
direction_command
|
|
||||||
} else {
|
|
||||||
&None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
&None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
&None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(command) = command {
|
|
||||||
command.execute(self.mouse_follows_focus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply grouping logic for the bar as a whole
|
// Apply grouping logic for the bar as a whole
|
||||||
let area_frame = if let Some(frame) = &self.config.frame {
|
let area_frame = if let Some(frame) = &self.config.frame {
|
||||||
Frame::NONE
|
Frame::NONE
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::bar::exec_powershell;
|
|
||||||
use crate::render::Grouping;
|
use crate::render::Grouping;
|
||||||
use crate::widgets::widget::WidgetConfig;
|
use crate::widgets::widget::WidgetConfig;
|
||||||
use crate::DEFAULT_PADDING;
|
use crate::DEFAULT_PADDING;
|
||||||
@@ -6,9 +5,7 @@ use eframe::egui::Pos2;
|
|||||||
use eframe::egui::TextBuffer;
|
use eframe::egui::TextBuffer;
|
||||||
use eframe::egui::Vec2;
|
use eframe::egui::Vec2;
|
||||||
use komorebi_client::KomorebiTheme;
|
use komorebi_client::KomorebiTheme;
|
||||||
use komorebi_client::PathExt;
|
|
||||||
use komorebi_client::Rect;
|
use komorebi_client::Rect;
|
||||||
use komorebi_client::SocketMessage;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -93,8 +90,6 @@ pub struct KomobarConfig {
|
|||||||
pub widget_spacing: Option<f32>,
|
pub widget_spacing: Option<f32>,
|
||||||
/// Visual grouping for widgets
|
/// Visual grouping for widgets
|
||||||
pub grouping: Option<Grouping>,
|
pub grouping: Option<Grouping>,
|
||||||
/// Options for mouse interaction on the bar
|
|
||||||
pub mouse: Option<MouseConfig>,
|
|
||||||
/// Left side widgets (ordered left-to-right)
|
/// Left side widgets (ordered left-to-right)
|
||||||
pub left_widgets: Vec<WidgetConfig>,
|
pub left_widgets: Vec<WidgetConfig>,
|
||||||
/// Center widgets (ordered left-to-right)
|
/// Center widgets (ordered left-to-right)
|
||||||
@@ -330,147 +325,6 @@ pub fn get_individual_spacing(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
||||||
pub enum MouseMessage {
|
|
||||||
/// Send a message to the komorebi client.
|
|
||||||
/// By default, a batch of messages are sent in the following order:
|
|
||||||
/// FocusMonitorAtCursor =>
|
|
||||||
/// MouseFollowsFocus(false) =>
|
|
||||||
/// {message} =>
|
|
||||||
/// MouseFollowsFocus({original.value})
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
/// ```json
|
|
||||||
/// "on_extra2_click": {
|
|
||||||
/// "message": {
|
|
||||||
/// "type": "NewWorkspace"
|
|
||||||
/// }
|
|
||||||
/// },
|
|
||||||
/// ```
|
|
||||||
/// or:
|
|
||||||
/// ```json
|
|
||||||
/// "on_middle_click": {
|
|
||||||
/// "focus_monitor_at_cursor": false,
|
|
||||||
/// "ignore_mouse_follows_focus": false,
|
|
||||||
/// "message": {
|
|
||||||
/// "type": "TogglePause"
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
/// or:
|
|
||||||
/// ```json
|
|
||||||
/// "on_scroll_up": {
|
|
||||||
/// "message": {
|
|
||||||
/// "type": "CycleFocusWorkspace",
|
|
||||||
/// "content": "Previous"
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[serde(untagged)]
|
|
||||||
Komorebi(KomorebiMouseMessage),
|
|
||||||
/// Execute a custom command.
|
|
||||||
/// CMD (%variable%), Bash ($variable) and PowerShell ($Env:variable) variables will be resolved.
|
|
||||||
/// Example: `komorebic toggle-pause`
|
|
||||||
#[serde(untagged)]
|
|
||||||
Command(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
||||||
pub struct KomorebiMouseMessage {
|
|
||||||
/// Send the FocusMonitorAtCursor message (default:true)
|
|
||||||
pub focus_monitor_at_cursor: Option<bool>,
|
|
||||||
/// Wrap the {message} with a MouseFollowsFocus(false) and MouseFollowsFocus({original.value}) message (default:true)
|
|
||||||
pub ignore_mouse_follows_focus: Option<bool>,
|
|
||||||
/// The message to send to the komorebi client
|
|
||||||
pub message: komorebi_client::SocketMessage,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
||||||
pub struct MouseConfig {
|
|
||||||
/// Command to send on primary/left double button click
|
|
||||||
pub on_primary_double_click: Option<MouseMessage>,
|
|
||||||
/// Command to send on secondary/right button click
|
|
||||||
pub on_secondary_click: Option<MouseMessage>,
|
|
||||||
/// Command to send on middle button click
|
|
||||||
pub on_middle_click: Option<MouseMessage>,
|
|
||||||
/// Command to send on extra1/back button click
|
|
||||||
pub on_extra1_click: Option<MouseMessage>,
|
|
||||||
/// Command to send on extra2/forward button click
|
|
||||||
pub on_extra2_click: Option<MouseMessage>,
|
|
||||||
|
|
||||||
/// Defines how many points a user needs to scroll vertically to make a "tick" on a mouse/touchpad/touchscreen (default: 30)
|
|
||||||
pub vertical_scroll_threshold: Option<f32>,
|
|
||||||
/// Command to send on scrolling up (every tick)
|
|
||||||
pub on_scroll_up: Option<MouseMessage>,
|
|
||||||
/// Command to send on scrolling down (every tick)
|
|
||||||
pub on_scroll_down: Option<MouseMessage>,
|
|
||||||
|
|
||||||
/// Defines how many points a user needs to scroll horizontally to make a "tick" on a mouse/touchpad/touchscreen (default: 30)
|
|
||||||
pub horizontal_scroll_threshold: Option<f32>,
|
|
||||||
/// Command to send on scrolling left (every tick)
|
|
||||||
pub on_scroll_left: Option<MouseMessage>,
|
|
||||||
/// Command to send on scrolling right (every tick)
|
|
||||||
pub on_scroll_right: Option<MouseMessage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MouseConfig {
|
|
||||||
pub fn has_command(&self) -> bool {
|
|
||||||
[
|
|
||||||
&self.on_primary_double_click,
|
|
||||||
&self.on_secondary_click,
|
|
||||||
&self.on_middle_click,
|
|
||||||
&self.on_extra1_click,
|
|
||||||
&self.on_extra2_click,
|
|
||||||
&self.on_scroll_up,
|
|
||||||
&self.on_scroll_down,
|
|
||||||
&self.on_scroll_left,
|
|
||||||
&self.on_scroll_right,
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.any(|opt| matches!(opt, Some(MouseMessage::Command(_))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MouseMessage {
|
|
||||||
pub fn execute(&self, mouse_follows_focus: bool) {
|
|
||||||
match self {
|
|
||||||
MouseMessage::Komorebi(config) => {
|
|
||||||
let mut messages = Vec::new();
|
|
||||||
|
|
||||||
if config.focus_monitor_at_cursor.unwrap_or(true) {
|
|
||||||
messages.push(SocketMessage::FocusMonitorAtCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.ignore_mouse_follows_focus.unwrap_or(true) {
|
|
||||||
messages.push(SocketMessage::MouseFollowsFocus(false));
|
|
||||||
messages.push(config.message.clone());
|
|
||||||
messages.push(SocketMessage::MouseFollowsFocus(mouse_follows_focus));
|
|
||||||
} else {
|
|
||||||
messages.push(config.message.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::debug!("Sending messages: {messages:?}");
|
|
||||||
|
|
||||||
if komorebi_client::send_batch(messages.into_iter()).is_err() {
|
|
||||||
tracing::error!("could not send commands");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MouseMessage::Command(cmd) => {
|
|
||||||
tracing::debug!("Executing command: {}", cmd);
|
|
||||||
|
|
||||||
let cmd_no_env = cmd.replace_env();
|
|
||||||
|
|
||||||
if exec_powershell(cmd_no_env.to_str().expect("Invalid command")).is_err() {
|
|
||||||
tracing::error!("Failed to execute '{}'", cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KomobarConfig {
|
impl KomobarConfig {
|
||||||
pub fn read(path: &PathBuf) -> color_eyre::Result<Self> {
|
pub fn read(path: &PathBuf) -> color_eyre::Result<Self> {
|
||||||
let content = std::fs::read_to_string(path)?;
|
let content = std::fs::read_to_string(path)?;
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ use eframe::egui::ViewportBuilder;
|
|||||||
use font_loader::system_fonts;
|
use font_loader::system_fonts;
|
||||||
use hotwatch::EventKind;
|
use hotwatch::EventKind;
|
||||||
use hotwatch::Hotwatch;
|
use hotwatch::Hotwatch;
|
||||||
|
use image::RgbaImage;
|
||||||
use komorebi_client::replace_env_in_path;
|
use komorebi_client::replace_env_in_path;
|
||||||
use komorebi_client::PathExt;
|
use komorebi_client::PathExt;
|
||||||
use komorebi_client::SocketMessage;
|
use komorebi_client::SocketMessage;
|
||||||
use komorebi_client::SubscribeOptions;
|
use komorebi_client::SubscribeOptions;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -26,6 +28,8 @@ use std::sync::atomic::AtomicI32;
|
|||||||
use std::sync::atomic::AtomicU32;
|
use std::sync::atomic::AtomicU32;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
use windows::Win32::Foundation::HWND;
|
use windows::Win32::Foundation::HWND;
|
||||||
@@ -49,6 +53,9 @@ pub static DEFAULT_PADDING: f32 = 10.0;
|
|||||||
pub static AUTO_SELECT_FILL_COLOUR: AtomicU32 = AtomicU32::new(0);
|
pub static AUTO_SELECT_FILL_COLOUR: AtomicU32 = AtomicU32::new(0);
|
||||||
pub static AUTO_SELECT_TEXT_COLOUR: AtomicU32 = AtomicU32::new(0);
|
pub static AUTO_SELECT_TEXT_COLOUR: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
|
pub static ICON_CACHE: LazyLock<Mutex<HashMap<isize, RgbaImage>>> =
|
||||||
|
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(author, about, version)]
|
#[clap(author, about, version)]
|
||||||
struct Opts {
|
struct Opts {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::ImageIcon;
|
use super::komorebi::img_to_texture;
|
||||||
use crate::render::RenderConfig;
|
use crate::render::RenderConfig;
|
||||||
use crate::selected_frame::SelectableFrame;
|
use crate::selected_frame::SelectableFrame;
|
||||||
use crate::widgets::widget::BarWidget;
|
use crate::widgets::widget::BarWidget;
|
||||||
@@ -17,13 +17,14 @@ use eframe::egui::Stroke;
|
|||||||
use eframe::egui::StrokeKind;
|
use eframe::egui::StrokeKind;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
use eframe::egui::Vec2;
|
use eframe::egui::Vec2;
|
||||||
|
use image::DynamicImage;
|
||||||
|
use image::RgbaImage;
|
||||||
use komorebi_client::PathExt;
|
use komorebi_client::PathExt;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tracing;
|
use tracing;
|
||||||
@@ -118,32 +119,42 @@ impl BarWidget for Applications {
|
|||||||
|
|
||||||
impl From<&ApplicationsConfig> for Applications {
|
impl From<&ApplicationsConfig> for Applications {
|
||||||
fn from(applications_config: &ApplicationsConfig) -> Self {
|
fn from(applications_config: &ApplicationsConfig) -> Self {
|
||||||
|
// Allow immediate launch by initializing last_launch in the past.
|
||||||
|
let last_launch = Instant::now() - 2 * MIN_LAUNCH_INTERVAL;
|
||||||
|
let mut applications_config = applications_config.clone();
|
||||||
let items = applications_config
|
let items = applications_config
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter_mut()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, config)| {
|
.map(|(index, app_config)| {
|
||||||
let command = UserCommand::new(&config.command);
|
app_config.command = app_config
|
||||||
|
.command
|
||||||
|
.replace_env()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
if let Some(icon) = &mut app_config.icon {
|
||||||
|
*icon = icon.replace_env().to_string_lossy().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
App {
|
App {
|
||||||
enable: config.enable.unwrap_or(applications_config.enable),
|
enable: app_config.enable.unwrap_or(applications_config.enable),
|
||||||
#[allow(clippy::obfuscated_if_else)]
|
name: app_config
|
||||||
name: config
|
|
||||||
.name
|
.name
|
||||||
.is_empty()
|
.is_empty()
|
||||||
.then(|| format!("App {}", index + 1))
|
.then(|| format!("App {}", index + 1))
|
||||||
.unwrap_or_else(|| config.name.clone()),
|
.unwrap_or_else(|| app_config.name.clone()),
|
||||||
icon: Icon::try_from_path(config.icon.as_deref())
|
icon: Icon::try_from(app_config),
|
||||||
.or_else(|| Icon::try_from_command(&command)),
|
command: app_config.command.clone(),
|
||||||
command,
|
display: app_config
|
||||||
display: config
|
|
||||||
.display
|
.display
|
||||||
.or(applications_config.display)
|
.or(applications_config.display)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
show_command_on_hover: config
|
show_command_on_hover: app_config
|
||||||
.show_command_on_hover
|
.show_command_on_hover
|
||||||
.or(applications_config.show_command_on_hover)
|
.or(applications_config.show_command_on_hover)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
|
last_launch,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -166,11 +177,13 @@ pub struct App {
|
|||||||
/// Icon to display for this application, if available.
|
/// Icon to display for this application, if available.
|
||||||
pub icon: Option<Icon>,
|
pub icon: Option<Icon>,
|
||||||
/// Command to execute when the application is launched.
|
/// Command to execute when the application is launched.
|
||||||
pub command: UserCommand,
|
pub command: String,
|
||||||
/// Display format (icon, text, or both).
|
/// Display format (icon, text, or both).
|
||||||
pub display: DisplayFormat,
|
pub display: DisplayFormat,
|
||||||
/// Whether to show the launch command on hover.
|
/// Whether to show the launch command on hover.
|
||||||
pub show_command_on_hover: bool,
|
pub show_command_on_hover: bool,
|
||||||
|
/// Last time this application was launched (used for cooldown control).
|
||||||
|
pub last_launch: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -192,15 +205,17 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add hover text with command information
|
// Add hover text with command information
|
||||||
let response = ui.response();
|
|
||||||
if self.show_command_on_hover {
|
if self.show_command_on_hover {
|
||||||
response.on_hover_text(format!("Launch: {}", self.command.as_ref()));
|
ui.response()
|
||||||
|
.on_hover_text(format!("Launch: {}", self.command));
|
||||||
|
} else {
|
||||||
|
ui.response();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
// Launch the application when clicked
|
// Launch the application when clicked
|
||||||
self.command.launch_if_ready();
|
self.launch_if_ready();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,75 +235,84 @@ impl App {
|
|||||||
fn draw_name(&self, ui: &mut Ui) {
|
fn draw_name(&self, ui: &mut Ui) {
|
||||||
ui.add(Label::new(&self.name).selectable(false));
|
ui.add(Label::new(&self.name).selectable(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to launch the specified command in a separate thread if enough time has passed
|
||||||
|
/// since the last launch. This prevents repeated launches from rapid consecutive clicks.
|
||||||
|
///
|
||||||
|
/// Errors during launch are logged using the `tracing` crate.
|
||||||
|
pub fn launch_if_ready(&mut self) {
|
||||||
|
let now = Instant::now();
|
||||||
|
if now.duration_since(self.last_launch) < MIN_LAUNCH_INTERVAL {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_launch = now;
|
||||||
|
let command_string = self.command.clone();
|
||||||
|
// Launch the application in a separate thread to avoid blocking the UI
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
if let Err(e) = Command::new("cmd").args(["/C", &command_string]).spawn() {
|
||||||
|
tracing::error!("Failed to launch command '{}': {}", command_string, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds image/text data to be used as an icon in the UI.
|
/// Holds decoded image data to be used as an icon in the UI.
|
||||||
/// This represents source icon data before rendering.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Icon {
|
pub enum Icon {
|
||||||
/// RGBA image used for rendering the icon.
|
/// RGBA image used for rendering the icon.
|
||||||
Image(ImageIcon),
|
Image(RgbaImage),
|
||||||
/// Text-based icon, e.g. from a font like Nerd Fonts.
|
/// Text-based icon, e.g. from a font like Nerd Fonts.
|
||||||
Text(String),
|
Text(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Icon {
|
impl Icon {
|
||||||
/// Attempts to create an [`Icon`] from a string path or text glyph/glyphs.
|
/// Attempts to create an `Icon` from the given `AppConfig`.
|
||||||
///
|
/// Loads the image from a specified icon path or extracts it from the application's
|
||||||
/// - Environment variables in the path are resolved using [`PathExt::replace_env`].
|
/// executable if the command points to a valid executable file.
|
||||||
/// - Uses [`ImageIcon::try_load`] to load and cache the icon image based on the resolved path.
|
|
||||||
/// - If the path is invalid but the string is non-empty, it is interpreted as a text-based icon and
|
|
||||||
/// returned as [`Icon::Text`].
|
|
||||||
/// - Returns `None` if the input is empty, `None`, or image loading fails.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_from_path(icon: Option<&str>) -> Option<Self> {
|
pub fn try_from(config: &AppConfig) -> Option<Self> {
|
||||||
let icon = icon.map(str::trim)?;
|
if let Some(icon) = config.icon.as_deref().map(str::trim) {
|
||||||
if icon.is_empty() {
|
if !icon.is_empty() {
|
||||||
return None;
|
let path = Path::new(&icon);
|
||||||
}
|
if path.is_file() {
|
||||||
|
match image::open(path).as_ref().map(DynamicImage::to_rgba8) {
|
||||||
let path = icon.replace_env();
|
Ok(image) => return Some(Icon::Image(image)),
|
||||||
if !path.is_file() {
|
Err(err) => {
|
||||||
return Some(Icon::Text(icon.to_owned()));
|
tracing::error!("Failed to load icon from {}, error: {}", icon, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let image_icon = ImageIcon::try_load(path.as_ref(), || match image::open(&path) {
|
} else {
|
||||||
Ok(img) => Some(img),
|
return Some(Icon::Text(icon.to_owned()));
|
||||||
Err(err) => {
|
}
|
||||||
tracing::error!("Failed to load icon from {:?}, error: {}", path, err);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})?;
|
}
|
||||||
|
|
||||||
Some(Icon::Image(image_icon))
|
let binary = PathBuf::from(config.command.split(".exe").next()?);
|
||||||
|
let path = if binary.is_file() {
|
||||||
|
Some(binary)
|
||||||
|
} else {
|
||||||
|
which(binary).ok()
|
||||||
|
};
|
||||||
|
|
||||||
|
match path {
|
||||||
|
Some(path) => windows_icons::get_icon_by_path(&path.to_string_lossy())
|
||||||
|
.or_else(|| windows_icons_fallback::get_icon_by_path(&path.to_string_lossy()))
|
||||||
|
.map(Icon::Image),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to create an [`Icon`] by extracting an image from the executable path of a [`UserCommand`].
|
/// Renders the icon in the given `Ui` context with the specified size.
|
||||||
///
|
|
||||||
/// - Uses [`ImageIcon::try_load`] to load and cache the icon image based on the resolved executable path.
|
|
||||||
/// - Returns [`Icon::Image`] if an icon is successfully extracted.
|
|
||||||
/// - Returns `None` if the executable path is unavailable or icon extraction fails.
|
|
||||||
#[inline]
|
|
||||||
pub fn try_from_command(command: &UserCommand) -> Option<Self> {
|
|
||||||
let path = command.get_executable()?;
|
|
||||||
let image_icon = ImageIcon::try_load(path.as_ref(), || {
|
|
||||||
let path_str = path.to_str()?;
|
|
||||||
windows_icons::get_icon_by_path(path_str)
|
|
||||||
.or_else(|| windows_icons_fallback::get_icon_by_path(path_str))
|
|
||||||
})?;
|
|
||||||
Some(Icon::Image(image_icon))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renders the icon in the given [`Ui`] using the provided [`IconConfig`].
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn draw(&self, ctx: &Context, ui: &mut Ui, icon_config: &IconConfig) {
|
pub fn draw(&self, ctx: &Context, ui: &mut Ui, icon_config: &IconConfig) {
|
||||||
match self {
|
match self {
|
||||||
Icon::Image(image_icon) => {
|
Icon::Image(image) => {
|
||||||
Frame::NONE
|
Frame::NONE
|
||||||
.inner_margin(Margin::same(ui.style().spacing.button_padding.y as i8))
|
.inner_margin(Margin::same(ui.style().spacing.button_padding.y as i8))
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
ui.add(
|
ui.add(
|
||||||
Image::from_texture(&image_icon.texture(ctx))
|
Image::from(&img_to_texture(ctx, image))
|
||||||
.maintain_aspect_ratio(true)
|
.maintain_aspect_ratio(true)
|
||||||
.fit_to_exact_size(Vec2::splat(icon_config.size)),
|
.fit_to_exact_size(Vec2::splat(icon_config.size)),
|
||||||
);
|
);
|
||||||
@@ -330,77 +354,3 @@ pub struct IconConfig {
|
|||||||
/// Color of the icon used for text-based icons
|
/// Color of the icon used for text-based icons
|
||||||
pub color: Color32,
|
pub color: Color32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A structure to manage command execution with cooldown prevention.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UserCommand {
|
|
||||||
/// The command string to execute
|
|
||||||
pub command: Arc<str>,
|
|
||||||
/// Last time this command was executed (used for cooldown control)
|
|
||||||
pub last_launch: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<str> for UserCommand {
|
|
||||||
#[inline]
|
|
||||||
fn as_ref(&self) -> &str {
|
|
||||||
&self.command
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserCommand {
|
|
||||||
/// Creates a new [`UserCommand`] with environment variables in the command path
|
|
||||||
/// resolved using [`PathExt::replace_env`].
|
|
||||||
#[inline]
|
|
||||||
pub fn new(command: &str) -> Self {
|
|
||||||
// Allow immediate launch by initializing last_launch in the past
|
|
||||||
let last_launch = Instant::now() - 2 * MIN_LAUNCH_INTERVAL;
|
|
||||||
|
|
||||||
Self {
|
|
||||||
command: Arc::from(command.replace_env().to_str().unwrap_or_default()),
|
|
||||||
last_launch,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempts to resolve the executable path from the command string.
|
|
||||||
///
|
|
||||||
/// Resolution logic:
|
|
||||||
/// - Splits the command by ".exe" and checks if the first part is an existing file.
|
|
||||||
/// - If not, attempts to locate the binary using [`which`] on this name.
|
|
||||||
/// - If still unresolved, takes the first word (separated by whitespace) and attempts
|
|
||||||
/// to find it in the system `PATH` using [`which`].
|
|
||||||
///
|
|
||||||
/// Returns `None` if no executable path can be determined.
|
|
||||||
#[inline]
|
|
||||||
pub fn get_executable(&self) -> Option<Cow<'_, Path>> {
|
|
||||||
if let Some(binary) = self.command.split(".exe").next().map(Path::new) {
|
|
||||||
if binary.is_file() {
|
|
||||||
return Some(Cow::Borrowed(binary));
|
|
||||||
} else if let Ok(binary) = which(binary) {
|
|
||||||
return Some(Cow::Owned(binary));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
which(self.command.split(' ').next()?).ok().map(Cow::Owned)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempts to launch the specified command in a separate thread if enough time has passed
|
|
||||||
/// since the last launch. This prevents repeated launches from rapid consecutive clicks.
|
|
||||||
///
|
|
||||||
/// Errors during launch are logged using the `tracing` crate.
|
|
||||||
pub fn launch_if_ready(&mut self) {
|
|
||||||
let now = Instant::now();
|
|
||||||
// Check if enough time has passed since the last launch
|
|
||||||
if now.duration_since(self.last_launch) < MIN_LAUNCH_INTERVAL {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.last_launch = now;
|
|
||||||
let command_string = self.command.clone();
|
|
||||||
// Launch the application in a separate thread to avoid blocking the UI
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
if let Err(e) = Command::new("cmd").args(["/C", &command_string]).spawn() {
|
|
||||||
tracing::error!("Failed to launch command '{}': {}", command_string, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use super::ImageIcon;
|
|
||||||
use crate::bar::apply_theme;
|
use crate::bar::apply_theme;
|
||||||
use crate::config::DisplayFormat;
|
use crate::config::DisplayFormat;
|
||||||
use crate::config::KomobarTheme;
|
use crate::config::KomobarTheme;
|
||||||
@@ -9,12 +8,14 @@ use crate::selected_frame::SelectableFrame;
|
|||||||
use crate::ui::CustomUi;
|
use crate::ui::CustomUi;
|
||||||
use crate::widgets::komorebi_layout::KomorebiLayout;
|
use crate::widgets::komorebi_layout::KomorebiLayout;
|
||||||
use crate::widgets::widget::BarWidget;
|
use crate::widgets::widget::BarWidget;
|
||||||
|
use crate::ICON_CACHE;
|
||||||
use crate::MAX_LABEL_WIDTH;
|
use crate::MAX_LABEL_WIDTH;
|
||||||
use crate::MONITOR_INDEX;
|
use crate::MONITOR_INDEX;
|
||||||
use eframe::egui::text::LayoutJob;
|
use eframe::egui::text::LayoutJob;
|
||||||
use eframe::egui::vec2;
|
use eframe::egui::vec2;
|
||||||
use eframe::egui::Align;
|
use eframe::egui::Align;
|
||||||
use eframe::egui::Color32;
|
use eframe::egui::Color32;
|
||||||
|
use eframe::egui::ColorImage;
|
||||||
use eframe::egui::Context;
|
use eframe::egui::Context;
|
||||||
use eframe::egui::CornerRadius;
|
use eframe::egui::CornerRadius;
|
||||||
use eframe::egui::Frame;
|
use eframe::egui::Frame;
|
||||||
@@ -26,8 +27,11 @@ use eframe::egui::Sense;
|
|||||||
use eframe::egui::Stroke;
|
use eframe::egui::Stroke;
|
||||||
use eframe::egui::StrokeKind;
|
use eframe::egui::StrokeKind;
|
||||||
use eframe::egui::TextFormat;
|
use eframe::egui::TextFormat;
|
||||||
|
use eframe::egui::TextureHandle;
|
||||||
|
use eframe::egui::TextureOptions;
|
||||||
use eframe::egui::Ui;
|
use eframe::egui::Ui;
|
||||||
use eframe::egui::Vec2;
|
use eframe::egui::Vec2;
|
||||||
|
use image::RgbaImage;
|
||||||
use komorebi_client::Container;
|
use komorebi_client::Container;
|
||||||
use komorebi_client::NotificationEvent;
|
use komorebi_client::NotificationEvent;
|
||||||
use komorebi_client::PathExt;
|
use komorebi_client::PathExt;
|
||||||
@@ -229,7 +233,7 @@ impl BarWidget for Komorebi {
|
|||||||
for (is_focused, container) in containers {
|
for (is_focused, container) in containers {
|
||||||
for icon in container.icons.iter().flatten().collect::<Vec<_>>() {
|
for icon in container.icons.iter().flatten().collect::<Vec<_>>() {
|
||||||
ui.add(
|
ui.add(
|
||||||
Image::from(&icon.texture(ctx))
|
Image::from(&img_to_texture(ctx, icon))
|
||||||
.maintain_aspect_ratio(true)
|
.maintain_aspect_ratio(true)
|
||||||
.fit_to_exact_size(if *is_focused { icon_size } else { text_size }),
|
.fit_to_exact_size(if *is_focused { icon_size } else { text_size }),
|
||||||
);
|
);
|
||||||
@@ -600,7 +604,7 @@ impl BarWidget for Komorebi {
|
|||||||
))
|
))
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
let response = ui.add(
|
let response = ui.add(
|
||||||
Image::from(&img.texture(ctx) )
|
Image::from(&img_to_texture(ctx, img))
|
||||||
.maintain_aspect_ratio(true)
|
.maintain_aspect_ratio(true)
|
||||||
.fit_to_exact_size(icon_size),
|
.fit_to_exact_size(icon_size),
|
||||||
);
|
);
|
||||||
@@ -666,6 +670,13 @@ impl BarWidget for Komorebi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn img_to_texture(ctx: &Context, rgba_image: &RgbaImage) -> TextureHandle {
|
||||||
|
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
||||||
|
let pixels = rgba_image.as_flat_samples();
|
||||||
|
let color_image = ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
|
||||||
|
ctx.load_texture("icon", color_image, TextureOptions::default())
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct KomorebiNotificationState {
|
pub struct KomorebiNotificationState {
|
||||||
@@ -857,7 +868,7 @@ impl KomorebiNotificationState {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct KomorebiNotificationStateContainerInformation {
|
pub struct KomorebiNotificationStateContainerInformation {
|
||||||
pub titles: Vec<String>,
|
pub titles: Vec<String>,
|
||||||
pub icons: Vec<Option<ImageIcon>>,
|
pub icons: Vec<Option<RgbaImage>>,
|
||||||
pub focused_window_idx: usize,
|
pub focused_window_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,17 +895,34 @@ impl From<&Workspace> for KomorebiNotificationStateContainerInformation {
|
|||||||
impl From<&Container> for KomorebiNotificationStateContainerInformation {
|
impl From<&Container> for KomorebiNotificationStateContainerInformation {
|
||||||
fn from(value: &Container) -> Self {
|
fn from(value: &Container) -> Self {
|
||||||
let windows = value.windows().iter().collect::<Vec<_>>();
|
let windows = value.windows().iter().collect::<Vec<_>>();
|
||||||
|
let mut icons = vec![];
|
||||||
|
|
||||||
let icons = windows
|
for window in windows {
|
||||||
.iter()
|
let mut icon_cache = ICON_CACHE.lock().unwrap();
|
||||||
.map(|window| {
|
let mut update_cache = false;
|
||||||
ImageIcon::try_load(window.hwnd, || {
|
let hwnd = window.hwnd;
|
||||||
windows_icons::get_icon_by_hwnd(window.hwnd).or_else(|| {
|
|
||||||
windows_icons_fallback::get_icon_by_process_id(window.process_id())
|
match icon_cache.get(&hwnd) {
|
||||||
})
|
None => {
|
||||||
})
|
let icon = match windows_icons::get_icon_by_hwnd(window.hwnd) {
|
||||||
})
|
None => windows_icons_fallback::get_icon_by_process_id(window.process_id()),
|
||||||
.collect::<Vec<_>>();
|
Some(icon) => Some(icon),
|
||||||
|
};
|
||||||
|
|
||||||
|
icons.push(icon);
|
||||||
|
update_cache = true;
|
||||||
|
}
|
||||||
|
Some(icon) => {
|
||||||
|
icons.push(Some(icon.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if update_cache {
|
||||||
|
if let Some(Some(icon)) = icons.last() {
|
||||||
|
icon_cache.insert(hwnd, icon.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
titles: value
|
titles: value
|
||||||
@@ -910,14 +938,35 @@ impl From<&Container> for KomorebiNotificationStateContainerInformation {
|
|||||||
|
|
||||||
impl From<&Window> for KomorebiNotificationStateContainerInformation {
|
impl From<&Window> for KomorebiNotificationStateContainerInformation {
|
||||||
fn from(value: &Window) -> Self {
|
fn from(value: &Window) -> Self {
|
||||||
let icons = ImageIcon::try_load(value.hwnd, || {
|
let mut icon_cache = ICON_CACHE.lock().unwrap();
|
||||||
windows_icons::get_icon_by_hwnd(value.hwnd)
|
let mut update_cache = false;
|
||||||
.or_else(|| windows_icons_fallback::get_icon_by_process_id(value.process_id()))
|
let mut icons = vec![];
|
||||||
});
|
let hwnd = value.hwnd;
|
||||||
|
|
||||||
|
match icon_cache.get(&hwnd) {
|
||||||
|
None => {
|
||||||
|
let icon = match windows_icons::get_icon_by_hwnd(hwnd) {
|
||||||
|
None => windows_icons_fallback::get_icon_by_process_id(value.process_id()),
|
||||||
|
Some(icon) => Some(icon),
|
||||||
|
};
|
||||||
|
|
||||||
|
icons.push(icon);
|
||||||
|
update_cache = true;
|
||||||
|
}
|
||||||
|
Some(icon) => {
|
||||||
|
icons.push(Some(icon.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if update_cache {
|
||||||
|
if let Some(Some(icon)) = icons.last() {
|
||||||
|
icon_cache.insert(hwnd, icon.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
titles: vec![value.title().unwrap_or_default()],
|
titles: vec![value.title().unwrap_or_default()],
|
||||||
icons: vec![icons],
|
icons,
|
||||||
focused_window_idx: 0,
|
focused_window_idx: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,3 @@
|
|||||||
use eframe::egui::ColorImage;
|
|
||||||
use eframe::egui::Context;
|
|
||||||
use eframe::egui::TextureHandle;
|
|
||||||
use eframe::egui::TextureOptions;
|
|
||||||
use image::RgbaImage;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
pub mod applications;
|
pub mod applications;
|
||||||
pub mod battery;
|
pub mod battery;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
@@ -23,151 +12,3 @@ pub mod storage;
|
|||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
|
|
||||||
/// Global cache for icon images and their associated GPU textures.
|
|
||||||
pub static ICONS_CACHE: IconsCache = IconsCache::new();
|
|
||||||
|
|
||||||
/// In-memory cache for icon images and their associated GPU textures.
|
|
||||||
///
|
|
||||||
/// Stores raw [`ColorImage`]s and [`TextureHandle`]s keyed by [`ImageIconId`].
|
|
||||||
/// Texture entries are context-dependent and automatically invalidated when the [`Context`] changes.
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub struct IconsCache {
|
|
||||||
textures: LazyLock<RwLock<(Option<Context>, HashMap<ImageIconId, TextureHandle>)>>,
|
|
||||||
images: LazyLock<RwLock<HashMap<ImageIconId, Arc<ColorImage>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IconsCache {
|
|
||||||
/// Creates a new empty IconsCache instance.
|
|
||||||
#[inline]
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
textures: LazyLock::new(|| RwLock::new((None, HashMap::new()))),
|
|
||||||
images: LazyLock::new(|| RwLock::new(HashMap::new())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves or creates a texture handle for the given icon ID and image.
|
|
||||||
///
|
|
||||||
/// If a texture for the given ID already exists for the current [`Context`], it is reused.
|
|
||||||
/// Otherwise, a new texture is created, inserted into the cache, and returned.
|
|
||||||
/// The cache is reset if the [`Context`] has changed.
|
|
||||||
#[inline]
|
|
||||||
pub fn texture(&self, ctx: &Context, id: &ImageIconId, img: &Arc<ColorImage>) -> TextureHandle {
|
|
||||||
if let Some(texture) = self.get_texture(ctx, id) {
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
let texture_handle = ctx.load_texture("icon", img.clone(), TextureOptions::default());
|
|
||||||
self.insert_texture(ctx, id.clone(), texture_handle.clone());
|
|
||||||
texture_handle
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the cached texture for the given icon ID if it exists and matches the current [`Context`].
|
|
||||||
pub fn get_texture(&self, ctx: &Context, id: &ImageIconId) -> Option<TextureHandle> {
|
|
||||||
let textures_lock = self.textures.read().unwrap();
|
|
||||||
if textures_lock.0.as_ref() == Some(ctx) {
|
|
||||||
return textures_lock.1.get(id).cloned();
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts a texture handle, resetting the cache if the [`Context`] has changed.
|
|
||||||
pub fn insert_texture(&self, ctx: &Context, id: ImageIconId, texture: TextureHandle) {
|
|
||||||
let mut textures_lock = self.textures.write().unwrap();
|
|
||||||
|
|
||||||
if textures_lock.0.as_ref() != Some(ctx) {
|
|
||||||
textures_lock.0 = Some(ctx.clone());
|
|
||||||
textures_lock.1.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
textures_lock.1.insert(id, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the cached image for the given icon ID, if available.
|
|
||||||
pub fn get_image(&self, id: &ImageIconId) -> Option<Arc<ColorImage>> {
|
|
||||||
self.images.read().unwrap().get(id).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Caches a raw [`ColorImage`] associated with the given icon ID.
|
|
||||||
pub fn insert_image(&self, id: ImageIconId, image: Arc<ColorImage>) {
|
|
||||||
self.images.write().unwrap().insert(id, image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rgba_to_color_image(rgba_image: &RgbaImage) -> ColorImage {
|
|
||||||
let size = [rgba_image.width() as usize, rgba_image.height() as usize];
|
|
||||||
let pixels = rgba_image.as_flat_samples();
|
|
||||||
ColorImage::from_rgba_unmultiplied(size, pixels.as_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents an image-based icon with a unique ID and pixel data.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct ImageIcon {
|
|
||||||
/// Unique identifier for the image icon, used for texture caching.
|
|
||||||
pub id: ImageIconId,
|
|
||||||
/// Shared pixel data of the icon in `ColorImage` format.
|
|
||||||
pub image: Arc<ColorImage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImageIcon {
|
|
||||||
/// Creates a new [`ImageIcon`] from the given ID and image data.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(id: ImageIconId, image: Arc<ColorImage>) -> Self {
|
|
||||||
Self { id, image }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Loads an [`ImageIcon`] from [`ICONS_CACHE`] or calls `loader` if not cached.
|
|
||||||
/// The loaded image is converted to a [`ColorImage`], cached, and returned.
|
|
||||||
#[inline]
|
|
||||||
pub fn try_load<F, I>(id: impl Into<ImageIconId>, loader: F) -> Option<Self>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> Option<I>,
|
|
||||||
I: Into<RgbaImage>,
|
|
||||||
{
|
|
||||||
let id = id.into();
|
|
||||||
let image = ICONS_CACHE.get_image(&id).or_else(|| {
|
|
||||||
let img = loader()?;
|
|
||||||
let img = Arc::new(rgba_to_color_image(&img.into()));
|
|
||||||
ICONS_CACHE.insert_image(id.clone(), img.clone());
|
|
||||||
Some(img)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Some(ImageIcon::new(id, image))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a texture handle for the icon, using the given [`Context`].
|
|
||||||
///
|
|
||||||
/// If the texture is already cached in [`ICONS_CACHE`], it is reused.
|
|
||||||
/// Otherwise, a new texture is created from the [`ColorImage`] and cached.
|
|
||||||
#[inline]
|
|
||||||
pub fn texture(&self, ctx: &Context) -> TextureHandle {
|
|
||||||
ICONS_CACHE.texture(ctx, &self.id, &self.image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unique identifier for an image-based icon.
|
|
||||||
///
|
|
||||||
/// Used to distinguish cached images and textures by either a file path
|
|
||||||
/// or a Windows window handle.
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
||||||
pub enum ImageIconId {
|
|
||||||
/// Identifier based on a file system path.
|
|
||||||
Path(Arc<Path>),
|
|
||||||
/// Windows HWND handle.
|
|
||||||
Hwnd(isize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Path> for ImageIconId {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: &Path) -> Self {
|
|
||||||
Self::Path(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for ImageIconId {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: isize) -> Self {
|
|
||||||
Self::Hwnd(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
komorebi = { path = "../komorebi", default-features = false }
|
komorebi = { path = "../komorebi" }
|
||||||
|
|
||||||
uds_windows = { workspace = true }
|
uds_windows = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["schemars"]
|
default = ["schemars"]
|
||||||
schemars = ["komorebi/default"]
|
schemars = ["komorebi/schemars"]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
komorebi-client = { path = "../komorebi-client", default-features = false }
|
komorebi-client = { path = "../komorebi-client" }
|
||||||
|
|
||||||
eframe = { workspace = true }
|
eframe = { workspace = true }
|
||||||
egui_extras = { workspace = true }
|
egui_extras = { workspace = true }
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
whkd-parser = { git = "https://github.com/LGUG2Z/whkd", rev = "v0.2.9" }
|
whkd-parser = { git = "https://github.com/LGUG2Z/whkd", rev = "29df24ff2dd715655b0366bd2a598837c699a8e9" }
|
||||||
whkd-core = { git = "https://github.com/LGUG2Z/whkd", rev = "v0.2.9" }
|
whkd-core = { git = "https://github.com/LGUG2Z/whkd", rev = "29df24ff2dd715655b0366bd2a598837c699a8e9" }
|
||||||
|
|
||||||
eframe = { workspace = true }
|
eframe = { workspace = true }
|
||||||
dirs = { workspace = true }
|
dirs = { workspace = true }
|
||||||
@@ -17,6 +17,7 @@ crossbeam-channel = { workspace = true }
|
|||||||
crossbeam-utils = { workspace = true }
|
crossbeam-utils = { workspace = true }
|
||||||
ctrlc = { version = "3", features = ["termination"] }
|
ctrlc = { version = "3", features = ["termination"] }
|
||||||
dirs = { workspace = true }
|
dirs = { workspace = true }
|
||||||
|
dunce = { workspace = true }
|
||||||
getset = "0.1"
|
getset = "0.1"
|
||||||
hotwatch = { workspace = true }
|
hotwatch = { workspace = true }
|
||||||
lazy_static = { workspace = true }
|
lazy_static = { workspace = true }
|
||||||
@@ -24,7 +25,7 @@ miow = "0.6"
|
|||||||
nanoid = "0.4"
|
nanoid = "0.4"
|
||||||
net2 = "0.2"
|
net2 = "0.2"
|
||||||
os_info = "3.10"
|
os_info = "3.10"
|
||||||
parking_lot = { workspace = true }
|
parking_lot = "0.12"
|
||||||
paste = { workspace = true }
|
paste = { workspace = true }
|
||||||
powershell_script = "1.0"
|
powershell_script = "1.0"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::core::BorderStyle;
|
|||||||
use crate::core::WindowKind;
|
use crate::core::WindowKind;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::windows_api;
|
use crate::windows_api;
|
||||||
use crate::workspace::Workspace;
|
|
||||||
use crate::workspace::WorkspaceLayer;
|
use crate::workspace::WorkspaceLayer;
|
||||||
use crate::WindowManager;
|
use crate::WindowManager;
|
||||||
use crate::WindowsApi;
|
use crate::WindowsApi;
|
||||||
@@ -213,8 +212,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
[focused_workspace_idx]
|
[focused_workspace_idx]
|
||||||
.layer();
|
.layer();
|
||||||
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
|
let foreground_window = WindowsApi::foreground_window().unwrap_or_default();
|
||||||
let layer_changed = previous_layer != workspace_layer;
|
|
||||||
let forced_update = matches!(notification, Notification::ForceUpdate);
|
|
||||||
|
|
||||||
drop(state);
|
drop(state);
|
||||||
|
|
||||||
@@ -237,17 +234,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.set_accent(window_kind_colour(window_kind))?;
|
.set_accent(window_kind_colour(window_kind))?;
|
||||||
|
|
||||||
if ws.layer() == &WorkspaceLayer::Floating {
|
|
||||||
for window in ws.floating_windows() {
|
|
||||||
let mut window_kind = WindowKind::Unfocused;
|
|
||||||
|
|
||||||
if foreground_window == window.hwnd {
|
|
||||||
window_kind = WindowKind::Floating;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.set_accent(window_kind_colour(window_kind))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue 'monitors;
|
continue 'monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,40 +448,14 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
windows_borders.insert(focused_window_hwnd, id);
|
windows_borders.insert(focused_window_hwnd, id);
|
||||||
|
|
||||||
let border_hwnd = border.hwnd;
|
let border_hwnd = border.hwnd;
|
||||||
|
// Remove all borders on this monitor except monocle
|
||||||
|
remove_borders(
|
||||||
|
&mut borders,
|
||||||
|
&mut windows_borders,
|
||||||
|
monitor_idx,
|
||||||
|
|_, b| border_hwnd != b.hwnd,
|
||||||
|
)?;
|
||||||
|
|
||||||
if ws.layer() == &WorkspaceLayer::Floating {
|
|
||||||
handle_floating_borders(
|
|
||||||
&mut borders,
|
|
||||||
&mut windows_borders,
|
|
||||||
ws,
|
|
||||||
monitor_idx,
|
|
||||||
foreground_window,
|
|
||||||
layer_changed,
|
|
||||||
forced_update,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Remove all borders on this monitor except monocle and floating borders
|
|
||||||
remove_borders(
|
|
||||||
&mut borders,
|
|
||||||
&mut windows_borders,
|
|
||||||
monitor_idx,
|
|
||||||
|_, b| {
|
|
||||||
border_hwnd != b.hwnd
|
|
||||||
&& !ws
|
|
||||||
.floating_windows()
|
|
||||||
.iter()
|
|
||||||
.any(|w| w.hwnd == b.tracking_hwnd)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
// Remove all borders on this monitor except monocle
|
|
||||||
remove_borders(
|
|
||||||
&mut borders,
|
|
||||||
&mut windows_borders,
|
|
||||||
monitor_idx,
|
|
||||||
|_, b| border_hwnd != b.hwnd,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
continue 'monitors;
|
continue 'monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,6 +569,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
};
|
};
|
||||||
border.window_rect = rect;
|
border.window_rect = rect;
|
||||||
|
|
||||||
|
let layer_changed = previous_layer != workspace_layer;
|
||||||
|
let forced_update = matches!(notification, Notification::ForceUpdate);
|
||||||
|
|
||||||
let should_invalidate = new_border
|
let should_invalidate = new_border
|
||||||
|| (last_focus_state != new_focus_state)
|
|| (last_focus_state != new_focus_state)
|
||||||
|| layer_changed
|
|| layer_changed
|
||||||
@@ -628,15 +591,65 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
windows_borders.insert(focused_window_hwnd, id);
|
windows_borders.insert(focused_window_hwnd, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_floating_borders(
|
{
|
||||||
&mut borders,
|
for window in ws.floating_windows() {
|
||||||
&mut windows_borders,
|
let mut new_border = false;
|
||||||
ws,
|
let id = window.hwnd.to_string();
|
||||||
monitor_idx,
|
let border = match borders.entry(id.clone()) {
|
||||||
foreground_window,
|
Entry::Occupied(entry) => entry.into_mut(),
|
||||||
layer_changed,
|
Entry::Vacant(entry) => {
|
||||||
forced_update,
|
if let Ok(border) = Border::create(
|
||||||
)?;
|
&window.hwnd.to_string(),
|
||||||
|
window.hwnd,
|
||||||
|
monitor_idx,
|
||||||
|
) {
|
||||||
|
new_border = true;
|
||||||
|
entry.insert(border)
|
||||||
|
} else {
|
||||||
|
continue 'monitors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let last_focus_state = border.window_kind;
|
||||||
|
|
||||||
|
let new_focus_state = if foreground_window == window.hwnd {
|
||||||
|
WindowKind::Floating
|
||||||
|
} else {
|
||||||
|
WindowKind::Unfocused
|
||||||
|
};
|
||||||
|
|
||||||
|
border.window_kind = new_focus_state;
|
||||||
|
|
||||||
|
// Update the border's monitor idx in case it changed
|
||||||
|
border.monitor_idx = Some(monitor_idx);
|
||||||
|
|
||||||
|
let rect = WindowsApi::window_rect(window.hwnd)?;
|
||||||
|
border.window_rect = rect;
|
||||||
|
|
||||||
|
let layer_changed = previous_layer != workspace_layer;
|
||||||
|
let forced_update =
|
||||||
|
matches!(notification, Notification::ForceUpdate);
|
||||||
|
|
||||||
|
let should_invalidate = new_border
|
||||||
|
|| (last_focus_state != new_focus_state)
|
||||||
|
|| layer_changed
|
||||||
|
|| forced_update;
|
||||||
|
|
||||||
|
if should_invalidate {
|
||||||
|
if forced_update && !new_border {
|
||||||
|
// Update the border brushes if there was a forced update
|
||||||
|
// notification and this is not a new border (new border's
|
||||||
|
// already have their brushes updated on creation)
|
||||||
|
border.update_brushes()?;
|
||||||
|
}
|
||||||
|
border.set_position(&rect, window.hwnd)?;
|
||||||
|
border.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
windows_borders.insert(window.hwnd, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -652,68 +665,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_floating_borders(
|
|
||||||
borders: &mut HashMap<String, Box<Border>>,
|
|
||||||
windows_borders: &mut HashMap<isize, String>,
|
|
||||||
ws: &Workspace,
|
|
||||||
monitor_idx: usize,
|
|
||||||
foreground_window: isize,
|
|
||||||
layer_changed: bool,
|
|
||||||
forced_update: bool,
|
|
||||||
) -> color_eyre::Result<()> {
|
|
||||||
for window in ws.floating_windows() {
|
|
||||||
let mut new_border = false;
|
|
||||||
let id = window.hwnd.to_string();
|
|
||||||
let border = match borders.entry(id.clone()) {
|
|
||||||
Entry::Occupied(entry) => entry.into_mut(),
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
if let Ok(border) =
|
|
||||||
Border::create(&window.hwnd.to_string(), window.hwnd, monitor_idx)
|
|
||||||
{
|
|
||||||
new_border = true;
|
|
||||||
entry.insert(border)
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let last_focus_state = border.window_kind;
|
|
||||||
|
|
||||||
let new_focus_state = if foreground_window == window.hwnd {
|
|
||||||
WindowKind::Floating
|
|
||||||
} else {
|
|
||||||
WindowKind::Unfocused
|
|
||||||
};
|
|
||||||
|
|
||||||
border.window_kind = new_focus_state;
|
|
||||||
|
|
||||||
// Update the border's monitor idx in case it changed
|
|
||||||
border.monitor_idx = Some(monitor_idx);
|
|
||||||
|
|
||||||
let rect = WindowsApi::window_rect(window.hwnd)?;
|
|
||||||
border.window_rect = rect;
|
|
||||||
|
|
||||||
let should_invalidate =
|
|
||||||
new_border || (last_focus_state != new_focus_state) || layer_changed || forced_update;
|
|
||||||
|
|
||||||
if should_invalidate {
|
|
||||||
if forced_update && !new_border {
|
|
||||||
// Update the border brushes if there was a forced update
|
|
||||||
// notification and this is not a new border (new border's
|
|
||||||
// already have their brushes updated on creation)
|
|
||||||
border.update_brushes()?;
|
|
||||||
}
|
|
||||||
border.set_position(&rect, window.hwnd)?;
|
|
||||||
border.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
windows_borders.insert(window.hwnd, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes all borders from monitor with index `monitor_idx` filtered by
|
/// Removes all borders from monitor with index `monitor_idx` filtered by
|
||||||
/// `condition`. This condition is a function that will take a reference to
|
/// `condition`. This condition is a function that will take a reference to
|
||||||
/// the container id and the border and returns a bool, if true that border
|
/// the container id and the border and returns a bool, if true that border
|
||||||
|
|||||||
@@ -341,7 +341,6 @@ pub enum StateQuery {
|
|||||||
FocusedWindowIndex,
|
FocusedWindowIndex,
|
||||||
FocusedWorkspaceName,
|
FocusedWorkspaceName,
|
||||||
FocusedWorkspaceLayout,
|
FocusedWorkspaceLayout,
|
||||||
FocusedContainerKind,
|
|
||||||
Version,
|
Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ use serde::Serialize;
|
|||||||
|
|
||||||
/// Path extension trait
|
/// Path extension trait
|
||||||
pub trait PathExt {
|
pub trait PathExt {
|
||||||
/// Resolve environment variable components in a path.
|
/// Resolve environment variables components in a path.
|
||||||
///
|
///
|
||||||
/// Resolves the following formats:
|
/// Resolves the follwing formats:
|
||||||
/// - CMD: `%variable%`
|
/// - CMD: `%variable%`
|
||||||
/// - PowerShell: `$Env:variable`
|
/// - PowerShell: `$Env:variable`
|
||||||
/// - Bash: `$variable`.
|
/// - Bash: `$variable`.
|
||||||
|
|||||||
@@ -631,25 +631,6 @@ mod tests {
|
|||||||
assert_eq!(m.workspaces().len(), 0);
|
assert_eq!(m.workspaces().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_remove_nonexistent_workspace() {
|
|
||||||
let mut m = Monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Try to remove a workspace that doesn't exist
|
|
||||||
let removed_workspace = m.remove_workspace_by_idx(1);
|
|
||||||
|
|
||||||
// Should return None since there is no workspace at index 1
|
|
||||||
assert!(removed_workspace.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_focus_workspace() {
|
fn test_focus_workspace() {
|
||||||
let mut m = Monitor::new(
|
let mut m = Monitor::new(
|
||||||
@@ -757,46 +738,6 @@ mod tests {
|
|||||||
assert_eq!(m.focused_workspace().unwrap().containers().len(), 2);
|
assert_eq!(m.focused_workspace().unwrap().containers().len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_move_container_to_nonexistent_workspace() {
|
|
||||||
let mut m = Monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Create workspace 1 and add 3 containers
|
|
||||||
let workspace = m.focused_workspace_mut().unwrap();
|
|
||||||
for _ in 0..3 {
|
|
||||||
let container = Container::default();
|
|
||||||
workspace.add_container_to_back(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should have 3 containers in workspace 1
|
|
||||||
assert_eq!(m.focused_workspace().unwrap().containers().len(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should only have 1 workspace
|
|
||||||
assert_eq!(m.workspaces().len(), 1);
|
|
||||||
|
|
||||||
// Try to move a container to a workspace that doesn't exist
|
|
||||||
m.move_container_to_workspace(8, true, None).unwrap();
|
|
||||||
|
|
||||||
// Should have 9 workspaces now
|
|
||||||
assert_eq!(m.workspaces().len(), 9);
|
|
||||||
|
|
||||||
// Should be focused on workspace 8
|
|
||||||
assert_eq!(m.focused_workspace_idx(), 8);
|
|
||||||
|
|
||||||
// Should have 1 container in workspace 8
|
|
||||||
assert_eq!(m.focused_workspace().unwrap().containers().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ensure_workspace_count_workspace_contains_two_workspaces() {
|
fn test_ensure_workspace_count_workspace_contains_two_workspaces() {
|
||||||
let mut m = Monitor::new(
|
let mut m = Monitor::new(
|
||||||
|
|||||||
@@ -1281,7 +1281,6 @@ impl WindowManager {
|
|||||||
if i == focused_idx {
|
if i == focused_idx {
|
||||||
to_focus = Some(*window);
|
to_focus = Some(*window);
|
||||||
} else {
|
} else {
|
||||||
window.restore();
|
|
||||||
window.raise()?;
|
window.raise()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1289,7 +1288,6 @@ impl WindowManager {
|
|||||||
if let Some(focused_window) = &to_focus {
|
if let Some(focused_window) = &to_focus {
|
||||||
// The focused window should be the last one raised to make sure it is
|
// The focused window should be the last one raised to make sure it is
|
||||||
// on top
|
// on top
|
||||||
focused_window.restore();
|
|
||||||
focused_window.raise()?;
|
focused_window.raise()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1299,8 +1297,8 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(monocle) = workspace.monocle_container() {
|
if let Some(container) = workspace.monocle_container() {
|
||||||
if let Some(window) = monocle.focused_window() {
|
if let Some(window) = container.focused_window() {
|
||||||
window.lower()?;
|
window.lower()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1308,41 +1306,30 @@ impl WindowManager {
|
|||||||
WorkspaceLayer::Floating => {
|
WorkspaceLayer::Floating => {
|
||||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||||
|
|
||||||
if let Some(monocle) = workspace.monocle_container() {
|
let focused_container_idx = workspace.focused_container_idx();
|
||||||
if let Some(window) = monocle.focused_window() {
|
for (i, container) in workspace.containers_mut().iter_mut().enumerate() {
|
||||||
to_focus = Some(*window);
|
if let Some(window) = container.focused_window() {
|
||||||
|
if i == focused_container_idx {
|
||||||
|
to_focus = Some(*window);
|
||||||
|
}
|
||||||
window.raise()?;
|
window.raise()?;
|
||||||
}
|
}
|
||||||
for window in workspace.floating_windows() {
|
}
|
||||||
window.hide();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let focused_container_idx = workspace.focused_container_idx();
|
|
||||||
for (i, container) in workspace.containers_mut().iter_mut().enumerate()
|
|
||||||
{
|
|
||||||
if let Some(window) = container.focused_window() {
|
|
||||||
if i == focused_container_idx {
|
|
||||||
to_focus = Some(*window);
|
|
||||||
}
|
|
||||||
window.raise()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut window_idx_pairs = workspace
|
let mut window_idx_pairs = workspace
|
||||||
.floating_windows_mut()
|
.floating_windows_mut()
|
||||||
.make_contiguous()
|
.make_contiguous()
|
||||||
.iter()
|
.iter()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Sort by window area
|
// Sort by window area
|
||||||
window_idx_pairs.sort_by_key(|w| {
|
window_idx_pairs.sort_by_key(|w| {
|
||||||
let rect = WindowsApi::window_rect(w.hwnd).unwrap_or_default();
|
let rect = WindowsApi::window_rect(w.hwnd).unwrap_or_default();
|
||||||
rect.right * rect.bottom
|
rect.right * rect.bottom
|
||||||
});
|
});
|
||||||
|
|
||||||
for window in window_idx_pairs {
|
for window in window_idx_pairs {
|
||||||
window.lower()?;
|
window.lower()?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1475,18 +1462,6 @@ impl WindowManager {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StateQuery::FocusedContainerKind => {
|
|
||||||
match self.focused_workspace()?.focused_container() {
|
|
||||||
None => "None".to_string(),
|
|
||||||
Some(container) => {
|
|
||||||
if container.windows().len() > 1 {
|
|
||||||
"Stack".to_string()
|
|
||||||
} else {
|
|
||||||
"Single".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reply.write_all(response.as_bytes())?;
|
reply.write_all(response.as_bytes())?;
|
||||||
|
|||||||
@@ -339,11 +339,10 @@ impl WindowManager {
|
|||||||
WindowManagerEvent::Show(_, window)
|
WindowManagerEvent::Show(_, window)
|
||||||
| WindowManagerEvent::Manage(window)
|
| WindowManagerEvent::Manage(window)
|
||||||
| WindowManagerEvent::Uncloak(_, window) => {
|
| WindowManagerEvent::Uncloak(_, window) => {
|
||||||
if matches!(event, WindowManagerEvent::Uncloak(_, _))
|
if matches!(event, WindowManagerEvent::Uncloak(_, _)) && self.uncloak_to_ignore >= 1
|
||||||
&& self.uncloack_to_ignore >= 1
|
|
||||||
{
|
{
|
||||||
tracing::info!("ignoring uncloak after monocle move by mouse across monitors");
|
tracing::info!("ignoring uncloak after monocle move by mouse across monitors");
|
||||||
self.uncloack_to_ignore = self.uncloack_to_ignore.saturating_sub(1);
|
self.uncloak_to_ignore = self.uncloak_to_ignore.saturating_sub(1);
|
||||||
} else {
|
} else {
|
||||||
let focused_monitor_idx = self.focused_monitor_idx();
|
let focused_monitor_idx = self.focused_monitor_idx();
|
||||||
let focused_workspace_idx =
|
let focused_workspace_idx =
|
||||||
@@ -402,6 +401,7 @@ impl WindowManager {
|
|||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
let workspace_contains_window = workspace.contains_window(window.hwnd);
|
let workspace_contains_window = workspace.contains_window(window.hwnd);
|
||||||
let monocle_container = workspace.monocle_container().clone();
|
let monocle_container = workspace.monocle_container().clone();
|
||||||
|
let mut workspace_layer = *workspace.layer();
|
||||||
|
|
||||||
if !workspace_contains_window && needs_reconciliation.is_none() {
|
if !workspace_contains_window && needs_reconciliation.is_none() {
|
||||||
let floating_applications = FLOATING_APPLICATIONS.lock();
|
let floating_applications = FLOATING_APPLICATIONS.lock();
|
||||||
@@ -445,6 +445,7 @@ impl WindowManager {
|
|||||||
placement.should_center() && workspace.tile;
|
placement.should_center() && workspace.tile;
|
||||||
workspace.floating_windows_mut().push_back(window);
|
workspace.floating_windows_mut().push_back(window);
|
||||||
workspace.set_layer(WorkspaceLayer::Floating);
|
workspace.set_layer(WorkspaceLayer::Floating);
|
||||||
|
workspace_layer = *workspace.layer();
|
||||||
if center_spawned_floats {
|
if center_spawned_floats {
|
||||||
let mut floating_window = window;
|
let mut floating_window = window;
|
||||||
floating_window.center(
|
floating_window.center(
|
||||||
@@ -458,6 +459,7 @@ impl WindowManager {
|
|||||||
WindowContainerBehaviour::Create => {
|
WindowContainerBehaviour::Create => {
|
||||||
workspace.new_container_for_window(window);
|
workspace.new_container_for_window(window);
|
||||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||||
|
workspace_layer = *workspace.layer();
|
||||||
self.update_focused_workspace(false, false)?;
|
self.update_focused_workspace(false, false)?;
|
||||||
}
|
}
|
||||||
WindowContainerBehaviour::Append => {
|
WindowContainerBehaviour::Append => {
|
||||||
@@ -468,6 +470,7 @@ impl WindowManager {
|
|||||||
})?
|
})?
|
||||||
.add_window(window);
|
.add_window(window);
|
||||||
workspace.set_layer(WorkspaceLayer::Tiling);
|
workspace.set_layer(WorkspaceLayer::Tiling);
|
||||||
|
workspace_layer = *workspace.layer();
|
||||||
self.update_focused_workspace(true, false)?;
|
self.update_focused_workspace(true, false)?;
|
||||||
stackbar_manager::send_notification();
|
stackbar_manager::send_notification();
|
||||||
}
|
}
|
||||||
@@ -500,10 +503,9 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let workspace = self.focused_workspace()?;
|
if !monocle_window_event
|
||||||
if !(monocle_window_event
|
|
||||||
|| workspace.layer() != &WorkspaceLayer::Tiling)
|
|
||||||
&& monocle_container.is_some()
|
&& monocle_container.is_some()
|
||||||
|
&& matches!(workspace_layer, WorkspaceLayer::Tiling)
|
||||||
{
|
{
|
||||||
window.hide();
|
window.hide();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub static STACKBAR_TAB_BACKGROUND_COLOUR: AtomicU32 = AtomicU32::new(3355443);
|
|||||||
pub static STACKBAR_TAB_HEIGHT: AtomicI32 = AtomicI32::new(40);
|
pub static STACKBAR_TAB_HEIGHT: AtomicI32 = AtomicI32::new(40);
|
||||||
pub static STACKBAR_TAB_WIDTH: AtomicI32 = AtomicI32::new(200);
|
pub static STACKBAR_TAB_WIDTH: AtomicI32 = AtomicI32::new(200);
|
||||||
pub static STACKBAR_LABEL: AtomicCell<StackbarLabel> = AtomicCell::new(StackbarLabel::Process);
|
pub static STACKBAR_LABEL: AtomicCell<StackbarLabel> = AtomicCell::new(StackbarLabel::Process);
|
||||||
pub static STACKBAR_MODE: AtomicCell<StackbarMode> = AtomicCell::new(StackbarMode::Never);
|
pub static STACKBAR_MODE: AtomicCell<StackbarMode> = AtomicCell::new(StackbarMode::OnStack);
|
||||||
|
|
||||||
pub static STACKBAR_TEMPORARILY_DISABLED: AtomicBool = AtomicBool::new(false);
|
pub static STACKBAR_TEMPORARILY_DISABLED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
|||||||
@@ -807,7 +807,7 @@ pub struct StackbarConfig {
|
|||||||
/// Stackbar label
|
/// Stackbar label
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub label: Option<StackbarLabel>,
|
pub label: Option<StackbarLabel>,
|
||||||
/// Stackbar mode (default: Never)
|
/// Stackbar mode
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub mode: Option<StackbarMode>,
|
pub mode: Option<StackbarMode>,
|
||||||
/// Stackbar tab configuration options
|
/// Stackbar tab configuration options
|
||||||
@@ -1299,7 +1299,7 @@ impl StaticConfig {
|
|||||||
has_pending_raise_op: false,
|
has_pending_raise_op: false,
|
||||||
pending_move_op: Arc::new(None),
|
pending_move_op: Arc::new(None),
|
||||||
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
|
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
|
||||||
uncloack_to_ignore: 0,
|
uncloak_to_ignore: 0,
|
||||||
known_hwnds: HashMap::new(),
|
known_hwnds: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1912,13 +1912,11 @@ mod tests {
|
|||||||
use crate::WorkspaceConfig;
|
use crate::WorkspaceConfig;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "this fails on github actions due to rate limiting changes introduced in may 2025"]
|
|
||||||
fn backwards_compat() {
|
fn backwards_compat() {
|
||||||
let root = vec!["0.1.17", "0.1.18", "0.1.19"];
|
let root = vec!["0.1.17", "0.1.18", "0.1.19"];
|
||||||
let docs = vec![
|
let docs = vec![
|
||||||
"0.1.20", "0.1.21", "0.1.22", "0.1.23", "0.1.24", "0.1.25", "0.1.26", "0.1.27",
|
"0.1.20", "0.1.21", "0.1.22", "0.1.23", "0.1.24", "0.1.25", "0.1.26", "0.1.27",
|
||||||
"0.1.28", "0.1.29", "0.1.30", "0.1.31", "0.1.32", "0.1.33", "0.1.34", "0.1.35",
|
"0.1.28", "0.1.29", "0.1.30", "0.1.31", "0.1.32", "0.1.33", "0.1.34",
|
||||||
"0.1.36",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut versions = vec![];
|
let mut versions = vec![];
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ pub struct WindowManager {
|
|||||||
pub has_pending_raise_op: bool,
|
pub has_pending_raise_op: bool,
|
||||||
pub pending_move_op: Arc<Option<(usize, usize, isize)>>,
|
pub pending_move_op: Arc<Option<(usize, usize, isize)>>,
|
||||||
pub already_moved_window_handles: Arc<Mutex<HashSet<isize>>>,
|
pub already_moved_window_handles: Arc<Mutex<HashSet<isize>>>,
|
||||||
pub uncloack_to_ignore: usize,
|
pub uncloak_to_ignore: usize,
|
||||||
/// Maps each known window hwnd to the (monitor, workspace) index pair managing it
|
/// Maps each known window hwnd to the (monitor, workspace) index pair managing it
|
||||||
pub known_hwnds: HashMap<isize, (usize, usize)>,
|
pub known_hwnds: HashMap<isize, (usize, usize)>,
|
||||||
}
|
}
|
||||||
@@ -447,7 +447,7 @@ impl WindowManager {
|
|||||||
has_pending_raise_op: false,
|
has_pending_raise_op: false,
|
||||||
pending_move_op: Arc::new(None),
|
pending_move_op: Arc::new(None),
|
||||||
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
|
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
|
||||||
uncloack_to_ignore: 0,
|
uncloak_to_ignore: 0,
|
||||||
known_hwnds: HashMap::new(),
|
known_hwnds: HashMap::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1234,7 +1234,7 @@ impl WindowManager {
|
|||||||
// That workspace reconciliation would focus the window on the origin monitor.
|
// That workspace reconciliation would focus the window on the origin monitor.
|
||||||
// So we need to ignore the uncloak events produced by the origin workspace
|
// So we need to ignore the uncloak events produced by the origin workspace
|
||||||
// restore to avoid that issue.
|
// restore to avoid that issue.
|
||||||
self.uncloack_to_ignore = uncloack_amount;
|
self.uncloak_to_ignore = uncloack_amount;
|
||||||
}
|
}
|
||||||
} else if origin_workspace
|
} else if origin_workspace
|
||||||
.maximized_window()
|
.maximized_window()
|
||||||
@@ -1314,67 +1314,43 @@ impl WindowManager {
|
|||||||
let (origin_monitor_idx, origin_workspace_idx, origin_container_idx) = origin;
|
let (origin_monitor_idx, origin_workspace_idx, origin_container_idx) = origin;
|
||||||
let (target_monitor_idx, target_workspace_idx, target_container_idx) = target;
|
let (target_monitor_idx, target_workspace_idx, target_container_idx) = target;
|
||||||
|
|
||||||
let origin_container_is_valid = self
|
let origin_container = self
|
||||||
.monitors_mut()
|
.monitors_mut()
|
||||||
.get_mut(origin_monitor_idx)
|
.get_mut(origin_monitor_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
||||||
.workspaces_mut()
|
.workspaces_mut()
|
||||||
.get_mut(origin_workspace_idx)
|
.get_mut(origin_workspace_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
||||||
.containers()
|
.remove_container(origin_container_idx)
|
||||||
.get(origin_container_idx)
|
.ok_or_else(|| anyhow!("there is no container at this index"))?;
|
||||||
.is_some();
|
|
||||||
|
|
||||||
let target_container_is_valid = self
|
let target_container = self
|
||||||
.monitors_mut()
|
.monitors_mut()
|
||||||
.get_mut(target_monitor_idx)
|
.get_mut(target_monitor_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
||||||
.workspaces_mut()
|
.workspaces_mut()
|
||||||
.get_mut(target_workspace_idx)
|
.get_mut(target_workspace_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
||||||
.containers()
|
.remove_container(target_container_idx);
|
||||||
.get(origin_container_idx)
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
if origin_container_is_valid && target_container_is_valid {
|
self.monitors_mut()
|
||||||
let origin_container = self
|
.get_mut(target_monitor_idx)
|
||||||
.monitors_mut()
|
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
||||||
|
.workspaces_mut()
|
||||||
|
.get_mut(target_workspace_idx)
|
||||||
|
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
||||||
|
.containers_mut()
|
||||||
|
.insert(target_container_idx, origin_container);
|
||||||
|
|
||||||
|
if let Some(target_container) = target_container {
|
||||||
|
self.monitors_mut()
|
||||||
.get_mut(origin_monitor_idx)
|
.get_mut(origin_monitor_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
||||||
.workspaces_mut()
|
.workspaces_mut()
|
||||||
.get_mut(origin_workspace_idx)
|
.get_mut(origin_workspace_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
||||||
.remove_container(origin_container_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no container at this index"))?;
|
|
||||||
|
|
||||||
let target_container = self
|
|
||||||
.monitors_mut()
|
|
||||||
.get_mut(target_monitor_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
|
||||||
.workspaces_mut()
|
|
||||||
.get_mut(target_workspace_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
|
||||||
.remove_container(target_container_idx);
|
|
||||||
|
|
||||||
self.monitors_mut()
|
|
||||||
.get_mut(target_monitor_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
|
||||||
.workspaces_mut()
|
|
||||||
.get_mut(target_workspace_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
|
||||||
.containers_mut()
|
.containers_mut()
|
||||||
.insert(target_container_idx, origin_container);
|
.insert(origin_container_idx, target_container);
|
||||||
|
|
||||||
if let Some(target_container) = target_container {
|
|
||||||
self.monitors_mut()
|
|
||||||
.get_mut(origin_monitor_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
|
|
||||||
.workspaces_mut()
|
|
||||||
.get_mut(origin_workspace_idx)
|
|
||||||
.ok_or_else(|| anyhow!("there is no workspace at this index"))?
|
|
||||||
.containers_mut()
|
|
||||||
.insert(origin_container_idx, target_container);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -3155,10 +3131,6 @@ impl WindowManager {
|
|||||||
pub fn toggle_float(&mut self, force_float: bool) -> Result<()> {
|
pub fn toggle_float(&mut self, force_float: bool) -> Result<()> {
|
||||||
let hwnd = WindowsApi::foreground_window()?;
|
let hwnd = WindowsApi::foreground_window()?;
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
if workspace.monocle_container().is_some() {
|
|
||||||
tracing::warn!("ignoring toggle-float command while workspace has a monocle container");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut is_floating_window = false;
|
let mut is_floating_window = false;
|
||||||
|
|
||||||
@@ -4316,44 +4288,6 @@ mod tests {
|
|||||||
assert_eq!(current_monitor_idx, 0);
|
assert_eq!(current_monitor_idx, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_switch_focus_to_nonexistent_monitor() {
|
|
||||||
let (mut wm, _test_context) = setup_window_manager();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Create a first monitor
|
|
||||||
let m = monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// monitor should have a single workspace
|
|
||||||
assert_eq!(m.workspaces().len(), 1);
|
|
||||||
|
|
||||||
// add the monitor to the window manager
|
|
||||||
wm.monitors_mut().push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should have 1 monitor and the monitor index should be 0
|
|
||||||
assert_eq!(wm.monitors().len(), 1);
|
|
||||||
assert_eq!(wm.focused_monitor_idx(), 0);
|
|
||||||
|
|
||||||
// Should receive an error when trying to focus a non-existent monitor
|
|
||||||
let result = wm.focus_monitor(1);
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when focusing a non-existent monitor"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should still be focused on the first monitor
|
|
||||||
assert_eq!(wm.focused_monitor_idx(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_focused_monitor_size() {
|
fn test_focused_monitor_size() {
|
||||||
let (mut wm, _test_context) = setup_window_manager();
|
let (mut wm, _test_context) = setup_window_manager();
|
||||||
@@ -4537,64 +4471,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_transfer_window_to_nonexistent_monitor() {
|
|
||||||
// NOTE: transfer_window is primarily used when a window is being dragged by a mouse. The
|
|
||||||
// transfer_window function does return an error when the target monitor doesn't exist but
|
|
||||||
// there is a bug where the window isn't in the container after the window fails to
|
|
||||||
// transfer. The test will test for the result of the transfer_window function but not if
|
|
||||||
// the window is in the container after the transfer fails.
|
|
||||||
|
|
||||||
let (mut wm, _context) = setup_window_manager();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Create a first monitor
|
|
||||||
let mut m = monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create a container
|
|
||||||
let workspace = m.focused_workspace_mut().unwrap();
|
|
||||||
let mut container = Container::default();
|
|
||||||
|
|
||||||
// Add a window to the container
|
|
||||||
container.windows_mut().push_back(Window::from(0));
|
|
||||||
workspace.add_container_to_back(container);
|
|
||||||
|
|
||||||
// Should contain 1 container
|
|
||||||
assert_eq!(workspace.containers().len(), 1);
|
|
||||||
|
|
||||||
wm.monitors_mut().push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Monitor 0, Workspace 0, Window 0
|
|
||||||
let origin = (0, 0, 0);
|
|
||||||
|
|
||||||
// Monitor 1, Workspace 0, Window 0
|
|
||||||
//
|
|
||||||
let target = (1, 0, 0);
|
|
||||||
|
|
||||||
// Attempt to transfer the window from monitor 0 to a non-existent monitor
|
|
||||||
let result = wm.transfer_window(origin, target);
|
|
||||||
|
|
||||||
// Result should be an error since the monitor doesn't exist
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when transferring to a non-existent monitor"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(wm.focused_container_idx().unwrap(), 0);
|
|
||||||
assert_eq!(wm.focused_workspace_idx().unwrap(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transfer_container() {
|
fn test_transfer_container() {
|
||||||
let (mut wm, _context) = setup_window_manager();
|
let (mut wm, _context) = setup_window_manager();
|
||||||
@@ -4986,71 +4862,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_swap_container_with_nonexistent_container() {
|
|
||||||
let (mut wm, _context) = setup_window_manager();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Create a first monitor
|
|
||||||
let mut m = monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create a container
|
|
||||||
let mut container = Container::default();
|
|
||||||
|
|
||||||
// Add three windows to the container
|
|
||||||
for i in 0..3 {
|
|
||||||
container.windows_mut().push_back(Window::from(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should have 3 windows in the container
|
|
||||||
assert_eq!(container.windows().len(), 3);
|
|
||||||
|
|
||||||
// Add the container to the workspace
|
|
||||||
let workspace = m.focused_workspace_mut().unwrap();
|
|
||||||
workspace.add_container_to_back(container);
|
|
||||||
|
|
||||||
// Add monitor to the window manager
|
|
||||||
wm.monitors_mut().push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor 0, Workspace 0, Window 0
|
|
||||||
let origin = (0, 0, 0);
|
|
||||||
|
|
||||||
// Monitor 1, Workspace 0, Window 0
|
|
||||||
let target = (0, 3, 0);
|
|
||||||
|
|
||||||
// Should be focused on the first container
|
|
||||||
assert_eq!(wm.focused_container_idx().unwrap(), 0);
|
|
||||||
|
|
||||||
// Should return an error since there is only one container in the workspace
|
|
||||||
let result = wm.swap_containers(origin, target);
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when swapping with a non-existent container"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should still be focused on the first container
|
|
||||||
assert_eq!(wm.focused_container_idx().unwrap(), 0);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Should still have 1 container in the workspace
|
|
||||||
let workspace = wm.focused_workspace_mut().unwrap();
|
|
||||||
assert_eq!(workspace.containers().len(), 1);
|
|
||||||
|
|
||||||
// Container should still have 3 windows
|
|
||||||
let container = workspace.focused_container_mut().unwrap();
|
|
||||||
assert_eq!(container.windows().len(), 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_swap_monitor_workspaces() {
|
fn test_swap_monitor_workspaces() {
|
||||||
let (mut wm, _context) = setup_window_manager();
|
let (mut wm, _context) = setup_window_manager();
|
||||||
@@ -5135,52 +4946,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_swap_workspace_with_nonexistent_monitor() {
|
|
||||||
let (mut wm, _context) = setup_window_manager();
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut m = monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add another workspace
|
|
||||||
let new_workspace_index = m.new_workspace_idx();
|
|
||||||
m.focus_workspace(new_workspace_index).unwrap();
|
|
||||||
|
|
||||||
// Should have 2 workspaces
|
|
||||||
assert_eq!(m.workspaces().len(), 2);
|
|
||||||
|
|
||||||
// Add monitor to window manager
|
|
||||||
wm.monitors_mut().push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be an error since Monitor 1 does not exist
|
|
||||||
let result = wm.swap_monitor_workspaces(1, 0);
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when swapping with a non-existent monitor"
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Should still have 2 workspaces in Monitor 0
|
|
||||||
let monitor = wm.monitors().front().unwrap();
|
|
||||||
let workspaces = monitor.workspaces();
|
|
||||||
assert_eq!(
|
|
||||||
workspaces.len(),
|
|
||||||
2,
|
|
||||||
"Expected 2 workspaces after swap attempt"
|
|
||||||
);
|
|
||||||
assert_eq!(wm.focused_monitor_idx(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_move_workspace_to_monitor() {
|
fn test_move_workspace_to_monitor() {
|
||||||
let (mut wm, _context) = setup_window_manager();
|
let (mut wm, _context) = setup_window_manager();
|
||||||
@@ -5203,7 +4968,7 @@ mod tests {
|
|||||||
// Should have 2 workspaces
|
// Should have 2 workspaces
|
||||||
assert_eq!(m.workspaces().len(), 2);
|
assert_eq!(m.workspaces().len(), 2);
|
||||||
|
|
||||||
// Add monitor to window manager
|
// Add monitor to workspace
|
||||||
wm.monitors_mut().push_back(m);
|
wm.monitors_mut().push_back(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5250,42 +5015,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_move_workspace_to_nonexistent_monitor() {
|
|
||||||
let (mut wm, _context) = setup_window_manager();
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut m = monitor::new(
|
|
||||||
0,
|
|
||||||
Rect::default(),
|
|
||||||
Rect::default(),
|
|
||||||
"TestMonitor".to_string(),
|
|
||||||
"TestDevice".to_string(),
|
|
||||||
"TestDeviceID".to_string(),
|
|
||||||
Some("TestMonitorID".to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add another workspace
|
|
||||||
let new_workspace_index = m.new_workspace_idx();
|
|
||||||
m.focus_workspace(new_workspace_index).unwrap();
|
|
||||||
|
|
||||||
// Should have 2 workspaces
|
|
||||||
assert_eq!(m.workspaces().len(), 2);
|
|
||||||
|
|
||||||
// Add monitor to window manager
|
|
||||||
wm.monitors_mut().push_back(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to move a workspace to a non-existent monitor
|
|
||||||
let result = wm.move_workspace_to_monitor(1);
|
|
||||||
|
|
||||||
// Should be an error since Monitor 1 does not exist
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when moving to a non-existent monitor"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_toggle_tiling() {
|
fn test_toggle_tiling() {
|
||||||
let (mut wm, _context) = setup_window_manager();
|
let (mut wm, _context) = setup_window_manager();
|
||||||
|
|||||||
@@ -1939,33 +1939,6 @@ mod tests {
|
|||||||
assert_eq!(container.windows().len(), 3);
|
assert_eq!(container.windows().len(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_remove_non_existent_window() {
|
|
||||||
let mut workspace = Workspace::default();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Add a container with one window
|
|
||||||
let mut container = Container::default();
|
|
||||||
container.windows_mut().push_back(Window::from(1));
|
|
||||||
workspace.add_container_to_back(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to remove a non-existent window
|
|
||||||
let result = workspace.remove_window(2);
|
|
||||||
|
|
||||||
// Should return an error
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when removing a non-existent window"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get focused container. Should be the index of the last container added
|
|
||||||
let container = workspace.focused_container_mut().unwrap();
|
|
||||||
|
|
||||||
// Should still have 1 window
|
|
||||||
assert_eq!(container.windows().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove_focused_container() {
|
fn test_remove_focused_container() {
|
||||||
let mut workspace = Workspace::default();
|
let mut workspace = Workspace::default();
|
||||||
@@ -2291,25 +2264,6 @@ mod tests {
|
|||||||
assert_eq!(container.windows().len(), 1);
|
assert_eq!(container.windows().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_move_window_to_non_existent_container() {
|
|
||||||
let mut workspace = Workspace::default();
|
|
||||||
|
|
||||||
// Add a container with one window
|
|
||||||
let mut container = Container::default();
|
|
||||||
container.windows_mut().push_back(Window::from(1));
|
|
||||||
workspace.add_container_to_back(container);
|
|
||||||
|
|
||||||
// Try to move window to a non-existent container
|
|
||||||
let result = workspace.move_window_to_container(8);
|
|
||||||
|
|
||||||
// Should return an error
|
|
||||||
assert!(
|
|
||||||
result.is_err(),
|
|
||||||
"Expected an error when moving a window to a non-existent container"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove_window() {
|
fn test_remove_window() {
|
||||||
let mut workspace = Workspace::default();
|
let mut workspace = Workspace::default();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
komorebi-client = { path = "../komorebi-client", default-features = false }
|
komorebi-client = { path = "../komorebi-client" }
|
||||||
|
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
@@ -36,7 +36,7 @@ shadow-rs = { workspace = true }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["schemars"]
|
default = ["schemars"]
|
||||||
schemars = ["dep:schemars", "komorebi-client/default"]
|
schemars = ["dep:schemars", "komorebi-client/schemars"]
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(FALSE)'] }
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(FALSE)'] }
|
||||||
@@ -80,6 +80,7 @@ nav:
|
|||||||
- common-workflows/tray-and-multi-window-applications.md
|
- common-workflows/tray-and-multi-window-applications.md
|
||||||
- common-workflows/mouse-follows-focus.md
|
- common-workflows/mouse-follows-focus.md
|
||||||
- common-workflows/dynamic-layout-switching.md
|
- common-workflows/dynamic-layout-switching.md
|
||||||
|
- common-workflows/set-display-index.md
|
||||||
- common-workflows/multiple-bar-instances.md
|
- common-workflows/multiple-bar-instances.md
|
||||||
- common-workflows/multi-monitor-setup.md
|
- common-workflows/multi-monitor-setup.md
|
||||||
- CLI reference:
|
- CLI reference:
|
||||||
@@ -95,7 +96,6 @@ nav:
|
|||||||
- cli/state.md
|
- cli/state.md
|
||||||
- cli/global-state.md
|
- cli/global-state.md
|
||||||
- cli/gui.md
|
- cli/gui.md
|
||||||
- cli/toggle-shortcuts.md
|
|
||||||
- cli/visible-windows.md
|
- cli/visible-windows.md
|
||||||
- cli/monitor-information.md
|
- cli/monitor-information.md
|
||||||
- cli/query.md
|
- cli/query.md
|
||||||
@@ -253,4 +253,4 @@ nav:
|
|||||||
- cli/static-config-schema.md
|
- cli/static-config-schema.md
|
||||||
- cli/generate-static-config.md
|
- cli/generate-static-config.md
|
||||||
- cli/enable-autostart.md
|
- cli/enable-autostart.md
|
||||||
- cli/disable-autostart.md
|
- cli/disable-autostart.md
|
||||||
|
|||||||
54655
schema.bar.json
54655
schema.bar.json
File diff suppressed because it is too large
Load Diff
@@ -2498,7 +2498,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mode": {
|
"mode": {
|
||||||
"description": "Stackbar mode (default: Never)",
|
"description": "Stackbar mode",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"Always",
|
"Always",
|
||||||
@@ -4627,7 +4627,7 @@
|
|||||||
"description": "Which Windows signal to use when hiding windows (default: Cloak)",
|
"description": "Which Windows signal to use when hiding windows (default: Cloak)",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"description": "END OF LIFE FEATURE: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)",
|
"description": "Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"Hide"
|
"Hide"
|
||||||
|
|||||||
Reference in New Issue
Block a user