mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-02-12 16:27:40 +01:00
Compare commits
32 Commits
v0.1.19
...
animate-wi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23cc38b1d3 | ||
|
|
a8aad69ecb | ||
|
|
e24835a4ae | ||
|
|
50b12431fa | ||
|
|
95df970860 | ||
|
|
9d1c0ad790 | ||
|
|
d9eea34266 | ||
|
|
7078b065f4 | ||
|
|
900051a24b | ||
|
|
1c589491a9 | ||
|
|
5a99a688a6 | ||
|
|
8980e3b16e | ||
|
|
ca9eccf247 | ||
|
|
e04ba0e033 | ||
|
|
8afad7246f | ||
|
|
8e9d63cd36 | ||
|
|
a673c69744 | ||
|
|
c0b65677a2 | ||
|
|
0cf7147e39 | ||
|
|
b39e65642b | ||
|
|
a68f3843b7 | ||
|
|
b3e989c6c7 | ||
|
|
4534a1511e | ||
|
|
1f87e3acd2 | ||
|
|
f67d0c7b9b | ||
|
|
aa0277d58c | ||
|
|
42ac13e0bd | ||
|
|
2a1d87d41b | ||
|
|
0d1595e543 | ||
|
|
4283dfb0ba | ||
|
|
2a6aa09b07 | ||
|
|
8c6bd13511 |
@@ -26,6 +26,15 @@ builds:
|
||||
post:
|
||||
- mkdir -p dist/windows_amd64
|
||||
- cp ".\target\x86_64-pc-windows-msvc\release\komorebic.exe" ".\dist\komorebic_windows_amd64_v1\komorebic.exe"
|
||||
- id: komorebic-no-console
|
||||
main: dummy.go
|
||||
goos: ["windows"]
|
||||
goarch: ["amd64"]
|
||||
binary: komorebic-no-console
|
||||
hooks:
|
||||
post:
|
||||
- mkdir -p dist/windows_amd64
|
||||
- cp ".\target\x86_64-pc-windows-msvc\release\komorebic-no-console.exe" ".\dist\komorebic_no_console_windows_amd64_v1\komorebic-no-console.exe"
|
||||
|
||||
archives:
|
||||
- name_template: "{{ .ProjectName }}-{{ .Version }}-x86_64-pc-windows-msvc"
|
||||
|
||||
282
Cargo.lock
generated
282
Cargo.lock
generated
@@ -148,9 +148,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.8"
|
||||
version = "4.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
|
||||
checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -158,9 +158,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.8"
|
||||
version = "4.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
|
||||
checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -204,9 +204,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
|
||||
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
@@ -222,9 +222,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -232,9 +232,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
@@ -328,6 +328,12 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.16"
|
||||
@@ -357,19 +363,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.6"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||
checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
@@ -422,9 +428,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
@@ -546,15 +552,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.21"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
|
||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -562,7 +568,7 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -571,15 +577,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -614,9 +614,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150"
|
||||
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -685,9 +685,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
@@ -699,16 +699,6 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
@@ -716,7 +706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.2",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -762,9 +752,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
|
||||
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -815,7 +805,7 @@ dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"winput",
|
||||
"winreg 0.51.0",
|
||||
"winreg 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -824,6 +814,8 @@ version = "0.1.19"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -840,6 +832,7 @@ dependencies = [
|
||||
"color-eyre",
|
||||
"derive-ahk",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"fs-tail",
|
||||
"heck",
|
||||
"komorebi-core",
|
||||
@@ -856,6 +849,10 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.19"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -887,9 +884,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1122,9 +1119,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.59"
|
||||
version = "0.10.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
|
||||
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -1154,9 +1151,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.95"
|
||||
version = "0.9.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
|
||||
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1216,7 +1213,7 @@ dependencies = [
|
||||
"redox_syscall 0.4.1",
|
||||
"smallvec",
|
||||
"thread-id",
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1227,9 +1224,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
@@ -1238,7 +1235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.1.0",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1303,9 +1300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1488,15 +1485,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
version = "0.38.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1531,9 +1528,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
|
||||
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
@@ -1543,9 +1540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
|
||||
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1584,18 +1581,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1642,7 +1639,7 @@ version = "0.9.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@@ -1745,9 +1742,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.29.10"
|
||||
version = "0.29.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5"
|
||||
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"core-foundation-sys",
|
||||
@@ -1945,11 +1942,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-appender"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
|
||||
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
@@ -1987,9 +1985,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.4"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
@@ -1998,9 +1996,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
@@ -2059,9 +2057,9 @@ checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@@ -2119,9 +2117,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
|
||||
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -2129,9 +2127,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
|
||||
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
@@ -2144,9 +2142,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.38"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
||||
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
@@ -2156,9 +2154,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
|
||||
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -2166,9 +2164,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2179,15 +2177,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.88"
|
||||
version = "0.2.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
|
||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
|
||||
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -2251,30 +2249,30 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb2b158efec5af20d8846836622f50a87e6556b9153a42772fa047f773c0e555"
|
||||
checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2283,9 +2281,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0546e63e1ce64c04403d2311fa0e3ab5ae3a367bd524b4a38d8d8d18c70cfa76"
|
||||
checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2313,7 +2311,16 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2331,6 +2338,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@@ -2343,6 +2365,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -2355,6 +2383,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
@@ -2367,6 +2401,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -2379,6 +2419,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
@@ -2391,6 +2437,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@@ -2403,6 +2455,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -2415,6 +2473,12 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winput"
|
||||
version = "0.2.5"
|
||||
@@ -2436,9 +2500,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.51.0"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc"
|
||||
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"windows-sys 0.48.0",
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -6,14 +6,18 @@ members = [
|
||||
"komorebi",
|
||||
"komorebi-core",
|
||||
"komorebic",
|
||||
"komorebic-no-console",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
windows-interface = { version = "0.51" }
|
||||
windows-implement = { version = "0.51" }
|
||||
windows-interface = { version = "0.52" }
|
||||
windows-implement = { version = "0.52" }
|
||||
dunce = "1"
|
||||
dirs = "5"
|
||||
color-eyre = "0.6"
|
||||
|
||||
[workspace.dependencies.windows]
|
||||
version = "0.51"
|
||||
version = "0.52"
|
||||
features = [
|
||||
"implement",
|
||||
"Win32_System_Com",
|
||||
|
||||
33
README.md
33
README.md
@@ -3,9 +3,6 @@
|
||||
Tiling Window Management for Windows.
|
||||
|
||||
<p>
|
||||
<a href="https://bdsmovement.net">
|
||||
<img alt="Stand With Palestine" src="https://img.shields.io/badge/Stand_With_Palestine-%F0%9F%87%B5%F0%9F%87%B8-white">
|
||||
</a>
|
||||
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/LGUG2Z/komorebi/.github/workflows/windows.yaml">
|
||||
<img alt="GitHub" src="https://img.shields.io/github/license/LGUG2Z/komorebi">
|
||||
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/LGUG2Z/komorebi/total">
|
||||
@@ -16,11 +13,14 @@ Tiling Window Management for Windows.
|
||||
<a href="https://github.com/sponsors/LGUG2Z">
|
||||
<img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/LGUG2Z">
|
||||
</a>
|
||||
<a href="https://ko-fi.com/lgug2z">
|
||||
<img alt="Ko-fi" src="https://img.shields.io/badge/kofi-tip-green">
|
||||
</a>
|
||||
<a href="https://notado.app/feeds/jado/software-development">
|
||||
<img alt="Notado Feed" src="https://img.shields.io/badge/Notado-Subscribe-informational">
|
||||
</a>
|
||||
<a href="https://twitter.com/LGUG2Z">
|
||||
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/LGUG2Z?style=flat">
|
||||
<a href="https://www.youtube.com/channel/UCeai3-do-9O4MNy9_xjO6mg?sub_confirmation=1">
|
||||
<img alt="YouTube" src="https://img.shields.io/youtube/channel/subscribers/UCeai3-do-9O4MNy9_xjO6mg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -88,21 +88,20 @@ Articles, blog posts, demos, and videos about _komorebi_ can be added to this li
|
||||
_komorebi_ is a free and open-source project, and one that encourages you to make charitable donations if
|
||||
you find the software to be useful and have the financial means.
|
||||
|
||||
I encourage you to make a charitable donation
|
||||
to [Fresh Start Refugee](https://www.freshstartrefugee.org/donate) before
|
||||
you consider sponsoring me on GitHub.
|
||||
I encourage you to make a charitable donation to the [Palestine Children's
|
||||
Relief Fund](https://pcrf1.app.neoncrm.com/forms/gaza-recovery) and [Fresh
|
||||
Start Refugee](https://www.freshstartrefugee.org/donate) before you consider
|
||||
sponsoring me on GitHub.
|
||||
|
||||
## GitHub Sponsors
|
||||
## Project Sponsorship
|
||||
|
||||
[GitHub Sponsors is enabled for this project](https://github.com/sponsors/LGUG2Z). Users who sponsor my work
|
||||
on `komorebi` at any of the predefined monthly tiers will be given access to a private fork of this repository where I
|
||||
push features-in-progress that are not yet quite ready to be pushed on the main repository.
|
||||
[GitHub Sponsors is enabled for this
|
||||
project](https://github.com/sponsors/LGUG2Z). Unfortunately I don't have
|
||||
anything specific to offer besides my gratitude and shout outs at the end of
|
||||
_komorebi_ live development videos and tutorials.
|
||||
|
||||
There will never be any feature of `komorebi` that is gated behind sponsorship; every new feature will always be
|
||||
available for free in the public repository once it meets the requisite level of code quality and completion.
|
||||
|
||||
Features-in-progress that are available in early access will be tagged in the issues with
|
||||
an ["early access" label](https://github.com/LGUG2Z/komorebi/issues?q=is%3Aopen+is%3Aissue+label%3A%22early+access%22).
|
||||
If you would like to tip or sponsor the project but are unable to use GitHub
|
||||
Sponsors, you may also sponsor through [Ko-fi](https://ko-fi.com/lgug2z).
|
||||
|
||||
## Demonstrations
|
||||
|
||||
|
||||
23
justfile
23
justfile
@@ -13,24 +13,23 @@ fmt:
|
||||
prettier --write .github/FUNDING.yml
|
||||
prettier --write .github/workflows/windows.yaml
|
||||
|
||||
install-komorebic:
|
||||
cargo +stable install --path komorebic --locked
|
||||
install-target target:
|
||||
cargo +stable install --path {{ target }} --locked
|
||||
|
||||
install-komorebi:
|
||||
cargo +stable install --path komorebi --locked
|
||||
|
||||
install:
|
||||
just install-komorebic
|
||||
just install-komorebi
|
||||
komorebic ahk-asc '~/komorebi-application-specific-configuration/applications.yaml'
|
||||
komorebic pwsh-asc '~/komorebi-application-specific-configuration/applications.yaml'
|
||||
prepare:
|
||||
komorebic ahk-asc '~/.config/komorebi/applications.yaml'
|
||||
komorebic pwsh-asc '~/.config/komorebi/applications.yaml'
|
||||
cat '~/.config/komorebi/komorebi.generated.ps1' >komorebi.generated.ps1
|
||||
cat '~/.config/komorebi/komorebi.generated.ahk' >komorebi.generated.ahk
|
||||
cat '~/.config/komorebi/komorebic.lib_newV2.ahk' >komorebic.lib.ahk
|
||||
|
||||
install:
|
||||
just install-target komorebic
|
||||
just install-target komorebic-no-console
|
||||
just install-target komorebi
|
||||
|
||||
run:
|
||||
just install-komorebic
|
||||
cargo +stable run --bin komorebi --locked -- -a
|
||||
cargo +stable run --bin komorebi --locked
|
||||
|
||||
warn $RUST_LOG="warn":
|
||||
just run
|
||||
|
||||
@@ -7,10 +7,12 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
color-eyre = "0.6"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_yaml = "0.9"
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
color-eyre = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
|
||||
43
komorebi-core/src/animation.rs
Normal file
43
komorebi-core/src/animation.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use clap::ValueEnum;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum EaseEnum {
|
||||
Linear,
|
||||
EaseInSine,
|
||||
EaseOutSine,
|
||||
EaseInOutSine,
|
||||
EaseInQuad,
|
||||
EaseOutQuad,
|
||||
EaseInOutQuad,
|
||||
EaseInCubic,
|
||||
EaseInOutCubic,
|
||||
EaseInQuart,
|
||||
EaseOutQuart,
|
||||
EaseInOutQuart,
|
||||
EaseInQuint,
|
||||
EaseOutQuint,
|
||||
EaseInOutQuint,
|
||||
EaseInExpo,
|
||||
EaseOutExpo,
|
||||
EaseInOutExpo,
|
||||
EaseInCirc,
|
||||
EaseOutCirc,
|
||||
EaseInOutCirc,
|
||||
EaseInBack,
|
||||
EaseOutBack,
|
||||
EaseInOutBack,
|
||||
EaseInElastic,
|
||||
EaseOutElastic,
|
||||
EaseInOutElastic,
|
||||
EaseInBounce,
|
||||
EaseOutBounce,
|
||||
EaseInOutBounce,
|
||||
}
|
||||
@@ -98,6 +98,19 @@ pub struct ApplicationConfiguration {
|
||||
pub float_identifiers: Option<Vec<IdWithIdentifierAndComment>>,
|
||||
}
|
||||
|
||||
impl ApplicationConfiguration {
|
||||
pub fn populate_default_matching_strategies(&mut self) {
|
||||
if self.identifier.matching_strategy.is_none() {
|
||||
match self.identifier.kind {
|
||||
ApplicationIdentifier::Exe => {
|
||||
self.identifier.matching_strategy = Option::from(MatchingStrategy::Equals);
|
||||
}
|
||||
ApplicationIdentifier::Class | ApplicationIdentifier::Title => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ApplicationConfigurationGenerator;
|
||||
|
||||
@@ -108,6 +121,10 @@ impl ApplicationConfigurationGenerator {
|
||||
|
||||
pub fn format(content: &str) -> Result<String> {
|
||||
let mut cfgen = Self::load(content)?;
|
||||
for cfg in &mut cfgen {
|
||||
cfg.populate_default_matching_strategies();
|
||||
}
|
||||
|
||||
cfgen.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
Ok(serde_yaml::to_string(&cfgen)?)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@ use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
@@ -31,23 +32,20 @@ impl DerefMut for CustomLayout {
|
||||
}
|
||||
|
||||
impl CustomLayout {
|
||||
pub fn from_path_buf(path: PathBuf) -> Result<Self> {
|
||||
let invalid_filetype = anyhow!("custom layouts must be json or yaml files");
|
||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||
let path = path.as_ref();
|
||||
let layout: Self = match path.extension() {
|
||||
Some(extension) => {
|
||||
if extension == "yaml" || extension == "yml" {
|
||||
serde_yaml::from_reader(BufReader::new(File::open(path)?))?
|
||||
} else if extension == "json" {
|
||||
serde_json::from_reader(BufReader::new(File::open(path)?))?
|
||||
} else {
|
||||
return Err(invalid_filetype);
|
||||
}
|
||||
Some(extension) if extension == "yaml" || extension == "yml" => {
|
||||
serde_json::from_reader(BufReader::new(File::open(path)?))?
|
||||
}
|
||||
None => return Err(invalid_filetype),
|
||||
Some(extension) if extension == "json" => {
|
||||
serde_json::from_reader(BufReader::new(File::open(path)?))?
|
||||
}
|
||||
_ => return Err(anyhow!("custom layouts must be json or yaml files")),
|
||||
};
|
||||
|
||||
if !layout.is_valid() {
|
||||
return Err(anyhow!("the layout file provided was invalid"));
|
||||
bail!("the layout file provided was invalid");
|
||||
}
|
||||
|
||||
Ok(layout)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc, clippy::use_self)]
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::ValueEnum;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
@@ -12,6 +14,7 @@ use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::EnumString;
|
||||
|
||||
pub use animation::EaseEnum;
|
||||
pub use arrangement::Arrangement;
|
||||
pub use arrangement::Axis;
|
||||
pub use custom_layout::CustomLayout;
|
||||
@@ -22,6 +25,7 @@ pub use layout::Layout;
|
||||
pub use operation_direction::OperationDirection;
|
||||
pub use rect::Rect;
|
||||
|
||||
pub mod animation;
|
||||
pub mod arrangement;
|
||||
pub mod config_generation;
|
||||
pub mod custom_layout;
|
||||
@@ -102,8 +106,10 @@ pub enum SocketMessage {
|
||||
FocusNamedWorkspace(String),
|
||||
ContainerPadding(usize, usize, i32),
|
||||
NamedWorkspaceContainerPadding(String, i32),
|
||||
FocusedWorkspaceContainerPadding(i32),
|
||||
WorkspacePadding(usize, usize, i32),
|
||||
NamedWorkspacePadding(String, i32),
|
||||
FocusedWorkspacePadding(i32),
|
||||
WorkspaceTiling(usize, usize, bool),
|
||||
NamedWorkspaceTiling(String, bool),
|
||||
WorkspaceName(usize, usize, String),
|
||||
@@ -123,6 +129,9 @@ pub enum SocketMessage {
|
||||
WatchConfiguration(bool),
|
||||
CompleteConfiguration,
|
||||
AltFocusHack(bool),
|
||||
Animation(bool),
|
||||
AnimationDuration(u64),
|
||||
AnimationEase(EaseEnum),
|
||||
ActiveWindowBorder(bool),
|
||||
ActiveWindowBorderColour(WindowKind, u32, u32, u32),
|
||||
ActiveWindowBorderWidth(i32),
|
||||
@@ -151,6 +160,7 @@ pub enum SocketMessage {
|
||||
ToggleTitleBars,
|
||||
AddSubscriber(String),
|
||||
RemoveSubscriber(String),
|
||||
ApplicationSpecificConfigurationSchema,
|
||||
NotificationSchema,
|
||||
SocketSchema,
|
||||
StaticConfigSchema,
|
||||
@@ -296,3 +306,36 @@ impl Sizing {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_home_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||
let mut resolved_path = PathBuf::new();
|
||||
let mut resolved = false;
|
||||
for c in path.as_ref().components() {
|
||||
match c {
|
||||
std::path::Component::Normal(c)
|
||||
if (c == "~" || c == "$Env:USERPROFILE" || c == "$HOME") && !resolved =>
|
||||
{
|
||||
let home = dirs::home_dir().ok_or_else(|| anyhow!("there is no home directory"))?;
|
||||
|
||||
resolved_path.extend(home.components());
|
||||
resolved = true;
|
||||
}
|
||||
|
||||
_ => resolved_path.push(c),
|
||||
}
|
||||
}
|
||||
|
||||
let parent = resolved_path
|
||||
.parent()
|
||||
.ok_or_else(|| anyhow!("cannot parse parent directory"))?;
|
||||
|
||||
Ok(if parent.is_dir() {
|
||||
let file = resolved_path
|
||||
.components()
|
||||
.last()
|
||||
.ok_or_else(|| anyhow!("cannot parse filename"))?;
|
||||
dunce::canonicalize(parent)?.join(file)
|
||||
} else {
|
||||
resolved_path
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,11 +15,9 @@ komorebi-core = { path = "../komorebi-core" }
|
||||
|
||||
bitflags = "2"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
color-eyre = "0.6"
|
||||
crossbeam-channel = "0.5"
|
||||
crossbeam-utils = "0.8"
|
||||
ctrlc = "3"
|
||||
dirs = "5"
|
||||
getset = "0.1"
|
||||
hotwatch = "0.4"
|
||||
lazy_static = "1"
|
||||
@@ -41,10 +39,12 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
uds_windows = "1"
|
||||
which = "5"
|
||||
winput = "0.2"
|
||||
winreg = "0.51"
|
||||
winreg = "0.52"
|
||||
windows-interface = { workspace = true }
|
||||
windows-implement = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
|
||||
[features]
|
||||
deadlock_detection = []
|
||||
|
||||
510
komorebi/src/animation.rs
Normal file
510
komorebi/src/animation.rs
Normal file
@@ -0,0 +1,510 @@
|
||||
use color_eyre::Result;
|
||||
use komorebi_core::EaseEnum;
|
||||
use komorebi_core::Rect;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
|
||||
use std::f64::consts::PI;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::ANIMATION_EASE;
|
||||
|
||||
pub trait Ease {
|
||||
fn evaluate(t: f64) -> f64;
|
||||
}
|
||||
|
||||
pub struct Linear;
|
||||
|
||||
impl Ease for Linear {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInSine;
|
||||
|
||||
impl Ease for EaseInSine {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - f64::cos((t * PI) / 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutSine;
|
||||
|
||||
impl Ease for EaseOutSine {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
f64::sin((t * PI) / 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutSine;
|
||||
|
||||
impl Ease for EaseInOutSine {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
-(f64::cos(PI * t) - 1.0) / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInQuad;
|
||||
|
||||
impl Ease for EaseInQuad {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
t * t
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutQuad;
|
||||
|
||||
impl Ease for EaseOutQuad {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
(1.0 - t).mul_add(-1.0 - t, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutQuad;
|
||||
|
||||
impl Ease for EaseInOutQuad {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
2.0 * t * t
|
||||
} else {
|
||||
1.0 - (-2.0f64).mul_add(t, 2.0).powi(2) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInCubic;
|
||||
|
||||
impl Ease for EaseInCubic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
t * t * t
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutCubic;
|
||||
|
||||
impl Ease for EaseOutCubic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - (1.0 - t).powi(3)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutCubic;
|
||||
|
||||
impl Ease for EaseInOutCubic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
4.0 * t * t * t
|
||||
} else {
|
||||
1.0 - (-2.0f64).mul_add(t, 2.0).powi(3) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInQuart;
|
||||
|
||||
impl Ease for EaseInQuart {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
t * t * t * t
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutQuart;
|
||||
|
||||
impl Ease for EaseOutQuart {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - (1.0 - t).powi(4)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutQuart;
|
||||
|
||||
impl Ease for EaseInOutQuart {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
8.0 * t * t * t * t
|
||||
} else {
|
||||
1.0 - (-2.0f64).mul_add(t, 2.0).powi(4) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInQuint;
|
||||
|
||||
impl Ease for EaseInQuint {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
t * t * t * t * t
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutQuint;
|
||||
|
||||
impl Ease for EaseOutQuint {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - (1.0 - t).powi(5)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutQuint;
|
||||
|
||||
impl Ease for EaseInOutQuint {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
16.0 * t * t * t * t
|
||||
} else {
|
||||
1.0 - (-2.0f64).mul_add(t, 2.0).powi(5) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInExpo;
|
||||
|
||||
impl Ease for EaseInExpo {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t == 0.0 {
|
||||
return t;
|
||||
}
|
||||
|
||||
10.0f64.mul_add(t, -10.0).exp2()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutExpo;
|
||||
|
||||
impl Ease for EaseOutExpo {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if (t - 1.0).abs() < f64::EPSILON {
|
||||
return t;
|
||||
}
|
||||
|
||||
1.0 - (-10.0 * t).exp2()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutExpo;
|
||||
|
||||
impl Ease for EaseInOutExpo {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t == 0.0 || (t - 1.0).abs() < f64::EPSILON {
|
||||
return t;
|
||||
}
|
||||
|
||||
if t < 0.5 {
|
||||
20.0f64.mul_add(t, -10.0).exp2() / 2.0
|
||||
} else {
|
||||
(2.0 - (-20.0f64).mul_add(t, 10.0).exp2()) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInCirc;
|
||||
|
||||
impl Ease for EaseInCirc {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - f64::sqrt(t.mul_add(-t, 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutCirc;
|
||||
|
||||
impl Ease for EaseOutCirc {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
f64::sqrt((t - 1.0).mul_add(-(t - 1.0), 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutCirc;
|
||||
|
||||
impl Ease for EaseInOutCirc {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
(1.0 - f64::sqrt((2.0 * t).mul_add(-(2.0 * t), 1.0))) / 2.0
|
||||
} else {
|
||||
(f64::sqrt(
|
||||
(-2.0f64)
|
||||
.mul_add(t, 2.0)
|
||||
.mul_add(-(-2.0f64).mul_add(t, 2.0), 1.0),
|
||||
) + 1.0)
|
||||
/ 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInBack;
|
||||
|
||||
impl Ease for EaseInBack {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
let c1 = 1.70158;
|
||||
let c3 = c1 + 1.0;
|
||||
|
||||
(c3 * t * t).mul_add(t, -c1 * t * t)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutBack;
|
||||
|
||||
impl Ease for EaseOutBack {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
let c1: f64 = 1.70158;
|
||||
let c3: f64 = c1 + 1.0;
|
||||
|
||||
c1.mul_add((t - 1.0).powi(2), c3.mul_add((t - 1.0).powi(3), 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutBack;
|
||||
|
||||
impl Ease for EaseInOutBack {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
let c1: f64 = 1.70158;
|
||||
let c2: f64 = c1 * 1.525;
|
||||
|
||||
if t < 0.5 {
|
||||
((2.0 * t).powi(2) * ((c2 + 1.0) * 2.0).mul_add(t, -c2)) / 2.0
|
||||
} else {
|
||||
((2.0f64.mul_add(t, -2.0))
|
||||
.powi(2)
|
||||
.mul_add((c2 + 1.0).mul_add(t.mul_add(2.0, -2.0), c2), 2.0))
|
||||
/ 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInElastic;
|
||||
|
||||
impl Ease for EaseInElastic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if (t - 1.0).abs() < f64::EPSILON || t == 0.0 {
|
||||
return t;
|
||||
}
|
||||
|
||||
let c4 = (2.0 * PI) / 3.0;
|
||||
|
||||
-(10.0f64.mul_add(t, -10.0).exp2()) * f64::sin(t.mul_add(10.0, -10.75) * c4)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutElastic;
|
||||
|
||||
impl Ease for EaseOutElastic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if (t - 1.0).abs() < f64::EPSILON || t == 0.0 {
|
||||
return t;
|
||||
}
|
||||
|
||||
let c4 = (2.0 * PI) / 3.0;
|
||||
|
||||
(-10.0 * t)
|
||||
.exp2()
|
||||
.mul_add(f64::sin(t.mul_add(10.0, -0.75) * c4), 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutElastic;
|
||||
|
||||
impl Ease for EaseInOutElastic {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if (t - 1.0).abs() < f64::EPSILON || t == 0.0 {
|
||||
return t;
|
||||
}
|
||||
|
||||
let c5 = (2.0 * PI) / 4.5;
|
||||
|
||||
if t < 0.5 {
|
||||
-(20.0f64.mul_add(t, -10.0).exp2() * f64::sin(20.0f64.mul_add(t, -11.125) * c5)) / 2.0
|
||||
} else {
|
||||
((-20.0f64).mul_add(t, 10.0).exp2() * f64::sin(20.0f64.mul_add(t, -11.125) * c5)) / 2.0
|
||||
+ 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInBounce;
|
||||
|
||||
impl Ease for EaseInBounce {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
1.0 - EaseOutBounce::evaluate(1.0 - t)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseOutBounce;
|
||||
|
||||
impl Ease for EaseOutBounce {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
let mut time = t;
|
||||
let n1 = 7.5625;
|
||||
let d1 = 2.75;
|
||||
|
||||
if t < 1.0 / d1 {
|
||||
n1 * time * time
|
||||
} else if time < 2.0 / d1 {
|
||||
time -= 1.5 / d1;
|
||||
(n1 * time).mul_add(time, 0.75)
|
||||
} else if time < 2.5 / d1 {
|
||||
time -= 2.25 / d1;
|
||||
(n1 * time).mul_add(time, 0.9375)
|
||||
} else {
|
||||
time -= 2.625 / d1;
|
||||
(n1 * time).mul_add(time, 0.984_375)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EaseInOutBounce;
|
||||
|
||||
impl Ease for EaseInOutBounce {
|
||||
fn evaluate(t: f64) -> f64 {
|
||||
if t < 0.5 {
|
||||
(1.0 - EaseOutBounce::evaluate(2.0f64.mul_add(-t, 1.0))) / 2.0
|
||||
} else {
|
||||
(1.0 + EaseOutBounce::evaluate(2.0f64.mul_add(t, -1.0))) / 2.0
|
||||
}
|
||||
}
|
||||
}
|
||||
fn apply_ease_func(t: f64) -> f64 {
|
||||
let ease = *ANIMATION_EASE.lock();
|
||||
|
||||
match ease {
|
||||
EaseEnum::Linear => Linear::evaluate(t),
|
||||
EaseEnum::EaseInSine => EaseInSine::evaluate(t),
|
||||
EaseEnum::EaseOutSine => EaseOutSine::evaluate(t),
|
||||
EaseEnum::EaseInOutSine => EaseInOutSine::evaluate(t),
|
||||
EaseEnum::EaseInQuad => EaseInQuad::evaluate(t),
|
||||
EaseEnum::EaseOutQuad => EaseOutQuad::evaluate(t),
|
||||
EaseEnum::EaseInOutQuad => EaseInOutQuad::evaluate(t),
|
||||
EaseEnum::EaseInCubic => EaseInCubic::evaluate(t),
|
||||
EaseEnum::EaseInOutCubic => EaseInOutCubic::evaluate(t),
|
||||
EaseEnum::EaseInQuart => EaseInQuart::evaluate(t),
|
||||
EaseEnum::EaseOutQuart => EaseOutQuart::evaluate(t),
|
||||
EaseEnum::EaseInOutQuart => EaseInOutQuart::evaluate(t),
|
||||
EaseEnum::EaseInQuint => EaseInQuint::evaluate(t),
|
||||
EaseEnum::EaseOutQuint => EaseOutQuint::evaluate(t),
|
||||
EaseEnum::EaseInOutQuint => EaseInOutQuint::evaluate(t),
|
||||
EaseEnum::EaseInExpo => EaseInExpo::evaluate(t),
|
||||
EaseEnum::EaseOutExpo => EaseOutExpo::evaluate(t),
|
||||
EaseEnum::EaseInOutExpo => EaseInOutExpo::evaluate(t),
|
||||
EaseEnum::EaseInCirc => EaseInCirc::evaluate(t),
|
||||
EaseEnum::EaseOutCirc => EaseOutCirc::evaluate(t),
|
||||
EaseEnum::EaseInOutCirc => EaseInOutCirc::evaluate(t),
|
||||
EaseEnum::EaseInBack => EaseInBack::evaluate(t),
|
||||
EaseEnum::EaseOutBack => EaseOutBack::evaluate(t),
|
||||
EaseEnum::EaseInOutBack => EaseInOutBack::evaluate(t),
|
||||
EaseEnum::EaseInElastic => EaseInElastic::evaluate(t),
|
||||
EaseEnum::EaseOutElastic => EaseOutElastic::evaluate(t),
|
||||
EaseEnum::EaseInOutElastic => EaseInOutElastic::evaluate(t),
|
||||
EaseEnum::EaseInBounce => EaseInBounce::evaluate(t),
|
||||
EaseEnum::EaseOutBounce => EaseOutBounce::evaluate(t),
|
||||
EaseEnum::EaseInOutBounce => EaseInOutBounce::evaluate(t),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, JsonSchema)]
|
||||
pub struct Animation {
|
||||
// is_cancel: AtomicBool,
|
||||
// pub in_progress: AtomicBool,
|
||||
is_cancel: bool,
|
||||
pub in_progress: bool,
|
||||
}
|
||||
|
||||
// impl Default for Animation {
|
||||
// fn default() -> Self {
|
||||
// Animation {
|
||||
// // I'm not sure if this is the right way to do it
|
||||
// // I've tried to use Arc<Mutex<bool>> but it dooes not implement Copy trait
|
||||
// // and I dont want to rewrite everything cause I'm not experienced with rust
|
||||
// // Down here you can see the idea I've tried to achive like in any other OOP language
|
||||
// // My thought is that in order to prevent Google Chrome breaking render window
|
||||
// // I need to cancel animation if user starting new window movement. So window stops
|
||||
// // moving at one point and then fires new animation.
|
||||
// // But my approach does not work because of rust borrowing rules and wired pointers
|
||||
// // lifetime annotation that I dont know how to use.
|
||||
// is_cancel: false,
|
||||
// in_progress: false,
|
||||
// // is_cancel: AtomicBool::new(false),
|
||||
// // in_progress: AtomicBool::new(false),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Animation {
|
||||
pub fn cancel(&mut self) {
|
||||
if !self.in_progress {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_cancel = true;
|
||||
let max_duration = Duration::from_secs(1);
|
||||
let spent_duration = Instant::now();
|
||||
|
||||
while self.in_progress {
|
||||
if spent_duration.elapsed() >= max_duration {
|
||||
self.in_progress = false;
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(16));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
pub fn lerp(x: i32, new_x: i32, t: f64) -> i32 {
|
||||
let time = apply_ease_func(t);
|
||||
f64::from(new_x - x).mul_add(time, f64::from(x)) as i32
|
||||
}
|
||||
|
||||
pub fn lerp_rect(original_rect: &Rect, new_rect: &Rect, t: f64) -> Rect {
|
||||
Rect {
|
||||
left: Self::lerp(original_rect.left, new_rect.left, t),
|
||||
top: Self::lerp(original_rect.top, new_rect.top, t),
|
||||
right: Self::lerp(original_rect.right, new_rect.right, t),
|
||||
bottom: Self::lerp(original_rect.bottom, new_rect.bottom, t),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
pub fn animate(
|
||||
&mut self,
|
||||
duration: Duration,
|
||||
mut f: impl FnMut(f64) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.in_progress = true;
|
||||
// set target frame time to match 240 fps (my max refresh rate of monitor)
|
||||
// probably not the best way to do it is take actual monitor refresh rate
|
||||
// or make it configurable
|
||||
let target_frame_time = Duration::from_millis(1000 / 240);
|
||||
let mut progress = 0.0;
|
||||
let animation_start = Instant::now();
|
||||
|
||||
// start animation
|
||||
while progress < 1.0 {
|
||||
// check if animation is cancelled
|
||||
if self.is_cancel {
|
||||
// cancel animation
|
||||
// set all flags
|
||||
self.is_cancel = !self.is_cancel;
|
||||
self.in_progress = false;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tick_start = Instant::now();
|
||||
// calculate progress
|
||||
progress = animation_start.elapsed().as_millis() as f64 / duration.as_millis() as f64;
|
||||
f(progress).ok();
|
||||
|
||||
// sleep until next frame
|
||||
while tick_start.elapsed() < target_frame_time {
|
||||
std::thread::sleep(target_frame_time - tick_start.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
self.in_progress = false;
|
||||
|
||||
// limit progress to 1.0 if animation took longer
|
||||
if progress > 1.0 {
|
||||
progress = 1.0;
|
||||
}
|
||||
|
||||
// process animation for 1.0 to set target position
|
||||
f(progress)
|
||||
}
|
||||
}
|
||||
@@ -16,17 +16,18 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::AtomicIsize;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::Backoff;
|
||||
use komorebi_core::EaseEnum;
|
||||
use lazy_static::lazy_static;
|
||||
use os_info::Version;
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
@@ -66,6 +67,7 @@ use crate::windows_api::WindowsApi;
|
||||
#[macro_use]
|
||||
mod ring;
|
||||
|
||||
mod animation;
|
||||
mod border;
|
||||
mod com;
|
||||
mod container;
|
||||
@@ -215,6 +217,8 @@ lazy_static! {
|
||||
static ref BORDER_OFFSET: Arc<Mutex<Option<Rect>>> =
|
||||
Arc::new(Mutex::new(None));
|
||||
|
||||
static ref ANIMATION_EASE: Arc<Mutex<EaseEnum>> = Arc::new(Mutex::new(EaseEnum::Linear));
|
||||
|
||||
// Use app-specific titlebar removal options where possible
|
||||
// eg. Windows Terminal, IntelliJ IDEA, Firefox
|
||||
static ref NO_TITLEBAR: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
||||
@@ -238,6 +242,8 @@ pub static BORDER_WIDTH: AtomicI32 = AtomicI32::new(20);
|
||||
// 0 0 0 aka pure black, I doubt anyone will want this as a border colour
|
||||
pub const TRANSPARENCY_COLOUR: u32 = 0;
|
||||
pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
|
||||
pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250);
|
||||
|
||||
pub static HIDDEN_HWND: AtomicIsize = AtomicIsize::new(0);
|
||||
|
||||
@@ -252,7 +258,7 @@ fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
}
|
||||
|
||||
let appender = tracing_appender::rolling::never(DATA_DIR.clone(), "komorebi.log");
|
||||
let appender = tracing_appender::rolling::never(&*DATA_DIR, "komorebi.log");
|
||||
let color_appender = tracing_appender::rolling::never(std::env::temp_dir(), "komorebi.log");
|
||||
let (non_blocking, guard) = tracing_appender::non_blocking(appender);
|
||||
let (color_non_blocking, color_guard) = tracing_appender::non_blocking(color_appender);
|
||||
@@ -305,13 +311,8 @@ fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
|
||||
}
|
||||
|
||||
pub fn load_configuration() -> Result<()> {
|
||||
let home = HOME_DIR.clone();
|
||||
|
||||
let mut config_pwsh = home.clone();
|
||||
config_pwsh.push("komorebi.ps1");
|
||||
|
||||
let mut config_ahk = home;
|
||||
config_ahk.push("komorebi.ahk");
|
||||
let config_pwsh = HOME_DIR.join("komorebi.ps1");
|
||||
let config_ahk = HOME_DIR.join("komorebi.ahk");
|
||||
|
||||
if config_pwsh.exists() {
|
||||
let powershell_exe = if which("pwsh.exe").is_ok() {
|
||||
@@ -320,25 +321,13 @@ pub fn load_configuration() -> Result<()> {
|
||||
"powershell.exe"
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"loading configuration file: {}",
|
||||
config_pwsh
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("cannot convert path to string"))?
|
||||
);
|
||||
tracing::info!("loading configuration file: {}", config_pwsh.display());
|
||||
|
||||
Command::new(powershell_exe)
|
||||
.arg(config_pwsh.as_os_str())
|
||||
.output()?;
|
||||
} else if config_ahk.exists() && which(&*AHK_EXE).is_ok() {
|
||||
tracing::info!(
|
||||
"loading configuration file: {}",
|
||||
config_ahk
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("cannot convert path to string"))?
|
||||
);
|
||||
tracing::info!("loading configuration file: {}", config_ahk.display());
|
||||
|
||||
Command::new(&*AHK_EXE)
|
||||
.arg(config_ahk.as_os_str())
|
||||
@@ -410,7 +399,7 @@ pub fn notify_subscribers(notification: &str) -> Result<()> {
|
||||
let mut subscriptions = SUBSCRIPTION_PIPES.lock();
|
||||
for (subscriber, pipe) in &mut *subscriptions {
|
||||
match writeln!(pipe, "{notification}") {
|
||||
Ok(_) => {
|
||||
Ok(()) => {
|
||||
tracing::debug!("pushed notification to subscriber: {}", subscriber);
|
||||
}
|
||||
Err(error) => {
|
||||
@@ -466,16 +455,16 @@ fn detect_deadlocks() {
|
||||
#[clap(author, about, version)]
|
||||
struct Opts {
|
||||
/// Allow the use of komorebi's custom focus-follows-mouse implementation
|
||||
#[clap(action, short, long = "ffm")]
|
||||
#[clap(short, long = "ffm")]
|
||||
focus_follows_mouse: bool,
|
||||
/// Wait for 'komorebic complete-configuration' to be sent before processing events
|
||||
#[clap(action, short, long)]
|
||||
#[clap(short, long)]
|
||||
await_configuration: bool,
|
||||
/// Start a TCP server on the given port to allow the direct sending of SocketMessages
|
||||
#[clap(action, short, long)]
|
||||
#[clap(short, long)]
|
||||
tcp_port: Option<usize>,
|
||||
/// Path to a static configuration JSON file
|
||||
#[clap(action, short, long)]
|
||||
#[clap(short, long)]
|
||||
config: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@@ -514,6 +503,8 @@ fn main() -> Result<()> {
|
||||
// File logging worker guard has to have an assignment in the main fn to work
|
||||
let (_guard, _color_guard) = setup()?;
|
||||
|
||||
WindowsApi::foreground_lock_timeout()?;
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
detect_deadlocks();
|
||||
|
||||
@@ -525,10 +516,22 @@ fn main() -> Result<()> {
|
||||
|
||||
Hidden::create("komorebi-hidden")?;
|
||||
|
||||
let wm = if let Some(config) = &opts.config {
|
||||
let static_config = opts.config.map_or_else(
|
||||
|| {
|
||||
let komorebi_json = HOME_DIR.join("komorebi.json");
|
||||
if komorebi_json.is_file() {
|
||||
Option::from(komorebi_json)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Option::from,
|
||||
);
|
||||
|
||||
let wm = if let Some(config) = &static_config {
|
||||
tracing::info!(
|
||||
"creating window manager from static configuration file: {}",
|
||||
config.as_os_str().to_str().unwrap()
|
||||
config.display()
|
||||
);
|
||||
|
||||
Arc::new(Mutex::new(StaticConfig::preload(
|
||||
@@ -542,7 +545,8 @@ fn main() -> Result<()> {
|
||||
};
|
||||
|
||||
wm.lock().init()?;
|
||||
if let Some(config) = &opts.config {
|
||||
|
||||
if let Some(config) = &static_config {
|
||||
StaticConfig::postload(config, &wm)?;
|
||||
}
|
||||
|
||||
@@ -556,10 +560,8 @@ fn main() -> Result<()> {
|
||||
listen_for_commands_tcp(wm.clone(), port);
|
||||
}
|
||||
|
||||
if opts.config.is_none() {
|
||||
std::thread::spawn(|| {
|
||||
load_configuration().expect("could not load configuration");
|
||||
});
|
||||
if static_config.is_none() {
|
||||
std::thread::spawn(|| load_configuration().expect("could not load configuration"));
|
||||
|
||||
if opts.await_configuration {
|
||||
let backoff = Backoff::new();
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use getset::CopyGetters;
|
||||
use getset::Getters;
|
||||
@@ -120,9 +121,7 @@ impl Monitor {
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
|
||||
if workspace.maximized_window().is_some() {
|
||||
return Err(anyhow!(
|
||||
"cannot move native maximized window to another monitor or workspace"
|
||||
));
|
||||
bail!("cannot move native maximized window to another monitor or workspace");
|
||||
}
|
||||
|
||||
let container = workspace
|
||||
|
||||
@@ -20,6 +20,7 @@ use parking_lot::Mutex;
|
||||
use schemars::schema_for;
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
use komorebi_core::config_generation::ApplicationConfiguration;
|
||||
use komorebi_core::config_generation::IdWithIdentifier;
|
||||
use komorebi_core::config_generation::MatchingStrategy;
|
||||
use komorebi_core::ApplicationIdentifier;
|
||||
@@ -46,6 +47,9 @@ use crate::windows_api::WindowsApi;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::ALT_FOCUS_HACK;
|
||||
use crate::ANIMATION_DURATION;
|
||||
use crate::ANIMATION_EASE;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use crate::BORDER_COLOUR_CURRENT;
|
||||
use crate::BORDER_COLOUR_MONOCLE;
|
||||
use crate::BORDER_COLOUR_SINGLE;
|
||||
@@ -322,6 +326,28 @@ impl WindowManager {
|
||||
monitor.update_focused_workspace(offset, &invisible_borders)?;
|
||||
}
|
||||
}
|
||||
SocketMessage::FocusedWorkspaceContainerPadding(adjustment) => {
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
|
||||
let focused_monitor = self
|
||||
.focused_monitor()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
|
||||
self.set_container_padding(focused_monitor_idx, focused_workspace_idx, adjustment)?;
|
||||
}
|
||||
SocketMessage::FocusedWorkspacePadding(adjustment) => {
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
|
||||
let focused_monitor = self
|
||||
.focused_monitor()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
let focused_workspace_idx = focused_monitor.focused_workspace_idx();
|
||||
|
||||
self.set_workspace_padding(focused_monitor_idx, focused_workspace_idx, adjustment)?;
|
||||
}
|
||||
SocketMessage::AdjustContainerPadding(sizing, adjustment) => {
|
||||
self.adjust_container_padding(sizing, adjustment)?;
|
||||
}
|
||||
@@ -450,10 +476,10 @@ impl WindowManager {
|
||||
SocketMessage::ChangeLayout(layout) => self.change_workspace_layout_default(layout)?,
|
||||
SocketMessage::CycleLayout(direction) => self.cycle_layout(direction)?,
|
||||
SocketMessage::ChangeLayoutCustom(ref path) => {
|
||||
self.change_workspace_custom_layout(path.clone())?;
|
||||
self.change_workspace_custom_layout(path)?;
|
||||
}
|
||||
SocketMessage::WorkspaceLayoutCustom(monitor_idx, workspace_idx, ref path) => {
|
||||
self.set_workspace_layout_custom(monitor_idx, workspace_idx, path.clone())?;
|
||||
self.set_workspace_layout_custom(monitor_idx, workspace_idx, path)?;
|
||||
}
|
||||
SocketMessage::WorkspaceTiling(monitor_idx, workspace_idx, tile) => {
|
||||
self.set_workspace_tiling(monitor_idx, workspace_idx, tile)?;
|
||||
@@ -484,7 +510,7 @@ impl WindowManager {
|
||||
monitor_idx,
|
||||
workspace_idx,
|
||||
at_container_count,
|
||||
path.clone(),
|
||||
path,
|
||||
)?;
|
||||
}
|
||||
SocketMessage::ClearWorkspaceLayoutRules(monitor_idx, workspace_idx) => {
|
||||
@@ -494,7 +520,7 @@ impl WindowManager {
|
||||
if let Some((monitor_idx, workspace_idx)) =
|
||||
self.monitor_workspace_index_by_name(workspace)
|
||||
{
|
||||
self.set_workspace_layout_custom(monitor_idx, workspace_idx, path.clone())?;
|
||||
self.set_workspace_layout_custom(monitor_idx, workspace_idx, path)?;
|
||||
}
|
||||
}
|
||||
SocketMessage::NamedWorkspaceTiling(ref workspace, tile) => {
|
||||
@@ -535,7 +561,7 @@ impl WindowManager {
|
||||
monitor_idx,
|
||||
workspace_idx,
|
||||
at_container_count,
|
||||
path.clone(),
|
||||
path,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -669,10 +695,7 @@ impl WindowManager {
|
||||
Err(error) => error.to_string(),
|
||||
};
|
||||
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(state.as_bytes())?;
|
||||
}
|
||||
@@ -692,10 +715,7 @@ impl WindowManager {
|
||||
}
|
||||
.to_string();
|
||||
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(response.as_bytes())?;
|
||||
}
|
||||
@@ -1012,8 +1032,7 @@ impl WindowManager {
|
||||
let workspace = self.focused_workspace()?;
|
||||
let resize = workspace.resize_dimensions();
|
||||
|
||||
let mut quicksave_json = std::env::temp_dir();
|
||||
quicksave_json.push("komorebi.quicksave.json");
|
||||
let quicksave_json = std::env::temp_dir().join("komorebi.quicksave.json");
|
||||
|
||||
let file = OpenOptions::new()
|
||||
.write(true)
|
||||
@@ -1026,15 +1045,10 @@ impl WindowManager {
|
||||
SocketMessage::QuickLoad => {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let mut quicksave_json = std::env::temp_dir();
|
||||
quicksave_json.push("komorebi.quicksave.json");
|
||||
let quicksave_json = std::env::temp_dir().join("komorebi.quicksave.json");
|
||||
|
||||
let file = File::open(&quicksave_json).map_err(|_| {
|
||||
anyhow!(
|
||||
"no quicksave found at {}",
|
||||
quicksave_json.display().to_string()
|
||||
)
|
||||
})?;
|
||||
let file = File::open(&quicksave_json)
|
||||
.map_err(|_| anyhow!("no quicksave found at {}", quicksave_json.display()))?;
|
||||
|
||||
let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;
|
||||
|
||||
@@ -1049,15 +1063,15 @@ impl WindowManager {
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(path.clone())?;
|
||||
.open(path)?;
|
||||
|
||||
serde_json::to_writer_pretty(&file, &resize)?;
|
||||
}
|
||||
SocketMessage::Load(ref path) => {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let file = File::open(path)
|
||||
.map_err(|_| anyhow!("no file found at {}", path.display().to_string()))?;
|
||||
let file =
|
||||
File::open(path).map_err(|_| anyhow!("no file found at {}", path.display()))?;
|
||||
|
||||
let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;
|
||||
|
||||
@@ -1129,6 +1143,15 @@ impl WindowManager {
|
||||
self.hide_border()?;
|
||||
}
|
||||
}
|
||||
SocketMessage::Animation(enable) => {
|
||||
ANIMATION_ENABLED.store(enable, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::AnimationDuration(duration) => {
|
||||
ANIMATION_DURATION.store(duration, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::AnimationEase(ease) => {
|
||||
*ANIMATION_EASE.lock() = ease;
|
||||
}
|
||||
SocketMessage::ActiveWindowBorderColour(kind, r, g, b) => {
|
||||
match kind {
|
||||
WindowKind::Single => {
|
||||
@@ -1166,12 +1189,18 @@ impl WindowManager {
|
||||
SocketMessage::AltFocusHack(enable) => {
|
||||
ALT_FOCUS_HACK.store(enable, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::ApplicationSpecificConfigurationSchema => {
|
||||
let asc = schema_for!(Vec<ApplicationConfiguration>);
|
||||
let schema = serde_json::to_string_pretty(&asc)?;
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(schema.as_bytes())?;
|
||||
}
|
||||
SocketMessage::NotificationSchema => {
|
||||
let notification = schema_for!(Notification);
|
||||
let schema = serde_json::to_string_pretty(¬ification)?;
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(schema.as_bytes())?;
|
||||
@@ -1179,9 +1208,7 @@ impl WindowManager {
|
||||
SocketMessage::SocketSchema => {
|
||||
let socket_message = schema_for!(SocketMessage);
|
||||
let schema = serde_json::to_string_pretty(&socket_message)?;
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(schema.as_bytes())?;
|
||||
@@ -1189,18 +1216,14 @@ impl WindowManager {
|
||||
SocketMessage::StaticConfigSchema => {
|
||||
let socket_message = schema_for!(StaticConfig);
|
||||
let schema = serde_json::to_string_pretty(&socket_message)?;
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(schema.as_bytes())?;
|
||||
}
|
||||
SocketMessage::GenerateStaticConfig => {
|
||||
let config = serde_json::to_string_pretty(&StaticConfig::from(&*self))?;
|
||||
let mut socket = DATA_DIR.clone();
|
||||
socket.push("komorebic.sock");
|
||||
let socket = socket.as_path();
|
||||
let socket = DATA_DIR.join("komorebic.sock");
|
||||
|
||||
let mut stream = UnixStream::connect(socket)?;
|
||||
stream.write_all(config.as_bytes())?;
|
||||
@@ -1284,7 +1307,7 @@ impl WindowManager {
|
||||
| SocketMessage::CycleMoveWindow(_)
|
||||
| SocketMessage::MoveWindow(_) => {
|
||||
let foreground = WindowsApi::foreground_window()?;
|
||||
let foreground_window = Window { hwnd: foreground };
|
||||
let foreground_window = Window::new(foreground);
|
||||
let mut rect = WindowsApi::window_rect(foreground_window.hwnd())?;
|
||||
rect.top -= self.invisible_borders.bottom;
|
||||
rect.bottom += self.invisible_borders.bottom;
|
||||
|
||||
@@ -515,7 +515,8 @@ impl WindowManager {
|
||||
WindowManagerEvent::DisplayChange(..)
|
||||
| WindowManagerEvent::MouseCapture(..)
|
||||
| WindowManagerEvent::Cloak(..)
|
||||
| WindowManagerEvent::Uncloak(..) => {}
|
||||
| WindowManagerEvent::Uncloak(..)
|
||||
| WindowManagerEvent::UpdateFocusedWindowBorder(..) => {}
|
||||
};
|
||||
|
||||
if *self.focused_workspace()?.tile() && BORDER_ENABLED.load(Ordering::SeqCst) {
|
||||
@@ -529,7 +530,8 @@ impl WindowManager {
|
||||
| WindowManagerEvent::Show(_, window)
|
||||
| WindowManagerEvent::FocusChange(_, window)
|
||||
| WindowManagerEvent::Hide(_, window)
|
||||
| WindowManagerEvent::Minimize(_, window) => {
|
||||
| WindowManagerEvent::Minimize(_, window)
|
||||
| WindowManagerEvent::UpdateFocusedWindowBorder(window) => {
|
||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
||||
let mut target_window = None;
|
||||
let mut target_window_is_monocle = false;
|
||||
@@ -595,6 +597,10 @@ impl WindowManager {
|
||||
WindowsApi::invalidate_border_rect()?;
|
||||
border.set_position(target_window, &self.invisible_borders, activate)?;
|
||||
|
||||
if matches!(event, WindowManagerEvent::UpdateFocusedWindowBorder(_)) {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
|
||||
if activate {
|
||||
BORDER_HIDDEN.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn listen_for_movements(wm: Arc<Mutex<WindowManager>>) {
|
||||
Event::MouseMoveRelative { .. } => {
|
||||
if !ignore_movement {
|
||||
match wm.lock().raise_window_at_cursor_pos() {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => tracing::error!("{}", error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,12 @@ use crate::monitor::Monitor;
|
||||
use crate::ring::Ring;
|
||||
use crate::window_manager::WindowManager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::ALT_FOCUS_HACK;
|
||||
use crate::ANIMATION_DURATION;
|
||||
use crate::ANIMATION_EASE;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use crate::BORDER_COLOUR_CURRENT;
|
||||
use crate::BORDER_COLOUR_MONOCLE;
|
||||
use crate::BORDER_COLOUR_SINGLE;
|
||||
@@ -29,15 +33,16 @@ use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WORKSPACE_RULES;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
use dirs::home_dir;
|
||||
use hotwatch::notify::DebouncedEvent;
|
||||
use hotwatch::Hotwatch;
|
||||
use komorebi_core::config_generation::ApplicationConfigurationGenerator;
|
||||
use komorebi_core::config_generation::ApplicationOptions;
|
||||
use komorebi_core::config_generation::IdWithIdentifier;
|
||||
use komorebi_core::config_generation::MatchingStrategy;
|
||||
use komorebi_core::resolve_home_path;
|
||||
use komorebi_core::ApplicationIdentifier;
|
||||
use komorebi_core::DefaultLayout;
|
||||
use komorebi_core::EaseEnum;
|
||||
use komorebi_core::FocusFollowsMouseImplementation;
|
||||
use komorebi_core::HidingBehaviour;
|
||||
use komorebi_core::Layout;
|
||||
@@ -311,6 +316,15 @@ pub struct StaticConfig {
|
||||
/// Set monitor index preferences
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
|
||||
/// Enable or disable animations (default: false)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub animation: Option<bool>,
|
||||
/// Set the animation ease function (default: Linear)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub animation_ease: Option<EaseEnum>,
|
||||
/// Set the animation duration in ms (default: 250)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub animation_duration: Option<u64>,
|
||||
}
|
||||
|
||||
impl From<&WindowManager> for StaticConfig {
|
||||
@@ -431,6 +445,9 @@ impl From<&WindowManager> for StaticConfig {
|
||||
layered_applications: None,
|
||||
object_name_change_applications: None,
|
||||
monitor_index_preferences: Option::from(MONITOR_INDEX_PREFERENCES.lock().clone()),
|
||||
animation: Option::from(ANIMATION_ENABLED.load(Ordering::SeqCst)),
|
||||
animation_duration: Option::from(ANIMATION_DURATION.load(Ordering::SeqCst)),
|
||||
animation_ease: Option::from(*ANIMATION_EASE.lock()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +465,19 @@ impl StaticConfig {
|
||||
*window_hiding_behaviour = behaviour;
|
||||
}
|
||||
|
||||
if let Some(animation) = self.animation {
|
||||
ANIMATION_ENABLED.store(animation, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(duration) = self.animation_duration {
|
||||
ANIMATION_DURATION.store(duration, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(ease) = self.animation_ease {
|
||||
let mut animation_ease = ANIMATION_EASE.lock();
|
||||
*animation_ease = ease;
|
||||
}
|
||||
|
||||
if let Some(hack) = self.alt_focus_hack {
|
||||
ALT_FOCUS_HACK.store(hack, Ordering::SeqCst);
|
||||
}
|
||||
@@ -616,13 +646,8 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
if let Some(path) = &self.app_specific_configuration_path {
|
||||
let stringified = path.to_string_lossy();
|
||||
let stringified = stringified.replace(
|
||||
"$Env:USERPROFILE",
|
||||
&home_dir().expect("no home dir").to_string_lossy(),
|
||||
);
|
||||
|
||||
let content = std::fs::read_to_string(stringified)?;
|
||||
let path = resolve_home_path(path)?;
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
||||
|
||||
for mut entry in asc {
|
||||
@@ -762,7 +787,7 @@ impl StaticConfig {
|
||||
let socket = DATA_DIR.join("komorebi.sock");
|
||||
|
||||
match std::fs::remove_file(&socket) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => match error.kind() {
|
||||
// Doing this because ::exists() doesn't work reliably on Windows via IntelliJ
|
||||
ErrorKind::NotFound => {}
|
||||
@@ -806,6 +831,14 @@ impl StaticConfig {
|
||||
already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())),
|
||||
};
|
||||
|
||||
match value.focus_follows_mouse {
|
||||
None => WindowsApi::disable_focus_follows_mouse()?,
|
||||
Some(FocusFollowsMouseImplementation::Windows) => {
|
||||
WindowsApi::enable_focus_follows_mouse()?;
|
||||
}
|
||||
Some(FocusFollowsMouseImplementation::Komorebi) => {}
|
||||
};
|
||||
|
||||
let bytes = SocketMessage::ReloadStaticConfiguration(path.clone()).as_bytes()?;
|
||||
|
||||
wm.hotwatch.watch(path, move |event| match event {
|
||||
@@ -949,6 +982,15 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
wm.work_area_offset = value.global_work_area_offset;
|
||||
|
||||
match value.focus_follows_mouse {
|
||||
None => WindowsApi::disable_focus_follows_mouse()?,
|
||||
Some(FocusFollowsMouseImplementation::Windows) => {
|
||||
WindowsApi::enable_focus_follows_mouse()?;
|
||||
}
|
||||
Some(FocusFollowsMouseImplementation::Komorebi) => {}
|
||||
};
|
||||
|
||||
wm.focus_follows_mouse = value.focus_follows_mouse;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
use crate::com::SetCloak;
|
||||
use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL;
|
||||
use crate::ANIMATION_DURATION;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
use std::fmt::Write as _;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
@@ -25,6 +29,7 @@ use komorebi_core::ApplicationIdentifier;
|
||||
use komorebi_core::HidingBehaviour;
|
||||
use komorebi_core::Rect;
|
||||
|
||||
use crate::animation::Animation;
|
||||
use crate::styles::ExtendedWindowStyle;
|
||||
use crate::styles::WindowStyle;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
@@ -44,6 +49,7 @@ use crate::WSL2_UI_PROCESSES;
|
||||
#[derive(Debug, Clone, Copy, JsonSchema)]
|
||||
pub struct Window {
|
||||
pub(crate) hwnd: isize,
|
||||
animation: Animation,
|
||||
}
|
||||
|
||||
impl Display for Window {
|
||||
@@ -103,6 +109,14 @@ impl Serialize for Window {
|
||||
}
|
||||
|
||||
impl Window {
|
||||
// for instantiation of animation struct
|
||||
pub fn new(hwnd: isize) -> Self {
|
||||
Self {
|
||||
hwnd,
|
||||
animation: Animation::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn hwnd(self) -> HWND {
|
||||
HWND(self.hwnd)
|
||||
}
|
||||
@@ -122,6 +136,47 @@ impl Window {
|
||||
true,
|
||||
)
|
||||
}
|
||||
pub fn animate_position(&mut self, layout: &Rect, top: bool) -> Result<()> {
|
||||
let hwnd = self.hwnd();
|
||||
let curr_rect = WindowsApi::window_rect(hwnd).unwrap();
|
||||
|
||||
if curr_rect.left == layout.left
|
||||
&& curr_rect.top == layout.top
|
||||
&& curr_rect.bottom == layout.bottom
|
||||
&& curr_rect.right == layout.right
|
||||
{
|
||||
WindowsApi::position_window(hwnd, layout, top)
|
||||
} else {
|
||||
let target_rect = *layout;
|
||||
let duration = Duration::from_millis(ANIMATION_DURATION.load(Ordering::SeqCst));
|
||||
let mut animation = self.animation;
|
||||
|
||||
let self_copied = *self;
|
||||
std::thread::spawn(move || {
|
||||
animation.animate(duration, |progress: f64| {
|
||||
let new_rect = Animation::lerp_rect(&curr_rect, &target_rect, progress);
|
||||
if progress < 1.0 {
|
||||
// using MoveWindow because it runs faster than SetWindowPos
|
||||
// so animation have more fps and feel smoother
|
||||
WindowsApi::move_window(hwnd, &new_rect, true)?;
|
||||
} else {
|
||||
WindowsApi::position_window(hwnd, &new_rect, top)?;
|
||||
|
||||
if WindowsApi::foreground_window()? == self_copied.hwnd {
|
||||
WINEVENT_CALLBACK_CHANNEL
|
||||
.lock()
|
||||
.0
|
||||
.send(WindowManagerEvent::UpdateFocusedWindowBorder(self_copied))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_position(
|
||||
&mut self,
|
||||
@@ -154,7 +209,17 @@ impl Window {
|
||||
rect.bottom += invisible_borders.bottom;
|
||||
}
|
||||
|
||||
WindowsApi::position_window(self.hwnd(), &rect, top)
|
||||
if ANIMATION_ENABLED.load(Ordering::SeqCst) {
|
||||
// check if animation is in progress
|
||||
if self.animation.in_progress {
|
||||
// wait for cancel animation
|
||||
self.animation.cancel();
|
||||
}
|
||||
|
||||
self.animate_position(&rect, top)
|
||||
} else {
|
||||
WindowsApi::position_window(self.hwnd(), &rect, top)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hide(self) {
|
||||
@@ -241,7 +306,7 @@ impl Window {
|
||||
|
||||
// Raise Window to foreground
|
||||
match WindowsApi::set_foreground_window(self.hwnd()) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not set as foreground window, but continuing execution of raise(): {}",
|
||||
@@ -252,7 +317,7 @@ impl Window {
|
||||
|
||||
// This isn't really needed when the above command works as expected via AHK
|
||||
match WindowsApi::set_focus(self.hwnd()) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not set focus, but continuing execution of raise(): {}",
|
||||
@@ -302,7 +367,7 @@ impl Window {
|
||||
}
|
||||
|
||||
match WindowsApi::set_foreground_window(self.hwnd()) {
|
||||
Ok(_) => {
|
||||
Ok(()) => {
|
||||
foregrounded = true;
|
||||
}
|
||||
Err(error) => {
|
||||
@@ -334,7 +399,7 @@ impl Window {
|
||||
|
||||
// This isn't really needed when the above command works as expected via AHK
|
||||
match WindowsApi::set_focus(self.hwnd()) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not set focus, but continuing execution of focus(): {}",
|
||||
|
||||
@@ -3,11 +3,13 @@ use std::collections::HashSet;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::ErrorKind;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
use hotwatch::notify::DebouncedEvent;
|
||||
@@ -166,7 +168,7 @@ impl WindowManager {
|
||||
let socket = DATA_DIR.join("komorebi.sock");
|
||||
|
||||
match std::fs::remove_file(&socket) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => match error.kind() {
|
||||
// Doing this because ::exists() doesn't work reliably on Windows via IntelliJ
|
||||
ErrorKind::NotFound => {}
|
||||
@@ -215,7 +217,7 @@ impl WindowManager {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn show_border(&self) -> Result<()> {
|
||||
let foreground = WindowsApi::foreground_window()?;
|
||||
let foreground_window = Window { hwnd: foreground };
|
||||
let foreground_window = Window::new(foreground);
|
||||
let mut rect = WindowsApi::window_rect(foreground_window.hwnd())?;
|
||||
rect.top -= self.invisible_borders.bottom;
|
||||
rect.bottom += self.invisible_borders.bottom;
|
||||
@@ -247,13 +249,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn watch_configuration(&mut self, enable: bool) -> Result<()> {
|
||||
let home = HOME_DIR.clone();
|
||||
|
||||
let mut config_pwsh = home.clone();
|
||||
config_pwsh.push("komorebi.ps1");
|
||||
|
||||
let mut config_ahk = home;
|
||||
config_ahk.push("komorebi.ahk");
|
||||
let config_pwsh = HOME_DIR.join("komorebi.ps1");
|
||||
let config_ahk = HOME_DIR.join("komorebi.ahk");
|
||||
|
||||
if config_pwsh.exists() {
|
||||
self.configure_watcher(enable, config_pwsh)?;
|
||||
@@ -265,50 +262,39 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
fn configure_watcher(&mut self, enable: bool, config: PathBuf) -> Result<()> {
|
||||
if config.exists() {
|
||||
if enable {
|
||||
tracing::info!(
|
||||
"watching configuration for changes: {}",
|
||||
config
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("cannot convert path to string"))?
|
||||
);
|
||||
// Always make absolutely sure that there isn't an already existing watch, because
|
||||
// hotwatch allows multiple watches to be registered for the same path
|
||||
match self.hotwatch.unwatch(config.clone()) {
|
||||
Ok(_) => {}
|
||||
Err(error) => match error {
|
||||
hotwatch::Error::Notify(error) => match error {
|
||||
hotwatch::notify::Error::WatchNotFound => {}
|
||||
error => return Err(error.into()),
|
||||
},
|
||||
error @ hotwatch::Error::Io(_) => return Err(error.into()),
|
||||
if enable {
|
||||
tracing::info!("watching configuration for changes: {}", config.display());
|
||||
// Always make absolutely sure that there isn't an already existing watch, because
|
||||
// hotwatch allows multiple watches to be registered for the same path
|
||||
match self.hotwatch.unwatch(&config) {
|
||||
Ok(()) => {}
|
||||
Err(error) => match error {
|
||||
hotwatch::Error::Notify(error) => match error {
|
||||
hotwatch::notify::Error::WatchNotFound => {}
|
||||
error => return Err(error.into()),
|
||||
},
|
||||
error @ hotwatch::Error::Io(_) => return Err(error.into()),
|
||||
},
|
||||
}
|
||||
|
||||
self.hotwatch.watch(config, |event| match event {
|
||||
// Editing in Notepad sends a NoticeWrite while editing in (Neo)Vim sends
|
||||
// a NoticeRemove, presumably because of the use of swap files?
|
||||
DebouncedEvent::NoticeWrite(_) | DebouncedEvent::NoticeRemove(_) => {
|
||||
std::thread::spawn(|| {
|
||||
load_configuration().expect("could not load configuration");
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
})?;
|
||||
} else {
|
||||
tracing::info!(
|
||||
"no longer watching configuration for changes: {}",
|
||||
config.display()
|
||||
);
|
||||
|
||||
self.hotwatch.watch(config, |event| match event {
|
||||
// Editing in Notepad sends a NoticeWrite while editing in (Neo)Vim sends
|
||||
// a NoticeRemove, presumably because of the use of swap files?
|
||||
DebouncedEvent::NoticeWrite(_) | DebouncedEvent::NoticeRemove(_) => {
|
||||
std::thread::spawn(|| {
|
||||
load_configuration().expect("could not load configuration");
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
})?;
|
||||
} else {
|
||||
tracing::info!(
|
||||
"no longer watching configuration for changes: {}",
|
||||
config
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("cannot convert path to string"))?
|
||||
);
|
||||
|
||||
self.hotwatch.unwatch(config)?;
|
||||
};
|
||||
}
|
||||
self.hotwatch.unwatch(config)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -603,7 +589,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 { hwnd: op.hwnd }.hide();
|
||||
Window::new(op.hwnd).hide();
|
||||
should_update_focused_workspace = true;
|
||||
}
|
||||
|
||||
@@ -633,7 +619,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 { hwnd: op.hwnd });
|
||||
target_workspace.new_container_for_window(Window::new(op.hwnd));
|
||||
}
|
||||
|
||||
// Only re-tile the focused workspace if we need to
|
||||
@@ -677,14 +663,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 { hwnd });
|
||||
let event = WindowManagerEvent::Manage(Window::new(hwnd));
|
||||
Ok(WINEVENT_CALLBACK_CHANNEL.lock().0.send(event)?)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn unmanage_focused_window(&mut self) -> Result<()> {
|
||||
let hwnd = WindowsApi::foreground_window()?;
|
||||
let event = WindowManagerEvent::Unmanage(Window { hwnd });
|
||||
let event = WindowManagerEvent::Unmanage(Window::new(hwnd));
|
||||
Ok(WINEVENT_CALLBACK_CHANNEL.lock().0.send(event)?)
|
||||
}
|
||||
|
||||
@@ -722,13 +708,14 @@ impl WindowManager {
|
||||
];
|
||||
|
||||
if !known_hwnd {
|
||||
let class = Window { hwnd }.class()?;
|
||||
let class = Window::new(hwnd).class()?;
|
||||
// Some applications (Electron/Chromium-based, explorer) have (invisible?) overlays
|
||||
// windows that we need to look beyond to find the actual window to raise
|
||||
if overlay_classes.contains(&class) {
|
||||
for monitor in self.monitors() {
|
||||
for workspace in monitor.workspaces() {
|
||||
if let Some(exe_hwnd) = workspace.hwnd_from_exe(&Window { hwnd }.exe()?)
|
||||
if let Some(exe_hwnd) =
|
||||
workspace.hwnd_from_exe(&Window::new(hwnd).exe()?)
|
||||
{
|
||||
hwnd = exe_hwnd;
|
||||
known_hwnd = true;
|
||||
@@ -739,11 +726,11 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
if known_hwnd {
|
||||
let event = WindowManagerEvent::Raise(Window { hwnd });
|
||||
let event = WindowManagerEvent::Raise(Window::new(hwnd));
|
||||
self.has_pending_raise_op = true;
|
||||
Ok(WINEVENT_CALLBACK_CHANNEL.lock().0.send(event)?)
|
||||
} else {
|
||||
tracing::debug!("not raising unknown window: {}", Window { hwnd });
|
||||
tracing::debug!("not raising unknown window: {}", Window::new(hwnd,));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -857,9 +844,7 @@ impl WindowManager {
|
||||
} else if let Ok(window) = self.focused_window_mut() {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
} else {
|
||||
let desktop_window = Window {
|
||||
hwnd: WindowsApi::desktop_window()?,
|
||||
};
|
||||
let desktop_window = Window::new(WindowsApi::desktop_window()?);
|
||||
|
||||
let rect = self.focused_monitor_size()?;
|
||||
WindowsApi::center_cursor_in_rect(&rect)?;
|
||||
@@ -868,7 +853,7 @@ impl WindowManager {
|
||||
// attach to the thread of the desktop window always seems to result in "Access is
|
||||
// denied (os error 5)"
|
||||
match WindowsApi::set_foreground_window(desktop_window.hwnd()) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::warn!("{} {}:{}", error, file!(), line!());
|
||||
}
|
||||
@@ -1002,9 +987,7 @@ impl WindowManager {
|
||||
let workspace = self.focused_workspace()?;
|
||||
let focused_hwnd = WindowsApi::foreground_window()?;
|
||||
if !workspace.contains_managed_window(focused_hwnd) {
|
||||
return Err(anyhow!(
|
||||
"ignoring commands while active window is not managed by komorebi"
|
||||
));
|
||||
bail!("ignoring commands while active window is not managed by komorebi");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1120,9 +1103,7 @@ impl WindowManager {
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
|
||||
if workspace.maximized_window().is_some() {
|
||||
return Err(anyhow!(
|
||||
"cannot move native maximized window to another monitor or workspace"
|
||||
));
|
||||
bail!("cannot move native maximized window to another monitor or workspace");
|
||||
}
|
||||
|
||||
let container = workspace
|
||||
@@ -1232,9 +1213,7 @@ impl WindowManager {
|
||||
// removing this messes up the monitor / container / window index somewhere
|
||||
// and results in the wrong window getting moved across the monitor boundary
|
||||
if workspace.is_focused_window_monocle_or_maximized()? {
|
||||
return Err(anyhow!(
|
||||
"ignoring command while active window is in monocle mode or maximized"
|
||||
));
|
||||
bail!("ignoring command while active window is in monocle mode or maximized");
|
||||
}
|
||||
|
||||
tracing::info!("moving container");
|
||||
@@ -1396,9 +1375,7 @@ impl WindowManager {
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
if workspace.is_focused_window_monocle_or_maximized()? {
|
||||
return Err(anyhow!(
|
||||
"ignoring command while active window is in monocle mode or maximized"
|
||||
));
|
||||
bail!("ignoring command while active window is in monocle mode or maximized");
|
||||
}
|
||||
|
||||
tracing::info!("moving container");
|
||||
@@ -1425,7 +1402,7 @@ impl WindowManager {
|
||||
.ok_or_else(|| anyhow!("there must be at least one window in a container"))?;
|
||||
|
||||
if len.get() == 1 {
|
||||
return Err(anyhow!("there is only one window in this container"));
|
||||
bail!("there is only one window in this container");
|
||||
}
|
||||
|
||||
let current_idx = container.focused_window_idx();
|
||||
@@ -1510,7 +1487,7 @@ impl WindowManager {
|
||||
tracing::info!("removing window");
|
||||
|
||||
if self.focused_container()?.windows().len() == 1 {
|
||||
return Err(anyhow!("a container must have at least one window"));
|
||||
bail!("a container must have at least one window");
|
||||
}
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -1729,10 +1706,13 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn change_workspace_custom_layout(&mut self, path: PathBuf) -> Result<()> {
|
||||
pub fn change_workspace_custom_layout<P>(&mut self, path: P) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path> + std::fmt::Debug,
|
||||
{
|
||||
tracing::info!("changing layout");
|
||||
|
||||
let layout = CustomLayout::from_path_buf(path)?;
|
||||
let layout = CustomLayout::from_path(path)?;
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
match workspace.layout() {
|
||||
@@ -1854,13 +1834,16 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn add_workspace_layout_custom_rule(
|
||||
pub fn add_workspace_layout_custom_rule<P>(
|
||||
&mut self,
|
||||
monitor_idx: usize,
|
||||
workspace_idx: usize,
|
||||
at_container_count: usize,
|
||||
path: PathBuf,
|
||||
) -> Result<()> {
|
||||
path: P,
|
||||
) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path> + std::fmt::Debug,
|
||||
{
|
||||
tracing::info!("setting workspace layout");
|
||||
|
||||
let invisible_borders = self.invisible_borders;
|
||||
@@ -1885,7 +1868,7 @@ impl WindowManager {
|
||||
.get_mut(workspace_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
let layout = CustomLayout::from_path_buf(path)?;
|
||||
let layout = CustomLayout::from_path(path)?;
|
||||
|
||||
let rules: &mut Vec<(usize, Layout)> = workspace.layout_rules_mut();
|
||||
rules.retain(|pair| pair.0 != at_container_count);
|
||||
@@ -1986,14 +1969,17 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_workspace_layout_custom(
|
||||
pub fn set_workspace_layout_custom<P>(
|
||||
&mut self,
|
||||
monitor_idx: usize,
|
||||
workspace_idx: usize,
|
||||
path: PathBuf,
|
||||
) -> Result<()> {
|
||||
path: P,
|
||||
) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path> + std::fmt::Debug,
|
||||
{
|
||||
tracing::info!("setting workspace layout");
|
||||
let layout = CustomLayout::from_path_buf(path)?;
|
||||
let layout = CustomLayout::from_path(path)?;
|
||||
let invisible_borders = self.invisible_borders;
|
||||
let offset = self.work_area_offset;
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
@@ -2164,7 +2150,7 @@ impl WindowManager {
|
||||
if self.monitors().get(idx).is_some() {
|
||||
self.monitors.focus(idx);
|
||||
} else {
|
||||
return Err(anyhow!("this is not a valid monitor index"));
|
||||
bail!("this is not a valid monitor index");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -27,6 +27,7 @@ pub enum WindowManagerEvent {
|
||||
Unmanage(Window),
|
||||
Raise(Window),
|
||||
DisplayChange(Window),
|
||||
UpdateFocusedWindowBorder(Window),
|
||||
}
|
||||
|
||||
impl Display for WindowManagerEvent {
|
||||
@@ -77,6 +78,9 @@ impl Display for WindowManagerEvent {
|
||||
Self::DisplayChange(window) => {
|
||||
write!(f, "DisplayChange (Window: {window})")
|
||||
}
|
||||
Self::UpdateFocusedWindowBorder(window) => {
|
||||
write!(f, "UpdateFocusedBorderWindow (Window: {window})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +101,8 @@ impl WindowManagerEvent {
|
||||
| Self::Raise(window)
|
||||
| Self::Manage(window)
|
||||
| Self::DisplayChange(window)
|
||||
| Self::Unmanage(window) => window,
|
||||
| Self::Unmanage(window)
|
||||
| Self::UpdateFocusedWindowBorder(window) => window,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsIconic;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
|
||||
use windows::Win32::UI::WindowsAndMessaging::MoveWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::RegisterClassA;
|
||||
@@ -105,7 +106,9 @@ use windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPIF_SENDCHANGE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MINIMIZE;
|
||||
@@ -352,6 +355,20 @@ impl WindowsApi {
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn move_window(hwnd: HWND, layout: &Rect, repaint: bool) -> Result<()> {
|
||||
unsafe {
|
||||
MoveWindow(
|
||||
hwnd,
|
||||
layout.left,
|
||||
layout.top,
|
||||
layout.right,
|
||||
layout.bottom,
|
||||
repaint,
|
||||
)
|
||||
}
|
||||
.process()
|
||||
}
|
||||
|
||||
fn show_window(hwnd: HWND, command: SHOW_WINDOW_CMD) {
|
||||
// BOOL is returned but does not signify whether or not the operation was succesful
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
|
||||
@@ -368,7 +385,7 @@ impl WindowsApi {
|
||||
|
||||
pub fn close_window(hwnd: HWND) -> Result<()> {
|
||||
match Self::post_message(hwnd, WM_CLOSE, WPARAM(0), LPARAM(0)) {
|
||||
Ok(_) => Ok(()),
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(anyhow!("could not close window")),
|
||||
}
|
||||
}
|
||||
@@ -679,6 +696,42 @@ impl WindowsApi {
|
||||
.process()
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub fn foreground_lock_timeout() -> Result<()> {
|
||||
let mut value: u32 = 0;
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
SPI_GETFOREGROUNDLOCKTIMEOUT,
|
||||
0,
|
||||
std::ptr::addr_of_mut!(value).cast(),
|
||||
SPIF_SENDCHANGE,
|
||||
)?;
|
||||
|
||||
tracing::info!("current value of ForegroundLockTimeout is {value}");
|
||||
|
||||
if value != 0 {
|
||||
tracing::info!("updating value of ForegroundLockTimeout to {value} in order to enable keyboard-driven focus updating");
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
SPI_SETFOREGROUNDLOCKTIMEOUT,
|
||||
0,
|
||||
std::ptr::null_mut::<c_void>(),
|
||||
SPIF_SENDCHANGE,
|
||||
)?;
|
||||
|
||||
Self::system_parameters_info_w(
|
||||
SPI_GETFOREGROUNDLOCKTIMEOUT,
|
||||
0,
|
||||
std::ptr::addr_of_mut!(value).cast(),
|
||||
SPIF_SENDCHANGE,
|
||||
)?;
|
||||
|
||||
tracing::info!("updated value of ForegroundLockTimeout is now {value}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn focus_follows_mouse() -> Result<bool> {
|
||||
let mut is_enabled: BOOL = unsafe { std::mem::zeroed() };
|
||||
|
||||
@@ -104,7 +104,7 @@ pub extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
let is_minimized = WindowsApi::is_iconic(hwnd);
|
||||
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
let window = Window::new(hwnd.0);
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None) {
|
||||
if should_manage {
|
||||
@@ -132,7 +132,7 @@ pub extern "system" fn win_event_hook(
|
||||
return;
|
||||
}
|
||||
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
let window = Window::new(hwnd.0);
|
||||
|
||||
let winevent = unsafe { ::std::mem::transmute(event) };
|
||||
let event_type = match WindowManagerEvent::from_win_event(winevent, window) {
|
||||
@@ -196,7 +196,7 @@ pub extern "system" fn hidden_window(
|
||||
unsafe {
|
||||
match message {
|
||||
WM_DISPLAYCHANGE => {
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window::new(window.0));
|
||||
WINEVENT_CALLBACK_CHANNEL
|
||||
.lock()
|
||||
.0
|
||||
@@ -211,7 +211,7 @@ pub extern "system" fn hidden_window(
|
||||
if wparam.0 as u32 == SPI_SETWORKAREA.0
|
||||
|| wparam.0 as u32 == SPI_ICONVERTICALSPACING.0
|
||||
{
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window::new(window.0));
|
||||
WINEVENT_CALLBACK_CHANNEL
|
||||
.lock()
|
||||
.0
|
||||
@@ -224,7 +224,7 @@ pub extern "system" fn hidden_window(
|
||||
WM_DEVICECHANGE => {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
if wparam.0 as u32 == DBT_DEVNODES_CHANGED {
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
|
||||
let event_type = WindowManagerEvent::DisplayChange(Window::new(window.0));
|
||||
WINEVENT_CALLBACK_CHANNEL
|
||||
.lock()
|
||||
.0
|
||||
|
||||
@@ -61,7 +61,7 @@ impl WinEventListener {
|
||||
MessageLoop::start(10, |_msg| {
|
||||
if let Ok(event) = WINEVENT_CALLBACK_CHANNEL.lock().1.try_recv() {
|
||||
match outgoing.send(event) {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!("{}", error);
|
||||
}
|
||||
|
||||
@@ -19,11 +19,15 @@ use komorebi_core::Layout;
|
||||
use komorebi_core::OperationDirection;
|
||||
use komorebi_core::Rect;
|
||||
|
||||
use crate::border::Border;
|
||||
use crate::container::Container;
|
||||
use crate::ring::Ring;
|
||||
use crate::static_config::WorkspaceConfig;
|
||||
use crate::window::Window;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use crate::BORDER_HIDDEN;
|
||||
use crate::BORDER_HWND;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::INITIAL_CONFIGURATION_LOADED;
|
||||
@@ -108,7 +112,7 @@ impl Workspace {
|
||||
}
|
||||
|
||||
if let Some(pathbuf) = &config.custom_layout {
|
||||
let layout = CustomLayout::from_path_buf(pathbuf.clone())?;
|
||||
let layout = CustomLayout::from_path(pathbuf)?;
|
||||
self.layout = Layout::Custom(layout);
|
||||
self.tile = true;
|
||||
}
|
||||
@@ -129,7 +133,7 @@ impl Workspace {
|
||||
if let Some(layout_rules) = &config.custom_layout_rules {
|
||||
let rules = self.layout_rules_mut();
|
||||
for (count, pathbuf) in layout_rules {
|
||||
let rule = CustomLayout::from_path_buf(pathbuf.clone())?;
|
||||
let rule = CustomLayout::from_path(pathbuf)?;
|
||||
rules.push((*count, Layout::Custom(rule)));
|
||||
}
|
||||
}
|
||||
@@ -244,6 +248,12 @@ impl Workspace {
|
||||
}
|
||||
|
||||
if *self.tile() {
|
||||
if ANIMATION_ENABLED.load(Ordering::SeqCst) {
|
||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
||||
border.hide()?;
|
||||
BORDER_HIDDEN.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(container) = self.monocle_container_mut() {
|
||||
if let Some(window) = container.focused_window_mut() {
|
||||
adjusted_work_area.add_padding(container_padding);
|
||||
|
||||
15
komorebic-no-console/Cargo.toml
Normal file
15
komorebic-no-console/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.19"
|
||||
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"]
|
||||
repository = "https://github.com/LGUG2Z/komorebi"
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
19
komorebic-no-console/src/main.rs
Normal file
19
komorebic-no-console/src/main.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#![windows_subsystem = "windows"]
|
||||
|
||||
use std::io;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let mut current_exe = std::env::current_exe().expect("unable to get exec path");
|
||||
current_exe.pop();
|
||||
let komorebic_exe = current_exe.join("komorebic.exe");
|
||||
|
||||
Command::new(komorebic_exe)
|
||||
.args(std::env::args_os().skip(1))
|
||||
.creation_flags(CREATE_NO_WINDOW)
|
||||
.status()
|
||||
.map(|_| ())
|
||||
}
|
||||
@@ -15,8 +15,6 @@ derive-ahk = { path = "../derive-ahk" }
|
||||
komorebi-core = { path = "../komorebi-core" }
|
||||
|
||||
clap = { version = "4", features = ["derive", "wrap_help"] }
|
||||
color-eyre = "0.6"
|
||||
dirs = "5"
|
||||
fs-tail = "0.1"
|
||||
heck = "0.4"
|
||||
lazy_static = "1"
|
||||
@@ -30,3 +28,6 @@ sysinfo = "0.29"
|
||||
uds_windows = "1"
|
||||
which = "5"
|
||||
windows = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
File diff suppressed because it is too large
Load Diff
128
schema.asc.json
Normal file
128
schema.asc.json
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Array_of_ApplicationConfiguration",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ApplicationConfiguration"
|
||||
},
|
||||
"definitions": {
|
||||
"ApplicationConfiguration": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"float_identifiers": {
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/IdWithIdentifierAndComment"
|
||||
}
|
||||
},
|
||||
"identifier": {
|
||||
"$ref": "#/definitions/IdWithIdentifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/ApplicationOptions"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ApplicationIdentifier": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title"
|
||||
]
|
||||
},
|
||||
"ApplicationOptions": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"object_name_change",
|
||||
"layered",
|
||||
"border_overflow",
|
||||
"tray_and_multi_window",
|
||||
"force"
|
||||
]
|
||||
},
|
||||
"IdWithIdentifier": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"$ref": "#/definitions/ApplicationIdentifier"
|
||||
},
|
||||
"matching_strategy": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MatchingStrategy"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"IdWithIdentifierAndComment": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"comment": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"$ref": "#/definitions/ApplicationIdentifier"
|
||||
},
|
||||
"matching_strategy": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MatchingStrategy"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"MatchingStrategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,9 @@
|
||||
<Component Id='binary1' Guid='*'>
|
||||
<File Id='exe1' Name='komorebic.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebic.exe' KeyPath='yes' />
|
||||
</Component>
|
||||
<Component Id='binary2' Guid='*'>
|
||||
<File Id='exe2' Name='komorebic-no-console.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebic-no-console.exe' KeyPath='yes' />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
@@ -108,6 +111,8 @@
|
||||
|
||||
<ComponentRef Id='binary1' />
|
||||
|
||||
<ComponentRef Id='binary2' />
|
||||
|
||||
<Feature Id='Environment' Title='PATH Environment Variable' Description='Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location.' Level='1' Absent='allow'>
|
||||
<ComponentRef Id='Path' />
|
||||
</Feature>
|
||||
|
||||
Reference in New Issue
Block a user