Compare commits

..

1 Commits

Author SHA1 Message Date
LGUG2Z
b101ea5916 feat(win32): set foregroundlocktimeout explicitly
After another round of deep diving to find a workaround to all of the
mechanisms within Windows that prevent a process from changing the
focused window, I came across this gist which I saw setting
SPI_SETFOREGROUNDLOCKTIMEOUT to 0:
https://gist.github.com/EBNull/1419093

This tentatively seems like it works and it removes the need for the
alt_focus_hack setting.

However, according to this StackOverflow discussion, it seems like on
Win10+ changes to ForegroundLockTimeout in the registry are no longer
respected and changes made via SPI_SETFOREGROUNDLOCKTIMEOUT are not
persisted:
https://stackoverflow.com/questions/73735129/setforegroundwindow-relationship-between-the-foregroundlocktimeout-registry-val

Therefore on starting, komorebi will now check the value with
SPI_GETFOREGROUNDLOCKTIMEOUT and if it is not 0, it will be set to 0.

Logging has been added to inform the user of the changes that are
happening.
2023-12-01 10:19:12 -08:00
26 changed files with 211 additions and 905 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1 @@
github: LGUG2Z
ko_fi: lgug2z

View File

@@ -81,7 +81,7 @@ jobs:
cargo install cargo-wix
cargo wix -p komorebi --nocapture -I .\wix\main.wxs --target x86_64-pc-windows-msvc
- name: Upload the built artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: komorebi-${{ matrix.target }}
path: |

View File

@@ -26,15 +26,6 @@ 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"

326
Cargo.lock generated
View File

