mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-02-27 15:37:38 +01:00
Compare commits
2 Commits
v0.1.27
...
monitor-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ceed09c20 | ||
|
|
1712042dda |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@
|
||||
/target
|
||||
CHANGELOG.md
|
||||
dummy.go
|
||||
komorebic/applications.yaml
|
||||
komorebi.ahk
|
||||
komorebic/applications.yaml
|
||||
396
Cargo.lock
generated
396
Cargo.lock
generated
@@ -226,9 +226,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.0"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -302,16 +302,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
"event-listener-strategy 0.5.2",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.12.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0"
|
||||
checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
@@ -354,17 +354,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.3.3"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964"
|
||||
checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884"
|
||||
dependencies = [
|
||||
"async-lock 3.4.0",
|
||||
"async-lock 3.3.0",
|
||||
"cfg-if 1.0.0",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite 2.3.0",
|
||||
"parking",
|
||||
"polling 3.7.2",
|
||||
"polling 3.7.0",
|
||||
"rustix 0.38.34",
|
||||
"slab",
|
||||
"tracing",
|
||||
@@ -382,12 +382,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
||||
checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
|
||||
dependencies = [
|
||||
"event-listener 5.3.1",
|
||||
"event-listener-strategy",
|
||||
"event-listener 4.0.3",
|
||||
"event-listener-strategy 0.4.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -427,12 +427,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.8"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d"
|
||||
checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda"
|
||||
dependencies = [
|
||||
"async-io 2.3.3",
|
||||
"async-lock 3.4.0",
|
||||
"async-io 2.3.2",
|
||||
"async-lock 3.3.0",
|
||||
"atomic-waker",
|
||||
"cfg-if 1.0.0",
|
||||
"futures-core",
|
||||
@@ -644,11 +644,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
||||
checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"futures-io",
|
||||
"futures-lite 2.3.0",
|
||||
@@ -684,18 +685,18 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.16.1"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
|
||||
checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.7.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b"
|
||||
checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -722,7 +723,7 @@ checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"log",
|
||||
"polling 3.7.2",
|
||||
"polling 3.7.0",
|
||||
"rustix 0.38.34",
|
||||
"slab",
|
||||
"thiserror",
|
||||
@@ -742,9 +743,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -800,9 +801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.7"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -810,9 +811,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.7"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -823,11 +824,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.5"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
@@ -835,9 +836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
@@ -1115,6 +1116,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-ahk"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -1358,9 +1368,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.10"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d"
|
||||
checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
@@ -1368,9 +1378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.10"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
|
||||
checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1446,22 +1456,43 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.3.1"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
|
||||
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
||||
dependencies = [
|
||||
"event-listener 4.0.3",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
||||
dependencies = [
|
||||
"event-listener 5.3.1",
|
||||
"event-listener 5.3.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -1922,6 +1953,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -1934,12 +1971,6 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
@@ -2006,12 +2037,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
@@ -2019,9 +2050,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.4"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
@@ -2043,23 +2074,6 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
@@ -2078,9 +2092,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.5"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56"
|
||||
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -2204,7 +2218,7 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.9",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -2301,7 +2315,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
|
||||
[[package]]
|
||||
name = "komorebi"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"clap",
|
||||
@@ -2343,7 +2357,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi-client"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
dependencies = [
|
||||
"komorebi",
|
||||
"komorebi-core",
|
||||
@@ -2353,7 +2367,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi-core"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
@@ -2369,7 +2383,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi-gui"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui_extras",
|
||||
@@ -2381,14 +2395,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebic"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"derive-ahk",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"fs-tail",
|
||||
"heck 0.5.0",
|
||||
"komorebi-client",
|
||||
"komorebi-core",
|
||||
"lazy_static",
|
||||
@@ -2403,13 +2419,12 @@ dependencies = [
|
||||
"thiserror",
|
||||
"uds_windows",
|
||||
"which",
|
||||
"win32-display-data",
|
||||
"windows 0.54.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
@@ -2538,9 +2553,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
@@ -2633,9 +2648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"simd-adler32",
|
||||
@@ -2693,10 +2708,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
@@ -2846,6 +2862,16 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.2"
|
||||
@@ -3157,9 +3183,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
@@ -3175,7 +3201,7 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"petgraph",
|
||||
"redox_syscall 0.5.2",
|
||||
"redox_syscall 0.5.1",
|
||||
"smallvec",
|
||||
"thread-id",
|
||||
"windows-targets 0.52.5",
|
||||
@@ -3237,9 +3263,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.3"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391"
|
||||
checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand 2.1.0",
|
||||
@@ -3283,13 +3309,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.7.2"
|
||||
version = "3.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b"
|
||||
checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"concurrent-queue",
|
||||
"hermit-abi 0.4.0",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 0.38.34",
|
||||
"tracing",
|
||||
@@ -3365,9 +3391,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -3492,9 +3518,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
]
|
||||
@@ -3512,14 +3538,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.5"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.7",
|
||||
"regex-syntax 0.8.4",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3533,13 +3559,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.4",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3550,9 +3576,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "renderdoc-sys"
|
||||
@@ -3562,9 +3588,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.5"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
|
||||
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -3577,7 +3603,6 @@ dependencies = [
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
@@ -3604,21 +3629,6 @@ dependencies = [
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
@@ -3658,19 +3668,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.2"
|
||||
@@ -3687,17 +3684,6 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
@@ -3802,18 +3788,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3844,9 +3830,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json_lenient"
|
||||
version = "0.2.1"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5d0bae483150302560d7cb52e7932f39b69a6fbdd099e48d33ef060a8c9c078"
|
||||
checksum = "dc61c66b53a4035fcce237ef38043f4b2f0ebf918fd0e69541a5166104065581"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -4019,12 +4005,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spirv"
|
||||
version = "0.3.0+sdk-1.3.268.0"
|
||||
@@ -4063,23 +4043,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "supports-color"
|
||||
version = "3.0.0"
|
||||
@@ -4125,9 +4099,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
@@ -4320,14 +4294,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.7",
|
||||
"windows-sys 0.48.0",
|
||||
@@ -4343,17 +4318,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.11"
|
||||
@@ -4408,6 +4372,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4428,6 +4393,7 @@ version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
@@ -4587,9 +4553,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -4603,17 +4569,11 @@ version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@@ -4622,9 +4582,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
@@ -4743,9 +4703,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.4"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07"
|
||||
checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
@@ -4757,9 +4717,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.31.3"
|
||||
version = "0.31.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133"
|
||||
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"rustix 0.38.34",
|
||||
@@ -4780,9 +4740,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.31.3"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9"
|
||||
checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba"
|
||||
dependencies = [
|
||||
"rustix 0.38.34",
|
||||
"wayland-client",
|
||||
@@ -4829,9 +4789,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.31.2"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565"
|
||||
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml",
|
||||
@@ -4840,9 +4800,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.31.2"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12"
|
||||
checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"log",
|
||||
@@ -5010,7 +4970,7 @@ checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
[[package]]
|
||||
name = "win32-display-data"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LGUG2Z/win32-display-data?rev=2a0f7166da154880a1750b91829b1186d9c6a00c#2a0f7166da154880a1750b91829b1186d9c6a00c"
|
||||
source = "git+https://github.com/LGUG2Z/win32-display-data#2c47b9f1ca1f359ba2481d0b6ea8667ccd9d075c"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"thiserror",
|
||||
@@ -5146,9 +5106,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
@@ -5481,12 +5441,12 @@ checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
|
||||
|
||||
[[package]]
|
||||
name = "xdg-home"
|
||||
version = "1.2.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8"
|
||||
checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5504,9 +5464,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xkeysym"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||
checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
@@ -5600,12 +5560,6 @@ dependencies = [
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "3.15.2"
|
||||
|
||||
18
Cargo.toml
18
Cargo.toml
@@ -2,6 +2,7 @@
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"derive-ahk",
|
||||
"komorebi",
|
||||
"komorebi-client",
|
||||
"komorebi-core",
|
||||
@@ -11,16 +12,15 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
color-eyre = "0.6"
|
||||
dirs = "5"
|
||||
dunce = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { package = "serde_json_lenient", version = "0.2" }
|
||||
sysinfo = "0.30"
|
||||
uds_windows = "1"
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "2a0f7166da154880a1750b91829b1186d9c6a00c" }
|
||||
windows-implement = { version = "0.53" }
|
||||
windows-interface = { version = "0.53" }
|
||||
windows-implement = { version = "0.53" }
|
||||
dunce = "1"
|
||||
dirs = "5"
|
||||
color-eyre = "0.6"
|
||||
serde_json = { package = "serde_json_lenient", version = "0.1" }
|
||||
sysinfo = "0.30"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
uds_windows = "1"
|
||||
|
||||
[workspace.dependencies.windows]
|
||||
version = "0.54"
|
||||
|
||||
14
derive-ahk/Cargo.toml
Normal file
14
derive-ahk/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "derive-ahk"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
syn = "1.0"
|
||||
quote = "1.0"
|
||||
225
derive-ahk/src/lib.rs
Normal file
225
derive-ahk/src/lib.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
#![no_implicit_prelude]
|
||||
|
||||
use ::std::clone::Clone;
|
||||
use ::std::convert::From;
|
||||
use ::std::convert::Into;
|
||||
use ::std::format;
|
||||
use ::std::iter::Extend;
|
||||
use ::std::iter::Iterator;
|
||||
use ::std::matches;
|
||||
use ::std::option::Option::Some;
|
||||
use ::std::string::String;
|
||||
use ::std::string::ToString;
|
||||
use ::std::unreachable;
|
||||
use ::std::vec::Vec;
|
||||
|
||||
use ::quote::quote;
|
||||
use ::syn::parse_macro_input;
|
||||
use ::syn::Data;
|
||||
use ::syn::DataEnum;
|
||||
use ::syn::DeriveInput;
|
||||
use ::syn::Fields;
|
||||
use ::syn::FieldsNamed;
|
||||
use ::syn::FieldsUnnamed;
|
||||
use ::syn::Meta;
|
||||
use ::syn::NestedMeta;
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[proc_macro_derive(AhkFunction)]
|
||||
pub fn ahk_function(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
|
||||
match input.data {
|
||||
Data::Struct(s) => match s.fields {
|
||||
Fields::Named(FieldsNamed { named, .. }) => {
|
||||
let argument_idents = named
|
||||
.iter()
|
||||
// Filter out the flags
|
||||
.filter(|&f| {
|
||||
let mut include = true;
|
||||
for attribute in &f.attrs {
|
||||
if let ::std::result::Result::Ok(Meta::List(list)) =
|
||||
attribute.parse_meta()
|
||||
{
|
||||
for nested in list.nested {
|
||||
if let NestedMeta::Meta(Meta::Path(path)) = nested {
|
||||
if path.is_ident("long") {
|
||||
include = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include
|
||||
})
|
||||
.map(|f| &f.ident);
|
||||
|
||||
let argument_idents_clone = argument_idents.clone();
|
||||
|
||||
let called_arguments = quote! {#(%#argument_idents_clone%) *}
|
||||
.to_string()
|
||||
.replace(" %", "%")
|
||||
.replace("% ", "%")
|
||||
.replace("%%", "% %");
|
||||
|
||||
let flag_idents = named
|
||||
.iter()
|
||||
// Filter only the flags
|
||||
.filter(|f| {
|
||||
let mut include = false;
|
||||
|
||||
for attribute in &f.attrs {
|
||||
if let ::std::result::Result::Ok(Meta::List(list)) =
|
||||
attribute.parse_meta()
|
||||
{
|
||||
for nested in list.nested {
|
||||
if let NestedMeta::Meta(Meta::Path(path)) = nested {
|
||||
// Identify them using the --long flag name
|
||||
if path.is_ident("long") {
|
||||
include = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include
|
||||
})
|
||||
.map(|f| &f.ident);
|
||||
|
||||
let has_flags = flag_idents.clone().count() != 0;
|
||||
|
||||
if has_flags {
|
||||
let flag_idents_concat = flag_idents.clone();
|
||||
let argument_idents_concat = argument_idents.clone();
|
||||
|
||||
// Concat the args and flag args if there are flags
|
||||
let all_arguments =
|
||||
quote! {#(#argument_idents_concat,) * #(#flag_idents_concat), *}
|
||||
.to_string();
|
||||
|
||||
let flag_idents_clone = flag_idents.clone();
|
||||
let flags = quote! {#(--#flag_idents_clone) *}
|
||||
.to_string()
|
||||
.replace("- - ", "--")
|
||||
.replace('_', "-");
|
||||
|
||||
let called_flag_arguments = quote! {#(%#flag_idents%) *}
|
||||
.to_string()
|
||||
.replace(" %", "%")
|
||||
.replace("% ", "%")
|
||||
.replace("%%", "% %");
|
||||
|
||||
let flags_split: Vec<_> = flags.split(' ').collect();
|
||||
let flag_args_split: Vec<_> = called_flag_arguments.split(' ').collect();
|
||||
let mut consolidated_flags: Vec<String> = Vec::new();
|
||||
|
||||
for (idx, flag) in flags_split.iter().enumerate() {
|
||||
consolidated_flags.push(format!("{} {}", flag, flag_args_split[idx]));
|
||||
}
|
||||
|
||||
let all_flags = consolidated_flags.join(" ");
|
||||
|
||||
quote! {
|
||||
impl AhkFunction for #name {
|
||||
fn generate_ahk_function() -> String {
|
||||
::std::format!(r#"
|
||||
{}({}) {{
|
||||
RunWait, komorebic.exe {} {} {}, , Hide
|
||||
}}"#,
|
||||
::std::stringify!(#name),
|
||||
#all_arguments,
|
||||
::std::stringify!(#name).to_kebab_case(),
|
||||
#called_arguments,
|
||||
#all_flags,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let arguments = quote! {#(#argument_idents), *}.to_string();
|
||||
|
||||
quote! {
|
||||
impl AhkFunction for #name {
|
||||
fn generate_ahk_function() -> String {
|
||||
::std::format!(r#"
|
||||
{}({}) {{
|
||||
RunWait, komorebic.exe {} {}, , Hide
|
||||
}}"#,
|
||||
::std::stringify!(#name),
|
||||
#arguments,
|
||||
::std::stringify!(#name).to_kebab_case(),
|
||||
#called_arguments
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!("only to be used on structs with named fields"),
|
||||
},
|
||||
_ => unreachable!("only to be used on structs"),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AhkLibrary)]
|
||||
pub fn ahk_library(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
|
||||
match input.data {
|
||||
Data::Enum(DataEnum { variants, .. }) => {
|
||||
let enums = variants.iter().filter(|&v| {
|
||||
matches!(v.fields, Fields::Unit) || matches!(v.fields, Fields::Unnamed(..))
|
||||
});
|
||||
|
||||
let mut stream = ::proc_macro2::TokenStream::new();
|
||||
|
||||
for variant in enums.clone() {
|
||||
match &variant.fields {
|
||||
Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
|
||||
for field in unnamed {
|
||||
stream.extend(quote! {
|
||||
v.push(#field::generate_ahk_function());
|
||||
});
|
||||
}
|
||||
}
|
||||
Fields::Unit => {
|
||||
let name = &variant.ident;
|
||||
stream.extend(quote! {
|
||||
v.push(::std::format!(r#"
|
||||
{}() {{
|
||||
RunWait, komorebic.exe {}, , Hide
|
||||
}}"#,
|
||||
::std::stringify!(#name),
|
||||
::std::stringify!(#name).to_kebab_case()
|
||||
));
|
||||
});
|
||||
}
|
||||
Fields::Named(_) => {
|
||||
unreachable!("only to be used with unnamed and unit fields");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
impl #name {
|
||||
fn generate_ahk_library() -> String {
|
||||
let mut v: Vec<String> = vec![String::from("; Generated by komorebic.exe")];
|
||||
|
||||
#stream
|
||||
|
||||
v.join("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!("only to be used on enums"),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
```
|
||||
Generate a library of AutoHotKey helper functions
|
||||
|
||||
Usage: komorebic.exe komorebic.exe ahk-library
|
||||
Usage: komorebic.exe ahk-library
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# monitor-information
|
||||
|
||||
```
|
||||
Show information about connected monitors
|
||||
|
||||
Usage: komorebic.exe monitor-information
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
# stack-all
|
||||
|
||||
```
|
||||
Stack all windows on the focused workspace
|
||||
|
||||
Usage: komorebic.exe stack-all
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
# transparency-alpha
|
||||
|
||||
```
|
||||
Set the alpha value for unfocused window transparency
|
||||
|
||||
Usage: komorebic.exe transparency-alpha <ALPHA>
|
||||
|
||||
Arguments:
|
||||
<ALPHA>
|
||||
Alpha
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
# transparency
|
||||
|
||||
```
|
||||
Enable or disable transparency for unfocused windows
|
||||
|
||||
Usage: komorebic.exe transparency <BOOLEAN_STATE>
|
||||
|
||||
Arguments:
|
||||
<BOOLEAN_STATE>
|
||||
[possible values: enable, disable]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,12 +0,0 @@
|
||||
# unstack-all
|
||||
|
||||
```
|
||||
Unstack all windows in the focused container
|
||||
|
||||
Usage: komorebic.exe unstack-all
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -1,4 +1,4 @@
|
||||
# AutoHotkey
|
||||
# AutoHotKey
|
||||
|
||||
If you would like to use Autohotkey, please make sure you have AutoHotKey v2
|
||||
installed.
|
||||
@@ -10,8 +10,8 @@ able to craft their own configuration files.
|
||||
If you would like to try out AHK, here is a simple sample configuration which
|
||||
largely matches the `whkdrc` sample configuration.
|
||||
|
||||
```autohotkey
|
||||
{% include "./komorebi.ahk.txt" %}
|
||||
```
|
||||
{% include "../komorebi.ahk" %}
|
||||
```
|
||||
|
||||
By default, the `komorebi.ahk` file should be located in the `$Env:USERPROFILE`
|
||||
@@ -19,4 +19,4 @@ directory, however, if `$Env:KOMOREBI_CONFIG_HOME` is set, it should be located
|
||||
there.
|
||||
|
||||
Once the file is in place, you can stop komorebi and whkd by running `komorebic stop --whkd`,
|
||||
and then start komorebi with Autohotkey by running `komorebic start --ahk`.
|
||||
and then start komorebi with Autohotkey by running `komorebic start --ahk`.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Dynamic Layout Switching
|
||||
# Dynamically Layout Switching
|
||||
|
||||
With `komorebi` it is possible to define rules to automatically change the
|
||||
layout on a specified workspace when a threshold of window containers is met.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# 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>"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,11 +1,11 @@
|
||||
# Getting started
|
||||
|
||||
`komorebi` is a tiling window manager for Windows that is comprised of two
|
||||
main binaries, `komorebi.exe`, which contains the window manager itself,
|
||||
`komorebi` is a tiling window manager for Windows that is comprised comprised
|
||||
of two main binaries, `komorebi.exe`, which contains the window manager itself,
|
||||
and `komorebic.exe`, which is the main way to send commands to the tiling
|
||||
window manager.
|
||||
|
||||
It is important to note that neither `komorebi.exe` nor `komorebic.exe` handle
|
||||
It is important to note that neither `komorebi.exe` or `komorebic.exe` handle
|
||||
key bindings, because `komorebi` is a tiling window manager and not a hotkey
|
||||
daemon.
|
||||
|
||||
@@ -27,7 +27,7 @@ to manipulate the window manager, you use
|
||||
|
||||
`komorebi` is available pre-built to install via
|
||||
[Scoop](https://scoop.sh/#/apps?q=komorebi) and
|
||||
[WinGet](https://winget.run/pkg/LGUG2Z/komorebi), and you may also build
|
||||
[WinGet](https://winget.run/pkg/LGUG2Z/komorebi), and you may also built
|
||||
it from [source](https://github.com/LGUG2Z/komorebi) if you would prefer.
|
||||
|
||||
- [Scoop](#scoop)
|
||||
@@ -37,7 +37,7 @@ it from [source](https://github.com/LGUG2Z/komorebi) if you would prefer.
|
||||
|
||||
## Long path support
|
||||
|
||||
It is highly recommended that you enable support for long paths in Windows by
|
||||
It highly recommended that you enable support for long paths in Windows by
|
||||
running the following command in an Administrator Terminal before installing
|
||||
`komorebi`.
|
||||
|
||||
@@ -45,7 +45,7 @@ running the following command in an Administrator Terminal before installing
|
||||
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
|
||||
```
|
||||
|
||||
## Disabling unnecessary system animations
|
||||
## Disabling Unnecessary System Animations
|
||||
|
||||
It is highly recommended that you enable the "Turn off all unnecessary animations (when possible)" option in
|
||||
"Control Panel > Ease of Access > Ease of Access Centre / Make the computer easier to see" for the best performance with
|
||||
@@ -128,21 +128,3 @@ an offline machine to install.
|
||||
|
||||
Once installed, proceed to get the [example configurations](example-configurations.md) (none of the commands for
|
||||
first-time set up and running komorebi require an internet connection).
|
||||
|
||||
## Uninstallation
|
||||
|
||||
Before uninstalling, first run `komorebic stop --whkd` to make sure that both
|
||||
the `komorebi` and `whkd` processes have been stopped.
|
||||
|
||||
Then, depending on whether you installed with Scoop or WinGet, run `scoop
|
||||
uninstall komorebi whkd` or `winget uninstall LGUG2Z.komorebi LGUG2Z.whkd`.
|
||||
|
||||
Finally, you can run the following commands in a PowerShell prompt to clean up
|
||||
files created by the `quickstart` command and any other runtime files:
|
||||
|
||||
```powershell
|
||||
rm $Env:USERPROFILE\komorebi.json
|
||||
rm $Env:USERPROFILE\applications.yaml
|
||||
rm $Env:USERPROFILE\.config\whkdrc
|
||||
rm -r -Force $Env:LOCALAPPDATA\komorebi
|
||||
```
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#Requires AutoHotkey v2.0.2
|
||||
#SingleInstance Force
|
||||
|
||||
Komorebic(cmd) {
|
||||
RunWait(format("komorebic.exe {}", cmd), , "Hide")
|
||||
}
|
||||
|
||||
!q::Komorebic("close")
|
||||
!m::Komorebic("minimize")
|
||||
|
||||
; Focus windows
|
||||
!h::Komorebic("focus left")
|
||||
!j::Komorebic("focus down")
|
||||
!k::Komorebic("focus up")
|
||||
!l::Komorebic("focus right")
|
||||
|
||||
!+[::Komorebic("cycle-focus previous")
|
||||
!+]::Komorebic("cycle-focus next")
|
||||
|
||||
; Move windows
|
||||
!+h::Komorebic("move left")
|
||||
!+j::Komorebic("move down")
|
||||
!+k::Komorebic("move up")
|
||||
!+l::Komorebic("move right")
|
||||
|
||||
; Stack windows
|
||||
!Left::Komorebic("stack left")
|
||||
!Down::Komorebic("stack down")
|
||||
!Up::Komorebic("stack up")
|
||||
!Right::Komorebic("stack right")
|
||||
!;::Komorebic("unstack")
|
||||
![::Komorebic("cycle-stack previous")
|
||||
!]::Komorebic("cycle-stack next")
|
||||
|
||||
; Resize
|
||||
!=::Komorebic("resize-axis horizontal increase")
|
||||
!-::Komorebic("resize-axis horizontal decrease")
|
||||
!+=::Komorebic("resize-axis vertical increase")
|
||||
!+_::Komorebic("resize-axis vertical decrease")
|
||||
|
||||
; Manipulate windows
|
||||
!t::Komorebic("toggle-float")
|
||||
!f::Komorebic("toggle-monocle")
|
||||
|
||||
; Window manager options
|
||||
!+r::Komorebic("retile")
|
||||
!p::Komorebic("toggle-pause")
|
||||
|
||||
; Layouts
|
||||
!x::Komorebic("flip-layout horizontal")
|
||||
!y::Komorebic("flip-layout vertical")
|
||||
|
||||
; Workspaces
|
||||
!1::Komorebic("focus-workspace 0")
|
||||
!2::Komorebic("focus-workspace 1")
|
||||
!3::Komorebic("focus-workspace 2")
|
||||
!4::Komorebic("focus-workspace 3")
|
||||
!5::Komorebic("focus-workspace 4")
|
||||
!6::Komorebic("focus-workspace 5")
|
||||
!7::Komorebic("focus-workspace 6")
|
||||
!8::Komorebic("focus-workspace 7")
|
||||
|
||||
; Move windows across workspaces
|
||||
!+1::Komorebic("move-to-workspace 0")
|
||||
!+2::Komorebic("move-to-workspace 1")
|
||||
!+3::Komorebic("move-to-workspace 2")
|
||||
!+4::Komorebic("move-to-workspace 3")
|
||||
!+5::Komorebic("move-to-workspace 4")
|
||||
!+6::Komorebic("move-to-workspace 5")
|
||||
!+7::Komorebic("move-to-workspace 6")
|
||||
!+8::Komorebic("move-to-workspace 7")
|
||||
@@ -1,5 +1,3 @@
|
||||
# v0.1.22
|
||||
|
||||
In addition to the [changelog](https://github.com/LGUG2Z/komorebi/releases/tag/v0.1.22) of new features and fixes,
|
||||
please note the following changes from `v0.1.21` to adjust your configuration files accordingly.
|
||||
|
||||
@@ -51,8 +49,8 @@ A 1px border is drawn around the window edge. Users may see a gap for a single p
|
||||
transparent edge - this is the windows themed edge, and is not present for all applications.
|
||||
|
||||
```json
|
||||
{
|
||||
{
|
||||
"border_offset": 0,
|
||||
"border_width": 1
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi-client"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
pub use komorebi::colour::Colour;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi-core"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -604,16 +604,7 @@ impl Arrangement for CustomLayout {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
PartialEq,
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum Axis {
|
||||
Horizontal,
|
||||
|
||||
@@ -14,7 +14,7 @@ use serde::Serialize;
|
||||
|
||||
use crate::Rect;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CustomLayout(Vec<Column>);
|
||||
|
||||
impl Deref for CustomLayout {
|
||||
@@ -250,7 +250,7 @@ impl CustomLayout {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "column", content = "configuration")]
|
||||
pub enum Column {
|
||||
Primary(Option<ColumnWidth>),
|
||||
@@ -258,18 +258,18 @@ pub enum Column {
|
||||
Tertiary(ColumnSplit),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum ColumnWidth {
|
||||
WidthPercentage(f32),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum ColumnSplit {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum ColumnSplitWithCapacity {
|
||||
Horizontal(usize),
|
||||
Vertical(usize),
|
||||
|
||||
@@ -90,13 +90,9 @@ impl Direction for DefaultLayout {
|
||||
idx: usize,
|
||||
count: usize,
|
||||
) -> bool {
|
||||
if count < 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
match op_direction {
|
||||
OperationDirection::Up => match self {
|
||||
Self::BSP => idx != 0 && idx != 1,
|
||||
Self::BSP => count > 2 && idx != 0 && idx != 1,
|
||||
Self::Columns => false,
|
||||
Self::Rows | Self::HorizontalStack => idx != 0,
|
||||
Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != 1,
|
||||
@@ -104,7 +100,7 @@ impl Direction for DefaultLayout {
|
||||
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||
},
|
||||
OperationDirection::Down => match self {
|
||||
Self::BSP => idx != count - 1 && idx % 2 != 0,
|
||||
Self::BSP => count > 2 && idx != count - 1 && idx % 2 != 0,
|
||||
Self::Columns => false,
|
||||
Self::Rows => idx != count - 1,
|
||||
Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != count - 1,
|
||||
@@ -113,22 +109,23 @@ impl Direction for DefaultLayout {
|
||||
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||
},
|
||||
OperationDirection::Left => match self {
|
||||
Self::BSP => idx != 0,
|
||||
Self::BSP => count > 1 && idx != 0,
|
||||
Self::Columns | Self::VerticalStack => idx != 0,
|
||||
Self::RightMainVerticalStack => idx == 0,
|
||||
Self::Rows => false,
|
||||
Self::HorizontalStack => idx != 0 && idx != 1,
|
||||
Self::UltrawideVerticalStack => idx != 1,
|
||||
Self::UltrawideVerticalStack => count > 1 && idx != 1,
|
||||
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||
},
|
||||
OperationDirection::Right => match self {
|
||||
Self::BSP => idx % 2 == 0 && idx != count - 1,
|
||||
Self::BSP => count > 1 && idx % 2 == 0 && idx != count - 1,
|
||||
Self::Columns => idx != count - 1,
|
||||
Self::Rows => false,
|
||||
Self::VerticalStack => idx == 0,
|
||||
Self::RightMainVerticalStack => idx != 0,
|
||||
Self::HorizontalStack => idx != 0 && idx != count - 1,
|
||||
Self::UltrawideVerticalStack => match count {
|
||||
0 | 1 => false,
|
||||
2 => idx != 0,
|
||||
_ => idx < 2,
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::CustomLayout;
|
||||
use crate::DefaultLayout;
|
||||
use crate::Direction;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum Layout {
|
||||
Default(DefaultLayout),
|
||||
Custom(CustomLayout),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::missing_errors_doc, clippy::use_self, clippy::doc_markdown)]
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc, clippy::use_self)]
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
@@ -43,8 +43,6 @@ pub enum SocketMessage {
|
||||
CycleFocusWindow(CycleDirection),
|
||||
CycleMoveWindow(CycleDirection),
|
||||
StackWindow(OperationDirection),
|
||||
StackAll,
|
||||
UnstackAll,
|
||||
ResizeWindowEdge(OperationDirection, Sizing),
|
||||
ResizeWindowAxis(Axis, Sizing),
|
||||
UnstackWindow,
|
||||
@@ -142,8 +140,6 @@ pub enum SocketMessage {
|
||||
BorderStyle(BorderStyle),
|
||||
BorderWidth(i32),
|
||||
BorderOffset(i32),
|
||||
Transparency(bool),
|
||||
TransparencyAlpha(u8),
|
||||
InvisibleBorders(Rect),
|
||||
StackbarMode(StackbarMode),
|
||||
StackbarLabel(StackbarLabel),
|
||||
@@ -168,7 +164,6 @@ pub enum SocketMessage {
|
||||
State,
|
||||
GlobalState,
|
||||
VisibleWindows,
|
||||
MonitorInformation,
|
||||
Query(StateQuery),
|
||||
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
||||
ToggleFocusFollowsMouse(FocusFollowsMouseImplementation),
|
||||
@@ -232,16 +227,7 @@ pub enum BorderStyle {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
PartialEq,
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum WindowKind {
|
||||
Single,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi-gui"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#![warn(clippy::all)]
|
||||
|
||||
use eframe::egui;
|
||||
use eframe::egui::color_picker::Alpha;
|
||||
use eframe::egui::Color32;
|
||||
@@ -715,7 +713,7 @@ impl eframe::App for KomorebiGui {
|
||||
.text_edit_singleline(workspace_name)
|
||||
.lost_focus()
|
||||
{
|
||||
workspace.name.clone_from(workspace_name);
|
||||
workspace.name = workspace_name.clone();
|
||||
komorebi_client::send_message(
|
||||
&SocketMessage::WorkspaceName(
|
||||
monitor_idx,
|
||||
|
||||
56
komorebi.sample.ahk
Normal file
56
komorebi.sample.ahk
Normal file
@@ -0,0 +1,56 @@
|
||||
#SingleInstance Force
|
||||
|
||||
; Load library
|
||||
#Include komorebic.lib.ahk
|
||||
|
||||
; Focus windows
|
||||
!h::Focus("left")
|
||||
!j::Focus("down")
|
||||
!k::Focus("up")
|
||||
!l::Focus("right")
|
||||
!+[::CycleFocus("previous")
|
||||
!+]::CycleFocus("next")
|
||||
|
||||
; Move windows
|
||||
!+h::Move("left")
|
||||
!+j::Move("down")
|
||||
!+k::Move("up")
|
||||
!+l::Move("right")
|
||||
!+Enter::Promote()
|
||||
|
||||
; Stack windows
|
||||
!Left::Stack("left")
|
||||
!Right::Stack("right")
|
||||
!Up::Stack("up")
|
||||
!Down::Stack("down")
|
||||
!;::Unstack()
|
||||
![::CycleStack("previous")
|
||||
!]::CycleStack("next")
|
||||
|
||||
; Resize
|
||||
!=::ResizeAxis("horizontal", "increase")
|
||||
!-::ResizeAxis("horizontal", "decrease")
|
||||
!+=::ResizeAxis("vertical", "increase")
|
||||
!+-::ResizeAxis("vertical", "decrease")
|
||||
|
||||
; Manipulate windows
|
||||
!t::ToggleFloat()
|
||||
!+f::ToggleMonocle()
|
||||
|
||||
; Window manager options
|
||||
!+r::Retile()
|
||||
!p::TogglePause()
|
||||
|
||||
; Layouts
|
||||
!x::FlipLayout("horizontal")
|
||||
!y::FlipLayout("vertical")
|
||||
|
||||
; Workspaces
|
||||
!1::FocusWorkspace(0)
|
||||
!2::FocusWorkspace(1)
|
||||
!3::FocusWorkspace(2)
|
||||
|
||||
; Move windows across workspaces
|
||||
!+1::MoveToWorkspace(0)
|
||||
!+2::MoveToWorkspace(1)
|
||||
!+3::MoveToWorkspace(2)
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "A tiling window manager for Windows"
|
||||
categories = ["tiling-window-manager", "windows"]
|
||||
@@ -18,7 +18,7 @@ clap = { version = "4", features = ["derive"] }
|
||||
color-eyre = { workspace = true }
|
||||
crossbeam-channel = "0.5"
|
||||
crossbeam-utils = "0.8"
|
||||
ctrlc = { version = "3", features = ["termination"] }
|
||||
ctrlc = "3"
|
||||
dirs = { workspace = true }
|
||||
getset = "0.1"
|
||||
hex_color = { version = "3", features = ["serde"] }
|
||||
@@ -28,7 +28,7 @@ miow = "0.6"
|
||||
nanoid = "0.4"
|
||||
net2 = "0.2"
|
||||
os_info = "3.8"
|
||||
parking_lot = "0.12"
|
||||
parking_lot = { version = "0.12", features = ["deadlock_detection"] }
|
||||
paste = "1"
|
||||
regex = "1"
|
||||
schemars = "0.8"
|
||||
@@ -42,12 +42,13 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
uds_windows = "1"
|
||||
which = "6"
|
||||
widestring = "1"
|
||||
win32-display-data = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
windows-implement = { workspace = true }
|
||||
windows-interface = { workspace = true }
|
||||
winput = "0.2"
|
||||
winreg = "0.52"
|
||||
|
||||
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data" }
|
||||
|
||||
[features]
|
||||
deadlock_detection = ["parking_lot/deadlock_detection"]
|
||||
deadlock_detection = []
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::border_manager::FOCUSED;
|
||||
use crate::border_manager::FOCUS_STATE;
|
||||
use crate::border_manager::MONOCLE;
|
||||
use crate::border_manager::RECT_STATE;
|
||||
use crate::border_manager::STACK;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::border_manager::UNFOCUSED;
|
||||
@@ -26,12 +27,12 @@ use windows::Win32::Foundation::LRESULT;
|
||||
use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::Graphics::Gdi::BeginPaint;
|
||||
use windows::Win32::Graphics::Gdi::CreatePen;
|
||||
use windows::Win32::Graphics::Gdi::DeleteObject;
|
||||
use windows::Win32::Graphics::Gdi::EndPaint;
|
||||
use windows::Win32::Graphics::Gdi::InvalidateRect;
|
||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||
use windows::Win32::Graphics::Gdi::RoundRect;
|
||||
use windows::Win32::Graphics::Gdi::SelectObject;
|
||||
use windows::Win32::Graphics::Gdi::ValidateRect;
|
||||
use windows::Win32::Graphics::Gdi::PAINTSTRUCT;
|
||||
use windows::Win32::Graphics::Gdi::PS_INSIDEFRAME;
|
||||
use windows::Win32::Graphics::Gdi::PS_SOLID;
|
||||
@@ -98,19 +99,13 @@ impl Border {
|
||||
let hwnd = WindowsApi::create_border_window(PCWSTR(name.as_ptr()), h_module)?;
|
||||
hwnd_sender.send(hwnd)?;
|
||||
|
||||
let mut msg: MSG = MSG::default();
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
if !GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() {
|
||||
tracing::debug!("border window event processing thread shutdown");
|
||||
break;
|
||||
};
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
let mut message = MSG::default();
|
||||
unsafe {
|
||||
while GetMessageW(&mut message, HWND(hwnd), 0, 0).into() {
|
||||
TranslateMessage(&message);
|
||||
DispatchMessageW(&message);
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(10))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -125,22 +120,25 @@ impl Border {
|
||||
WindowsApi::close_window(self.hwnd())
|
||||
}
|
||||
|
||||
pub fn update(&self, rect: &Rect, mut should_invalidate: bool) -> color_eyre::Result<()> {
|
||||
pub fn update(&self, rect: &Rect) -> color_eyre::Result<()> {
|
||||
// Make adjustments to the border
|
||||
let mut rect = *rect;
|
||||
rect.add_margin(BORDER_WIDTH.load(Ordering::SeqCst));
|
||||
rect.add_padding(-BORDER_OFFSET.load(Ordering::SeqCst));
|
||||
|
||||
// Store the border rect so that it can be used by the callback
|
||||
{
|
||||
let mut rects = RECT_STATE.lock();
|
||||
rects.insert(self.hwnd, rect);
|
||||
}
|
||||
|
||||
// Update the position of the border if required
|
||||
if !WindowsApi::window_rect(self.hwnd())?.eq(&rect) {
|
||||
WindowsApi::set_border_pos(self.hwnd(), &rect, HWND((Z_ORDER.load()).into()))?;
|
||||
should_invalidate = true;
|
||||
WindowsApi::set_border_pos(self.hwnd(), &rect, HWND((*Z_ORDER.lock()).into()))?;
|
||||
}
|
||||
|
||||
// Invalidate the rect to trigger the callback to update colours etc.
|
||||
if should_invalidate {
|
||||
self.invalidate();
|
||||
}
|
||||
self.invalidate();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -158,68 +156,63 @@ impl Border {
|
||||
unsafe {
|
||||
match message {
|
||||
WM_PAINT => {
|
||||
let mut ps = PAINTSTRUCT::default();
|
||||
let hdc = BeginPaint(window, &mut ps);
|
||||
let rects = RECT_STATE.lock();
|
||||
|
||||
// With the rect that we set in Self::update
|
||||
match WindowsApi::window_rect(window) {
|
||||
Ok(rect) => {
|
||||
// Grab the focus kind for this border
|
||||
let focus_kind = {
|
||||
FOCUS_STATE
|
||||
.lock()
|
||||
.get(&window.0)
|
||||
.copied()
|
||||
.unwrap_or(WindowKind::Unfocused)
|
||||
};
|
||||
// With the rect that we stored in Self::update
|
||||
if let Some(rect) = rects.get(&window.0).copied() {
|
||||
// Grab the focus kind for this border
|
||||
let focus_kind = {
|
||||
FOCUS_STATE
|
||||
.lock()
|
||||
.get(&window.0)
|
||||
.copied()
|
||||
.unwrap_or(WindowKind::Unfocused)
|
||||
};
|
||||
|
||||
// Set up the brush to draw the border
|
||||
let hpen = CreatePen(
|
||||
PS_SOLID | PS_INSIDEFRAME,
|
||||
BORDER_WIDTH.load(Ordering::SeqCst),
|
||||
COLORREF(match focus_kind {
|
||||
WindowKind::Unfocused => UNFOCUSED.load(Ordering::SeqCst),
|
||||
WindowKind::Single => FOCUSED.load(Ordering::SeqCst),
|
||||
WindowKind::Stack => STACK.load(Ordering::SeqCst),
|
||||
WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst),
|
||||
}),
|
||||
);
|
||||
// Set up the brush to draw the border
|
||||
let mut ps = PAINTSTRUCT::default();
|
||||
let hdc = BeginPaint(window, &mut ps);
|
||||
let hpen = CreatePen(
|
||||
PS_SOLID | PS_INSIDEFRAME,
|
||||
BORDER_WIDTH.load(Ordering::SeqCst),
|
||||
COLORREF(match focus_kind {
|
||||
WindowKind::Unfocused => UNFOCUSED.load(Ordering::SeqCst),
|
||||
WindowKind::Single => FOCUSED.load(Ordering::SeqCst),
|
||||
WindowKind::Stack => STACK.load(Ordering::SeqCst),
|
||||
WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst),
|
||||
}),
|
||||
);
|
||||
|
||||
let hbrush = WindowsApi::create_solid_brush(0);
|
||||
let hbrush = WindowsApi::create_solid_brush(0);
|
||||
|
||||
// Draw the border
|
||||
SelectObject(hdc, hpen);
|
||||
SelectObject(hdc, hbrush);
|
||||
// TODO(raggi): this is approximately the correct curvature for
|
||||
// the top left of a Windows 11 window (DWMWCP_DEFAULT), but
|
||||
// often the bottom right has a different shape. Furthermore if
|
||||
// the window was made with DWMWCP_ROUNDSMALL then this is the
|
||||
// wrong size. In the future we should read the DWM properties
|
||||
// of windows and attempt to match appropriately.
|
||||
match STYLE.load() {
|
||||
BorderStyle::System => {
|
||||
if *WINDOWS_11 {
|
||||
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
|
||||
} else {
|
||||
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
|
||||
}
|
||||
}
|
||||
BorderStyle::Rounded => {
|
||||
// Draw the border
|
||||
SelectObject(hdc, hpen);
|
||||
SelectObject(hdc, hbrush);
|
||||
// TODO(raggi): this is approximately the correct curvature for
|
||||
// the top left of a Windows 11 window (DWMWCP_DEFAULT), but
|
||||
// often the bottom right has a different shape. Furthermore if
|
||||
// the window was made with DWMWCP_ROUNDSMALL then this is the
|
||||
// wrong size. In the future we should read the DWM properties
|
||||
// of windows and attempt to match appropriately.
|
||||
match *STYLE.lock() {
|
||||
BorderStyle::System => {
|
||||
if *WINDOWS_11 {
|
||||
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
|
||||
}
|
||||
BorderStyle::Square => {
|
||||
} else {
|
||||
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
|
||||
}
|
||||
}
|
||||
DeleteObject(hpen);
|
||||
DeleteObject(hbrush);
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!("could not get border rect: {}", error.to_string())
|
||||
BorderStyle::Rounded => {
|
||||
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
|
||||
}
|
||||
BorderStyle::Square => {
|
||||
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
|
||||
}
|
||||
}
|
||||
EndPaint(window, &ps);
|
||||
ValidateRect(window, None);
|
||||
}
|
||||
|
||||
EndPaint(window, &ps);
|
||||
LRESULT(0)
|
||||
}
|
||||
WM_DESTROY => {
|
||||
|
||||
@@ -4,7 +4,6 @@ mod border;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use komorebi_core::BorderStyle;
|
||||
use lazy_static::lazy_static;
|
||||
@@ -19,11 +18,13 @@ use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
|
||||
use crate::ring::Ring;
|
||||
use crate::workspace_reconciliator::ALT_TAB_HWND;
|
||||
use crate::Colour;
|
||||
use crate::Rect;
|
||||
use crate::Rgb;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
@@ -37,8 +38,8 @@ pub static BORDER_OFFSET: AtomicI32 = AtomicI32::new(-1);
|
||||
pub static BORDER_ENABLED: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
lazy_static! {
|
||||
pub static ref Z_ORDER: AtomicCell<ZOrder> = AtomicCell::new(ZOrder::Bottom);
|
||||
pub static ref STYLE: AtomicCell<BorderStyle> = AtomicCell::new(BorderStyle::System);
|
||||
pub static ref Z_ORDER: Arc<Mutex<ZOrder>> = Arc::new(Mutex::new(ZOrder::Bottom));
|
||||
pub static ref STYLE: Arc<Mutex<BorderStyle>> = Arc::new(Mutex::new(BorderStyle::System));
|
||||
pub static ref FOCUSED: AtomicU32 =
|
||||
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(66, 165, 245))));
|
||||
pub static ref UNFOCUSED: AtomicU32 =
|
||||
@@ -51,6 +52,7 @@ lazy_static! {
|
||||
lazy_static! {
|
||||
static ref BORDERS_MONITORS: Mutex<HashMap<String, usize>> = Mutex::new(HashMap::new());
|
||||
static ref BORDER_STATE: Mutex<HashMap<String, Border>> = Mutex::new(HashMap::new());
|
||||
static ref RECT_STATE: Mutex<HashMap<isize, Rect>> = Mutex::new(HashMap::new());
|
||||
static ref FOCUS_STATE: Mutex<HashMap<isize, WindowKind>> = Mutex::new(HashMap::new());
|
||||
}
|
||||
|
||||
@@ -59,23 +61,17 @@ pub struct Notification;
|
||||
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
|
||||
|
||||
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
|
||||
CHANNEL.get_or_init(crossbeam_channel::unbounded)
|
||||
}
|
||||
|
||||
fn event_tx() -> Sender<Notification> {
|
||||
pub fn event_tx() -> Sender<Notification> {
|
||||
channel().0.clone()
|
||||
}
|
||||
|
||||
fn event_rx() -> Receiver<Notification> {
|
||||
pub fn event_rx() -> Receiver<Notification> {
|
||||
channel().1.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification() {
|
||||
if event_tx().try_send(Notification).is_err() {
|
||||
tracing::warn!("channel is full; dropping notification")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_all_borders() -> color_eyre::Result<()> {
|
||||
let mut borders = BORDER_STATE.lock();
|
||||
tracing::info!(
|
||||
@@ -88,6 +84,7 @@ pub fn destroy_all_borders() -> color_eyre::Result<()> {
|
||||
}
|
||||
|
||||
borders.clear();
|
||||
RECT_STATE.lock().clear();
|
||||
BORDERS_MONITORS.lock().clear();
|
||||
FOCUS_STATE.lock().clear();
|
||||
|
||||
@@ -126,57 +123,28 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
tracing::info!("listening");
|
||||
|
||||
let receiver = event_rx();
|
||||
let mut instant: Option<Instant> = None;
|
||||
event_tx().send(Notification)?;
|
||||
|
||||
let mut previous_snapshot = Ring::default();
|
||||
let mut previous_pending_move_op = None;
|
||||
let mut previous_is_paused = false;
|
||||
|
||||
'receiver: for _ in receiver {
|
||||
// Check the wm state every time we receive a notification
|
||||
let state = wm.lock();
|
||||
let is_paused = state.is_paused;
|
||||
let focused_monitor_idx = state.focused_monitor_idx();
|
||||
let monitors = state.monitors.clone();
|
||||
let pending_move_op = state.pending_move_op;
|
||||
drop(state);
|
||||
|
||||
let mut should_process_notification = true;
|
||||
|
||||
if monitors == previous_snapshot
|
||||
// handle the window dragging edge case
|
||||
&& pending_move_op == previous_pending_move_op
|
||||
{
|
||||
should_process_notification = false;
|
||||
if let Some(instant) = instant {
|
||||
if instant.elapsed().lt(&Duration::from_millis(50)) {
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
|
||||
// handle the pause edge case
|
||||
if is_paused && !previous_is_paused {
|
||||
should_process_notification = true;
|
||||
}
|
||||
|
||||
// handle the unpause edge case
|
||||
if previous_is_paused && !is_paused {
|
||||
should_process_notification = true;
|
||||
}
|
||||
|
||||
// handle the retile edge case
|
||||
if !should_process_notification && BORDER_STATE.lock().is_empty() {
|
||||
should_process_notification = true;
|
||||
}
|
||||
|
||||
if !should_process_notification {
|
||||
tracing::trace!("monitor state matches latest snapshot, skipping notification");
|
||||
continue 'receiver;
|
||||
}
|
||||
instant = Some(Instant::now());
|
||||
|
||||
let mut borders = BORDER_STATE.lock();
|
||||
let mut borders_monitors = BORDERS_MONITORS.lock();
|
||||
|
||||
// Check the wm state every time we receive a notification
|
||||
let state = wm.lock();
|
||||
|
||||
// If borders are disabled
|
||||
if !BORDER_ENABLED.load_consume()
|
||||
// Or if the wm is paused
|
||||
|| is_paused
|
||||
|| state.is_paused
|
||||
// Or if we are handling an alt-tab across workspaces
|
||||
|| ALT_TAB_HWND.load().is_some()
|
||||
{
|
||||
@@ -186,12 +154,12 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
}
|
||||
|
||||
borders.clear();
|
||||
|
||||
previous_is_paused = is_paused;
|
||||
continue 'receiver;
|
||||
}
|
||||
|
||||
'monitors: for (monitor_idx, m) in monitors.elements().iter().enumerate() {
|
||||
let focused_monitor_idx = state.focused_monitor_idx();
|
||||
|
||||
'monitors: for (monitor_idx, m) in state.monitors.elements().iter().enumerate() {
|
||||
// Only operate on the focused workspace of each monitor
|
||||
if let Some(ws) = m.focused_workspace() {
|
||||
// Workspaces with tiling disabled don't have borders
|
||||
@@ -208,7 +176,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
borders.remove(id);
|
||||
}
|
||||
|
||||
continue 'monitors;
|
||||
continue 'receiver;
|
||||
}
|
||||
|
||||
// Handle the monocle container separately
|
||||
@@ -219,7 +187,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
if let Ok(border) = Border::create(monocle.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'monitors;
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -242,7 +210,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
monocle.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
border.update(&rect, true)?;
|
||||
border.update(&rect)?;
|
||||
|
||||
let border_hwnd = border.hwnd;
|
||||
let mut to_remove = vec![];
|
||||
@@ -258,7 +226,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
for id in &to_remove {
|
||||
borders.remove(id);
|
||||
}
|
||||
|
||||
continue 'monitors;
|
||||
}
|
||||
|
||||
@@ -305,9 +272,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
|
||||
for (idx, c) in ws.containers().iter().enumerate() {
|
||||
// Update border when moving or resizing with mouse
|
||||
if pending_move_op.is_some() && idx == ws.focused_container_idx() {
|
||||
let restore_z_order = Z_ORDER.load();
|
||||
Z_ORDER.store(ZOrder::TopMost);
|
||||
if state.pending_move_op.is_some() && idx == ws.focused_container_idx() {
|
||||
let restore_z_order = *Z_ORDER.lock();
|
||||
*Z_ORDER.lock() = ZOrder::TopMost;
|
||||
|
||||
let mut rect = WindowsApi::window_rect(
|
||||
c.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
@@ -320,7 +287,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
if let Ok(border) = Border::create(c.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'monitors;
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -331,13 +298,13 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
|
||||
if rect != new_rect {
|
||||
rect = new_rect;
|
||||
border.update(&rect, true)?;
|
||||
border.update(&rect)?;
|
||||
}
|
||||
}
|
||||
|
||||
Z_ORDER.store(restore_z_order);
|
||||
*Z_ORDER.lock() = restore_z_order;
|
||||
|
||||
continue 'monitors;
|
||||
continue 'receiver;
|
||||
}
|
||||
|
||||
// Get the border entry for this container from the map or create one
|
||||
@@ -347,49 +314,38 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
if let Ok(border) = Border::create(c.id()) {
|
||||
entry.insert(border)
|
||||
} else {
|
||||
continue 'monitors;
|
||||
continue 'receiver;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
borders_monitors.insert(c.id().clone(), monitor_idx);
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
let mut last_focus_state = None;
|
||||
|
||||
let new_focus_state = if idx != ws.focused_container_idx()
|
||||
|| monitor_idx != focused_monitor_idx
|
||||
{
|
||||
WindowKind::Unfocused
|
||||
} else if c.windows().len() > 1 {
|
||||
WindowKind::Stack
|
||||
} else {
|
||||
WindowKind::Single
|
||||
};
|
||||
|
||||
// Update the focused state for all containers on this workspace
|
||||
{
|
||||
let mut focus_state = FOCUS_STATE.lock();
|
||||
last_focus_state = focus_state.insert(border.hwnd, new_focus_state);
|
||||
focus_state.insert(
|
||||
border.hwnd,
|
||||
if idx != ws.focused_container_idx()
|
||||
|| monitor_idx != focused_monitor_idx
|
||||
{
|
||||
WindowKind::Unfocused
|
||||
} else if c.windows().len() > 1 {
|
||||
WindowKind::Stack
|
||||
} else {
|
||||
WindowKind::Single
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let rect = WindowsApi::window_rect(
|
||||
c.focused_window().copied().unwrap_or_default().hwnd(),
|
||||
)?;
|
||||
|
||||
let should_invalidate = match last_focus_state {
|
||||
None => true,
|
||||
Some(last_focus_state) => last_focus_state != new_focus_state,
|
||||
};
|
||||
|
||||
border.update(&rect, should_invalidate)?;
|
||||
border.update(&rect)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previous_snapshot = monitors;
|
||||
previous_pending_move_op = pending_move_op;
|
||||
previous_is_paused = is_paused;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -104,7 +104,11 @@ impl Container {
|
||||
|
||||
pub fn remove_window_by_idx(&mut self, idx: usize) -> Option<Window> {
|
||||
let window = self.windows_mut().remove(idx);
|
||||
self.focus_window(idx.saturating_sub(1));
|
||||
|
||||
if idx != 0 {
|
||||
self.focus_window(idx - 1);
|
||||
};
|
||||
|
||||
window
|
||||
}
|
||||
|
||||
@@ -115,7 +119,7 @@ impl Container {
|
||||
|
||||
pub fn add_window(&mut self, window: Window) {
|
||||
self.windows_mut().push_back(window);
|
||||
self.focus_window(self.windows().len().saturating_sub(1));
|
||||
self.focus_window(self.windows().len() - 1);
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#![warn(clippy::all)]
|
||||
|
||||
pub mod border_manager;
|
||||
pub mod com;
|
||||
#[macro_use]
|
||||
@@ -16,7 +14,6 @@ pub mod set_window_position;
|
||||
pub mod stackbar_manager;
|
||||
pub mod static_config;
|
||||
pub mod styles;
|
||||
pub mod transparency_manager;
|
||||
pub mod window;
|
||||
pub mod window_manager;
|
||||
pub mod window_manager_event;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(
|
||||
clippy::missing_errors_doc,
|
||||
clippy::redundant_pub_crate,
|
||||
clippy::significant_drop_tightening,
|
||||
clippy::significant_drop_in_scrutinee,
|
||||
clippy::doc_markdown
|
||||
clippy::significant_drop_in_scrutinee
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
@@ -34,7 +33,6 @@ use komorebi::process_movement::listen_for_movements;
|
||||
use komorebi::reaper;
|
||||
use komorebi::stackbar_manager;
|
||||
use komorebi::static_config::StaticConfig;
|
||||
use komorebi::transparency_manager;
|
||||
use komorebi::window_manager::WindowManager;
|
||||
use komorebi::windows_api::WindowsApi;
|
||||
use komorebi::winevent_listener;
|
||||
@@ -259,7 +257,6 @@ fn main() -> Result<()> {
|
||||
|
||||
border_manager::listen_for_notifications(wm.clone());
|
||||
stackbar_manager::listen_for_notifications(wm.clone());
|
||||
transparency_manager::listen_for_notifications(wm.clone());
|
||||
workspace_reconciliator::listen_for_notifications(wm.clone());
|
||||
monitor_reconciliator::listen_for_notifications(wm.clone())?;
|
||||
reaper::watch_for_orphans(wm.clone());
|
||||
|
||||
@@ -19,16 +19,7 @@ use crate::ring::Ring;
|
||||
use crate::workspace::Workspace;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Getters,
|
||||
CopyGetters,
|
||||
MutGetters,
|
||||
Setters,
|
||||
JsonSchema,
|
||||
PartialEq,
|
||||
Debug, Clone, Serialize, Deserialize, Getters, CopyGetters, MutGetters, Setters, JsonSchema,
|
||||
)]
|
||||
pub struct Monitor {
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
@@ -127,7 +118,7 @@ impl Monitor {
|
||||
if idx == 0 {
|
||||
self.workspaces_mut().push_back(Workspace::default());
|
||||
} else {
|
||||
self.focus_workspace(idx.saturating_sub(1)).ok()?;
|
||||
self.focus_workspace(idx - 1).ok()?;
|
||||
};
|
||||
|
||||
None
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
use windows::core::PCWSTR;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
@@ -69,19 +68,13 @@ impl Hidden {
|
||||
let hwnd = WindowsApi::create_hidden_window(PCWSTR(name.as_ptr()), h_module)?;
|
||||
hwnd_sender.send(hwnd)?;
|
||||
|
||||
let mut msg: MSG = MSG::default();
|
||||
let mut message = MSG::default();
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
if !GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() {
|
||||
tracing::debug!("hidden window event processing thread shutdown");
|
||||
break;
|
||||
};
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
unsafe {
|
||||
while GetMessageW(&mut message, HWND(hwnd), 0, 0).into() {
|
||||
TranslateMessage(&message);
|
||||
DispatchMessageW(&message);
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(10))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -110,7 +103,7 @@ impl Hidden {
|
||||
tracing::debug!(
|
||||
"WM_POWERBROADCAST event received - resume from suspend"
|
||||
);
|
||||
monitor_reconciliator::send_notification(
|
||||
let _ = monitor_reconciliator::event_tx().send(
|
||||
monitor_reconciliator::Notification::ResumingFromSuspendedState,
|
||||
);
|
||||
LRESULT(0)
|
||||
@@ -120,9 +113,8 @@ impl Hidden {
|
||||
tracing::debug!(
|
||||
"WM_POWERBROADCAST event received - entering suspended state"
|
||||
);
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::EnteringSuspendedState,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::EnteringSuspendedState);
|
||||
LRESULT(0)
|
||||
}
|
||||
_ => LRESULT(0),
|
||||
@@ -133,16 +125,14 @@ impl Hidden {
|
||||
WTS_SESSION_LOCK => {
|
||||
tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_LOCK - screen locked");
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::SessionLocked,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::SessionLocked);
|
||||
}
|
||||
WTS_SESSION_UNLOCK => {
|
||||
tracing::debug!("WM_WTSSESSION_CHANGE event received with WTS_SESSION_UNLOCK - screen unlocked");
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::SessionUnlocked,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::SessionUnlocked);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -161,9 +151,8 @@ impl Hidden {
|
||||
"WM_DISPLAYCHANGE event received with wparam: {}- work area or display resolution changed", wparam.0
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::ResolutionScalingChanged,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::ResolutionScalingChanged);
|
||||
LRESULT(0)
|
||||
}
|
||||
// Unfortunately this is the event sent with ButteryTaskbar which I use a lot
|
||||
@@ -175,9 +164,8 @@ impl Hidden {
|
||||
"WM_SETTINGCHANGE event received with SPI_SETWORKAREA - work area changed (probably butterytaskbar or something similar)"
|
||||
);
|
||||
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::WorkAreaChanged,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::WorkAreaChanged);
|
||||
}
|
||||
LRESULT(0)
|
||||
}
|
||||
@@ -189,9 +177,8 @@ impl Hidden {
|
||||
tracing::debug!(
|
||||
"WM_DEVICECHANGE event received with DBT_DEVNODES_CHANGED - display added or removed"
|
||||
);
|
||||
monitor_reconciliator::send_notification(
|
||||
monitor_reconciliator::Notification::DisplayConnectionChange,
|
||||
);
|
||||
let _ = monitor_reconciliator::event_tx()
|
||||
.send(monitor_reconciliator::Notification::DisplayConnectionChange);
|
||||
}
|
||||
|
||||
LRESULT(0)
|
||||
|
||||
@@ -40,20 +40,14 @@ pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(1))
|
||||
}
|
||||
|
||||
fn event_tx() -> Sender<Notification> {
|
||||
pub fn event_tx() -> Sender<Notification> {
|
||||
channel().0.clone()
|
||||
}
|
||||
|
||||
fn event_rx() -> Receiver<Notification> {
|
||||
pub fn event_rx() -> Receiver<Notification> {
|
||||
channel().1.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification(notification: Notification) {
|
||||
if event_tx().try_send(notification).is_err() {
|
||||
tracing::warn!("channel is full; dropping notification")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_in_monitor_cache(device_id: &str, config: MonitorConfig) {
|
||||
let mut monitor_cache = MONITOR_CACHE
|
||||
.get_or_init(|| Mutex::new(HashMap::new()))
|
||||
@@ -63,7 +57,7 @@ pub fn insert_in_monitor_cache(device_id: &str, config: MonitorConfig) {
|
||||
}
|
||||
|
||||
pub fn attached_display_devices() -> color_eyre::Result<Vec<Monitor>> {
|
||||
Ok(win32_display_data::connected_displays_all()
|
||||
Ok(win32_display_data::connected_displays()
|
||||
.flatten()
|
||||
.map(|display| {
|
||||
let path = display.device_path;
|
||||
@@ -166,7 +160,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
if should_update {
|
||||
tracing::info!("updated work area for {}", monitor.device_id());
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
border_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"work areas match, reconciliation not required for {}",
|
||||
@@ -213,7 +207,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
);
|
||||
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
border_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"resolutions match, reconciliation not required for {}",
|
||||
@@ -400,7 +394,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
// Second retile to fix DPI/resolution related jank
|
||||
wm.retile_all(true)?;
|
||||
// Border updates to fix DPI/resolution related jank
|
||||
border_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ use crate::current_virtual_desktop;
|
||||
use crate::notify_subscribers;
|
||||
use crate::stackbar_manager;
|
||||
use crate::static_config::StaticConfig;
|
||||
use crate::transparency_manager;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window::Window;
|
||||
use crate::window_manager;
|
||||
@@ -81,33 +80,26 @@ use stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn listen_for_commands(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
let wm = wm.clone();
|
||||
let listener = wm
|
||||
.lock()
|
||||
.command_listener
|
||||
.try_clone()
|
||||
.expect("could not clone unix listener");
|
||||
|
||||
let _ = std::thread::spawn(move || {
|
||||
let listener = wm
|
||||
.lock()
|
||||
.command_listener
|
||||
.try_clone()
|
||||
.expect("could not clone unix listener");
|
||||
|
||||
tracing::info!("listening on komorebi.sock");
|
||||
for client in listener.incoming() {
|
||||
match client {
|
||||
Ok(stream) => match read_commands_uds(&wm, stream) {
|
||||
Ok(()) => {}
|
||||
Err(error) => tracing::error!("{}", error),
|
||||
},
|
||||
Err(error) => {
|
||||
tracing::error!("{}", error);
|
||||
break;
|
||||
}
|
||||
std::thread::spawn(move || {
|
||||
tracing::info!("listening on komorebi.sock");
|
||||
for client in listener.incoming() {
|
||||
match client {
|
||||
Ok(stream) => match read_commands_uds(&wm, stream) {
|
||||
Ok(()) => {}
|
||||
Err(error) => tracing::error!("{}", error),
|
||||
},
|
||||
Err(error) => {
|
||||
tracing::error!("{}", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.join();
|
||||
|
||||
tracing::error!("restarting failed thread");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -213,8 +205,6 @@ impl WindowManager {
|
||||
}
|
||||
SocketMessage::StackWindow(direction) => self.add_window_to_container(direction)?,
|
||||
SocketMessage::UnstackWindow => self.remove_window_from_container()?,
|
||||
SocketMessage::StackAll => self.stack_all()?,
|
||||
SocketMessage::UnstackAll => self.unstack_all()?,
|
||||
SocketMessage::CycleStack(direction) => {
|
||||
self.cycle_container_window_in_direction(direction)?;
|
||||
self.focused_window()?.focus(self.mouse_follows_focus)?;
|
||||
@@ -226,10 +216,16 @@ impl WindowManager {
|
||||
WindowsApi::left_click();
|
||||
}
|
||||
SocketMessage::Close => {
|
||||
Window::from(WindowsApi::foreground_window()?).close()?;
|
||||
Window {
|
||||
hwnd: WindowsApi::foreground_window()?,
|
||||
}
|
||||
.close()?;
|
||||
}
|
||||
SocketMessage::Minimize => {
|
||||
Window::from(WindowsApi::foreground_window()?).minimize();
|
||||
Window {
|
||||
hwnd: WindowsApi::foreground_window()?,
|
||||
}
|
||||
.minimize();
|
||||
}
|
||||
SocketMessage::ToggleFloat => self.toggle_float()?,
|
||||
SocketMessage::ToggleMonocle => self.toggle_monocle()?,
|
||||
@@ -798,22 +794,15 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
let visible_windows_state = serde_json::to_string_pretty(&monitor_visible_windows)
|
||||
.unwrap_or_else(|error| error.to_string());
|
||||
let visible_windows_state =
|
||||
match serde_json::to_string_pretty(&monitor_visible_windows) {
|
||||
Ok(state) => state,
|
||||
Err(error) => error.to_string(),
|
||||
};
|
||||
|
||||
reply.write_all(visible_windows_state.as_bytes())?;
|
||||
}
|
||||
SocketMessage::MonitorInformation => {
|
||||
let mut monitors = HashMap::new();
|
||||
for monitor in self.monitors() {
|
||||
monitors.insert(monitor.device_id(), monitor.size());
|
||||
}
|
||||
|
||||
let monitors_state = serde_json::to_string_pretty(&monitors)
|
||||
.unwrap_or_else(|error| error.to_string());
|
||||
|
||||
reply.write_all(monitors_state.as_bytes())?;
|
||||
}
|
||||
SocketMessage::Query(query) => {
|
||||
let response = match query {
|
||||
StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(),
|
||||
@@ -1256,7 +1245,8 @@ impl WindowManager {
|
||||
}
|
||||
},
|
||||
SocketMessage::BorderStyle(style) => {
|
||||
STYLE.store(style);
|
||||
let mut border_style = STYLE.lock();
|
||||
*border_style = style;
|
||||
}
|
||||
SocketMessage::BorderWidth(width) => {
|
||||
border_manager::BORDER_WIDTH.store(width, Ordering::SeqCst);
|
||||
@@ -1264,12 +1254,6 @@ impl WindowManager {
|
||||
SocketMessage::BorderOffset(offset) => {
|
||||
border_manager::BORDER_OFFSET.store(offset, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::Transparency(enable) => {
|
||||
transparency_manager::TRANSPARENCY_ENABLED.store(enable, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::TransparencyAlpha(alpha) => {
|
||||
transparency_manager::TRANSPARENCY_ALPHA.store(alpha, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::StackbarMode(mode) => {
|
||||
STACKBAR_MODE.store(mode);
|
||||
}
|
||||
@@ -1342,7 +1326,7 @@ impl WindowManager {
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::DebugWindow(hwnd) => {
|
||||
let window = Window::from(hwnd);
|
||||
let window = Window { hwnd };
|
||||
let mut rule_debug = RuleDebug::default();
|
||||
let _ = window.should_manage(None, &mut rule_debug);
|
||||
let schema = serde_json::to_string_pretty(&rule_debug)?;
|
||||
@@ -1360,9 +1344,8 @@ impl WindowManager {
|
||||
};
|
||||
|
||||
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||
border_manager::send_notification();
|
||||
transparency_manager::send_notification();
|
||||
stackbar_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
stackbar_manager::event_tx().send(stackbar_manager::Notification)?;
|
||||
|
||||
tracing::info!("processed");
|
||||
Ok(())
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::time::Instant;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use komorebi_core::OperationDirection;
|
||||
@@ -20,7 +19,6 @@ use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::current_virtual_desktop;
|
||||
use crate::notify_subscribers;
|
||||
use crate::stackbar_manager;
|
||||
use crate::transparency_manager;
|
||||
use crate::window::should_act;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window_manager::WindowManager;
|
||||
@@ -45,8 +43,7 @@ pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
tracing::info!("listening");
|
||||
loop {
|
||||
if let Ok(event) = receiver.recv() {
|
||||
let mut guard = wm.lock();
|
||||
match guard.process_event(event) {
|
||||
match wm.lock().process_event(event) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
@@ -77,32 +74,7 @@ impl WindowManager {
|
||||
// All event handlers below this point should only be processed if the event is
|
||||
// related to a window that should be managed by the WindowManager.
|
||||
if !should_manage {
|
||||
let mut transparency_override = false;
|
||||
|
||||
if transparency_manager::TRANSPARENCY_ENABLED.load_consume() {
|
||||
for m in self.monitors() {
|
||||
for w in m.workspaces() {
|
||||
let event_hwnd = event.window().hwnd;
|
||||
|
||||
let visible_hwnds = w
|
||||
.visible_windows()
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|w| w.hwnd)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if w.contains_managed_window(event_hwnd)
|
||||
&& !visible_hwnds.contains(&event_hwnd)
|
||||
{
|
||||
transparency_override = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !transparency_override {
|
||||
return Ok(());
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(virtual_desktop_id) = &self.virtual_desktop_id {
|
||||
@@ -299,7 +271,13 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
workspace_reconciliator::send_notification(i, j);
|
||||
workspace_reconciliator::event_tx().send(
|
||||
workspace_reconciliator::Notification {
|
||||
monitor_idx: i,
|
||||
workspace_idx: j,
|
||||
},
|
||||
)?;
|
||||
|
||||
needs_reconciliation = true;
|
||||
}
|
||||
}
|
||||
@@ -630,9 +608,8 @@ impl WindowManager {
|
||||
};
|
||||
|
||||
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||
border_manager::send_notification();
|
||||
transparency_manager::send_notification();
|
||||
stackbar_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
stackbar_manager::event_tx().send(stackbar_manager::Notification)?;
|
||||
|
||||
// Too many spammy OBJECT_NAMECHANGE events from JetBrains IDEs
|
||||
if !matches!(
|
||||
|
||||
@@ -51,7 +51,7 @@ pub fn find_orphans(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
|
||||
let reaped_orphans = workspace.reap_orphans()?;
|
||||
if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 {
|
||||
workspace.update(&work_area, offset, window_based_work_area_offset)?;
|
||||
border_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
tracing::info!(
|
||||
"reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}",
|
||||
reaped_orphans.0,
|
||||
|
||||
@@ -4,7 +4,7 @@ use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct Ring<T> {
|
||||
elements: VecDeque<T>,
|
||||
focused: usize,
|
||||
|
||||
@@ -40,23 +40,17 @@ pub struct Notification;
|
||||
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
|
||||
|
||||
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
|
||||
CHANNEL.get_or_init(crossbeam_channel::unbounded)
|
||||
}
|
||||
|
||||
fn event_tx() -> Sender<Notification> {
|
||||
pub fn event_tx() -> Sender<Notification> {
|
||||
channel().0.clone()
|
||||
}
|
||||
|
||||
fn event_rx() -> Receiver<Notification> {
|
||||
pub fn event_rx() -> Receiver<Notification> {
|
||||
channel().1.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification() {
|
||||
if event_tx().try_send(Notification).is_err() {
|
||||
tracing::warn!("channel is full; dropping notification")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_have_stackbar(window_count: usize) -> bool {
|
||||
match STACKBAR_MODE.load() {
|
||||
StackbarMode::Always => true,
|
||||
|
||||
@@ -27,7 +27,6 @@ use windows::Win32::Foundation::WPARAM;
|
||||
use windows::Win32::Graphics::Gdi::CreateFontIndirectW;
|
||||
use windows::Win32::Graphics::Gdi::CreatePen;
|
||||
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
|
||||
use windows::Win32::Graphics::Gdi::DeleteObject;
|
||||
use windows::Win32::Graphics::Gdi::DrawTextW;
|
||||
use windows::Win32::Graphics::Gdi::GetDC;
|
||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||
@@ -120,17 +119,11 @@ impl Stackbar {
|
||||
SetLayeredWindowAttributes(hwnd, COLORREF(0), 0, LWA_COLORKEY)?;
|
||||
hwnd_sender.send(hwnd)?;
|
||||
|
||||
let mut msg: MSG = MSG::default();
|
||||
|
||||
loop {
|
||||
if !GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() {
|
||||
tracing::debug!("stackbar window event processing thread shutdown");
|
||||
break;
|
||||
};
|
||||
let mut msg = MSG::default();
|
||||
while GetMessageW(&mut msg, hwnd, 0, 0).into() {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
|
||||
std::thread::sleep(Duration::from_millis(10))
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +197,7 @@ impl Stackbar {
|
||||
bottom: height,
|
||||
};
|
||||
|
||||
match STYLE.load() {
|
||||
match *STYLE.lock() {
|
||||
BorderStyle::System => {
|
||||
if *WINDOWS_11 {
|
||||
RoundRect(hdc, rect.left, rect.top, rect.right, rect.bottom, 20, 20);
|
||||
@@ -242,9 +235,6 @@ impl Stackbar {
|
||||
}
|
||||
|
||||
ReleaseDC(self.hwnd(), hdc);
|
||||
DeleteObject(hpen);
|
||||
DeleteObject(hbrush);
|
||||
DeleteObject(hfont);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -14,7 +14,6 @@ use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_WIDTH;
|
||||
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::transparency_manager;
|
||||
use crate::window_manager::WindowManager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
@@ -230,7 +229,7 @@ impl From<&Monitor> for MonitorConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.27`
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.26`
|
||||
pub struct StaticConfig {
|
||||
/// DEPRECATED from v0.1.22: no longer required
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
@@ -279,12 +278,6 @@ pub struct StaticConfig {
|
||||
/// Active window border z-order (default: System)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub border_z_order: Option<ZOrder>,
|
||||
/// Add transparency to unfocused windows (default: false)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub transparency: Option<bool>,
|
||||
/// Alpha value for unfocused window transparency [[0-255]] (default: 200)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub transparency_alpha: Option<u8>,
|
||||
/// Global default workspace padding (default: 10)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub default_workspace_padding: Option<i32>,
|
||||
@@ -340,7 +333,7 @@ impl StaticConfig {
|
||||
|
||||
let mut display = false;
|
||||
|
||||
for aliases in map.values() {
|
||||
for (_, aliases) in &map {
|
||||
for a in aliases {
|
||||
if raw.contains(a) {
|
||||
display = true;
|
||||
@@ -475,14 +468,8 @@ impl From<&WindowManager> for StaticConfig {
|
||||
border_offset: Option::from(border_manager::BORDER_OFFSET.load(Ordering::SeqCst)),
|
||||
border: Option::from(border_manager::BORDER_ENABLED.load(Ordering::SeqCst)),
|
||||
border_colours,
|
||||
transparency: Option::from(
|
||||
transparency_manager::TRANSPARENCY_ENABLED.load(Ordering::SeqCst),
|
||||
),
|
||||
transparency_alpha: Option::from(
|
||||
transparency_manager::TRANSPARENCY_ALPHA.load(Ordering::SeqCst),
|
||||
),
|
||||
border_style: Option::from(STYLE.load()),
|
||||
border_z_order: Option::from(Z_ORDER.load()),
|
||||
border_style: Option::from(*STYLE.lock()),
|
||||
border_z_order: Option::from(*Z_ORDER.lock()),
|
||||
default_workspace_padding: Option::from(
|
||||
DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst),
|
||||
),
|
||||
@@ -510,12 +497,12 @@ impl StaticConfig {
|
||||
fn apply_globals(&mut self) -> Result<()> {
|
||||
if let Some(monitor_index_preferences) = &self.monitor_index_preferences {
|
||||
let mut preferences = MONITOR_INDEX_PREFERENCES.lock();
|
||||
preferences.clone_from(monitor_index_preferences);
|
||||
*preferences = monitor_index_preferences.clone();
|
||||
}
|
||||
|
||||
if let Some(display_index_preferences) = &self.display_index_preferences {
|
||||
let mut preferences = DISPLAY_INDEX_PREFERENCES.lock();
|
||||
preferences.clone_from(display_index_preferences);
|
||||
*preferences = display_index_preferences.clone();
|
||||
}
|
||||
|
||||
if let Some(behaviour) = self.window_hiding_behaviour {
|
||||
@@ -556,12 +543,8 @@ impl StaticConfig {
|
||||
}
|
||||
}
|
||||
|
||||
STYLE.store(self.border_style.unwrap_or_default());
|
||||
|
||||
transparency_manager::TRANSPARENCY_ENABLED
|
||||
.store(self.transparency.unwrap_or(false), Ordering::SeqCst);
|
||||
transparency_manager::TRANSPARENCY_ALPHA
|
||||
.store(self.transparency_alpha.unwrap_or(200), Ordering::SeqCst);
|
||||
let border_style = self.border_style.unwrap_or_default();
|
||||
*STYLE.lock() = border_style;
|
||||
|
||||
let mut float_identifiers = FLOAT_IDENTIFIERS.lock();
|
||||
let mut regex_identifiers = REGEX_IDENTIFIERS.lock();
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU8;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
|
||||
use crate::Window;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
|
||||
pub static TRANSPARENCY_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
pub static TRANSPARENCY_ALPHA: AtomicU8 = AtomicU8::new(200);
|
||||
|
||||
static KNOWN_HWNDS: OnceLock<Mutex<Vec<isize>>> = OnceLock::new();
|
||||
|
||||
pub struct Notification;
|
||||
|
||||
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
|
||||
|
||||
pub fn known_hwnds() -> Vec<isize> {
|
||||
let known = KNOWN_HWNDS.get_or_init(|| Mutex::new(Vec::new())).lock();
|
||||
known.iter().copied().collect()
|
||||
}
|
||||
|
||||
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
|
||||
}
|
||||
|
||||
fn event_tx() -> Sender<Notification> {
|
||||
channel().0.clone()
|
||||
}
|
||||
|
||||
fn event_rx() -> Receiver<Notification> {
|
||||
channel().1.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification() {
|
||||
if event_tx().try_send(Notification).is_err() {
|
||||
tracing::warn!("channel is full; dropping notification")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
Ok(()) => {
|
||||
tracing::warn!("restarting finished thread");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!("restarting failed thread: {}", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
|
||||
tracing::info!("listening");
|
||||
|
||||
let receiver = event_rx();
|
||||
event_tx().send(Notification)?;
|
||||
|
||||
'receiver: for _ in receiver {
|
||||
let known_hwnds = KNOWN_HWNDS.get_or_init(|| Mutex::new(Vec::new()));
|
||||
if !TRANSPARENCY_ENABLED.load_consume() {
|
||||
for hwnd in known_hwnds.lock().iter() {
|
||||
if let Err(error) = Window::from(*hwnd).opaque() {
|
||||
tracing::error!("failed to make window {hwnd} opaque: {error}")
|
||||
}
|
||||
}
|
||||
|
||||
continue 'receiver;
|
||||
}
|
||||
|
||||
known_hwnds.lock().clear();
|
||||
|
||||
// Check the wm state every time we receive a notification
|
||||
let state = wm.lock();
|
||||
|
||||
let focused_monitor_idx = state.focused_monitor_idx();
|
||||
|
||||
'monitors: for (monitor_idx, m) in state.monitors.elements().iter().enumerate() {
|
||||
let focused_workspace_idx = m.focused_workspace_idx();
|
||||
|
||||
'workspaces: for (workspace_idx, ws) in m.workspaces().iter().enumerate() {
|
||||
// Only operate on the focused workspace of each monitor
|
||||
// Workspaces with tiling disabled don't have transparent windows
|
||||
if !ws.tile() || workspace_idx != focused_workspace_idx {
|
||||
for window in ws.visible_windows().iter().flatten() {
|
||||
if let Err(error) = window.opaque() {
|
||||
let hwnd = window.hwnd;
|
||||
tracing::error!("failed to make window {hwnd} opaque: {error}")
|
||||
}
|
||||
}
|
||||
|
||||
continue 'workspaces;
|
||||
}
|
||||
|
||||
// Monocle container is never transparent
|
||||
if let Some(monocle) = ws.monocle_container() {
|
||||
if let Some(window) = monocle.focused_window() {
|
||||
if let Err(error) = window.opaque() {
|
||||
let hwnd = window.hwnd;
|
||||
tracing::error!("failed to make monocle window {hwnd} opaque: {error}")
|
||||
}
|
||||
}
|
||||
|
||||
continue 'monitors;
|
||||
}
|
||||
|
||||
let foreground_hwnd = WindowsApi::foreground_window().unwrap_or_default();
|
||||
let is_maximized = WindowsApi::is_zoomed(HWND(foreground_hwnd));
|
||||
|
||||
if is_maximized {
|
||||
if let Err(error) = Window::from(foreground_hwnd).opaque() {
|
||||
let hwnd = foreground_hwnd;
|
||||
tracing::error!("failed to make maximized window {hwnd} opaque: {error}")
|
||||
}
|
||||
|
||||
continue 'monitors;
|
||||
}
|
||||
|
||||
for (idx, c) in ws.containers().iter().enumerate() {
|
||||
// Update the transparency for all containers on this workspace
|
||||
|
||||
// If the window is not focused on the current workspace, or isn't on the focused monitor
|
||||
// make it transparent
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if idx != ws.focused_container_idx() || monitor_idx != focused_monitor_idx {
|
||||
let focused_window_idx = c.focused_window_idx();
|
||||
for (window_idx, window) in c.windows().iter().enumerate() {
|
||||
if window_idx == focused_window_idx {
|
||||
match window.transparent() {
|
||||
Err(error) => {
|
||||
let hwnd = foreground_hwnd;
|
||||
tracing::error!(
|
||||
"failed to make unfocused window {hwnd} transparent: {error}"
|
||||
)
|
||||
}
|
||||
Ok(..) => {
|
||||
known_hwnds.lock().push(window.hwnd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just in case, this is useful when people are clicking around
|
||||
// on unfocused stackbar tabs
|
||||
known_hwnds.lock().push(window.hwnd);
|
||||
}
|
||||
}
|
||||
// Otherwise, make it opaque
|
||||
} else {
|
||||
let focused_window_idx = c.focused_window_idx();
|
||||
for (window_idx, window) in c.windows().iter().enumerate() {
|
||||
if window_idx != focused_window_idx {
|
||||
known_hwnds.lock().push(window.hwnd);
|
||||
} else {
|
||||
if let Err(error) =
|
||||
c.focused_window().copied().unwrap_or_default().opaque()
|
||||
{
|
||||
let hwnd = foreground_hwnd;
|
||||
tracing::error!(
|
||||
"failed to make focused window {hwnd} opaque: {error}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -7,8 +7,8 @@ use std::fmt::Write as _;
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use komorebi_core::config_generation::IdWithIdentifier;
|
||||
use komorebi_core::config_generation::MatchingRule;
|
||||
use komorebi_core::config_generation::MatchingStrategy;
|
||||
@@ -26,7 +26,6 @@ use komorebi_core::Rect;
|
||||
|
||||
use crate::styles::ExtendedWindowStyle;
|
||||
use crate::styles::WindowStyle;
|
||||
use crate::transparency_manager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::FLOAT_IDENTIFIERS;
|
||||
@@ -39,23 +38,11 @@ use crate::PERMAIGNORE_CLASSES;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::WSL2_UI_PROCESSES;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema)]
|
||||
pub struct Window {
|
||||
pub hwnd: isize,
|
||||
}
|
||||
|
||||
impl From<isize> for Window {
|
||||
fn from(value: isize) -> Self {
|
||||
Self { hwnd: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HWND> for Window {
|
||||
fn from(value: HWND) -> Self {
|
||||
Self { hwnd: value.0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct WindowDetails {
|
||||
@@ -263,10 +250,7 @@ impl Window {
|
||||
let mut ex_style = self.ex_style()?;
|
||||
ex_style.insert(ExtendedWindowStyle::LAYERED);
|
||||
self.update_ex_style(&ex_style)?;
|
||||
WindowsApi::set_transparent(
|
||||
self.hwnd(),
|
||||
transparency_manager::TRANSPARENCY_ALPHA.load_consume(),
|
||||
)
|
||||
WindowsApi::set_transparent(self.hwnd())
|
||||
}
|
||||
|
||||
pub fn opaque(self) -> Result<()> {
|
||||
@@ -286,12 +270,12 @@ impl Window {
|
||||
|
||||
pub fn style(self) -> Result<WindowStyle> {
|
||||
let bits = u32::try_from(WindowsApi::gwl_style(self.hwnd())?)?;
|
||||
Ok(WindowStyle::from_bits_truncate(bits))
|
||||
WindowStyle::from_bits(bits).ok_or_else(|| anyhow!("there is no gwl style"))
|
||||
}
|
||||
|
||||
pub fn ex_style(self) -> Result<ExtendedWindowStyle> {
|
||||
let bits = u32::try_from(WindowsApi::gwl_ex_style(self.hwnd())?)?;
|
||||
Ok(ExtendedWindowStyle::from_bits_truncate(bits))
|
||||
ExtendedWindowStyle::from_bits(bits).ok_or_else(|| anyhow!("there is no gwl style"))
|
||||
}
|
||||
|
||||
pub fn title(self) -> Result<String> {
|
||||
@@ -391,7 +375,7 @@ impl Window {
|
||||
if let (Ok(style), Ok(ex_style)) = (&self.style(), &self.ex_style()) {
|
||||
debug.window_style = Some(*style);
|
||||
debug.extended_window_style = Some(*ex_style);
|
||||
let eligible = window_is_eligible(self.hwnd, &title, &exe_name, &class, &path, style, ex_style, event, debug);
|
||||
let eligible = window_is_eligible(&title, &exe_name, &class, &path, style, ex_style, event, debug);
|
||||
debug.should_manage = eligible;
|
||||
return Ok(eligible);
|
||||
}
|
||||
@@ -411,7 +395,6 @@ pub struct RuleDebug {
|
||||
pub has_title: bool,
|
||||
pub is_cloaked: bool,
|
||||
pub allow_cloaked: bool,
|
||||
pub allow_layered_transparency: bool,
|
||||
pub window_style: Option<WindowStyle>,
|
||||
pub extended_window_style: Option<ExtendedWindowStyle>,
|
||||
pub title: Option<String>,
|
||||
@@ -428,7 +411,6 @@ pub struct RuleDebug {
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn window_is_eligible(
|
||||
hwnd: isize,
|
||||
title: &String,
|
||||
exe_name: &String,
|
||||
class: &String,
|
||||
@@ -483,7 +465,7 @@ fn window_is_eligible(
|
||||
}
|
||||
|
||||
let layered_whitelist = LAYERED_WHITELIST.lock();
|
||||
let mut allow_layered = if let Some(rule) = should_act(
|
||||
let allow_layered = if let Some(rule) = should_act(
|
||||
title,
|
||||
exe_name,
|
||||
class,
|
||||
@@ -497,14 +479,8 @@ fn window_is_eligible(
|
||||
false
|
||||
};
|
||||
|
||||
let known_layered_hwnds = transparency_manager::known_hwnds();
|
||||
|
||||
allow_layered = if known_layered_hwnds.contains(&hwnd) {
|
||||
debug.allow_layered_transparency = true;
|
||||
true
|
||||
} else {
|
||||
allow_layered
|
||||
};
|
||||
// TODO: might need this for transparency
|
||||
// let allow_layered = true;
|
||||
|
||||
let allow_wsl2_gui = {
|
||||
let wsl2_ui_processes = WSL2_UI_PROCESSES.lock();
|
||||
|
||||
@@ -55,7 +55,6 @@ use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_WIDTH;
|
||||
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::static_config::StaticConfig;
|
||||
use crate::transparency_manager;
|
||||
use crate::window::Window;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
@@ -164,7 +163,7 @@ impl Default for GlobalState {
|
||||
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||
))),
|
||||
},
|
||||
border_style: STYLE.load(),
|
||||
border_style: *STYLE.lock(),
|
||||
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
|
||||
border_width: border_manager::BORDER_WIDTH.load(Ordering::SeqCst),
|
||||
stackbar_mode: STACKBAR_MODE.load(),
|
||||
@@ -520,7 +519,7 @@ impl WindowManager {
|
||||
|
||||
// Hide the window we are about to remove if it is on the currently focused workspace
|
||||
if op.is_origin(focused_monitor_idx, focused_workspace_idx) {
|
||||
Window::from(op.hwnd).hide();
|
||||
Window { hwnd: op.hwnd }.hide();
|
||||
should_update_focused_workspace = true;
|
||||
}
|
||||
|
||||
@@ -550,7 +549,7 @@ impl WindowManager {
|
||||
.get_mut(op.target_workspace_idx)
|
||||
.ok_or_else(|| anyhow!("there is no workspace with that index"))?;
|
||||
|
||||
target_workspace.new_container_for_window(Window::from(op.hwnd));
|
||||
target_workspace.new_container_for_window(Window { hwnd: op.hwnd });
|
||||
}
|
||||
|
||||
// Only re-tile the focused workspace if we need to
|
||||
@@ -598,14 +597,14 @@ impl WindowManager {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn manage_focused_window(&mut self) -> Result<()> {
|
||||
let hwnd = WindowsApi::foreground_window()?;
|
||||
let event = WindowManagerEvent::Manage(Window::from(hwnd));
|
||||
let event = WindowManagerEvent::Manage(Window { hwnd });
|
||||
Ok(winevent_listener::event_tx().send(event)?)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn unmanage_focused_window(&mut self) -> Result<()> {
|
||||
let hwnd = WindowsApi::foreground_window()?;
|
||||
let event = WindowManagerEvent::Unmanage(Window::from(hwnd));
|
||||
let event = WindowManagerEvent::Unmanage(Window { hwnd });
|
||||
Ok(winevent_listener::event_tx().send(event)?)
|
||||
}
|
||||
|
||||
@@ -614,7 +613,6 @@ impl WindowManager {
|
||||
let mut hwnd = None;
|
||||
|
||||
let workspace = self.focused_workspace()?;
|
||||
// first check the focused workspace
|
||||
if let Some(container_idx) = workspace.container_idx_from_current_point() {
|
||||
if let Some(container) = workspace.containers().get(container_idx) {
|
||||
if let Some(window) = container.focused_window() {
|
||||
@@ -623,34 +621,6 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
// then check all workspaces
|
||||
if hwnd.is_none() {
|
||||
for monitor in self.monitors() {
|
||||
for ws in monitor.workspaces() {
|
||||
if let Some(container_idx) = ws.container_idx_from_current_point() {
|
||||
if let Some(container) = ws.containers().get(container_idx) {
|
||||
if let Some(window) = container.focused_window() {
|
||||
hwnd = Some(window.hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally try matching the other way using a hwnd returned from the cursor pos
|
||||
if hwnd.is_none() {
|
||||
let cursor_pos_hwnd = WindowsApi::window_at_cursor_pos()?;
|
||||
|
||||
for monitor in self.monitors() {
|
||||
for ws in monitor.workspaces() {
|
||||
if ws.container_for_window(cursor_pos_hwnd).is_some() {
|
||||
hwnd = Some(cursor_pos_hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hwnd) = hwnd {
|
||||
if self.has_pending_raise_op
|
||||
|| self.focused_window()?.hwnd == hwnd
|
||||
@@ -662,13 +632,15 @@ impl WindowManager {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let event = WindowManagerEvent::Raise(Window::from(hwnd));
|
||||
let event = WindowManagerEvent::Raise(Window { hwnd });
|
||||
self.has_pending_raise_op = true;
|
||||
winevent_listener::event_tx().send(event)?;
|
||||
} else {
|
||||
tracing::debug!(
|
||||
"not raising unknown window: {}",
|
||||
Window::from(WindowsApi::window_at_cursor_pos()?)
|
||||
Window {
|
||||
hwnd: WindowsApi::window_at_cursor_pos()?
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -792,7 +764,9 @@ impl WindowManager {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
} else {
|
||||
let desktop_window = Window::from(WindowsApi::desktop_window()?);
|
||||
let desktop_window = Window {
|
||||
hwnd: WindowsApi::desktop_window()?,
|
||||
};
|
||||
|
||||
let rect = self.focused_monitor_size()?;
|
||||
WindowsApi::center_cursor_in_rect(&rect)?;
|
||||
@@ -933,7 +907,6 @@ impl WindowManager {
|
||||
tracing::info!("restoring all hidden windows");
|
||||
|
||||
let no_titlebar = NO_TITLEBAR.lock();
|
||||
let known_transparent_hwnds = transparency_manager::known_hwnds();
|
||||
|
||||
for monitor in self.monitors_mut() {
|
||||
for workspace in monitor.workspaces_mut() {
|
||||
@@ -943,10 +916,6 @@ impl WindowManager {
|
||||
window.add_title_bar()?;
|
||||
}
|
||||
|
||||
if known_transparent_hwnds.contains(&window.hwnd) {
|
||||
window.opaque()?;
|
||||
}
|
||||
|
||||
window.restore();
|
||||
}
|
||||
}
|
||||
@@ -1068,14 +1037,6 @@ impl WindowManager {
|
||||
|
||||
tracing::info!("moving container");
|
||||
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
|
||||
if focused_monitor_idx == monitor_idx {
|
||||
if let Some(workspace_idx) = workspace_idx {
|
||||
return self.move_container_to_workspace(workspace_idx, follow);
|
||||
}
|
||||
}
|
||||
|
||||
let offset = self.work_area_offset;
|
||||
let mouse_follows_focus = self.mouse_follows_focus;
|
||||
|
||||
@@ -1095,12 +1056,6 @@ impl WindowManager {
|
||||
.remove_focused_container()
|
||||
.ok_or_else(|| anyhow!("there is no container"))?;
|
||||
|
||||
let container_hwnds = container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.hwnd)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
|
||||
let target_monitor = self
|
||||
@@ -1114,22 +1069,9 @@ impl WindowManager {
|
||||
target_monitor.focus_workspace(workspace_idx)?;
|
||||
}
|
||||
|
||||
if let Some(workspace) = target_monitor.focused_workspace() {
|
||||
if !*workspace.tile() {
|
||||
for hwnd in container_hwnds {
|
||||
Window::from(hwnd).center(target_monitor.work_area_size())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target_monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
target_monitor.update_focused_workspace(offset)?;
|
||||
|
||||
// this second one is for DPI changes when the target is another monitor
|
||||
// if we don't do this the layout on the other monitor could look funny
|
||||
// until it is interacted with again
|
||||
target_monitor.update_focused_workspace(offset)?;
|
||||
|
||||
if follow {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
@@ -1175,7 +1117,7 @@ impl WindowManager {
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
target_monitor.workspaces_mut().push_back(workspace);
|
||||
target_monitor.focus_workspace(target_monitor.workspaces().len().saturating_sub(1))?;
|
||||
target_monitor.focus_workspace(target_monitor.workspaces().len() - 1)?;
|
||||
target_monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
}
|
||||
|
||||
@@ -1310,9 +1252,10 @@ impl WindowManager {
|
||||
let origin_workspace =
|
||||
self.focused_workspace_for_monitor_idx_mut(origin_monitor_idx)?;
|
||||
|
||||
origin_workspace.focus_container(
|
||||
origin_workspace.focused_container_idx().saturating_sub(1),
|
||||
);
|
||||
if origin_workspace.focused_container_idx() != 0 {
|
||||
origin_workspace
|
||||
.focus_container(origin_workspace.focused_container_idx() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1463,67 +1406,6 @@ impl WindowManager {
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn stack_all(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
tracing::info!("stacking all windows on workspace");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let mut focused_hwnd = None;
|
||||
if let Some(container) = workspace.focused_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
focused_hwnd = Some(window.hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
workspace.focus_container(workspace.containers().len().saturating_sub(1));
|
||||
while workspace.focused_container_idx() > 0 {
|
||||
workspace.move_window_to_container(0)?;
|
||||
workspace.focus_container(workspace.containers().len().saturating_sub(1));
|
||||
}
|
||||
|
||||
if let Some(hwnd) = focused_hwnd {
|
||||
workspace.focus_container_by_window(hwnd)?;
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn unstack_all(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
tracing::info!("unstacking all windows in container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let mut focused_hwnd = None;
|
||||
if let Some(container) = workspace.focused_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
focused_hwnd = Some(window.hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
let initial_focused_container_index = workspace.focused_container_idx();
|
||||
let mut focused_container = workspace.focused_container().cloned();
|
||||
|
||||
while let Some(focused) = &focused_container {
|
||||
if focused.windows().len() > 1 {
|
||||
workspace.new_container_for_focused_window()?;
|
||||
workspace.focus_container(initial_focused_container_index);
|
||||
focused_container = workspace.focused_container().cloned();
|
||||
} else {
|
||||
focused_container = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hwnd) = focused_hwnd {
|
||||
workspace.focus_container_by_window(hwnd)?;
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn add_window_to_container(&mut self, direction: OperationDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
@@ -1555,20 +1437,12 @@ impl WindowManager {
|
||||
Layout::Default(DefaultLayout::Grid)
|
||||
| Layout::Default(DefaultLayout::UltrawideVerticalStack)
|
||||
) {
|
||||
new_idx.saturating_sub(1)
|
||||
new_idx - 1
|
||||
} else {
|
||||
new_idx
|
||||
};
|
||||
|
||||
if let Some(current) = workspace.focused_container() {
|
||||
if current.windows().len() > 1 {
|
||||
workspace.focus_container(adjusted_new_index);
|
||||
workspace.move_window_to_container(current_container_idx)?;
|
||||
} else {
|
||||
workspace.move_window_to_container(adjusted_new_index)?;
|
||||
}
|
||||
}
|
||||
|
||||
workspace.move_window_to_container(adjusted_new_index)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
pub fn valid_hmonitors() -> Result<Vec<(String, isize)>> {
|
||||
Ok(win32_display_data::connected_displays_all()
|
||||
Ok(win32_display_data::connected_displays()
|
||||
.flatten()
|
||||
.map(|d| {
|
||||
let name = d.device_name.trim_start_matches(r"\\.\").to_string();
|
||||
@@ -232,7 +232,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
pub fn load_monitor_information(monitors: &mut Ring<Monitor>) -> Result<()> {
|
||||
'read: for display in win32_display_data::connected_displays_all().flatten() {
|
||||
'read: for display in win32_display_data::connected_displays().flatten() {
|
||||
let path = display.device_path.clone();
|
||||
let mut split: Vec<_> = path.split('#').collect();
|
||||
split.remove(0);
|
||||
@@ -276,7 +276,8 @@ impl WindowsApi {
|
||||
if monitors.elements().is_empty() {
|
||||
monitors.elements_mut().push_back(m);
|
||||
} else if let Some(preference) = index_preference {
|
||||
while *preference > monitors.elements().len() {
|
||||
let current_len = monitors.elements().len();
|
||||
while *preference > current_len {
|
||||
monitors.elements_mut().reserve(1);
|
||||
}
|
||||
|
||||
@@ -790,7 +791,7 @@ impl WindowsApi {
|
||||
}
|
||||
|
||||
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
|
||||
for display in win32_display_data::connected_displays_all().flatten() {
|
||||
for display in win32_display_data::connected_displays().flatten() {
|
||||
if display.hmonitor == hmonitor {
|
||||
let path = display.device_path;
|
||||
let mut split: Vec<_> = path.split('#').collect();
|
||||
@@ -979,10 +980,11 @@ impl WindowsApi {
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn set_transparent(hwnd: HWND, alpha: u8) -> Result<()> {
|
||||
pub fn set_transparent(hwnd: HWND) -> Result<()> {
|
||||
unsafe {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
SetLayeredWindowAttributes(hwnd, COLORREF(-1i32 as u32), alpha, LWA_ALPHA)?;
|
||||
// TODO: alpha should be configurable
|
||||
SetLayeredWindowAttributes(hwnd, COLORREF(-1i32 as u32), 150, LWA_ALPHA)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -22,7 +22,7 @@ pub extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
let is_maximized = WindowsApi::is_zoomed(hwnd);
|
||||
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window::from(hwnd);
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default()) {
|
||||
if should_manage {
|
||||
@@ -48,7 +48,7 @@ pub extern "system" fn alt_tab_windows(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
let is_minimized = WindowsApi::is_iconic(hwnd);
|
||||
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window::from(hwnd);
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default()) {
|
||||
if should_manage {
|
||||
@@ -74,7 +74,7 @@ pub extern "system" fn win_event_hook(
|
||||
return;
|
||||
}
|
||||
|
||||
let window = Window::from(hwnd);
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
|
||||
let winevent = match WinEvent::try_from(event) {
|
||||
Ok(event) => event,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
@@ -35,26 +34,23 @@ pub fn start() {
|
||||
)
|
||||
};
|
||||
|
||||
let mut msg: MSG = MSG::default();
|
||||
|
||||
loop {
|
||||
let mut msg: MSG = MSG::default();
|
||||
unsafe {
|
||||
if !GetMessageW(&mut msg, HWND(0), 0, 0).as_bool() {
|
||||
tracing::debug!("windows event processing thread shutdown");
|
||||
tracing::info!("windows event processing shutdown");
|
||||
break;
|
||||
};
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(10))
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn channel() -> &'static (Sender<WindowManagerEvent>, Receiver<WindowManagerEvent>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
|
||||
CHANNEL.get_or_init(crossbeam_channel::unbounded)
|
||||
}
|
||||
|
||||
pub fn event_tx() -> Sender<WindowManagerEvent> {
|
||||
|
||||
@@ -38,16 +38,7 @@ use crate::REMOVE_TITLEBARS;
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Getters,
|
||||
CopyGetters,
|
||||
MutGetters,
|
||||
Setters,
|
||||
JsonSchema,
|
||||
PartialEq,
|
||||
Debug, Clone, Serialize, Deserialize, Getters, CopyGetters, MutGetters, Setters, JsonSchema,
|
||||
)]
|
||||
pub struct Workspace {
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
@@ -406,28 +397,6 @@ impl Workspace {
|
||||
pub fn reap_orphans(&mut self) -> Result<(usize, usize)> {
|
||||
let mut hwnds = vec![];
|
||||
let mut floating_hwnds = vec![];
|
||||
let mut remove_monocle = false;
|
||||
let mut remove_maximized = false;
|
||||
|
||||
if let Some(monocle) = &self.monocle_container {
|
||||
let window_count = monocle.windows().len();
|
||||
let mut orphan_count = 0;
|
||||
for window in monocle.windows() {
|
||||
if !window.is_window() {
|
||||
hwnds.push(window.hwnd);
|
||||
orphan_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
remove_monocle = orphan_count == window_count;
|
||||
}
|
||||
|
||||
if let Some(window) = &self.maximized_window {
|
||||
if !window.is_window() {
|
||||
hwnds.push(window.hwnd);
|
||||
remove_maximized = true;
|
||||
}
|
||||
}
|
||||
|
||||
for window in self.visible_windows_mut().into_iter().flatten() {
|
||||
if !window.is_window() {
|
||||
@@ -462,14 +431,6 @@ impl Workspace {
|
||||
self.containers_mut()
|
||||
.retain(|c| !container_ids.contains(c.id()));
|
||||
|
||||
if remove_monocle {
|
||||
self.set_monocle_container(None);
|
||||
}
|
||||
|
||||
if remove_maximized {
|
||||
self.set_maximized_window(None);
|
||||
}
|
||||
|
||||
Ok((hwnds.len() + floating_hwnds.len(), container_ids.len()))
|
||||
}
|
||||
|
||||
@@ -802,7 +763,7 @@ impl Workspace {
|
||||
self.resize_dimensions_mut().remove(focused_idx);
|
||||
|
||||
if focused_idx < target_container_idx {
|
||||
target_container_idx.saturating_sub(1)
|
||||
target_container_idx - 1
|
||||
} else {
|
||||
target_container_idx
|
||||
}
|
||||
@@ -924,8 +885,8 @@ impl Workspace {
|
||||
self.containers_mut().remove(focused_idx);
|
||||
self.resize_dimensions_mut().remove(focused_idx);
|
||||
|
||||
if focused_idx == self.containers().len() {
|
||||
self.focus_container(focused_idx.saturating_sub(1));
|
||||
if focused_idx == self.containers().len() && focused_idx != 0 {
|
||||
self.focus_container(focused_idx - 1);
|
||||
}
|
||||
} else {
|
||||
container.load_focused_window();
|
||||
@@ -1333,8 +1294,7 @@ impl Workspace {
|
||||
.ok_or_else(|| anyhow!("there is no monocle container"))?;
|
||||
|
||||
let window = *window;
|
||||
if !self.containers().is_empty() && restore_idx > self.containers().len().saturating_sub(1)
|
||||
{
|
||||
if !self.containers().is_empty() && restore_idx > self.containers().len() - 1 {
|
||||
self.containers_mut()
|
||||
.resize(restore_idx, Container::default());
|
||||
}
|
||||
@@ -1423,10 +1383,13 @@ impl Workspace {
|
||||
|
||||
pub fn focus_previous_container(&mut self) {
|
||||
let focused_idx = self.focused_container_idx();
|
||||
self.focus_container(focused_idx.saturating_sub(1));
|
||||
|
||||
if focused_idx != 0 {
|
||||
self.focus_container(focused_idx - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn focus_last_container(&mut self) {
|
||||
self.focus_container(self.containers().len().saturating_sub(1));
|
||||
self.focus_container(self.containers().len() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,26 +30,14 @@ pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||
CHANNEL.get_or_init(|| crossbeam_channel::bounded(1))
|
||||
}
|
||||
|
||||
fn event_tx() -> Sender<Notification> {
|
||||
pub fn event_tx() -> Sender<Notification> {
|
||||
channel().0.clone()
|
||||
}
|
||||
|
||||
fn event_rx() -> Receiver<Notification> {
|
||||
pub fn event_rx() -> Receiver<Notification> {
|
||||
channel().1.clone()
|
||||
}
|
||||
|
||||
pub fn send_notification(monitor_idx: usize, workspace_idx: usize) {
|
||||
if event_tx()
|
||||
.try_send(Notification {
|
||||
monitor_idx,
|
||||
workspace_idx,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
tracing::warn!("channel is full; dropping notification")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || loop {
|
||||
match handle_notifications(wm.clone()) {
|
||||
@@ -118,7 +106,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
|
||||
// Unblock the border manager
|
||||
ALT_TAB_HWND.store(None);
|
||||
// Send a notification to the border manager to update the borders
|
||||
border_manager::send_notification();
|
||||
border_manager::event_tx().send(border_manager::Notification)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "The command-line interface (without a console) for Komorebi, a tiling window manager for Windows"
|
||||
categories = ["cli", "tiling-window-manager", "windows"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebic"
|
||||
version = "0.1.27"
|
||||
version = "0.1.27-dev.0"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "The command-line interface for Komorebi, a tiling window manager for Windows"
|
||||
categories = ["cli", "tiling-window-manager", "windows"]
|
||||
@@ -11,6 +11,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
derive-ahk = { path = "../derive-ahk" }
|
||||
komorebi-core = { path = "../komorebi-core" }
|
||||
komorebi-client = { path = "../komorebi-client" }
|
||||
|
||||
@@ -20,6 +21,7 @@ color-eyre = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
fs-tail = "0.1"
|
||||
heck = "0.5"
|
||||
lazy_static = "1"
|
||||
miette = { version = "7", features = ["fancy"] }
|
||||
paste = "1"
|
||||
@@ -32,7 +34,6 @@ sysinfo = { workspace = true }
|
||||
thiserror = "1"
|
||||
uds_windows = "1"
|
||||
which = "6"
|
||||
win32-display-data = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::missing_errors_doc, clippy::doc_markdown)]
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
use chrono::Utc;
|
||||
use chrono::Local;
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::BufRead;
|
||||
@@ -24,6 +24,7 @@ use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use dirs::data_local_dir;
|
||||
use fs_tail::TailedFile;
|
||||
use heck::ToKebabCase;
|
||||
use komorebi_core::resolve_home_path;
|
||||
use lazy_static::lazy_static;
|
||||
use miette::NamedSource;
|
||||
@@ -38,6 +39,8 @@ use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_RESTORE;
|
||||
|
||||
use derive_ahk::AhkFunction;
|
||||
use derive_ahk::AhkLibrary;
|
||||
use komorebi_client::StaticConfig;
|
||||
use komorebi_core::config_generation::ApplicationConfigurationGenerator;
|
||||
use komorebi_core::ApplicationIdentifier;
|
||||
@@ -99,6 +102,14 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
trait AhkLibrary {
|
||||
fn generate_ahk_library() -> String;
|
||||
}
|
||||
|
||||
trait AhkFunction {
|
||||
fn generate_ahk_function() -> String;
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, miette::Diagnostic)]
|
||||
#[error("{message}")]
|
||||
#[diagnostic(code(komorebi::configuration), help("try fixing this syntax error"))]
|
||||
@@ -130,7 +141,7 @@ macro_rules! gen_enum_subcommand_args {
|
||||
( $( $name:ident: $element:ty ),+ $(,)? ) => {
|
||||
$(
|
||||
paste! {
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
#[clap(value_enum)]
|
||||
[<$element:snake>]: $element
|
||||
@@ -170,7 +181,7 @@ macro_rules! gen_target_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
/// Target index (zero-indexed)
|
||||
target: usize,
|
||||
@@ -195,7 +206,7 @@ macro_rules! gen_named_target_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -219,7 +230,7 @@ macro_rules! gen_workspace_subcommand_args {
|
||||
( $( $name:ident: $(#[enum] $(@$value_enum:tt)?)? $value:ty ),+ $(,)? ) => (
|
||||
paste! {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct [<Workspace $name>] {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -251,7 +262,7 @@ macro_rules! gen_named_workspace_subcommand_args {
|
||||
( $( $name:ident: $(#[enum] $(@$value_enum:tt)?)? $value:ty ),+ $(,)? ) => (
|
||||
paste! {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct [<NamedWorkspace $name>] {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -273,7 +284,7 @@ gen_named_workspace_subcommand_args! {
|
||||
Tiling: #[enum] BooleanState,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct ClearWorkspaceLayoutRules {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -282,7 +293,7 @@ pub struct ClearWorkspaceLayoutRules {
|
||||
workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct WorkspaceCustomLayout {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -294,7 +305,7 @@ pub struct WorkspaceCustomLayout {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct NamedWorkspaceCustomLayout {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -303,7 +314,7 @@ pub struct NamedWorkspaceCustomLayout {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct WorkspaceLayoutRule {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -318,7 +329,7 @@ pub struct WorkspaceLayoutRule {
|
||||
layout: DefaultLayout,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct NamedWorkspaceLayoutRule {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -330,7 +341,7 @@ pub struct NamedWorkspaceLayoutRule {
|
||||
layout: DefaultLayout,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct WorkspaceCustomLayoutRule {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -345,7 +356,7 @@ pub struct WorkspaceCustomLayoutRule {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct NamedWorkspaceCustomLayoutRule {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -357,7 +368,7 @@ pub struct NamedWorkspaceCustomLayoutRule {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct Resize {
|
||||
#[clap(value_enum)]
|
||||
edge: OperationDirection,
|
||||
@@ -365,7 +376,7 @@ struct Resize {
|
||||
sizing: Sizing,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct ResizeAxis {
|
||||
#[clap(value_enum)]
|
||||
axis: Axis,
|
||||
@@ -373,13 +384,13 @@ struct ResizeAxis {
|
||||
sizing: Sizing,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct ResizeDelta {
|
||||
/// The delta of pixels by which to increase or decrease window dimensions when resizing
|
||||
pixels: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct InvisibleBorders {
|
||||
/// Size of the left invisible border
|
||||
left: i32,
|
||||
@@ -391,7 +402,7 @@ struct InvisibleBorders {
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct GlobalWorkAreaOffset {
|
||||
/// Size of the left work area offset (set right to left * 2 to maintain right padding)
|
||||
left: i32,
|
||||
@@ -403,7 +414,7 @@ struct GlobalWorkAreaOffset {
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct MonitorWorkAreaOffset {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -417,7 +428,7 @@ struct MonitorWorkAreaOffset {
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct MonitorIndexPreference {
|
||||
/// Preferred monitor index (zero-indexed)
|
||||
index_preference: usize,
|
||||
@@ -431,7 +442,7 @@ struct MonitorIndexPreference {
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct DisplayIndexPreference {
|
||||
/// Preferred monitor index (zero-indexed)
|
||||
index_preference: usize,
|
||||
@@ -439,7 +450,7 @@ struct DisplayIndexPreference {
|
||||
display: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct EnsureWorkspaces {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -447,7 +458,7 @@ struct EnsureWorkspaces {
|
||||
workspace_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct EnsureNamedWorkspaces {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -455,7 +466,7 @@ struct EnsureNamedWorkspaces {
|
||||
names: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct FocusMonitorWorkspace {
|
||||
/// Target monitor index (zero-indexed)
|
||||
target_monitor: usize,
|
||||
@@ -463,7 +474,7 @@ struct FocusMonitorWorkspace {
|
||||
target_workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct SendToMonitorWorkspace {
|
||||
/// Target monitor index (zero-indexed)
|
||||
target_monitor: usize,
|
||||
@@ -471,7 +482,7 @@ pub struct SendToMonitorWorkspace {
|
||||
target_workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct MoveToMonitorWorkspace {
|
||||
/// Target monitor index (zero-indexed)
|
||||
target_monitor: usize,
|
||||
@@ -483,7 +494,7 @@ macro_rules! gen_focused_workspace_padding_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
/// Pixels size to set as an integer
|
||||
size: i32,
|
||||
@@ -501,7 +512,7 @@ macro_rules! gen_padding_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
/// Monitor index (zero-indexed)
|
||||
monitor: usize,
|
||||
@@ -523,7 +534,7 @@ macro_rules! gen_named_padding_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
/// Target workspace name
|
||||
workspace: String,
|
||||
@@ -544,7 +555,7 @@ macro_rules! gen_padding_adjustment_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
#[clap(value_enum)]
|
||||
sizing: Sizing,
|
||||
@@ -564,7 +575,7 @@ macro_rules! gen_application_target_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
$(
|
||||
#[derive(clap::Parser)]
|
||||
#[derive(clap::Parser, derive_ahk::AhkFunction)]
|
||||
pub struct $name {
|
||||
#[clap(value_enum)]
|
||||
identifier: ApplicationIdentifier,
|
||||
@@ -585,7 +596,7 @@ gen_application_target_subcommand_args! {
|
||||
RemoveTitleBar,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct InitialWorkspaceRule {
|
||||
#[clap(value_enum)]
|
||||
identifier: ApplicationIdentifier,
|
||||
@@ -597,7 +608,7 @@ struct InitialWorkspaceRule {
|
||||
workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct InitialNamedWorkspaceRule {
|
||||
#[clap(value_enum)]
|
||||
identifier: ApplicationIdentifier,
|
||||
@@ -607,7 +618,7 @@ struct InitialNamedWorkspaceRule {
|
||||
workspace: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct WorkspaceRule {
|
||||
#[clap(value_enum)]
|
||||
identifier: ApplicationIdentifier,
|
||||
@@ -619,7 +630,7 @@ struct WorkspaceRule {
|
||||
workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct NamedWorkspaceRule {
|
||||
#[clap(value_enum)]
|
||||
identifier: ApplicationIdentifier,
|
||||
@@ -629,13 +640,13 @@ struct NamedWorkspaceRule {
|
||||
workspace: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct ToggleFocusFollowsMouse {
|
||||
#[clap(value_enum, short, long, default_value = "windows")]
|
||||
implementation: FocusFollowsMouseImplementation,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct FocusFollowsMouse {
|
||||
#[clap(value_enum, short, long, default_value = "windows")]
|
||||
implementation: FocusFollowsMouseImplementation,
|
||||
@@ -643,25 +654,13 @@ struct FocusFollowsMouse {
|
||||
boolean_state: BooleanState,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct Border {
|
||||
#[clap(value_enum)]
|
||||
boolean_state: BooleanState,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Transparency {
|
||||
#[clap(value_enum)]
|
||||
boolean_state: BooleanState,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct TransparencyAlpha {
|
||||
/// Alpha
|
||||
alpha: u8,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct BorderColour {
|
||||
#[clap(value_enum, short, long, default_value = "single")]
|
||||
window_kind: WindowKind,
|
||||
@@ -673,19 +672,19 @@ struct BorderColour {
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct BorderWidth {
|
||||
/// Desired width of the window border
|
||||
width: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct BorderOffset {
|
||||
/// Desired offset of the window border
|
||||
offset: i32,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
struct Start {
|
||||
/// Allow the use of komorebi's custom focus-follows-mouse implementation
|
||||
@@ -708,56 +707,56 @@ struct Start {
|
||||
ahk: bool,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct Stop {
|
||||
/// Stop whkd if it is running as a background process
|
||||
#[clap(long)]
|
||||
whkd: bool,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct SaveResize {
|
||||
/// File to which the resize layout dimensions should be saved
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct LoadResize {
|
||||
/// File from which the resize layout dimensions should be loaded
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct LoadCustomLayout {
|
||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct SubscribeSocket {
|
||||
/// Name of the socket to send event notifications to
|
||||
socket: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct UnsubscribeSocket {
|
||||
/// Name of the socket to stop sending event notifications to
|
||||
socket: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct SubscribePipe {
|
||||
/// Name of the pipe to send event notifications to (without "\\.\pipe\" prepended)
|
||||
named_pipe: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct UnsubscribePipe {
|
||||
/// Name of the pipe to stop sending event notifications to (without "\\.\pipe\" prepended)
|
||||
named_pipe: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct AhkAppSpecificConfiguration {
|
||||
/// YAML file from which the application-specific configurations should be loaded
|
||||
path: PathBuf,
|
||||
@@ -765,7 +764,7 @@ struct AhkAppSpecificConfiguration {
|
||||
override_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct PwshAppSpecificConfiguration {
|
||||
/// YAML file from which the application-specific configurations should be loaded
|
||||
path: PathBuf,
|
||||
@@ -773,19 +772,19 @@ struct PwshAppSpecificConfiguration {
|
||||
override_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct FormatAppSpecificConfiguration {
|
||||
/// YAML file from which the application-specific configurations should be loaded
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct AltFocusHack {
|
||||
#[clap(value_enum)]
|
||||
boolean_state: BooleanState,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkFunction)]
|
||||
struct EnableAutostart {
|
||||
/// Path to a static configuration JSON file
|
||||
#[clap(action, short, long)]
|
||||
@@ -808,7 +807,7 @@ struct Opts {
|
||||
subcmd: SubCommand,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Parser, AhkLibrary)]
|
||||
enum SubCommand {
|
||||
#[clap(hide = true)]
|
||||
Docgen,
|
||||
@@ -834,9 +833,6 @@ enum SubCommand {
|
||||
Gui,
|
||||
/// Show a JSON representation of visible windows
|
||||
VisibleWindows,
|
||||
/// Show information about connected monitors
|
||||
#[clap(alias = "monitor-info")]
|
||||
MonitorInformation,
|
||||
/// Query the current window manager state
|
||||
#[clap(arg_required_else_help = true)]
|
||||
Query(Query),
|
||||
@@ -891,10 +887,6 @@ enum SubCommand {
|
||||
/// Stack the focused window in the specified direction
|
||||
#[clap(arg_required_else_help = true)]
|
||||
Stack(Stack),
|
||||
/// Stack all windows on the focused workspace
|
||||
StackAll,
|
||||
/// Unstack all windows in the focused container
|
||||
UnstackAll,
|
||||
/// Resize the focused window in the specified direction
|
||||
#[clap(arg_required_else_help = true)]
|
||||
#[clap(alias = "resize")]
|
||||
@@ -1176,12 +1168,6 @@ enum SubCommand {
|
||||
#[clap(arg_required_else_help = true)]
|
||||
#[clap(alias = "active-window-border-offset")]
|
||||
BorderOffset(BorderOffset),
|
||||
/// Enable or disable transparency for unfocused windows
|
||||
#[clap(arg_required_else_help = true)]
|
||||
Transparency(Transparency),
|
||||
/// Set the alpha value for unfocused window transparency
|
||||
#[clap(arg_required_else_help = true)]
|
||||
TransparencyAlpha(TransparencyAlpha),
|
||||
/// Enable or disable focus follows mouse for the operating system
|
||||
#[clap(arg_required_else_help = true)]
|
||||
FocusFollowsMouse(FocusFollowsMouse),
|
||||
@@ -1193,6 +1179,8 @@ enum SubCommand {
|
||||
MouseFollowsFocus(MouseFollowsFocus),
|
||||
/// Toggle mouse follows focus on all workspaces
|
||||
ToggleMouseFollowsFocus,
|
||||
/// Generate a library of AutoHotKey helper functions
|
||||
AhkLibrary,
|
||||
/// Generate common app-specific configurations and fixes to use in komorebi.ahk
|
||||
#[clap(arg_required_else_help = true)]
|
||||
#[clap(alias = "ahk-asc")]
|
||||
@@ -1302,25 +1290,21 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
SubCommand::Quickstart => {
|
||||
let home_dir = dirs::home_dir().expect("could not find home dir");
|
||||
let config_dir = home_dir.join(".config");
|
||||
let local_appdata_dir = data_local_dir().expect("could not find localdata dir");
|
||||
let data_dir = local_appdata_dir.join("komorebi");
|
||||
std::fs::create_dir_all(&*WHKD_CONFIG_DIR)?;
|
||||
std::fs::create_dir_all(&*HOME_DIR)?;
|
||||
std::fs::create_dir_all(&config_dir)?;
|
||||
std::fs::create_dir_all(data_dir)?;
|
||||
|
||||
let mut komorebi_json = include_str!("../../docs/komorebi.example.json").to_string();
|
||||
if std::env::var("KOMOREBI_CONFIG_HOME").is_ok() {
|
||||
komorebi_json =
|
||||
komorebi_json.replace("Env:USERPROFILE", "Env:KOMOREBI_CONFIG_HOME");
|
||||
}
|
||||
|
||||
let komorebi_json = include_str!("../../docs/komorebi.example.json");
|
||||
std::fs::write(HOME_DIR.join("komorebi.json"), komorebi_json)?;
|
||||
|
||||
let applications_yaml = include_str!("../applications.yaml");
|
||||
std::fs::write(HOME_DIR.join("applications.yaml"), applications_yaml)?;
|
||||
|
||||
let whkdrc = include_str!("../../docs/whkdrc.sample");
|
||||
std::fs::write(WHKD_CONFIG_DIR.join("whkdrc"), whkdrc)?;
|
||||
std::fs::write(config_dir.join("whkdrc"), whkdrc)?;
|
||||
|
||||
println!("Example ~/komorebi.json, ~/.config/whkdrc and latest ~/applications.yaml files downloaded");
|
||||
println!("You can now run komorebic start --whkd");
|
||||
@@ -1480,8 +1464,37 @@ fn main() -> Result<()> {
|
||||
println!("{}", whkdrc.display());
|
||||
}
|
||||
}
|
||||
SubCommand::AhkLibrary => {
|
||||
let library = HOME_DIR.join("komorebic.lib.ahk");
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(library.clone())?;
|
||||
|
||||
let output: String = SubCommand::generate_ahk_library();
|
||||
let fixed_id = output.replace("%id%", "\"%id%\"");
|
||||
let fixed_stop_def = fixed_id.replace("Stop(whkd)", "Stop()");
|
||||
let fixed_output =
|
||||
fixed_stop_def.replace("komorebic.exe stop --whkd %whkd%", "komorebic.exe stop");
|
||||
|
||||
file.write_all(fixed_output.as_bytes())?;
|
||||
|
||||
println!(
|
||||
"\nAHKv1 helper library for komorebic written to {}",
|
||||
library.to_string_lossy()
|
||||
);
|
||||
|
||||
println!("\nYou can convert this file to AHKv2 syntax using https://github.com/mmikeww/AHK-v2-script-converter");
|
||||
|
||||
println!(
|
||||
"\nYou can include the converted library at the top of your komorebi.ahk config with this line:"
|
||||
);
|
||||
|
||||
println!("\n#Include komorebic.lib.ahk");
|
||||
}
|
||||
SubCommand::Log => {
|
||||
let timestamp = Utc::now().format("%Y-%m-%d").to_string();
|
||||
let timestamp = Local::now().format("%Y-%m-%d").to_string();
|
||||
let color_log = std::env::temp_dir().join(format!("komorebi.log.{timestamp}"));
|
||||
let file = TailedFile::new(File::open(color_log)?);
|
||||
let locked = file.lock();
|
||||
@@ -2045,15 +2058,9 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
|
||||
SubCommand::Stack(arg) => {
|
||||
send_message(&SocketMessage::StackWindow(arg.operation_direction).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::StackAll => {
|
||||
send_message(&SocketMessage::StackAll.as_bytes()?)?;
|
||||
}
|
||||
SubCommand::Unstack => {
|
||||
send_message(&SocketMessage::UnstackWindow.as_bytes()?)?;
|
||||
}
|
||||
SubCommand::UnstackAll => {
|
||||
send_message(&SocketMessage::UnstackAll.as_bytes()?)?;
|
||||
}
|
||||
SubCommand::CycleStack(arg) => {
|
||||
send_message(&SocketMessage::CycleStack(arg.cycle_direction).as_bytes()?)?;
|
||||
}
|
||||
@@ -2151,9 +2158,6 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
|
||||
SubCommand::VisibleWindows => {
|
||||
print_query(&SocketMessage::VisibleWindows.as_bytes()?);
|
||||
}
|
||||
SubCommand::MonitorInformation => {
|
||||
print_query(&SocketMessage::MonitorInformation.as_bytes()?);
|
||||
}
|
||||
SubCommand::Query(arg) => {
|
||||
print_query(&SocketMessage::Query(arg.state_query).as_bytes()?);
|
||||
}
|
||||
@@ -2269,12 +2273,6 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
|
||||
SubCommand::BorderOffset(arg) => {
|
||||
send_message(&SocketMessage::BorderOffset(arg.offset).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::Transparency(arg) => {
|
||||
send_message(&SocketMessage::Transparency(arg.boolean_state.into()).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::TransparencyAlpha(arg) => {
|
||||
send_message(&SocketMessage::TransparencyAlpha(arg.alpha).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::ResizeDelta(arg) => {
|
||||
send_message(&SocketMessage::ResizeDelta(arg.pixels).as_bytes()?)?;
|
||||
}
|
||||
@@ -2417,11 +2415,6 @@ fn show_window(hwnd: HWND, command: SHOW_WINDOW_CMD) {
|
||||
unsafe { ShowWindow(hwnd, command) };
|
||||
}
|
||||
|
||||
fn remove_transparency(hwnd: HWND) {
|
||||
let _ = komorebi_client::Window::from(hwnd.0).opaque();
|
||||
}
|
||||
|
||||
fn restore_window(hwnd: HWND) {
|
||||
show_window(hwnd, SW_RESTORE);
|
||||
remove_transparency(hwnd);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ nav:
|
||||
- Troubleshooting: troubleshooting.md
|
||||
- Common workflows:
|
||||
- common-workflows/komorebi-config-home.md
|
||||
- common-workflows/autohotkey.md
|
||||
- common-workflows/borders.md
|
||||
- common-workflows/stackbar.md
|
||||
- common-workflows/remove-gaps.md
|
||||
@@ -68,7 +67,7 @@ nav:
|
||||
- common-workflows/mouse-follows-focus.md
|
||||
- common-workflows/custom-layouts.md
|
||||
- common-workflows/dynamic-layout-switching.md
|
||||
- common-workflows/set-display-index.md
|
||||
- common-workflows/autohotkey.md
|
||||
- Release notes:
|
||||
- release/v0-1-22.md
|
||||
- Configuration reference: https://komorebi.lgug2z.com/schema
|
||||
@@ -83,7 +82,6 @@ nav:
|
||||
- cli/global-state.md
|
||||
- cli/gui.md
|
||||
- cli/visible-windows.md
|
||||
- cli/monitor-information.md
|
||||
- cli/query.md
|
||||
- cli/subscribe-socket.md
|
||||
- cli/unsubscribe-socket.md
|
||||
@@ -102,8 +100,6 @@ nav:
|
||||
- cli/cycle-focus.md
|
||||
- cli/cycle-move.md
|
||||
- cli/stack.md
|
||||
- cli/stack-all.md
|
||||
- cli/unstack-all.md
|
||||
- cli/resize-edge.md
|
||||
- cli/resize-axis.md
|
||||
- cli/unstack.md
|
||||
@@ -200,12 +196,11 @@ nav:
|
||||
- cli/border-colour.md
|
||||
- cli/border-width.md
|
||||
- cli/border-offset.md
|
||||
- cli/transparency.md
|
||||
- cli/transparency-alpha.md
|
||||
- cli/focus-follows-mouse.md
|
||||
- cli/toggle-focus-follows-mouse.md
|
||||
- cli/mouse-follows-focus.md
|
||||
- cli/toggle-mouse-follows-focus.md
|
||||
- cli/ahk-library.md
|
||||
- cli/ahk-app-specific-configuration.md
|
||||
- cli/pwsh-app-specific-configuration.md
|
||||
- cli/format-app-specific-configuration.md
|
||||
|
||||
12
schema.json
12
schema.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "StaticConfig",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.27`",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.26`",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"app_specific_configuration_path": {
|
||||
@@ -1183,16 +1183,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"transparency": {
|
||||
"description": "Add transparency to unfocused windows (default: false)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"transparency_alpha": {
|
||||
"description": "Alpha value for unfocused window transparency [[0-255]] (default: 200)",
|
||||
"type": "integer",
|
||||
"format": "uint8",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"tray_and_multi_window_applications": {
|
||||
"description": "Identify tray and multi-window applications",
|
||||
"type": "array",
|
||||
|
||||
Reference in New Issue
Block a user