@@ -95,15 +95,6 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "backtrace-ext"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
dependencies = [
"backtrace",
]
[[package]]
name = "base64"
version = "0.21.5"
@@ -157,9 +148,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.11"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
dependencies = [
"clap_builder",
"clap_derive",
@@ -167,15 +158,15 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.11"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"terminal_size 0.3.0",
"terminal_size",
]
[[package]]
@@ -213,9 +204,9 @@ dependencies = [
[[package]]
name = "color-spantrace"
version = "0.2.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
dependencies = [
"once_cell",
"owo-colors",
@@ -231,9 +222,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "core-foundation"
version = "0.9.4"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
@@ -241,15 +232,15 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "crossbeam-channel"
version = "0.5.10"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
@@ -281,21 +272,21 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.18"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "ctrlc"
version = "3.4.2"
version = "3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
dependencies = [
"nix",
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -372,19 +363,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
name = "eyre"
version = "0.6.9"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd"
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
dependencies = [
"indenter",
"once_cell",
@@ -437,9 +428,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
@@ -561,15 +552,15 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.28.1"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "h2"
version = "0.3.22"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
dependencies = [
"bytes",
"fnv",
@@ -577,7 +568,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
"indexmap",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
@@ -586,9 +577,15 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.14.3"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
[[package]]
name = "heck"
@@ -623,9 +620,9 @@ dependencies = [
[[package]]
name = "http"
version = "0.2.11"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150"
dependencies = [
"bytes",
"fnv",
@@ -694,9 +691,9 @@ dependencies = [
[[package]]
name = "idna"
version = "0.5.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
@@ -708,6 +705,16 @@ 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"
@@ -715,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.2",
]
[[package]]
@@ -753,23 +760,6 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
[[package]]
name = "itoa"
version = "1.0.9"
@@ -778,9 +768,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.66"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
dependencies = [
"wasm-bindgen",
]
@@ -827,7 +817,6 @@ dependencies = [
"tracing-subscriber",
"uds_windows",
"which",
"widestring",
"windows",
"windows-implement",
"windows-interface",
@@ -864,7 +853,6 @@ dependencies = [
"heck",
"komorebi-core",
"lazy_static",
"miette",
"paste",
"powershell_script",
"reqwest",
@@ -872,16 +860,11 @@ dependencies = [
"serde_json",
"serde_yaml",
"sysinfo",
"thiserror",
"uds_windows",
"which",
"windows",
]
[[package]]
name = "komorebic-no-console"
version = "0.1.19"
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -913,9 +896,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
[[package]]
name = "lock_api"
@@ -957,38 +940,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "miette"
version = "5.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
dependencies = [
"backtrace",
"backtrace-ext",
"is-terminal",
"miette-derive",
"once_cell",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"terminal_size 0.1.17",
"textwrap",
"thiserror",
"unicode-width",
]
[[package]]
name = "miette-derive"
version = "5.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "mime"
version = "0.3.17"
@@ -1285,9 +1236,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "percent-encoding"
version = "2.3.1"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "petgraph"
@@ -1296,7 +1247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap",
"indexmap 2.1.0",
]
[[package]]
@@ -1361,18 +1312,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.76"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@@ -1546,15 +1497,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.26"
version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -1696,11 +1647,11 @@ dependencies = [
[[package]]
name = "serde_yaml"
version = "0.9.29"
version = "0.9.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129"
checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
dependencies = [
"indexmap",
"indexmap 2.1.0",
"itoa",
"ryu",
"serde",
@@ -1731,12 +1682,6 @@ version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "smawk"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
[[package]]
name = "socket2"
version = "0.4.10"
@@ -1785,34 +1730,6 @@ dependencies = [
"syn 2.0.39",
]
[[package]]
name = "supports-color"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
dependencies = [
"is-terminal",
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
dependencies = [
"is-terminal",
]
[[package]]
name = "supports-unicode"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7"
dependencies = [
"is-terminal",
]
[[package]]
name = "syn"
version = "1.0.109"
@@ -1837,9 +1754,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.30.5"
version = "0.29.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2"
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
@@ -1847,7 +1764,7 @@ dependencies = [
"ntapi",
"once_cell",
"rayon",
"windows",
"winapi 0.3.9",
]
[[package]]
@@ -1884,16 +1801,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "terminal_size"
version = "0.3.0"
@@ -1904,31 +1811,20 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "textwrap"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.51"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.51"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
@@ -2136,11 +2032,10 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "uds_windows"
version = "1.1.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
dependencies = [
"memoffset",
"tempfile",
"winapi 0.3.9",
]
@@ -2157,12 +2052,6 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
@@ -2172,23 +2061,17 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unsafe-libyaml"
version = "0.2.10"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
[[package]]
name = "url"
version = "2.5.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
"idna",
@@ -2246,9 +2129,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@@ -2256,9 +2139,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
dependencies = [
"bumpalo",
"log",
@@ -2271,9 +2154,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.39"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@@ -2283,9 +2166,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -2293,9 +2176,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [
"proc-macro2",
"quote",
@@ -2306,15 +2189,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
[[package]]
name = "web-sys"
version = "0.3.66"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -2333,12 +2216,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "widestring"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]]
name = "winapi"
version = "0.2.8"
@@ -2449,15 +2326,6 @@ dependencies = [
"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]]
name = "windows-targets"
version = "0.48.5"

View File

@@ -6,7 +6,6 @@ members = [
"komorebi",
"komorebi-core",
"komorebic",
"komorebic-no-console",
]
[workspace.dependencies]

View File

@@ -3,9 +3,6 @@
Tiling Window Management for Windows.
<p>
<a href="https://techforpalestine.org/learn-more">
<img alt="Tech for Palestine" src="https://badge.techforpalestine.org/default">
</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">

View File

@@ -13,23 +13,24 @@ fmt:
prettier --write .github/FUNDING.yml
prettier --write .github/workflows/windows.yaml
install-target target:
cargo +stable install --path {{ target }} --locked
install-komorebic:
cargo +stable install --path komorebic --locked
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
install-komorebi:
cargo +stable install --path komorebi --locked
install:
just install-target komorebic
just install-target komorebic-no-console
just install-target komorebi
just install-komorebic
just install-komorebi
komorebic ahk-asc '~/komorebi-application-specific-configuration/applications.yaml'
komorebic pwsh-asc '~/komorebi-application-specific-configuration/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
run:
just install-target komorebic
cargo +stable run --bin komorebi --locked
just install-komorebic
cargo +stable run --bin komorebi --locked -- -a
warn $RUST_LOG="warn":
just run

View File

@@ -84,7 +84,6 @@ pub enum SocketMessage {
FlipLayout(Axis),
// Monitor and Workspace Commands
MonitorIndexPreference(usize, i32, i32, i32, i32),
DisplayIndexPreference(usize, String),
EnsureWorkspaces(usize, usize),
EnsureNamedWorkspaces(usize, Vec<String>),
NewWorkspace,
@@ -99,7 +98,6 @@ pub enum SocketMessage {
CycleFocusMonitor(CycleDirection),
CycleFocusWorkspace(CycleDirection),
FocusMonitorNumber(usize),
FocusLastWorkspace,
FocusWorkspaceNumber(usize),
FocusWorkspaceNumbers(usize),
FocusMonitorWorkspaceNumber(usize, usize),
@@ -148,7 +146,6 @@ pub enum SocketMessage {
IdentifyLayeredApplication(ApplicationIdentifier, String),
IdentifyBorderOverflowApplication(ApplicationIdentifier, String),
State,
VisibleWindows,
Query(StateQuery),
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
ToggleFocusFollowsMouse(FocusFollowsMouseImplementation),
@@ -158,7 +155,6 @@ pub enum SocketMessage {
ToggleTitleBars,
AddSubscriber(String),
RemoveSubscriber(String),
ApplicationSpecificConfigurationSchema,
NotificationSchema,
SocketSchema,
StaticConfigSchema,

View File

@@ -32,7 +32,7 @@ schemars = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
strum = { version = "0.25", features = ["derive"] }
sysinfo = "0.30"
sysinfo = "0.29"
tracing = "0.1"
tracing-appender = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
@@ -45,7 +45,6 @@ windows-implement = { workspace = true }
windows = { workspace = true }
color-eyre = { workspace = true }
dirs = { workspace = true }
widestring = "1"
[features]
deadlock_detection = []

View File

@@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use windows::core::PCWSTR;
use windows::core::PCSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use komorebi_core::Rect;
@@ -43,11 +43,11 @@ impl Border {
}
pub fn create(name: &str) -> Result<()> {
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let name = format!("{name}\0");
let instance = WindowsApi::module_handle_w()?;
let class_name = PCWSTR(name.as_ptr());
let class_name = PCSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSW {
let window_class = WNDCLASSA {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
@@ -56,18 +56,18 @@ impl Border {
..Default::default()
};
let _atom = WindowsApi::register_class_w(&window_class)?;
let _atom = WindowsApi::register_class_a(&window_class)?;
let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_border_window(PCWSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_border_window(PCSTR(name_cl.as_ptr()), instance)?;
let border = Self::from(hwnd);
let mut message = MSG::default();
unsafe {
while GetMessageW(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
while GetMessageA(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
@@ -77,7 +77,7 @@ impl Border {
let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
}
BORDER_HWND.store(hwnd.0, Ordering::SeqCst);

View File

@@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use windows::core::PCWSTR;
use windows::core::PCSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use crate::windows_callbacks;
use crate::WindowsApi;
@@ -34,11 +34,11 @@ impl Hidden {
}
pub fn create(name: &str) -> Result<()> {
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let name = format!("{name}\0");
let instance = WindowsApi::module_handle_w()?;
let class_name = PCWSTR(name.as_ptr());
let class_name = PCSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSW {
let window_class = WNDCLASSA {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
@@ -47,18 +47,18 @@ impl Hidden {
..Default::default()
};
let _atom = WindowsApi::register_class_w(&window_class)?;
let _atom = WindowsApi::register_class_a(&window_class)?;
let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_hidden_window(PCWSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_hidden_window(PCSTR(name_cl.as_ptr()), instance)?;
let hidden = Self::from(hwnd);
let mut message = MSG::default();
unsafe {
while GetMessageW(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
while GetMessageA(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
@@ -68,7 +68,7 @@ impl Hidden {
let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
}
HIDDEN_HWND.store(hwnd.0, Ordering::SeqCst);

View File

@@ -35,6 +35,8 @@ use regex::Regex;
use schemars::JsonSchema;
use serde::Serialize;
use sysinfo::Process;
use sysinfo::ProcessExt;
use sysinfo::SystemExt;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::EnvFilter;
@@ -141,8 +143,6 @@ lazy_static! {
]));
static ref MONITOR_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, Rect>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref DISPLAY_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, String>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref WORKSPACE_RULES: Arc<Mutex<HashMap<String, WorkspaceRule>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> =
@@ -251,7 +251,7 @@ fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
std::env::set_var("RUST_LOG", "info");
}
let appender = tracing_appender::rolling::never(std::env::temp_dir(), "komorebi_plaintext.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);
@@ -448,16 +448,16 @@ fn detect_deadlocks() {
#[clap(author, about, version)]
struct Opts {
/// Allow the use of komorebi's custom focus-follows-mouse implementation
#[clap(short, long = "ffm")]
#[clap(action, short, long = "ffm")]
focus_follows_mouse: bool,
/// Wait for 'komorebic complete-configuration' to be sent before processing events
#[clap(short, long)]
#[clap(action, short, long)]
await_configuration: bool,
/// Start a TCP server on the given port to allow the direct sending of SocketMessages
#[clap(short, long)]
#[clap(action, short, long)]
tcp_port: Option<usize>,
/// Path to a static configuration JSON file
#[clap(short, long)]
#[clap(action, short, long)]
config: Option<PathBuf>,
}
@@ -482,10 +482,8 @@ fn main() -> Result<()> {
if matched_procs.len() > 1 {
let mut len = matched_procs.len();
for proc in matched_procs {
if let Some(root) = proc.root() {
if root.ends_with("shims") {
len -= 1;
}
if proc.root().ends_with("shims") {
len -= 1;
}
}
@@ -511,19 +509,7 @@ fn main() -> Result<()> {
Hidden::create("komorebi-hidden")?;
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 {
let wm = if let Some(config) = &opts.config {
tracing::info!(
"creating window manager from static configuration file: {}",
config.display()
@@ -540,8 +526,7 @@ fn main() -> Result<()> {
};
wm.lock().init()?;
if let Some(config) = &static_config {
if let Some(config) = &opts.config {
StaticConfig::postload(config, &wm)?;
}
@@ -555,7 +540,7 @@ fn main() -> Result<()> {
listen_for_commands_tcp(wm.clone(), port);
}
if static_config.is_none() {
if opts.config.is_none() {
std::thread::spawn(|| load_configuration().expect("could not load configuration"));
if opts.await_configuration {

View File

@@ -24,10 +24,6 @@ pub struct Monitor {
#[getset(get = "pub", set = "pub")]
name: String,
#[getset(get = "pub", set = "pub")]
device: Option<String>,
#[getset(get = "pub", set = "pub")]
device_id: Option<String>,
#[getset(get = "pub", set = "pub")]
size: Rect,
#[getset(get = "pub", set = "pub")]
work_area_size: Rect,
@@ -35,9 +31,6 @@ pub struct Monitor {
work_area_offset: Option<Rect>,
workspaces: Ring<Workspace>,
#[serde(skip_serializing)]
#[getset(get_copy = "pub", set = "pub")]
last_focused_workspace: Option<usize>,
#[serde(skip_serializing)]
#[getset(get_mut = "pub")]
workspace_names: HashMap<usize, String>,
}
@@ -51,13 +44,10 @@ pub fn new(id: isize, size: Rect, work_area_size: Rect, name: String) -> Monitor
Monitor {
id,
name,
device: None,
device_id: None,
size,
work_area_size,
work_area_offset: None,
workspaces,
last_focused_workspace: None,
workspace_names: HashMap::default(),
}
}

View File

@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::BufRead;
@@ -21,7 +20,6 @@ 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;
@@ -60,7 +58,6 @@ use crate::BORDER_OVERFLOW_IDENTIFIERS;
use crate::BORDER_WIDTH;
use crate::CUSTOM_FFM;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDING_BEHAVIOUR;
use crate::INITIAL_CONFIGURATION_LOADED;
@@ -172,23 +169,6 @@ impl WindowManager {
_ => {}
};
match message {
SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => {
if let Some(monitor) = self.focused_monitor_mut() {
let idx = monitor.focused_workspace_idx();
monitor.set_last_focused_workspace(Option::from(idx));
}
}
SocketMessage::FocusMonitorWorkspaceNumber(target_monitor_idx, _) => {
let idx = self.focused_workspace_idx_for_monitor_idx(target_monitor_idx)?;
if let Some(monitor) = self.monitors_mut().get_mut(target_monitor_idx) {
monitor.set_last_focused_workspace(Option::from(idx));
}
}
_ => {}
};
match message {
SocketMessage::Promote => self.promote_container_to_front()?,
SocketMessage::PromoteFocus => self.promote_focus_to_front()?,
@@ -615,33 +595,6 @@ impl WindowManager {
self.show_border()?;
};
}
SocketMessage::FocusLastWorkspace => {
// This is to ensure that even on an empty workspace on a secondary monitor, the
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
self.focus_monitor(monitor_idx)?;
}
let idx = self
.focused_monitor()
.ok_or_else(|| anyhow!("there is no monitor"))?
.focused_workspace_idx();
if let Some(monitor) = self.focused_monitor_mut() {
if let Some(last_focused_workspace) = monitor.last_focused_workspace() {
self.focus_workspace(last_focused_workspace)?;
}
}
self.focused_monitor_mut()
.ok_or_else(|| anyhow!("there is no monitor"))?
.set_last_focused_workspace(Option::from(idx));
if BORDER_ENABLED.load(Ordering::SeqCst) {
self.show_border()?;
};
}
SocketMessage::FocusWorkspaceNumber(workspace_idx) => {
// This is to ensure that even on an empty workspace on a secondary monitor, the
// secondary monitor where the cursor is focused will be used as the target for
@@ -719,10 +672,6 @@ impl WindowManager {
},
);
}
SocketMessage::DisplayIndexPreference(index_preference, ref display) => {
let mut display_index_preferences = DISPLAY_INDEX_PREFERENCES.lock();
display_index_preferences.insert(index_preference, display.clone());
}
SocketMessage::EnsureWorkspaces(monitor_idx, workspace_count) => {
self.ensure_workspaces_for_monitor(monitor_idx, workspace_count)?;
}
@@ -746,32 +695,6 @@ impl WindowManager {
let mut stream = UnixStream::connect(socket)?;
stream.write_all(state.as_bytes())?;
}
SocketMessage::VisibleWindows => {
let mut monitor_visible_windows = HashMap::new();
for (index, monitor) in self.monitors().iter().enumerate() {
if let Some(ws) = monitor.focused_workspace() {
monitor_visible_windows.insert(
monitor
.device_id()
.clone()
.unwrap_or_else(|| format!("{index}")),
ws.visible_window_details().clone(),
);
}
}
let visible_windows_state =
match serde_json::to_string_pretty(&monitor_visible_windows) {
Ok(state) => state,
Err(error) => error.to_string(),
};
let socket = DATA_DIR.join("komorebic.sock");
let mut stream = UnixStream::connect(socket)?;
stream.write_all(visible_windows_state.as_bytes())?;
}
SocketMessage::Query(query) => {
let response = match query {
StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(),
@@ -1253,14 +1176,6 @@ 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(&notification)?;
@@ -1369,32 +1284,13 @@ impl WindowManager {
| SocketMessage::InvisibleBorders(_)
| SocketMessage::WorkAreaOffset(_)
| SocketMessage::CycleMoveWindow(_)
| SocketMessage::MoveWindow(_)
| SocketMessage::CycleFocusMonitor(_)
| SocketMessage::CycleFocusWorkspace(_)
| SocketMessage::FocusMonitorNumber(_)
| SocketMessage::FocusMonitorWorkspaceNumber(_, _)
| SocketMessage::FocusWorkspaceNumber(_) => {
| SocketMessage::MoveWindow(_) => {
let foreground = WindowsApi::foreground_window()?;
let foreground_window = Window { hwnd: foreground };
let mut rect = WindowsApi::window_rect(foreground_window.hwnd())?;
rect.top -= self.invisible_borders.bottom;
rect.bottom += self.invisible_borders.bottom;
let monocle = BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst);
if monocle != 0 && self.focused_workspace()?.monocle_container().is_some() {
BORDER_COLOUR_CURRENT.store(
monocle,
Ordering::SeqCst,
);
}
let stack = BORDER_COLOUR_STACK.load(Ordering::SeqCst);
if stack != 0 && self.focused_container()?.windows().len() > 1 {
BORDER_COLOUR_CURRENT
.store(stack, Ordering::SeqCst);
}
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
border.set_position(foreground_window, &self.invisible_borders, false)?;
}

View File

@@ -19,7 +19,6 @@ use crate::BORDER_WIDTH;
use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDING_BEHAVIOUR;
use crate::LAYERED_WHITELIST;
@@ -313,9 +312,6 @@ pub struct StaticConfig {
/// Set monitor index preferences
#[serde(skip_serializing_if = "Option::is_none")]
pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
/// Set display index preferences
#[serde(skip_serializing_if = "Option::is_none")]
pub display_index_preferences: Option<HashMap<usize, String>>,
}
impl From<&WindowManager> for StaticConfig {
@@ -436,7 +432,6 @@ impl From<&WindowManager> for StaticConfig {
layered_applications: None,
object_name_change_applications: None,
monitor_index_preferences: Option::from(MONITOR_INDEX_PREFERENCES.lock().clone()),
display_index_preferences: Option::from(DISPLAY_INDEX_PREFERENCES.lock().clone()),
}
}
}
@@ -449,11 +444,6 @@ impl StaticConfig {
*preferences = monitor_index_preferences.clone();
}
if let Some(display_index_preferences) = &self.display_index_preferences {
let mut preferences = DISPLAY_INDEX_PREFERENCES.lock();
*preferences = display_index_preferences.clone();
}
if let Some(behaviour) = self.window_hiding_behaviour {
let mut window_hiding_behaviour = HIDING_BEHAVIOUR.lock();
*window_hiding_behaviour = behaviour;

View File

@@ -6,7 +6,6 @@ use std::fmt::Formatter;
use std::fmt::Write as _;
use std::sync::atomic::Ordering;
use color_eyre::eyre;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use komorebi_core::config_generation::IdWithIdentifier;
@@ -47,26 +46,6 @@ pub struct Window {
pub(crate) hwnd: isize,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct WindowDetails {
pub title: String,
pub exe: String,
pub class: String,
}
impl TryFrom<Window> for WindowDetails {
type Error = eyre::ErrReport;
fn try_from(value: Window) -> std::result::Result<Self, Self::Error> {
Ok(Self {
title: value.title()?,
exe: value.exe()?,
class: value.class()?,
})
}
}
impl Display for Window {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut display = format!("(hwnd: {}", self.hwnd);

View File

@@ -49,7 +49,6 @@ use crate::workspace::Workspace;
use crate::BORDER_HWND;
use crate::BORDER_OVERFLOW_IDENTIFIERS;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS;
use crate::HOME_DIR;
use crate::LAYERED_WHITELIST;
@@ -104,7 +103,6 @@ pub struct State {
pub border_overflow_identifiers: Vec<IdWithIdentifier>,
pub name_change_on_launch_identifiers: Vec<IdWithIdentifier>,
pub monitor_index_preferences: HashMap<usize, Rect>,
pub display_index_preferences: HashMap<usize, String>,
}
impl AsRef<Self> for WindowManager {
@@ -134,7 +132,6 @@ impl From<&WindowManager> for State {
border_overflow_identifiers: BORDER_OVERFLOW_IDENTIFIERS.lock().clone(),
name_change_on_launch_identifiers: OBJECT_NAME_CHANGE_ON_LAUNCH.lock().clone(),
monitor_index_preferences: MONITOR_INDEX_PREFERENCES.lock().clone(),
display_index_preferences: DISPLAY_INDEX_PREFERENCES.lock().clone(),
}
}
}
@@ -1322,7 +1319,7 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
.id();
if !WindowsApi::monitors_have_same_dpi(a, b)? {
if !WindowsApi::monitors_have_same_scale_factor(a, b)? {
self.update_focused_workspace(self.mouse_follows_focus)?;
}
}
@@ -2198,14 +2195,6 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no workspace"))
}
pub fn focused_workspace_idx_for_monitor_idx(&self, idx: usize) -> Result<usize> {
Ok(self
.monitors()
.get(idx)
.ok_or_else(|| anyhow!("there is no monitor at this index"))?
.focused_workspace_idx())
}
pub fn focused_workspace_for_monitor_idx(&self, idx: usize) -> Result<&Workspace> {
self.monitors()
.get(idx)

View File

@@ -1,14 +1,15 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::atomic::Ordering;
use color_eyre::eyre::anyhow;
use color_eyre::eyre::Error;
use color_eyre::Result;
use widestring::U16CStr;
use windows::core::Result as WindowsCrateResult;
use windows::core::PCWSTR;
use windows::core::PCSTR;
use windows::core::PWSTR;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::Foundation::BOOL;
@@ -29,13 +30,11 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW;
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
use windows::Win32::Graphics::Gdi::InvalidateRect;
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEW;
use windows::Win32::Graphics::Gdi::HBRUSH;
use windows::Win32::Graphics::Gdi::HDC;
use windows::Win32::Graphics::Gdi::HMONITOR;
@@ -52,10 +51,8 @@ use windows::Win32::System::Threading::QueryFullProcessImageNameW;
use windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS;
use windows::Win32::System::Threading::PROCESS_NAME_WIN32;
use windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION;
use windows::Win32::UI::HiDpi::GetDpiForMonitor;
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
use windows::Win32::UI::HiDpi::MDT_EFFECTIVE_DPI;
use windows::Win32::UI::Input::KeyboardAndMouse::GetKeyState;
use windows::Win32::UI::Input::KeyboardAndMouse::SendInput;
use windows::Win32::UI::Input::KeyboardAndMouse::SetFocus;
@@ -66,9 +63,11 @@ use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTDOWN;
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTUP;
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT;
use windows::Win32::UI::Input::KeyboardAndMouse::VK_MENU;
use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR;
use windows::Win32::UI::Shell::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow;
@@ -84,7 +83,7 @@ use windows::Win32::UI::WindowsAndMessaging::IsWindow;
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassW;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassA;
use windows::Win32::UI::WindowsAndMessaging::SetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
@@ -94,7 +93,6 @@ use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
use windows::Win32::UI::WindowsAndMessaging::EDD_GET_DEVICE_INTERFACE_NAME;
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
@@ -119,7 +117,7 @@ use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED;
@@ -166,8 +164,8 @@ impl_from_integer_for_windows_result!(usize, isize, u16, u32, i32);
impl<T, E> From<WindowsResult<T, E>> for Result<T, E> {
fn from(result: WindowsResult<T, E>) -> Self {
match result {
WindowsResult::Err(error) => Err(error),
WindowsResult::Ok(ok) => Ok(ok),
WindowsResult::Err(error) => Self::Err(error),
WindowsResult::Ok(ok) => Self::Ok(ok),
}
}
}
@@ -223,7 +221,7 @@ impl WindowsApi {
let mut monitors: Vec<(String, isize)> = vec![];
let monitors_ref: &mut Vec<(String, isize)> = monitors.as_mut();
Self::enum_display_monitors(
Some(windows_callbacks::valid_display_monitors),
Option::Some(windows_callbacks::valid_display_monitors),
monitors_ref as *mut Vec<(String, isize)> as isize,
)?;
@@ -232,46 +230,9 @@ impl WindowsApi {
pub fn load_monitor_information(monitors: &mut Ring<Monitor>) -> Result<()> {
Self::enum_display_monitors(
Some(windows_callbacks::enum_display_monitor),
Option::Some(windows_callbacks::enum_display_monitor),
monitors as *mut Ring<Monitor> as isize,
)?;
Ok(())
}
pub fn enum_display_devices(
index: u32,
lp_device: Option<*const u16>,
) -> Result<DISPLAY_DEVICEW> {
#[allow(clippy::option_if_let_else)]
let lp_device = match lp_device {
None => PCWSTR::null(),
Some(lp_device) => PCWSTR(lp_device),
};
let mut display_device = DISPLAY_DEVICEW {
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEW>())?,
..Default::default()
};
match unsafe {
EnumDisplayDevicesW(
lp_device,
index,
std::ptr::addr_of_mut!(display_device),
EDD_GET_DEVICE_INTERFACE_NAME,
)
}
.ok()
{
Ok(_) => {}
Err(error) => {
tracing::error!("enum_display_devices: {}", error);
return Err(error.into());
}
}
Ok(display_device)
)
}
pub fn enum_windows(callback: WNDENUMPROC, callback_data_address: isize) -> Result<()> {
@@ -284,7 +245,7 @@ impl WindowsApi {
if let Some(workspace) = monitor.workspaces_mut().front_mut() {
// EnumWindows will enumerate through windows on all monitors
Self::enum_windows(
Some(windows_callbacks::enum_window),
Option::Some(windows_callbacks::enum_window),
workspace.containers_mut() as *mut VecDeque<Container> as isize,
)?;
@@ -689,10 +650,10 @@ impl WindowsApi {
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
let ex_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
let name = U16CStr::from_slice_truncate(&ex_info.szDevice)
.expect("monitor name was not a valid u16 c string")
.to_ustring()
let name = OsString::from_wide(&ex_info.szDevice);
let name = name
.to_string_lossy()
.replace('\u{0000}', "")
.trim_start_matches(r"\\.\")
.to_string();
@@ -739,7 +700,7 @@ impl WindowsApi {
Self::system_parameters_info_w(
SPI_SETFOREGROUNDLOCKTIMEOUT,
0,
std::ptr::null_mut::<c_void>(),
0 as *mut c_void,
SPIF_SENDCHANGE,
)?;
@@ -798,33 +759,19 @@ impl WindowsApi {
unsafe { CreateSolidBrush(COLORREF(colour)) }
}
pub fn register_class_w(window_class: &WNDCLASSW) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassW(window_class) }))
pub fn register_class_a(window_class: &WNDCLASSA) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassA(window_class) }))
}
pub fn dpi_for_monitor(hmonitor: isize) -> Result<f32> {
let mut dpi_x = u32::default();
let mut dpi_y = u32::default();
unsafe {
GetDpiForMonitor(
HMONITOR(hmonitor),
MDT_EFFECTIVE_DPI,
std::ptr::addr_of_mut!(dpi_x),
std::ptr::addr_of_mut!(dpi_y),
)
}
.process()?;
#[allow(clippy::cast_precision_loss)]
Ok(dpi_y as f32 / 96.0)
pub fn scale_factor_for_monitor(hmonitor: isize) -> Result<DEVICE_SCALE_FACTOR> {
unsafe { GetScaleFactorForMonitor(HMONITOR(hmonitor)) }.process()
}
pub fn monitors_have_same_dpi(hmonitor_a: isize, hmonitor_b: isize) -> Result<bool> {
let dpi_a = Self::dpi_for_monitor(hmonitor_a)?;
let dpi_b = Self::dpi_for_monitor(hmonitor_b)?;
pub fn monitors_have_same_scale_factor(a: isize, b: isize) -> Result<bool> {
let a = Self::scale_factor_for_monitor(a)?;
let b = Self::scale_factor_for_monitor(b)?;
Ok((dpi_a - dpi_b).abs() < f32::EPSILON)
Ok(a == b)
}
pub fn round_corners(hwnd: isize) -> Result<()> {
@@ -841,9 +788,9 @@ impl WindowsApi {
.process()
}
pub fn create_border_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
pub fn create_border_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
unsafe {
let hwnd = CreateWindowExW(
let hwnd = CreateWindowExA(
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
name,
name,
@@ -875,9 +822,9 @@ impl WindowsApi {
Ok(())
}
pub fn create_hidden_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
pub fn create_hidden_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
unsafe {
CreateWindowExW(
CreateWindowExA(
WS_EX_NOACTIVATE,
name,
name,

View File

@@ -1,6 +1,5 @@
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use widestring::U16CStr;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::COLORREF;
@@ -41,7 +40,6 @@ use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL;
use crate::BORDER_COLOUR_CURRENT;
use crate::BORDER_RECT;
use crate::BORDER_WIDTH;
use crate::DISPLAY_INDEX_PREFERENCES;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::TRANSPARENCY_COLOUR;
@@ -74,38 +72,7 @@ pub extern "system" fn enum_display_monitor(
}
}
let current_index = monitors.elements().len();
if let Ok(mut m) = WindowsApi::monitor(hmonitor.0) {
#[allow(clippy::cast_possible_truncation)]
if let Ok(d) = WindowsApi::enum_display_devices(current_index as u32, None) {
let name = U16CStr::from_slice_truncate(d.DeviceName.as_ref())
.expect("display device name was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\.\")
.to_string();
if name.eq(m.name()) {
if let Ok(device) = WindowsApi::enum_display_devices(0, Some(d.DeviceName.as_ptr()))
{
let id = U16CStr::from_slice_truncate(device.DeviceID.as_ref())
.expect("display device id was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\?\")
.to_string();
let mut split: Vec<_> = id.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
m.set_device(Option::from(split[0].to_string()));
m.set_device_id(Option::from(split.join("-")));
}
}
}
if let Ok(m) = WindowsApi::monitor(hmonitor.0) {
let monitor_index_preferences = MONITOR_INDEX_PREFERENCES.lock();
let mut index_preference = None;
for (index, monitor_size) in &*monitor_index_preferences {
@@ -114,18 +81,7 @@ pub extern "system" fn enum_display_monitor(
}
}
let display_index_preferences = DISPLAY_INDEX_PREFERENCES.lock();
for (index, device) in &*display_index_preferences {
if let Some(known_device) = m.device_id() {
if device == known_device {
index_preference = Option::from(index);
}
}
}
if monitors.elements().is_empty() {
monitors.elements_mut().push_back(m);
} else if let Some(preference) = index_preference {
if let Some(preference) = index_preference {
let current_len = monitors.elements().len();
if *preference > current_len {
monitors.elements_mut().reserve(1);

View File

@@ -23,7 +23,6 @@ use crate::container::Container;
use crate::ring::Ring;
use crate::static_config::WorkspaceConfig;
use crate::window::Window;
use crate::window::WindowDetails;
use crate::windows_api::WindowsApi;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
@@ -1088,20 +1087,6 @@ impl Workspace {
vec
}
pub fn visible_window_details(&self) -> Vec<WindowDetails> {
let mut vec: Vec<WindowDetails> = vec![];
for container in self.containers() {
if let Some(focused) = container.focused_window() {
if let Ok(details) = (*focused).try_into() {
vec.push(details);
}
}
}
vec
}
pub fn visible_windows_mut(&mut self) -> Vec<Option<&mut Window>> {
let mut vec = vec![];
for container in self.containers_mut() {

View File

@@ -1,15 +0,0 @@
[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]

View File

@@ -1,19 +0,0 @@
#![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(|_| ())
}

View File

@@ -15,21 +15,19 @@ derive-ahk = { path = "../derive-ahk" }
komorebi-core = { path = "../komorebi-core" }
clap = { version = "4", features = ["derive", "wrap_help"] }
color-eyre = { workspace = true }
dirs = { workspace = true }
dunce = { workspace = true }
fs-tail = "0.1"
heck = "0.4"
lazy_static = "1"
miette = { version = "5", features = ["fancy"] }
paste = "1"
powershell_script = "1.0"
reqwest = { version = "0.11", features = ["blocking"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
sysinfo = "0.30"
thiserror = "1"
sysinfo = "0.29"
uds_windows = "1"
which = "5"
windows = { workspace = true }
windows = { workspace = true }
color-eyre = { workspace = true }
dirs = { workspace = true }
dunce = { workspace = true }

View File

@@ -7,7 +7,6 @@ use std::io::BufRead;
use std::io::BufReader;
use std::io::ErrorKind;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::sync::atomic::AtomicBool;
@@ -23,11 +22,8 @@ use fs_tail::TailedFile;
use heck::ToKebabCase;
use komorebi_core::resolve_home_path;
use lazy_static::lazy_static;
use miette::NamedSource;
use miette::Report;
use miette::SourceOffset;
use miette::SourceSpan;
use paste::paste;
use sysinfo::SystemExt;
use uds_windows::UnixListener;
use uds_windows::UnixStream;
use which::which;
@@ -86,17 +82,6 @@ trait AhkFunction {
fn generate_ahk_function() -> String;
}
#[derive(thiserror::Error, Debug, miette::Diagnostic)]
#[error("{message}")]
#[diagnostic(code(komorebi::configuration), help("try fixing this syntax error"))]
struct ConfigurationError {
message: String,
#[source_code]
src: NamedSource,
#[label("This bit here")]
bad_bit: SourceSpan,
}
#[derive(Copy, Clone, ValueEnum)]
enum BooleanState {
Enable,
@@ -416,14 +401,6 @@ struct MonitorIndexPreference {
bottom: i32,
}
#[derive(Parser, AhkFunction)]
struct DisplayIndexPreference {
/// Preferred monitor index (zero-indexed)
index_preference: usize,
/// Display name as identified in komorebic state
display: String,
}
#[derive(Parser, AhkFunction)]
struct EnsureWorkspaces {
/// Monitor index (zero-indexed)
@@ -654,29 +631,29 @@ struct ActiveWindowBorderOffset {
#[allow(clippy::struct_excessive_bools)]
struct Start {
/// Allow the use of komorebi's custom focus-follows-mouse implementation
#[clap(short, long = "ffm")]
#[clap(action, short, long = "ffm")]
ffm: bool,
/// Path to a static configuration JSON file
#[clap(short, long)]
#[clap(action, short, long)]
config: Option<PathBuf>,
/// Wait for 'komorebic complete-configuration' to be sent before processing events
#[clap(short, long)]
#[clap(action, short, long)]
await_configuration: bool,
/// Start a TCP server on the given port to allow the direct sending of SocketMessages
#[clap(short, long)]
#[clap(action, short, long)]
tcp_port: Option<usize>,
/// Start whkd in a background process
#[clap(long)]
#[clap(action, long)]
whkd: bool,
/// Start autohotkey configuration file
#[clap(long)]
#[clap(action, long)]
ahk: bool,
}
#[derive(Parser, AhkFunction)]
struct Stop {
/// Stop whkd if it is running as a background process
#[clap(long)]
#[clap(action, long)]
whkd: bool,
}
@@ -742,15 +719,15 @@ struct AltFocusHack {
struct EnableAutostart {
/// Path to a static configuration JSON file
#[clap(action, short, long)]
config: Option<PathBuf>,
config: PathBuf,
/// Enable komorebi's custom focus-follows-mouse implementation
#[clap(short, long = "ffm")]
#[clap(action, short, long = "ffm")]
ffm: bool,
/// Enable autostart of whkd
#[clap(long)]
#[clap(action, long)]
whkd: bool,
/// Enable autostart of ahk
#[clap(long)]
#[clap(action, long)]
ahk: bool,
}
@@ -773,8 +750,6 @@ enum SubCommand {
Check,
/// Show a JSON representation of the current window manager state
State,
/// Show a JSON representation of visible windows
VisibleWindows,
/// Query the current window manager state
#[clap(arg_required_else_help = true)]
Query(Query),
@@ -869,8 +844,6 @@ enum SubCommand {
/// Focus the specified monitor
#[clap(arg_required_else_help = true)]
FocusMonitor(FocusMonitor),
/// Focus the last focused workspace on the focused monitor
FocusLastWorkspace,
/// Focus the specified workspace on the focused monitor
#[clap(arg_required_else_help = true)]
FocusWorkspace(FocusWorkspace),
@@ -942,9 +915,6 @@ enum SubCommand {
/// Set the monitor index preference for a monitor identified using its size
#[clap(arg_required_else_help = true)]
MonitorIndexPreference(MonitorIndexPreference),
/// Set the display index preference for a monitor identified using its display name
#[clap(arg_required_else_help = true)]
DisplayIndexPreference(DisplayIndexPreference),
/// Create at least this many workspaces for the specified monitor
#[clap(arg_required_else_help = true)]
EnsureWorkspaces(EnsureWorkspaces),
@@ -1117,9 +1087,6 @@ enum SubCommand {
/// Fetch the latest version of applications.yaml from komorebi-application-specific-configuration
#[clap(alias = "fetch-asc")]
FetchAppSpecificConfiguration,
/// Generate a JSON Schema for applications.yaml
#[clap(alias = "asc-schema")]
ApplicationSpecificConfigurationSchema,
/// Generate a JSON Schema of subscription notifications
NotificationSchema,
/// Generate a JSON Schema of socket messages
@@ -1129,6 +1096,7 @@ enum SubCommand {
/// Generates a static configuration JSON file based on the current window manager state
GenerateStaticConfig,
/// Generates the komorebi.lnk shortcut in shell:startup to autostart komorebi
#[clap(arg_required_else_help = true)]
EnableAutostart(EnableAutostart),
/// Deletes the komorebi.lnk shortcut in shell:startup to disable autostart
DisableAutostart,
@@ -1225,21 +1193,20 @@ fn main() -> Result<()> {
);
}
SubCommand::EnableAutostart(args) => {
let mut current_exe = std::env::current_exe().expect("unable to get exec path");
current_exe.pop();
let komorebic_exe = current_exe.join("komorebic-no-console.exe");
let mut current_exe_dir = std::env::current_exe().expect("unable to get exec path");
current_exe_dir.pop();
let komorebic_exe = current_exe_dir.join("komorebic.exe");
let komorebic_exe = dunce::simplified(&komorebic_exe);
let startup_dir = startup_dir()?;
let shortcut_file = startup_dir.join("komorebi.lnk");
let shortcut_file = dunce::simplified(&shortcut_file);
let mut arguments = String::from("start");
if let Some(config) = args.config {
arguments.push_str(" --config ");
arguments.push_str(&config.to_string_lossy());
}
let mut arguments = format!(
"start --config {}",
dunce::canonicalize(args.config)?.display()
);
if args.ffm {
arguments.push_str(" --ffm");
@@ -1291,49 +1258,7 @@ fn main() -> Result<()> {
.join("whkdrc");
if static_config.exists() {
let config_source = std::fs::read_to_string(&static_config)?;
let lines: Vec<_> = config_source.lines().collect();
let parsed_config = serde_json::from_str::<serde_json::Value>(&config_source);
if let Err(serde_error) = &parsed_config {
let line = lines[serde_error.line() - 2];
let offset = SourceOffset::from_location(
config_source.clone(),
serde_error.line() - 1,
line.len(),
);
let error_string = serde_error.to_string();
let msgs: Vec<_> = error_string.split(" at ").collect();
let diagnostic = ConfigurationError {
message: msgs[0].to_string(),
src: NamedSource::new("komorebi.json", config_source.clone()),
bad_bit: SourceSpan::new(offset, 2.into()),
};
println!("{:?}", Report::new(diagnostic));
}
println!("Found komorebi.json; this file can be passed to the start command with the --config flag\n");
if let Ok(config) = &parsed_config {
if let Some(asc_path) = config.get("app_specific_configuration_path") {
let normalized_asc_path = asc_path
.to_string()
.replace(
"$Env:USERPROFILE",
&dirs::home_dir().unwrap().to_string_lossy(),
)
.replace('"', "")
.replace('\\', "/");
if !Path::exists(Path::new(&normalized_asc_path)) {
println!("Application specific configuration file path '{normalized_asc_path}' does not exist. Try running 'komorebic fetch-asc'\n");
}
}
}
if config_whkd.exists() {
println!("Found ~/.config/whkdrc; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n");
} else {
@@ -1785,7 +1710,7 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue))
let script = format!(
r#"
Start-Process '{ahk}' '{config}' -WindowStyle hidden
Start-Process {ahk} {config} -WindowStyle hidden
"#,
config = config_ahk.display()
);
@@ -1878,9 +1803,6 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
SubCommand::FocusMonitor(arg) => {
send_message(&SocketMessage::FocusMonitorNumber(arg.target).as_bytes()?)?;
}
SubCommand::FocusLastWorkspace => {
send_message(&SocketMessage::FocusLastWorkspace.as_bytes()?)?;
}
SubCommand::FocusWorkspace(arg) => {
send_message(&SocketMessage::FocusWorkspaceNumber(arg.target).as_bytes()?)?;
}
@@ -1926,12 +1848,6 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
.as_bytes()?,
)?;
}
SubCommand::DisplayIndexPreference(arg) => {
send_message(
&SocketMessage::DisplayIndexPreference(arg.index_preference, arg.display)
.as_bytes()?,
)?;
}
SubCommand::EnsureWorkspaces(workspaces) => {
send_message(
&SocketMessage::EnsureWorkspaces(workspaces.monitor, workspaces.workspace_count)
@@ -1946,9 +1862,6 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
SubCommand::State => {
with_komorebic_socket(|| send_message(&SocketMessage::State.as_bytes()?))?;
}
SubCommand::VisibleWindows => {
with_komorebic_socket(|| send_message(&SocketMessage::VisibleWindows.as_bytes()?))?;
}
SubCommand::Query(arg) => {
with_komorebic_socket(|| {
send_message(&SocketMessage::Query(arg.state_query).as_bytes()?)
@@ -2182,11 +2095,6 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
output_file.display()
);
}
SubCommand::ApplicationSpecificConfigurationSchema => {
with_komorebic_socket(|| {
send_message(&SocketMessage::ApplicationSpecificConfigurationSchema.as_bytes()?)
})?;
}
SubCommand::NotificationSchema => {
with_komorebic_socket(|| send_message(&SocketMessage::NotificationSchema.as_bytes()?))?;
}

View File

@@ -1,128 +0,0 @@
{
"$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"
]
}
}
}

View File

@@ -92,9 +92,6 @@
<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>
@@ -111,8 +108,6 @@
<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>