mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-01-14 06:13:36 +01:00
Compare commits
44 Commits
feature/po
...
v0.1.25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62900c59cb | ||
|
|
a2e9a46582 | ||
|
|
871a53821c | ||
|
|
bcd1c50d82 | ||
|
|
0c41d9ded2 | ||
|
|
4af62fe97b | ||
|
|
7cab062124 | ||
|
|
611fa34567 | ||
|
|
95990d682b | ||
|
|
e363a494c3 | ||
|
|
383533e2d9 | ||
|
|
0b04e3ef93 | ||
|
|
3370e6acc5 | ||
|
|
4ffffc5eec | ||
|
|
2b5f737d14 | ||
|
|
8a455c8ab7 | ||
|
|
3d9871c576 | ||
|
|
cafb8e9a48 | ||
|
|
740cb3c877 | ||
|
|
b8b3b3d615 | ||
|
|
6fce630be5 | ||
|
|
dfd0d604aa | ||
|
|
aff1081ccd | ||
|
|
793e81d43d | ||
|
|
eac4c8e9b1 | ||
|
|
6b42587af4 | ||
|
|
46152621c0 | ||
|
|
b78693118b | ||
|
|
7caa839a00 | ||
|
|
1671f31e3e | ||
|
|
6fe46610fc | ||
|
|
4ba3125dde | ||
|
|
efa562de5c | ||
|
|
b476bee1d8 | ||
|
|
86b07f28dd | ||
|
|
311e37c8a2 | ||
|
|
15c3b32608 | ||
|
|
28b46c54da | ||
|
|
732aca77b5 | ||
|
|
f56fc36557 | ||
|
|
5334e1944e | ||
|
|
d8d087e621 | ||
|
|
b61146ead4 | ||
|
|
16cb811aa9 |
@@ -10,8 +10,8 @@ before:
|
||||
builds:
|
||||
- id: komorebi
|
||||
main: dummy.go
|
||||
goos: ["windows"]
|
||||
goarch: ["amd64"]
|
||||
goos: [ "windows" ]
|
||||
goarch: [ "amd64" ]
|
||||
binary: komorebi
|
||||
hooks:
|
||||
post:
|
||||
@@ -19,8 +19,8 @@ builds:
|
||||
- cp ".\target\x86_64-pc-windows-msvc\release\komorebi.exe" ".\dist\komorebi_windows_amd64_v1\komorebi.exe"
|
||||
- id: komorebic
|
||||
main: dummy.go
|
||||
goos: ["windows"]
|
||||
goarch: ["amd64"]
|
||||
goos: [ "windows" ]
|
||||
goarch: [ "amd64" ]
|
||||
binary: komorebic
|
||||
hooks:
|
||||
post:
|
||||
@@ -28,8 +28,8 @@ builds:
|
||||
- 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"]
|
||||
goos: [ "windows" ]
|
||||
goarch: [ "amd64" ]
|
||||
binary: komorebic-no-console
|
||||
hooks:
|
||||
post:
|
||||
@@ -40,7 +40,7 @@ archives:
|
||||
- name_template: "{{ .ProjectName }}-{{ .Version }}-x86_64-pc-windows-msvc"
|
||||
format: zip
|
||||
files:
|
||||
- LICENSE
|
||||
- LICENSE.md
|
||||
- CHANGELOG.md
|
||||
|
||||
checksum:
|
||||
|
||||
45
CONTRIBUTING.md
Normal file
45
CONTRIBUTING.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Contributing to the Project
|
||||
|
||||
The project is a collection of contributions from both the project leaders and
|
||||
community members. There are many ways to contribute, this can include content
|
||||
in the project repositories, as well as contributing in public and private
|
||||
conversation, assisting users, writing blog posts, and many other ways.
|
||||
|
||||
## How contributions are made
|
||||
|
||||
Contributions to the project primarily happen in the project source
|
||||
repositories, but may also occur in other places, such as discussion forums and
|
||||
public and private discourse.
|
||||
|
||||
## Contributing content to the Project
|
||||
|
||||
In order for the project leaders to manage sustained progress toward the
|
||||
project goals and maintain project velocity, focus and quality, the project may
|
||||
adjust the license terms over time.
|
||||
|
||||
Content contributed to the project must therefore be provided under
|
||||
sufficiently liberal terms to allow these operations to proceed unimpeded. As
|
||||
such contributions are accepted with the following understanding:
|
||||
|
||||
* Contributed content is licensed under the terms of the 0-BSD license
|
||||
* Contributors accept the terms of the project license at the time of
|
||||
contribution
|
||||
|
||||
By making a contribution, you accept both the current project license terms,
|
||||
and that all contributions that you have made are provided under the terms of
|
||||
the 0-BSD license.
|
||||
|
||||
## Zero-Clause BSD
|
||||
|
||||
```
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
||||
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
```
|
||||
289
Cargo.lock
generated
289
Cargo.lock
generated
@@ -127,6 +127,9 @@ name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
@@ -142,9 +145,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.92"
|
||||
version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
|
||||
checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -196,7 +199,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -351,9 +354,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
@@ -392,9 +395,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.2"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "file-id"
|
||||
@@ -413,7 +416,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@@ -571,9 +574,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -666,9 +669,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
|
||||
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -795,7 +798,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"clap",
|
||||
@@ -836,7 +839,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi-client"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
dependencies = [
|
||||
"komorebi",
|
||||
"komorebi-core",
|
||||
@@ -846,7 +849,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebi-core"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
@@ -862,7 +865,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebic"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
@@ -871,6 +874,7 @@ dependencies = [
|
||||
"dunce",
|
||||
"fs-tail",
|
||||
"heck 0.5.0",
|
||||
"komorebi-client",
|
||||
"komorebi-core",
|
||||
"lazy_static",
|
||||
"miette",
|
||||
@@ -889,7 +893,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
@@ -919,9 +923,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
version = "0.2.154"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -941,9 +945,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
@@ -1007,7 +1011,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1039,11 +1043,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
|
||||
checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
|
||||
dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1201,7 +1205,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1259,9 +1263,9 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
@@ -1269,18 +1273,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.9"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"petgraph",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.5.1",
|
||||
"smallvec",
|
||||
"thread-id",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1322,7 +1326,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1387,9 +1391,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1462,6 +1466,15 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.5"
|
||||
@@ -1519,9 +1532,9 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19"
|
||||
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -1568,9 +1581,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.32"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"errno",
|
||||
@@ -1591,9 +1604,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
|
||||
checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
@@ -1627,9 +1640,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.16"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
|
||||
checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
@@ -1639,14 +1652,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.16"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
|
||||
checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1680,40 +1693,40 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
version = "1.0.199"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
version = "1.0.199"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.26.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
|
||||
checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.115"
|
||||
version = "1.0.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
|
||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -1788,9 +1801,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.6"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
|
||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -1821,7 +1834,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1858,9 +1871,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.58"
|
||||
version = "2.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1875,9 +1888,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.10"
|
||||
version = "0.30.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d7c217777061d5a2d652aea771fb9ba98b6dade657204b08c4b9604d11555b"
|
||||
checksum = "87341a165d73787554941cd5ef55ad728011566fe714e987d1b976c15dbc3a83"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"core-foundation-sys",
|
||||
@@ -1944,22 +1957,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.58"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.58"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2128,7 +2141,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2226,9 +2239,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
@@ -2317,7 +2330,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -2351,7 +2364,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -2408,11 +2421,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2428,7 +2441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2440,7 +2453,7 @@ dependencies = [
|
||||
"windows-core 0.54.0",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2449,7 +2462,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2459,7 +2472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2470,7 +2483,7 @@ checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2481,31 +2494,16 @@ checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64"
|
||||
checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2523,7 +2521,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2543,25 +2541,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.4",
|
||||
"windows_aarch64_msvc 0.52.4",
|
||||
"windows_i686_gnu 0.52.4",
|
||||
"windows_i686_msvc 0.52.4",
|
||||
"windows_x86_64_gnu 0.52.4",
|
||||
"windows_x86_64_gnullvm 0.52.4",
|
||||
"windows_x86_64_msvc 0.52.4",
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@@ -2570,15 +2563,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@@ -2588,15 +2575,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@@ -2606,15 +2587,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@@ -2624,15 +2605,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@@ -2642,15 +2617,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@@ -2660,15 +2629,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@@ -2678,9 +2641,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winput"
|
||||
|
||||
@@ -17,6 +17,7 @@ dunce = "1"
|
||||
dirs = "5"
|
||||
color-eyre = "0.6"
|
||||
serde_json = { package = "serde_json_lenient", version = "0.1" }
|
||||
sysinfo = "0.30"
|
||||
|
||||
[workspace.dependencies.windows]
|
||||
version = "0.54"
|
||||
|
||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Jade Iqbal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
105
LICENSE.md
Normal file
105
LICENSE.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# PolyForm Strict License 1.0.0
|
||||
|
||||
<https://polyformproject.org/licenses/strict/1.0.0>
|
||||
|
||||
## Acceptance
|
||||
|
||||
In order to get any license under these terms, you must agree
|
||||
to them as both strict obligations and conditions to all
|
||||
your licenses.
|
||||
|
||||
## Copyright License
|
||||
|
||||
The licensor grants you a copyright license for the software
|
||||
to do everything you might do with the software that would
|
||||
otherwise infringe the licensor's copyright in it for any
|
||||
permitted purpose, other than distributing the software or
|
||||
making changes or new works based on the software.
|
||||
|
||||
## Patent License
|
||||
|
||||
The licensor grants you a patent license for the software that
|
||||
covers patent claims the licensor can license, or becomes able
|
||||
to license, that you would infringe by using the software.
|
||||
|
||||
## Noncommercial Purposes
|
||||
|
||||
Any noncommercial purpose is a permitted purpose.
|
||||
|
||||
## Personal Uses
|
||||
|
||||
Personal use for research, experiment, and testing for
|
||||
the benefit of public knowledge, personal study, private
|
||||
entertainment, hobby projects, amateur pursuits, or religious
|
||||
observance, without any anticipated commercial application,
|
||||
is use for a permitted purpose.
|
||||
|
||||
## Noncommercial Organizations
|
||||
|
||||
Use by any charitable organization, educational institution,
|
||||
public research organization, public safety or health
|
||||
organization, environmental protection organization,
|
||||
or government institution is use for a permitted purpose
|
||||
regardless of the source of funding or obligations resulting
|
||||
from the funding.
|
||||
|
||||
## Fair Use
|
||||
|
||||
You may have "fair use" rights for the software under the
|
||||
law. These terms do not limit them.
|
||||
|
||||
## No Other Rights
|
||||
|
||||
These terms do not allow you to sublicense or transfer any of
|
||||
your licenses to anyone else, or prevent the licensor from
|
||||
granting licenses to anyone else. These terms do not imply
|
||||
any other licenses.
|
||||
|
||||
## Patent Defense
|
||||
|
||||
If you make any written claim that the software infringes or
|
||||
contributes to infringement of any patent, your patent license
|
||||
for the software granted under these terms ends immediately. If
|
||||
your company makes such a claim, your patent license ends
|
||||
immediately for work on behalf of your company.
|
||||
|
||||
## Violations
|
||||
|
||||
The first time you are notified in writing that you have
|
||||
violated any of these terms, or done anything with the software
|
||||
not covered by your licenses, your licenses can nonetheless
|
||||
continue if you come into full compliance with these terms,
|
||||
and take practical steps to correct past violations, within
|
||||
32 days of receiving notice. Otherwise, all your licenses
|
||||
end immediately.
|
||||
|
||||
## No Liability
|
||||
|
||||
***As far as the law allows, the software comes as is, without
|
||||
any warranty or condition, and the licensor will not be liable
|
||||
to you for any damages arising out of these terms or the use
|
||||
or nature of the software, under any kind of legal claim.***
|
||||
|
||||
## Definitions
|
||||
|
||||
The **licensor** is the individual or entity offering these
|
||||
terms, and the **software** is the software the licensor makes
|
||||
available under these terms.
|
||||
|
||||
**You** refers to the individual or entity agreeing to these
|
||||
terms.
|
||||
|
||||
**Your company** is any legal entity, sole proprietorship,
|
||||
or other kind of organization that you work for, plus all
|
||||
organizations that have control over, are under the control of,
|
||||
or are under common control with that organization. **Control**
|
||||
means ownership of substantially all the assets of an entity,
|
||||
or the power to direct its management and policies by vote,
|
||||
contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
**Your licenses** are all the licenses granted to you for the
|
||||
software under these terms.
|
||||
|
||||
**Use** means anything you do with the software requiring one
|
||||
of your licenses.
|
||||
|
||||
16
README.md
16
README.md
@@ -169,6 +169,20 @@ ability for users to specify colours in `komorebi.json` in Hex format alongside
|
||||
There is also a process in place for graceful, non-breaking, deprecation of configuration options that are no longer
|
||||
required.
|
||||
|
||||
## License
|
||||
|
||||
`komorebi` is licensed under the [PolyForm Strict 1.0.0
|
||||
license](https://polyformproject.org/licenses/strict/1.0.0). On a high level
|
||||
this means that you are free to do whatever you want with `komorebi` other than
|
||||
redistribution, or distribution of new works (ie. hard-forks) based on the
|
||||
software.
|
||||
|
||||
Anyone is free to make their own fork of `komorebi` with changes intended
|
||||
either for personal use or for integration back upstream via pull requests.
|
||||
|
||||
Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about how
|
||||
code contributions to `komorebi` are licensed.
|
||||
|
||||
# Development
|
||||
|
||||
If you use IntelliJ, you should enable the following settings to ensure that code generated by macros is recognised by
|
||||
@@ -324,7 +338,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
|
||||
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
|
||||
|
||||
```rust
|
||||
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.24"}
|
||||
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.25"}
|
||||
|
||||
use anyhow::Result;
|
||||
use komorebi_client::Notification;
|
||||
|
||||
@@ -7,7 +7,7 @@ Usage: komorebic.exe change-layout <DEFAULT_LAYOUT>
|
||||
|
||||
Arguments:
|
||||
<DEFAULT_LAYOUT>
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid]
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid, right-main-vertical-stack]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
12
docs/cli/global-state.md
Normal file
12
docs/cli/global-state.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# global-state
|
||||
|
||||
```
|
||||
Show a JSON representation of the current global state
|
||||
|
||||
Usage: komorebic.exe global-state
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
19
docs/cli/move-to-monitor-workspace.md
Normal file
19
docs/cli/move-to-monitor-workspace.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# move-to-monitor-workspace
|
||||
|
||||
```
|
||||
Move the focused window to the specified monitor workspace
|
||||
|
||||
Usage: komorebic.exe move-to-monitor-workspace <TARGET_MONITOR> <TARGET_WORKSPACE>
|
||||
|
||||
Arguments:
|
||||
<TARGET_MONITOR>
|
||||
Target monitor index (zero-indexed)
|
||||
|
||||
<TARGET_WORKSPACE>
|
||||
Workspace index on the target monitor (zero-indexed)
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -13,7 +13,7 @@ Arguments:
|
||||
The number of window containers on-screen required to trigger this layout rule
|
||||
|
||||
<LAYOUT>
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid]
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid, right-main-vertical-stack]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
@@ -10,7 +10,7 @@ Arguments:
|
||||
Target workspace name
|
||||
|
||||
<VALUE>
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid]
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid, right-main-vertical-stack]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
@@ -16,7 +16,7 @@ Arguments:
|
||||
The number of window containers on-screen required to trigger this layout rule
|
||||
|
||||
<LAYOUT>
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid]
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid, right-main-vertical-stack]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
@@ -13,7 +13,7 @@ Arguments:
|
||||
Workspace index on the specified monitor (zero-indexed)
|
||||
|
||||
<VALUE>
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid]
|
||||
[possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack, grid, right-main-vertical-stack]
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
|
||||
@@ -21,9 +21,6 @@ hotkey bindings.
|
||||
# save the latest generated komorebic library to ~/komorebic.lib.ahk
|
||||
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.20/komorebic.lib.ahk -OutFile $Env:USERPROFILE\komorebic.lib.ahk
|
||||
|
||||
# save the latest generated app-specific config tweaks and fixes to ~/komorebi.generated.ahk
|
||||
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.20/komorebi.generated.ahk -OutFile $Env:USERPROFILE\komorebi.generated.ahk
|
||||
|
||||
# save the sample komorebi configuration file to ~/komorebi.ahk
|
||||
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.20/komorebi.sample.ahk -OutFile $Env:USERPROFILE\komorebi.ahk
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
❗️**NOTE**: A significant number of force-manage window rules for the most
|
||||
common applications are [already generated for
|
||||
you](https://github.com/LGUG2Z/komorebi/#generating-common-application-specific-configurations)
|
||||
you](https://github.com/LGUG2Z/komorebi-application-specific-configuration)
|
||||
|
||||
In some rare cases, a window may not automatically be registered to be managed
|
||||
by `komorebi`. You can add rules to enforce this behaviour in the
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
❗️**NOTE**: A significant number of ignored window rules for the most common
|
||||
applications are [already generated for
|
||||
you](https://github.com/LGUG2Z/komorebi/#generating-common-application-specific-configurations)
|
||||
you](https://github.com/LGUG2Z/komorebi-application-specific-configuration)
|
||||
|
||||
Sometimes you will want a specific application to never be tiled, and instead
|
||||
float all the time. You can add rules to enforce this behaviour in the
|
||||
|
||||
@@ -101,6 +101,16 @@ monocle.
|
||||
+-------+-----+
|
||||
```
|
||||
|
||||
### RightMainVerticalStack
|
||||
|
||||
```
|
||||
+-----+-------+
|
||||
| | |
|
||||
+-----+ |
|
||||
| | |
|
||||
+-----+-------+
|
||||
```
|
||||
|
||||
#### Horizontal Stack
|
||||
|
||||
```
|
||||
@@ -122,6 +132,7 @@ monocle.
|
||||
```
|
||||
|
||||
#### Rows
|
||||
|
||||
If you have a vertical monitor, I recommend using this layout.
|
||||
|
||||
```
|
||||
@@ -133,6 +144,7 @@ If you have a vertical monitor, I recommend using this layout.
|
||||
```
|
||||
|
||||
#### Ultrawide Vertical Stack
|
||||
|
||||
If you have an ultrawide monitor, I recommend using this layout.
|
||||
|
||||
```
|
||||
@@ -146,6 +158,7 @@ If you have an ultrawide monitor, I recommend using this layout.
|
||||
```
|
||||
|
||||
### Grid
|
||||
|
||||
If you like the `grid` layout in [LeftWM](https://github.com/leftwm/leftwm-layouts) this is almost exactly the same!
|
||||
|
||||
```
|
||||
@@ -183,7 +196,8 @@ which shell you use in your terminal.
|
||||
* `powershell` - set this if you are using the version of PowerShell that comes
|
||||
installed with Windows 10+ (the executable file for this is `powershell.exe`)
|
||||
|
||||
* `pwsh` - set this if you are using PowerShell 7+, which you have installed yourself either through the Windows Store or WinGet (the executable file for this is `pwsh.exe`)
|
||||
* `pwsh` - set this if you are using PowerShell 7+, which you have installed yourself either through the Windows Store
|
||||
or WinGet (the executable file for this is `pwsh.exe`)
|
||||
|
||||
* `cmd` - set this if you don't want to use PowerShell at all and instead you
|
||||
want to call commands through the shell used by the old-school Command
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.24/schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.25/schema.json",
|
||||
"app_specific_configuration_path": "$Env:USERPROFILE/applications.yaml",
|
||||
"window_hiding_behaviour": "Cloak",
|
||||
"cross_monitor_move_behaviour": "Insert",
|
||||
"default_workspace_padding": 20,
|
||||
"default_container_padding": 20,
|
||||
"border_padding": 8,
|
||||
"border_width": 8,
|
||||
"border_offset": -1,
|
||||
"active_window_border": false,
|
||||
"active_window_border_colours": {
|
||||
@@ -13,6 +13,16 @@
|
||||
"stack": "#00a542",
|
||||
"monocle": "#ff3399"
|
||||
},
|
||||
"stackbar": {
|
||||
"height": 40,
|
||||
"mode": "Never",
|
||||
"tabs": {
|
||||
"width": 300,
|
||||
"focused_text": "#00a542",
|
||||
"unfocused_text": "#b3b3b3",
|
||||
"background": "#141414"
|
||||
}
|
||||
},
|
||||
"monitors": [
|
||||
{
|
||||
"workspaces": [
|
||||
@@ -35,6 +45,14 @@
|
||||
{
|
||||
"name": "V",
|
||||
"layout": "Rows"
|
||||
},
|
||||
{
|
||||
"name": "VI",
|
||||
"layout": "Grid"
|
||||
},
|
||||
{
|
||||
"name": "VII",
|
||||
"layout": "RightMainVerticalStack"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi-client"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
pub use komorebi::colour::Colour;
|
||||
pub use komorebi::colour::Rgb;
|
||||
pub use komorebi::container::Container;
|
||||
pub use komorebi::monitor::Monitor;
|
||||
pub use komorebi::ring::Ring;
|
||||
pub use komorebi::window::Window;
|
||||
pub use komorebi::window_manager_event::WindowManagerEvent;
|
||||
pub use komorebi::workspace::Workspace;
|
||||
pub use komorebi::ActiveWindowBorderColours;
|
||||
pub use komorebi::GlobalState;
|
||||
pub use komorebi::Notification;
|
||||
pub use komorebi::NotificationEvent;
|
||||
pub use komorebi::RuleDebug;
|
||||
pub use komorebi::StackbarConfig;
|
||||
pub use komorebi::State;
|
||||
pub use komorebi::StaticConfig;
|
||||
pub use komorebi::TabsConfig;
|
||||
pub use komorebi_core::ActiveWindowBorderStyle;
|
||||
pub use komorebi_core::Arrangement;
|
||||
pub use komorebi_core::Axis;
|
||||
pub use komorebi_core::CustomLayout;
|
||||
@@ -20,6 +29,8 @@ pub use komorebi_core::Layout;
|
||||
pub use komorebi_core::OperationDirection;
|
||||
pub use komorebi_core::Rect;
|
||||
pub use komorebi_core::SocketMessage;
|
||||
pub use komorebi_core::StackbarMode;
|
||||
pub use komorebi_core::WindowKind;
|
||||
|
||||
use komorebi::DATA_DIR;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi-core"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -44,8 +44,54 @@ impl Arrangement for DefaultLayout {
|
||||
layout_flip,
|
||||
calculate_resize_adjustments(resize_dimensions),
|
||||
),
|
||||
Self::Columns => columns(area, len),
|
||||
Self::Rows => rows(area, len),
|
||||
Self::Columns => {
|
||||
let mut layouts = columns(area, len);
|
||||
|
||||
let adjustment = calculate_columns_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) => match len {
|
||||
2.. => columns_reverse(&mut layouts),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::Rows => {
|
||||
let mut layouts = rows(area, len);
|
||||
|
||||
let adjustment = calculate_rows_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) => match len {
|
||||
2.. => rows_reverse(&mut layouts),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::VerticalStack => {
|
||||
let mut layouts: Vec<Rect> = vec![];
|
||||
|
||||
@@ -54,16 +100,8 @@ impl Arrangement for DefaultLayout {
|
||||
_ => area.right / 2,
|
||||
};
|
||||
|
||||
let mut main_left = area.left;
|
||||
let mut stack_left = area.left + primary_right;
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => {
|
||||
main_left = main_left + area.right - primary_right;
|
||||
stack_left = area.left;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let main_left = area.left;
|
||||
let stack_left = area.left + primary_right;
|
||||
|
||||
if len >= 1 {
|
||||
layouts.push(Rect {
|
||||
@@ -86,6 +124,113 @@ impl Arrangement for DefaultLayout {
|
||||
}
|
||||
}
|
||||
|
||||
let adjustment = calculate_vertical_stack_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) => match len {
|
||||
2.. => {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left;
|
||||
}
|
||||
primary.left = rest[0].left + rest[0].right;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) => match len {
|
||||
3.. => rows_reverse(&mut layouts[1..]),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::RightMainVerticalStack => {
|
||||
// Shamelessly borrowed from LeftWM: https://github.com/leftwm/leftwm/commit/f673851745295ae7584a102535566f559d96a941
|
||||
let mut layouts: Vec<Rect> = vec![];
|
||||
|
||||
let primary_width = match len {
|
||||
1 => area.right,
|
||||
_ => area.right / 2,
|
||||
};
|
||||
|
||||
let primary_left = match len {
|
||||
1 => 0,
|
||||
_ => area.right - primary_width,
|
||||
};
|
||||
|
||||
if len >= 1 {
|
||||
layouts.push(Rect {
|
||||
left: area.left + primary_left,
|
||||
top: area.top,
|
||||
right: primary_width,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
|
||||
if len > 1 {
|
||||
layouts.append(&mut rows(
|
||||
&Rect {
|
||||
left: area.left,
|
||||
top: area.top,
|
||||
right: primary_left,
|
||||
bottom: area.bottom,
|
||||
},
|
||||
len - 1,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let adjustment = calculate_right_vertical_stack_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) => match len {
|
||||
2.. => {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
primary.left = rest[0].left;
|
||||
for rect in rest.iter_mut() {
|
||||
rect.left = primary.left + primary.right;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) => match len {
|
||||
3.. => rows_reverse(&mut layouts[1..]),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::HorizontalStack => {
|
||||
@@ -96,16 +241,8 @@ impl Arrangement for DefaultLayout {
|
||||
_ => area.bottom / 2,
|
||||
};
|
||||
|
||||
let mut main_top = area.top;
|
||||
let mut stack_top = area.top + bottom;
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) if len > 1 => {
|
||||
main_top = main_top + area.bottom - bottom;
|
||||
stack_top = area.top;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let main_top = area.top;
|
||||
let stack_top = area.top + bottom;
|
||||
|
||||
if len >= 1 {
|
||||
layouts.push(Rect {
|
||||
@@ -128,9 +265,152 @@ impl Arrangement for DefaultLayout {
|
||||
}
|
||||
}
|
||||
|
||||
let adjustment = calculate_horizontal_stack_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) => match len {
|
||||
2.. => {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
|
||||
for rect in rest.iter_mut() {
|
||||
rect.top = primary.top;
|
||||
}
|
||||
primary.top = rest[0].top + rest[0].bottom;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) => match len {
|
||||
3.. => columns_reverse(&mut layouts[1..]),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
}
|
||||
Self::UltrawideVerticalStack => ultrawide(area, len, layout_flip, resize_dimensions),
|
||||
Self::UltrawideVerticalStack => {
|
||||
let mut layouts: Vec<Rect> = vec![];
|
||||
|
||||
let primary_right = match len {
|
||||
1 => area.right,
|
||||
_ => area.right / 2,
|
||||
};
|
||||
|
||||
let secondary_right = match len {
|
||||
1 => 0,
|
||||
2 => area.right - primary_right,
|
||||
_ => (area.right - primary_right) / 2,
|
||||
};
|
||||
|
||||
let (primary_left, secondary_left, stack_left) = match len {
|
||||
1 => (area.left, 0, 0),
|
||||
2 => {
|
||||
let primary = area.left + secondary_right;
|
||||
let secondary = area.left;
|
||||
|
||||
(primary, secondary, 0)
|
||||
}
|
||||
_ => {
|
||||
let primary = area.left + secondary_right;
|
||||
let secondary = area.left;
|
||||
let stack = area.left + primary_right + secondary_right;
|
||||
|
||||
(primary, secondary, stack)
|
||||
}
|
||||
};
|
||||
|
||||
if len >= 1 {
|
||||
layouts.push(Rect {
|
||||
left: primary_left,
|
||||
top: area.top,
|
||||
right: primary_right,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
|
||||
if len >= 2 {
|
||||
layouts.push(Rect {
|
||||
left: secondary_left,
|
||||
top: area.top,
|
||||
right: secondary_right,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
|
||||
if len > 2 {
|
||||
layouts.append(&mut rows(
|
||||
&Rect {
|
||||
left: stack_left,
|
||||
top: area.top,
|
||||
right: secondary_right,
|
||||
bottom: area.bottom,
|
||||
},
|
||||
len - 2,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let adjustment = calculate_ultrawide_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) => match len {
|
||||
2 => {
|
||||
let (primary, secondary) = layouts.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
let secondary = &mut secondary[0];
|
||||
|
||||
primary.left = secondary.left;
|
||||
secondary.left = primary.left + primary.right;
|
||||
}
|
||||
3.. => {
|
||||
let (primary, rest) = layouts.split_at_mut(1);
|
||||
let (secondary, tertiary) = rest.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
let secondary = &mut secondary[0];
|
||||
|
||||
for rect in tertiary.iter_mut() {
|
||||
rect.left = secondary.left;
|
||||
}
|
||||
primary.left = tertiary[0].left + tertiary[0].right;
|
||||
secondary.left = primary.left + primary.right;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Vertical | Axis::HorizontalAndVertical) => match len {
|
||||
4.. => rows_reverse(&mut layouts[2..]),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
layouts
|
||||
},
|
||||
#[allow(
|
||||
clippy::cast_precision_loss,
|
||||
clippy::cast_possible_truncation,
|
||||
@@ -321,7 +601,6 @@ impl Arrangement for CustomLayout {
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Axis {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
@@ -370,6 +649,22 @@ fn rows(area: &Rect, len: usize) -> Vec<Rect> {
|
||||
layouts
|
||||
}
|
||||
|
||||
fn columns_reverse(columns: &mut [Rect]) {
|
||||
let len = columns.len();
|
||||
columns[len - 1].left = columns[0].left;
|
||||
for i in (0..len - 1).rev() {
|
||||
columns[i].left = columns[i + 1].left + columns[i + 1].right;
|
||||
}
|
||||
}
|
||||
|
||||
fn rows_reverse(rows: &mut [Rect]) {
|
||||
let len = rows.len();
|
||||
rows[len - 1].top = rows[0].top;
|
||||
for i in (0..len - 1).rev() {
|
||||
rows[i].top = rows[i + 1].top + rows[i + 1].bottom;
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_resize_adjustments(resize_dimensions: &[Option<Rect>]) -> Vec<Option<Rect>> {
|
||||
let mut resize_adjustments = resize_dimensions.to_vec();
|
||||
|
||||
@@ -563,6 +858,187 @@ fn recursive_fibonacci(
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_columns_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
match len {
|
||||
0 | 1 => (),
|
||||
_ => {
|
||||
for (i, rect) in resize_dimensions.iter().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
if i != 0 {
|
||||
resize_right(&mut result[i - 1], rect.left);
|
||||
resize_left(&mut result[i], rect.left);
|
||||
}
|
||||
|
||||
if i != len - 1 {
|
||||
resize_right(&mut result[i], rect.right);
|
||||
resize_left(&mut result[i + 1], rect.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn calculate_rows_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
match len {
|
||||
0 | 1 => (),
|
||||
_ => {
|
||||
for (i, rect) in resize_dimensions.iter().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
if i != 0 {
|
||||
resize_bottom(&mut result[i - 1], rect.top);
|
||||
resize_top(&mut result[i], rect.top);
|
||||
}
|
||||
|
||||
if i != len - 1 {
|
||||
resize_bottom(&mut result[i], rect.bottom);
|
||||
resize_top(&mut result[i + 1], rect.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn calculate_vertical_stack_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
match len {
|
||||
// One container can't be resized
|
||||
0 | 1 => (),
|
||||
_ => {
|
||||
let (master, stack) = result.split_at_mut(1);
|
||||
let primary = &mut master[0];
|
||||
|
||||
if let Some(resize) = resize_dimensions[0] {
|
||||
resize_right(primary, resize.right);
|
||||
for s in &mut *stack {
|
||||
resize_left(s, resize.right);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stack on the right
|
||||
for (i, rect) in resize_dimensions[1..].iter().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
resize_right(primary, rect.left);
|
||||
stack
|
||||
.iter_mut()
|
||||
.for_each(|vertical_element| resize_left(vertical_element, rect.left));
|
||||
|
||||
// Containers in stack except first can be resized up displacing container
|
||||
// above them
|
||||
if i != 0 {
|
||||
resize_bottom(&mut stack[i - 1], rect.top);
|
||||
resize_top(&mut stack[i], rect.top);
|
||||
}
|
||||
|
||||
// Containers in stack except last can be resized down displacing container
|
||||
// below them
|
||||
if i != stack.len() - 1 {
|
||||
resize_bottom(&mut stack[i], rect.bottom);
|
||||
resize_top(&mut stack[i + 1], rect.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn calculate_right_vertical_stack_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
match len {
|
||||
// One container can't be resized
|
||||
0 | 1 => (),
|
||||
_ => {
|
||||
let (master, stack) = result.split_at_mut(1);
|
||||
let primary = &mut master[0];
|
||||
|
||||
if let Some(resize) = resize_dimensions[0] {
|
||||
resize_left(primary, resize.left);
|
||||
for s in &mut *stack {
|
||||
resize_right(s, resize.left);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stack on the left
|
||||
for (i, rect) in resize_dimensions[1..].iter().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
resize_left(primary, rect.right);
|
||||
stack
|
||||
.iter_mut()
|
||||
.for_each(|vertical_element| resize_right(vertical_element, rect.right));
|
||||
|
||||
// Containers in stack except first can be resized up displacing container
|
||||
// above them
|
||||
if i != 0 {
|
||||
resize_bottom(&mut stack[i - 1], rect.top);
|
||||
resize_top(&mut stack[i], rect.top);
|
||||
}
|
||||
|
||||
// Containers in stack except last can be resized down displacing container
|
||||
// below them
|
||||
if i != stack.len() - 1 {
|
||||
resize_bottom(&mut stack[i], rect.bottom);
|
||||
resize_top(&mut stack[i + 1], rect.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn calculate_horizontal_stack_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
match len {
|
||||
0 | 1 => (),
|
||||
_ => {
|
||||
let (primary, rest) = result.split_at_mut(1);
|
||||
let primary = &mut primary[0];
|
||||
if let Some(resize_primary) = resize_dimensions[0] {
|
||||
resize_bottom(primary, resize_primary.bottom);
|
||||
|
||||
for horizontal_element in &mut *rest {
|
||||
resize_top(horizontal_element, resize_primary.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
for (i, rect) in resize_dimensions[1..].iter().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
resize_bottom(primary, rect.top);
|
||||
rest.iter_mut()
|
||||
.for_each(|vertical_element| resize_top(vertical_element, rect.top));
|
||||
|
||||
if i != 0 {
|
||||
resize_right(&mut rest[i - 1], rect.left);
|
||||
resize_left(&mut rest[i], rect.left);
|
||||
}
|
||||
|
||||
if i != rest.len() - 1 {
|
||||
resize_right(&mut rest[i], rect.right);
|
||||
resize_left(&mut rest[i + 1], rect.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn calculate_ultrawide_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
|
||||
let len = resize_dimensions.len();
|
||||
let mut result = vec![Rect::default(); len];
|
||||
@@ -653,99 +1129,3 @@ fn resize_top(rect: &mut Rect, resize: i32) {
|
||||
fn resize_bottom(rect: &mut Rect, resize: i32) {
|
||||
rect.bottom += resize / 2;
|
||||
}
|
||||
|
||||
fn ultrawide(
|
||||
area: &Rect,
|
||||
len: usize,
|
||||
layout_flip: Option<Axis>,
|
||||
resize_dimensions: &[Option<Rect>],
|
||||
) -> Vec<Rect> {
|
||||
let mut layouts: Vec<Rect> = vec![];
|
||||
|
||||
let primary_right = match len {
|
||||
1 => area.right,
|
||||
_ => area.right / 2,
|
||||
};
|
||||
|
||||
let secondary_right = match len {
|
||||
1 => 0,
|
||||
2 => area.right - primary_right,
|
||||
_ => (area.right - primary_right) / 2,
|
||||
};
|
||||
|
||||
let (primary_left, secondary_left, stack_left) = match len {
|
||||
1 => (area.left, 0, 0),
|
||||
2 => {
|
||||
let mut primary = area.left + secondary_right;
|
||||
let mut secondary = area.left;
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => {
|
||||
primary = area.left;
|
||||
secondary = area.left + primary_right;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
(primary, secondary, 0)
|
||||
}
|
||||
_ => {
|
||||
let primary = area.left + secondary_right;
|
||||
let mut secondary = area.left;
|
||||
let mut stack = area.left + primary_right + secondary_right;
|
||||
|
||||
match layout_flip {
|
||||
Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => {
|
||||
secondary = area.left + primary_right + secondary_right;
|
||||
stack = area.left;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
(primary, secondary, stack)
|
||||
}
|
||||
};
|
||||
|
||||
if len >= 1 {
|
||||
layouts.push(Rect {
|
||||
left: primary_left,
|
||||
top: area.top,
|
||||
right: primary_right,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
|
||||
if len >= 2 {
|
||||
layouts.push(Rect {
|
||||
left: secondary_left,
|
||||
top: area.top,
|
||||
right: secondary_right,
|
||||
bottom: area.bottom,
|
||||
});
|
||||
|
||||
if len > 2 {
|
||||
layouts.append(&mut rows(
|
||||
&Rect {
|
||||
left: stack_left,
|
||||
top: area.top,
|
||||
right: secondary_right,
|
||||
bottom: area.bottom,
|
||||
},
|
||||
len - 2,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let adjustment = calculate_ultrawide_adjustment(resize_dimensions);
|
||||
layouts
|
||||
.iter_mut()
|
||||
.zip(adjustment.iter())
|
||||
.for_each(|(layout, adjustment)| {
|
||||
layout.top += adjustment.top;
|
||||
layout.bottom += adjustment.bottom;
|
||||
layout.left += adjustment.left;
|
||||
layout.right += adjustment.right;
|
||||
});
|
||||
|
||||
layouts
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use strum::EnumString;
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum CycleDirection {
|
||||
Previous,
|
||||
Next,
|
||||
|
||||
@@ -10,9 +10,18 @@ use crate::Rect;
|
||||
use crate::Sizing;
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum DefaultLayout {
|
||||
BSP,
|
||||
Columns,
|
||||
@@ -21,6 +30,7 @@ pub enum DefaultLayout {
|
||||
HorizontalStack,
|
||||
UltrawideVerticalStack,
|
||||
Grid,
|
||||
RightMainVerticalStack,
|
||||
// NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle`
|
||||
}
|
||||
|
||||
@@ -35,7 +45,16 @@ impl DefaultLayout {
|
||||
sizing: Sizing,
|
||||
delta: i32,
|
||||
) -> Option<Rect> {
|
||||
if !matches!(self, Self::BSP) && !matches!(self, Self::UltrawideVerticalStack) {
|
||||
if !matches!(
|
||||
self,
|
||||
Self::BSP
|
||||
| Self::Columns
|
||||
| Self::Rows
|
||||
| Self::VerticalStack
|
||||
| Self::RightMainVerticalStack
|
||||
| Self::HorizontalStack
|
||||
| Self::UltrawideVerticalStack
|
||||
) {
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -137,7 +156,8 @@ impl DefaultLayout {
|
||||
Self::VerticalStack => Self::HorizontalStack,
|
||||
Self::HorizontalStack => Self::UltrawideVerticalStack,
|
||||
Self::UltrawideVerticalStack => Self::Grid,
|
||||
Self::Grid => Self::BSP,
|
||||
Self::Grid => Self::RightMainVerticalStack,
|
||||
Self::RightMainVerticalStack => Self::BSP,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +170,8 @@ impl DefaultLayout {
|
||||
Self::VerticalStack => Self::Rows,
|
||||
Self::Rows => Self::Columns,
|
||||
Self::Columns => Self::Grid,
|
||||
Self::Grid => Self::BSP,
|
||||
Self::Grid => Self::RightMainVerticalStack,
|
||||
Self::RightMainVerticalStack => Self::BSP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ impl Direction for DefaultLayout {
|
||||
Self::BSP => count > 2 && idx != 0 && idx != 1,
|
||||
Self::Columns => false,
|
||||
Self::Rows | Self::HorizontalStack => idx != 0,
|
||||
Self::VerticalStack => idx != 0 && idx != 1,
|
||||
Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != 1,
|
||||
Self::UltrawideVerticalStack => idx > 2,
|
||||
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||
},
|
||||
@@ -103,7 +103,7 @@ impl Direction for DefaultLayout {
|
||||
Self::BSP => count > 2 && idx != count - 1 && idx % 2 != 0,
|
||||
Self::Columns => false,
|
||||
Self::Rows => idx != count - 1,
|
||||
Self::VerticalStack => idx != 0 && idx != count - 1,
|
||||
Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != count - 1,
|
||||
Self::HorizontalStack => idx == 0,
|
||||
Self::UltrawideVerticalStack => idx > 1 && idx != count - 1,
|
||||
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||
@@ -111,6 +111,7 @@ impl Direction for DefaultLayout {
|
||||
OperationDirection::Left => match self {
|
||||
Self::BSP => count > 1 && idx != 0,
|
||||
Self::Columns | Self::VerticalStack => idx != 0,
|
||||
Self::RightMainVerticalStack => idx == 0,
|
||||
Self::Rows => false,
|
||||
Self::HorizontalStack => idx != 0 && idx != 1,
|
||||
Self::UltrawideVerticalStack => count > 1 && idx != 1,
|
||||
@@ -121,6 +122,7 @@ impl Direction for DefaultLayout {
|
||||
Self::Columns => idx != count - 1,
|
||||
Self::Rows => false,
|
||||
Self::VerticalStack => idx == 0,
|
||||
Self::RightMainVerticalStack => idx != 0,
|
||||
Self::HorizontalStack => idx != 0 && idx != count - 1,
|
||||
Self::UltrawideVerticalStack => match count {
|
||||
0 | 1 => false,
|
||||
@@ -147,7 +149,10 @@ impl Direction for DefaultLayout {
|
||||
}
|
||||
}
|
||||
Self::Columns => unreachable!(),
|
||||
Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx - 1,
|
||||
Self::Rows
|
||||
| Self::VerticalStack
|
||||
| Self::UltrawideVerticalStack
|
||||
| Self::RightMainVerticalStack => idx - 1,
|
||||
Self::HorizontalStack => 0,
|
||||
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||
}
|
||||
@@ -160,7 +165,11 @@ impl Direction for DefaultLayout {
|
||||
count: Option<usize>,
|
||||
) -> usize {
|
||||
match self {
|
||||
Self::BSP | Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx + 1,
|
||||
Self::BSP
|
||||
| Self::Rows
|
||||
| Self::VerticalStack
|
||||
| Self::UltrawideVerticalStack
|
||||
| Self::RightMainVerticalStack => idx + 1,
|
||||
Self::Columns => unreachable!(),
|
||||
Self::HorizontalStack => 1,
|
||||
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||
@@ -184,6 +193,7 @@ impl Direction for DefaultLayout {
|
||||
Self::Columns | Self::HorizontalStack => idx - 1,
|
||||
Self::Rows => unreachable!(),
|
||||
Self::VerticalStack => 0,
|
||||
Self::RightMainVerticalStack => 1,
|
||||
Self::UltrawideVerticalStack => match idx {
|
||||
0 => 1,
|
||||
1 => unreachable!(),
|
||||
@@ -203,6 +213,7 @@ impl Direction for DefaultLayout {
|
||||
Self::BSP | Self::Columns | Self::HorizontalStack => idx + 1,
|
||||
Self::Rows => unreachable!(),
|
||||
Self::VerticalStack => 1,
|
||||
Self::RightMainVerticalStack => 0,
|
||||
Self::UltrawideVerticalStack => match idx {
|
||||
1 => 0,
|
||||
0 => 2,
|
||||
|
||||
@@ -57,6 +57,7 @@ pub enum SocketMessage {
|
||||
SendContainerToWorkspaceNumber(usize),
|
||||
CycleSendContainerToWorkspace(CycleDirection),
|
||||
SendContainerToMonitorWorkspaceNumber(usize, usize),
|
||||
MoveContainerToMonitorWorkspaceNumber(usize, usize),
|
||||
SendContainerToNamedWorkspace(String),
|
||||
MoveWorkspaceToMonitorNumber(usize),
|
||||
SwapWorkspacesToMonitorNumber(usize),
|
||||
@@ -131,9 +132,16 @@ pub enum SocketMessage {
|
||||
AltFocusHack(bool),
|
||||
ActiveWindowBorder(bool),
|
||||
ActiveWindowBorderColour(WindowKind, u32, u32, u32),
|
||||
ActiveWindowBorderWidth(i32),
|
||||
ActiveWindowBorderOffset(i32),
|
||||
ActiveWindowBorderStyle(ActiveWindowBorderStyle),
|
||||
BorderWidth(i32),
|
||||
BorderOffset(i32),
|
||||
InvisibleBorders(Rect),
|
||||
StackbarMode(StackbarMode),
|
||||
StackbarFocusedTextColour(u32, u32, u32),
|
||||
StackbarUnfocusedTextColour(u32, u32, u32),
|
||||
StackbarBackgroundColour(u32, u32, u32),
|
||||
StackbarHeight(i32),
|
||||
StackbarTabWidth(i32),
|
||||
WorkAreaOffset(Rect),
|
||||
MonitorWorkAreaOffset(usize, Rect),
|
||||
ResizeDelta(i32),
|
||||
@@ -148,6 +156,7 @@ pub enum SocketMessage {
|
||||
IdentifyLayeredApplication(ApplicationIdentifier, String),
|
||||
IdentifyBorderOverflowApplication(ApplicationIdentifier, String),
|
||||
State,
|
||||
GlobalState,
|
||||
VisibleWindows,
|
||||
Query(StateQuery),
|
||||
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
||||
@@ -165,6 +174,7 @@ pub enum SocketMessage {
|
||||
SocketSchema,
|
||||
StaticConfigSchema,
|
||||
GenerateStaticConfig,
|
||||
DebugWindow(isize),
|
||||
}
|
||||
|
||||
impl SocketMessage {
|
||||
@@ -181,10 +191,29 @@ impl FromStr for SocketMessage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum StackbarMode {
|
||||
Always,
|
||||
Never,
|
||||
OnStack,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default, Copy, Clone, Debug, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
pub enum ActiveWindowBorderStyle {
|
||||
#[default]
|
||||
/// Use the system border style
|
||||
System,
|
||||
/// Use the Windows 11-style rounded borders
|
||||
Rounded,
|
||||
/// Use the Windows 10-style square borders
|
||||
Square,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum WindowKind {
|
||||
Single,
|
||||
Stack,
|
||||
@@ -194,7 +223,6 @@ pub enum WindowKind {
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum StateQuery {
|
||||
FocusedMonitorIndex,
|
||||
FocusedWorkspaceIndex,
|
||||
@@ -215,7 +243,6 @@ pub enum StateQuery {
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum ApplicationIdentifier {
|
||||
#[serde(alias = "exe")]
|
||||
Exe,
|
||||
@@ -230,7 +257,6 @@ pub enum ApplicationIdentifier {
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum FocusFollowsMouseImplementation {
|
||||
/// A custom FFM implementation (slightly more CPU-intensive)
|
||||
Komorebi,
|
||||
@@ -241,7 +267,6 @@ pub enum FocusFollowsMouseImplementation {
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum WindowContainerBehaviour {
|
||||
/// Create a new container for each new window
|
||||
Create,
|
||||
@@ -252,7 +277,6 @@ pub enum WindowContainerBehaviour {
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum MoveBehaviour {
|
||||
/// Swap the window container with the window container at the edge of the adjacent monitor
|
||||
Swap,
|
||||
@@ -263,7 +287,6 @@ pub enum MoveBehaviour {
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum HidingBehaviour {
|
||||
/// Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
|
||||
Hide,
|
||||
@@ -276,7 +299,6 @@ pub enum HidingBehaviour {
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum OperationBehaviour {
|
||||
/// Process komorebic commands on temporarily unmanaged/floated windows
|
||||
Op,
|
||||
@@ -287,7 +309,6 @@ pub enum OperationBehaviour {
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Sizing {
|
||||
Increase,
|
||||
Decrease,
|
||||
|
||||
@@ -13,7 +13,6 @@ use crate::Axis;
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum OperationDirection {
|
||||
Left,
|
||||
Right,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebi"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "A tiling window manager for Windows"
|
||||
categories = ["tiling-window-manager", "windows"]
|
||||
@@ -13,7 +13,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
komorebi-core = { path = "../komorebi-core" }
|
||||
|
||||
bitflags = "2"
|
||||
bitflags = { version = "2", features = ["serde"] }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
color-eyre = { workspace = true }
|
||||
crossbeam-channel = "0.5"
|
||||
@@ -24,7 +24,7 @@ getset = "0.1"
|
||||
hex_color = { version = "3", features = ["serde"] }
|
||||
hotwatch = "0.5"
|
||||
lazy_static = "1"
|
||||
miow = "0.5"
|
||||
miow = "0.6"
|
||||
nanoid = "0.4"
|
||||
net2 = "0.2"
|
||||
os_info = "3.8"
|
||||
@@ -35,7 +35,7 @@ schemars = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
sysinfo = "0.30"
|
||||
sysinfo = { workspace = true }
|
||||
tracing = "0.1"
|
||||
tracing-appender = "0.2"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
@@ -9,14 +9,16 @@ use serde::Serialize;
|
||||
use crate::ring::Ring;
|
||||
use crate::stackbar::Stackbar;
|
||||
use crate::window::Window;
|
||||
use crate::StackbarMode;
|
||||
use crate::WindowsApi;
|
||||
use crate::STACKBAR_MODE;
|
||||
use komorebi_core::StackbarMode;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Getters, JsonSchema)]
|
||||
pub struct Container {
|
||||
#[getset(get = "pub")]
|
||||
id: String,
|
||||
windows: Ring<Window>,
|
||||
#[serde(skip)]
|
||||
#[getset(get = "pub", get_mut = "pub")]
|
||||
stackbar: Option<Stackbar>,
|
||||
}
|
||||
@@ -123,7 +125,10 @@ impl Container {
|
||||
let window = self.windows_mut().remove(idx);
|
||||
|
||||
if matches!(*STACKBAR_MODE.lock(), StackbarMode::OnStack) && self.windows().len() <= 1 {
|
||||
self.stackbar = None;
|
||||
if let Some(stackbar) = &self.stackbar {
|
||||
let _ = WindowsApi::close_window(stackbar.hwnd());
|
||||
self.stackbar = None;
|
||||
}
|
||||
}
|
||||
|
||||
if idx != 0 {
|
||||
@@ -156,4 +161,41 @@ impl Container {
|
||||
tracing::info!("focusing window");
|
||||
self.windows.focus(idx);
|
||||
}
|
||||
|
||||
pub fn set_stackbar_mode(&mut self, mode: StackbarMode) {
|
||||
match mode {
|
||||
StackbarMode::Always => {
|
||||
if self.stackbar.is_none() {
|
||||
self.stackbar = Stackbar::create().ok();
|
||||
}
|
||||
}
|
||||
StackbarMode::Never => {
|
||||
if let Some(stackbar) = &self.stackbar {
|
||||
let _ = WindowsApi::close_window(stackbar.hwnd());
|
||||
}
|
||||
|
||||
self.stackbar = None
|
||||
}
|
||||
StackbarMode::OnStack => {
|
||||
if self.windows().len() > 1 && self.stackbar().is_none() {
|
||||
self.stackbar = Stackbar::create().ok();
|
||||
}
|
||||
|
||||
if let Some(stackbar) = &self.stackbar {
|
||||
if self.windows().len() == 1 {
|
||||
let _ = WindowsApi::close_window(stackbar.hwnd());
|
||||
self.stackbar = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn renew_stackbar(&mut self) {
|
||||
if let Some(stackbar) = &self.stackbar {
|
||||
if !WindowsApi::is_window(stackbar.hwnd()) {
|
||||
self.stackbar = Stackbar::create().ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,13 @@ use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use colour::*;
|
||||
pub use hidden::*;
|
||||
pub use process_command::*;
|
||||
pub use process_event::*;
|
||||
pub use stackbar::*;
|
||||
pub use static_config::*;
|
||||
pub use window::*;
|
||||
pub use window_manager::*;
|
||||
pub use window_manager_event::*;
|
||||
pub use windows_api::WindowsApi;
|
||||
@@ -51,10 +53,12 @@ use color_eyre::Result;
|
||||
use komorebi_core::config_generation::IdWithIdentifier;
|
||||
use komorebi_core::config_generation::MatchingRule;
|
||||
use komorebi_core::config_generation::MatchingStrategy;
|
||||
use komorebi_core::ActiveWindowBorderStyle;
|
||||
use komorebi_core::ApplicationIdentifier;
|
||||
use komorebi_core::HidingBehaviour;
|
||||
use komorebi_core::Rect;
|
||||
use komorebi_core::SocketMessage;
|
||||
use komorebi_core::StackbarMode;
|
||||
use os_info::Version;
|
||||
use parking_lot::Mutex;
|
||||
use regex::Regex;
|
||||
|
||||
@@ -13,6 +13,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::Result;
|
||||
use miow::pipe::connect;
|
||||
use net2::TcpStreamExt;
|
||||
@@ -43,12 +44,15 @@ use crate::colour::Rgb;
|
||||
use crate::current_virtual_desktop;
|
||||
use crate::notify_subscribers;
|
||||
use crate::static_config::StaticConfig;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window::Window;
|
||||
use crate::window_manager;
|
||||
use crate::window_manager::WindowManager;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::GlobalState;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
||||
use crate::BORDER_COLOUR_CURRENT;
|
||||
use crate::BORDER_COLOUR_MONOCLE;
|
||||
use crate::BORDER_COLOUR_SINGLE;
|
||||
@@ -70,6 +74,12 @@ use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::NO_TITLEBAR;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::REMOVE_TITLEBARS;
|
||||
use crate::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::STACKBAR_MODE;
|
||||
use crate::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::STACKBAR_TAB_HEIGHT;
|
||||
use crate::STACKBAR_TAB_WIDTH;
|
||||
use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::SUBSCRIPTION_PIPES;
|
||||
use crate::SUBSCRIPTION_SOCKETS;
|
||||
use crate::TCP_CONNECTIONS;
|
||||
@@ -455,6 +465,9 @@ impl WindowManager {
|
||||
SocketMessage::SendContainerToMonitorWorkspaceNumber(monitor_idx, workspace_idx) => {
|
||||
self.move_container_to_monitor(monitor_idx, Option::from(workspace_idx), false)?;
|
||||
}
|
||||
SocketMessage::MoveContainerToMonitorWorkspaceNumber(monitor_idx, workspace_idx) => {
|
||||
self.move_container_to_monitor(monitor_idx, Option::from(workspace_idx), true)?;
|
||||
}
|
||||
SocketMessage::SendContainerToNamedWorkspace(ref workspace) => {
|
||||
if let Some((monitor_idx, workspace_idx)) =
|
||||
self.monitor_workspace_index_by_name(workspace)
|
||||
@@ -498,11 +511,11 @@ impl WindowManager {
|
||||
);
|
||||
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)?;
|
||||
}
|
||||
SocketMessage::FocusMonitorNumber(monitor_idx) => {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)?;
|
||||
}
|
||||
SocketMessage::Retile => self.retile_all(false)?,
|
||||
SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?,
|
||||
@@ -765,6 +778,18 @@ impl WindowManager {
|
||||
|
||||
tracing::info!("replying to state done");
|
||||
}
|
||||
SocketMessage::GlobalState => {
|
||||
let state = match serde_json::to_string_pretty(&GlobalState::default()) {
|
||||
Ok(state) => state,
|
||||
Err(error) => error.to_string(),
|
||||
};
|
||||
|
||||
tracing::info!("replying to global state");
|
||||
|
||||
reply.write_all(state.as_bytes())?;
|
||||
|
||||
tracing::info!("replying to global state done");
|
||||
}
|
||||
SocketMessage::VisibleWindows => {
|
||||
let mut monitor_visible_windows = HashMap::new();
|
||||
|
||||
@@ -913,7 +938,7 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::FocusFollowsMouse(mut implementation, enable) => {
|
||||
if !CUSTOM_FFM.load(Ordering::SeqCst) {
|
||||
@@ -1019,7 +1044,7 @@ impl WindowManager {
|
||||
SocketMessage::CompleteConfiguration => {
|
||||
if !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) {
|
||||
INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst);
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
}
|
||||
SocketMessage::WatchConfiguration(enable) => {
|
||||
@@ -1126,7 +1151,7 @@ impl WindowManager {
|
||||
let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;
|
||||
|
||||
workspace.set_resize_dimensions(resize);
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::Save(ref path) => {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -1149,7 +1174,7 @@ impl WindowManager {
|
||||
let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;
|
||||
|
||||
workspace.set_resize_dimensions(resize);
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::AddSubscriberSocket(ref socket) => {
|
||||
let mut sockets = SUBSCRIPTION_SOCKETS.lock();
|
||||
@@ -1241,14 +1266,50 @@ impl WindowManager {
|
||||
|
||||
WindowsApi::invalidate_border_rect()?;
|
||||
}
|
||||
SocketMessage::ActiveWindowBorderWidth(width) => {
|
||||
SocketMessage::ActiveWindowBorderStyle(style) => {
|
||||
let mut active_window_border_style = ACTIVE_WINDOW_BORDER_STYLE.lock();
|
||||
*active_window_border_style = style;
|
||||
|
||||
WindowsApi::invalidate_border_rect()?;
|
||||
}
|
||||
SocketMessage::BorderWidth(width) => {
|
||||
BORDER_WIDTH.store(width, Ordering::SeqCst);
|
||||
WindowsApi::invalidate_border_rect()?;
|
||||
}
|
||||
SocketMessage::ActiveWindowBorderOffset(offset) => {
|
||||
SocketMessage::BorderOffset(offset) => {
|
||||
BORDER_OFFSET.store(offset, Ordering::SeqCst);
|
||||
WindowsApi::invalidate_border_rect()?;
|
||||
}
|
||||
SocketMessage::StackbarMode(mode) => {
|
||||
let mut stackbar_mode = STACKBAR_MODE.lock();
|
||||
*stackbar_mode = mode;
|
||||
|
||||
for m in self.monitors_mut() {
|
||||
for w in m.workspaces_mut() {
|
||||
for c in w.containers_mut() {
|
||||
c.set_stackbar_mode(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SocketMessage::StackbarFocusedTextColour(r, g, b) => {
|
||||
let rgb = Rgb::new(r, g, b);
|
||||
STACKBAR_FOCUSED_TEXT_COLOUR.store(rgb.into(), Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::StackbarUnfocusedTextColour(r, g, b) => {
|
||||
let rgb = Rgb::new(r, g, b);
|
||||
STACKBAR_UNFOCUSED_TEXT_COLOUR.store(rgb.into(), Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::StackbarBackgroundColour(r, g, b) => {
|
||||
let rgb = Rgb::new(r, g, b);
|
||||
STACKBAR_TAB_BACKGROUND_COLOUR.store(rgb.into(), Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::StackbarHeight(height) => {
|
||||
STACKBAR_TAB_HEIGHT.store(height, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::StackbarTabWidth(width) => {
|
||||
STACKBAR_TAB_WIDTH.store(width, Ordering::SeqCst);
|
||||
}
|
||||
SocketMessage::ApplicationSpecificConfigurationSchema => {
|
||||
let asc = schema_for!(Vec<ApplicationConfiguration>);
|
||||
let schema = serde_json::to_string_pretty(&asc)?;
|
||||
@@ -1294,7 +1355,15 @@ impl WindowManager {
|
||||
SocketMessage::ToggleTitleBars => {
|
||||
let current = REMOVE_TITLEBARS.load(Ordering::SeqCst);
|
||||
REMOVE_TITLEBARS.store(!current, Ordering::SeqCst);
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::DebugWindow(hwnd) => {
|
||||
let window = Window { hwnd };
|
||||
let mut rule_debug = RuleDebug::default();
|
||||
let _ = window.should_manage(None, &mut rule_debug);
|
||||
let schema = serde_json::to_string_pretty(&rule_debug)?;
|
||||
|
||||
reply.write_all(schema.as_bytes())?;
|
||||
}
|
||||
// Deprecated commands
|
||||
SocketMessage::AltFocusHack(_)
|
||||
@@ -1345,6 +1414,8 @@ impl WindowManager {
|
||||
| SocketMessage::MoveWorkspaceToMonitorNumber(_)
|
||||
| SocketMessage::MoveContainerToMonitorNumber(_)
|
||||
| SocketMessage::MoveContainerToWorkspaceNumber(_)
|
||||
| SocketMessage::MoveContainerToMonitorWorkspaceNumber(_, _)
|
||||
| SocketMessage::MoveContainerToNamedWorkspace(_)
|
||||
| SocketMessage::ResizeWindowEdge(_, _)
|
||||
| SocketMessage::ResizeWindowAxis(_, _)
|
||||
| SocketMessage::ToggleFloat
|
||||
@@ -1357,7 +1428,7 @@ impl WindowManager {
|
||||
| SocketMessage::Retile
|
||||
// Adding this one so that changes can be seen instantly after
|
||||
// modifying the active window border offset
|
||||
| SocketMessage::ActiveWindowBorderOffset(_)
|
||||
| SocketMessage::BorderOffset(_)
|
||||
// Adding this one because sometimes EVENT_SYSTEM_FOREGROUND isn't
|
||||
// getting sent on FocusWindow, meaning the border won't be set
|
||||
// when processing events
|
||||
@@ -1371,7 +1442,33 @@ impl WindowManager {
|
||||
| SocketMessage::FocusMonitorNumber(_)
|
||||
| SocketMessage::FocusMonitorWorkspaceNumber(_, _)
|
||||
| SocketMessage::FocusWorkspaceNumber(_) => {
|
||||
let foreground = WindowsApi::foreground_window()?;
|
||||
// The foreground window might be de-activating if we've just
|
||||
// set it as a result of our own actions, so wait until the new
|
||||
// one returns. This particularly happens when switching monitors.
|
||||
//
|
||||
// TODO(raggi): re-evaluate this branch. I checked the
|
||||
// suggestion from the comment above, that we don't get
|
||||
// EVENT_SYSTEM_FOREGROUND, but if I print out trace events I
|
||||
// see that we do.
|
||||
// XXX(raggi) We drop FocusChange events though for windows that
|
||||
// we're not managing, so that's one of the ways that the border
|
||||
// window gets stuck. We should stop overloading `should_manage`
|
||||
// as an event filter, and separately filter events that we want
|
||||
// to handle, and windows that we want to handle, as some events
|
||||
// must be handled even if we're not managing the target window.
|
||||
let mut attempts = 0;
|
||||
let foreground = loop {
|
||||
match WindowsApi::foreground_window() {
|
||||
Ok(foreground) => break foreground,
|
||||
Err(_) => {
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
attempts+=1;
|
||||
if attempts == 10 {
|
||||
bail!("failed to get foreground window after 100ms")
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
let foreground_window = Window { hwnd: foreground };
|
||||
|
||||
let monocle = BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst);
|
||||
@@ -1485,9 +1582,10 @@ pub fn read_commands_uds(wm: &Arc<Mutex<WindowManager>>, mut stream: UnixStream)
|
||||
|
||||
if wm.is_paused {
|
||||
return match message {
|
||||
SocketMessage::TogglePause | SocketMessage::State | SocketMessage::Stop => {
|
||||
Ok(wm.process_command(message, &mut stream)?)
|
||||
}
|
||||
SocketMessage::TogglePause
|
||||
| SocketMessage::State
|
||||
| SocketMessage::GlobalState
|
||||
| SocketMessage::Stop => Ok(wm.process_command(message, &mut stream)?),
|
||||
_ => {
|
||||
tracing::trace!("ignoring while paused");
|
||||
Ok(())
|
||||
@@ -1534,9 +1632,10 @@ pub fn read_commands_tcp(
|
||||
|
||||
if wm.is_paused {
|
||||
return match message {
|
||||
SocketMessage::TogglePause | SocketMessage::State | SocketMessage::Stop => {
|
||||
Ok(wm.process_command(message, stream)?)
|
||||
}
|
||||
SocketMessage::TogglePause
|
||||
| SocketMessage::State
|
||||
| SocketMessage::GlobalState
|
||||
| SocketMessage::Stop => Ok(wm.process_command(message, stream)?),
|
||||
_ => {
|
||||
tracing::trace!("ignoring while paused");
|
||||
Ok(())
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::sync::Arc;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::select;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use komorebi_core::OperationDirection;
|
||||
@@ -16,6 +15,7 @@ use crate::border::Border;
|
||||
use crate::current_virtual_desktop;
|
||||
use crate::notify_subscribers;
|
||||
use crate::window::should_act;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window_manager::WindowManager;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
@@ -42,12 +42,14 @@ pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
std::thread::spawn(move || {
|
||||
tracing::info!("listening");
|
||||
loop {
|
||||
select! {
|
||||
recv(receiver) -> mut maybe_event => {
|
||||
if let Ok(event) = maybe_event.as_mut() {
|
||||
match wm.lock().process_event(event) {
|
||||
Ok(()) => {},
|
||||
Err(error) => tracing::error!("{}", error)
|
||||
if let Ok(event) = receiver.recv() {
|
||||
match wm.lock().process_event(event) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
if cfg!(debug_assertions) {
|
||||
tracing::error!("{:?}", error)
|
||||
} else {
|
||||
tracing::error!("{}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,12 +61,44 @@ pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||
impl WindowManager {
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn process_event(&mut self, event: &mut WindowManagerEvent) -> Result<()> {
|
||||
pub fn process_event(&mut self, event: WindowManagerEvent) -> Result<()> {
|
||||
if self.is_paused {
|
||||
tracing::trace!("ignoring while paused");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut rule_debug = RuleDebug::default();
|
||||
|
||||
let should_manage = event.window().should_manage(Some(event), &mut rule_debug)?;
|
||||
|
||||
// Hide or reposition the window based on whether the target is managed.
|
||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
||||
if let WindowManagerEvent::FocusChange(_, window) = event {
|
||||
let border_window = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
||||
|
||||
if should_manage {
|
||||
border_window.set_position(window, true)?;
|
||||
} else {
|
||||
let mut stackbar = false;
|
||||
if let Ok(class) = window.class() {
|
||||
if class == "komorebi_stackbar" {
|
||||
stackbar = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !stackbar {
|
||||
border_window.hide()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All event handlers below this point should only be processed if the event is
|
||||
// related to a window that should be managed by the WindowManager.
|
||||
if !should_manage && !matches!(event, WindowManagerEvent::DisplayChange(_)) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(virtual_desktop_id) = &self.virtual_desktop_id {
|
||||
if let Some(id) = current_virtual_desktop() {
|
||||
if id != *virtual_desktop_id {
|
||||
@@ -85,7 +119,7 @@ impl WindowManager {
|
||||
| WindowManagerEvent::MoveResizeEnd(_, window) => {
|
||||
self.reconcile_monitors()?;
|
||||
|
||||
let monitor_idx = self.monitor_idx_from_window(*window)
|
||||
let monitor_idx = self.monitor_idx_from_window(window)
|
||||
.ok_or_else(|| anyhow!("there is no monitor associated with this window, it may have already been destroyed"))?;
|
||||
|
||||
// This is a hidden window apparently associated with COM support mechanisms (based
|
||||
@@ -122,6 +156,10 @@ impl WindowManager {
|
||||
};
|
||||
|
||||
for (j, workspace) in monitor.workspaces_mut().iter_mut().enumerate() {
|
||||
if let WindowManagerEvent::FocusChange(_, window) = event {
|
||||
let _ = workspace.focus_changed(window.hwnd);
|
||||
}
|
||||
|
||||
let reaped_orphans = workspace.reap_orphans()?;
|
||||
if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 {
|
||||
workspace.update(&work_area, offset)?;
|
||||
@@ -151,12 +189,14 @@ impl WindowManager {
|
||||
self.has_pending_raise_op = false;
|
||||
}
|
||||
WindowManagerEvent::Destroy(_, window) | WindowManagerEvent::Unmanage(window) => {
|
||||
self.focused_workspace_mut()?.remove_window(window.hwnd)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
if self.focused_workspace()?.contains_window(window.hwnd) {
|
||||
self.focused_workspace_mut()?.remove_window(window.hwnd)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
|
||||
let mut already_moved_window_handles = self.already_moved_window_handles.lock();
|
||||
let mut already_moved_window_handles = self.already_moved_window_handles.lock();
|
||||
|
||||
already_moved_window_handles.remove(&window.hwnd);
|
||||
already_moved_window_handles.remove(&window.hwnd);
|
||||
}
|
||||
}
|
||||
WindowManagerEvent::Minimize(_, window) => {
|
||||
let mut hide = false;
|
||||
@@ -170,7 +210,7 @@ impl WindowManager {
|
||||
|
||||
if hide {
|
||||
self.focused_workspace_mut()?.remove_window(window.hwnd)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
}
|
||||
WindowManagerEvent::Hide(_, window) => {
|
||||
@@ -199,7 +239,8 @@ impl WindowManager {
|
||||
path,
|
||||
&tray_and_multi_window_identifiers,
|
||||
®ex_identifiers,
|
||||
);
|
||||
)
|
||||
.is_some();
|
||||
|
||||
if !window.is_window()
|
||||
|| should_act
|
||||
@@ -211,7 +252,7 @@ impl WindowManager {
|
||||
|
||||
if hide {
|
||||
self.focused_workspace_mut()?.remove_window(window.hwnd)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
|
||||
let mut already_moved_window_handles = self.already_moved_window_handles.lock();
|
||||
@@ -219,6 +260,8 @@ impl WindowManager {
|
||||
already_moved_window_handles.remove(&window.hwnd);
|
||||
}
|
||||
WindowManagerEvent::FocusChange(_, window) => {
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)?;
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
if !workspace
|
||||
.floating_windows()
|
||||
@@ -292,15 +335,15 @@ impl WindowManager {
|
||||
if !workspace.contains_window(window.hwnd) {
|
||||
match behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
workspace.new_container_for_window(*window);
|
||||
self.update_focused_workspace(false)?;
|
||||
workspace.new_container_for_window(window);
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
WindowContainerBehaviour::Append => {
|
||||
workspace
|
||||
.focused_container_mut()
|
||||
.ok_or_else(|| anyhow!("there is no focused container"))?
|
||||
.add_window(*window);
|
||||
self.update_focused_workspace(true)?;
|
||||
.add_window(window);
|
||||
self.update_focused_workspace(true, false)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,11 +493,11 @@ impl WindowManager {
|
||||
// the origin monitor's focused workspace
|
||||
self.focus_monitor(origin_monitor_idx)?;
|
||||
self.focus_workspace(origin_workspace_idx)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
|
||||
self.focus_monitor(target_monitor_idx)?;
|
||||
self.focus_workspace(target_workspace_idx)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
// Here we handle a simple move on the same monitor which is treated as
|
||||
// a container swap
|
||||
@@ -465,11 +508,12 @@ impl WindowManager {
|
||||
Some(target_idx) => {
|
||||
workspace
|
||||
.swap_containers(focused_container_idx, target_idx);
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
None => {
|
||||
self.update_focused_workspace(
|
||||
self.mouse_follows_focus,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -478,11 +522,12 @@ impl WindowManager {
|
||||
match workspace.container_idx_from_current_point() {
|
||||
Some(target_idx) => {
|
||||
workspace.move_window_to_container(target_idx)?;
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
None => {
|
||||
self.update_focused_workspace(
|
||||
self.mouse_follows_focus,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -529,12 +574,12 @@ impl WindowManager {
|
||||
self.resize_window(edge, sizing, delta, true)?;
|
||||
}
|
||||
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
WindowManagerEvent::ForceUpdate(_) => {
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, true)?;
|
||||
}
|
||||
WindowManagerEvent::DisplayChange(..)
|
||||
| WindowManagerEvent::MouseCapture(..)
|
||||
@@ -570,7 +615,7 @@ impl WindowManager {
|
||||
.iter()
|
||||
.any(|w| w.hwnd == window.hwnd)
|
||||
{
|
||||
target_window = Option::from(*window);
|
||||
target_window = Option::from(window);
|
||||
WindowsApi::raise_window(border.hwnd())?;
|
||||
};
|
||||
|
||||
@@ -663,7 +708,7 @@ impl WindowManager {
|
||||
|
||||
serde_json::to_writer_pretty(&file, &known_hwnds)?;
|
||||
notify_subscribers(&serde_json::to_string(&Notification {
|
||||
event: NotificationEvent::WindowManager(*event),
|
||||
event: NotificationEvent::WindowManager(event),
|
||||
state: self.as_ref().into(),
|
||||
})?)?;
|
||||
|
||||
|
||||
@@ -55,9 +55,6 @@ use komorebi_core::Rect;
|
||||
|
||||
use crate::window::Window;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::winevent_listener;
|
||||
use crate::WindowManagerEvent;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
@@ -67,29 +64,11 @@ use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::TRANSPARENCY_COLOUR;
|
||||
use crate::WINDOWS_BY_BAR_HWNDS;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct Stackbar {
|
||||
pub(crate) hwnd: isize,
|
||||
#[serde(skip)]
|
||||
pub is_cloned: bool,
|
||||
}
|
||||
|
||||
impl Drop for Stackbar {
|
||||
fn drop(&mut self) {
|
||||
if !self.is_cloned {
|
||||
let _ = WindowsApi::close_window(self.hwnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Stackbar {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
hwnd: self.hwnd,
|
||||
is_cloned: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Stackbar {
|
||||
unsafe extern "system" fn window_proc(
|
||||
hwnd: HWND,
|
||||
@@ -116,12 +95,10 @@ impl Stackbar {
|
||||
|
||||
if x >= left && x <= right && y >= top && y <= bottom {
|
||||
let window = Window { hwnd: *win_hwnd };
|
||||
let event_sender = winevent_listener::event_tx();
|
||||
let _ = event_sender.send(WindowManagerEvent::FocusChange(
|
||||
WinEvent::ObjectFocus,
|
||||
window,
|
||||
));
|
||||
let _ = event_sender.send(WindowManagerEvent::ForceUpdate(window));
|
||||
window.restore();
|
||||
if let Err(err) = window.focus(false) {
|
||||
tracing::error!("Stackbar focus error: HWND:{} {}", *win_hwnd, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,7 +173,6 @@ impl Stackbar {
|
||||
|
||||
Ok(Self {
|
||||
hwnd: hwnd_receiver.recv()?.0,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -240,8 +216,6 @@ impl Stackbar {
|
||||
for (i, window) in windows.iter().enumerate() {
|
||||
if window.hwnd == focused_hwnd {
|
||||
SetTextColor(hdc, COLORREF(focused_text_colour));
|
||||
|
||||
window.focus(false)?;
|
||||
} else {
|
||||
SetTextColor(hdc, COLORREF(unfocused_text_colour));
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ use crate::STACKBAR_TAB_WIDTH;
|
||||
use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WORKSPACE_RULES;
|
||||
use komorebi_core::StackbarMode;
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
@@ -47,6 +48,7 @@ use komorebi_core::config_generation::IdWithIdentifier;
|
||||
use komorebi_core::config_generation::MatchingRule;
|
||||
use komorebi_core::config_generation::MatchingStrategy;
|
||||
use komorebi_core::resolve_home_path;
|
||||
use komorebi_core::ActiveWindowBorderStyle;
|
||||
use komorebi_core::ApplicationIdentifier;
|
||||
use komorebi_core::DefaultLayout;
|
||||
use komorebi_core::FocusFollowsMouseImplementation;
|
||||
@@ -82,17 +84,6 @@ pub struct ActiveWindowBorderColours {
|
||||
pub monocle: Colour,
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum ActiveWindowBorderStyle {
|
||||
#[default]
|
||||
/// Use the system border style
|
||||
System,
|
||||
/// Use the Windows 11-style rounded borders
|
||||
Rounded,
|
||||
/// Use the Windows 10-style square borders
|
||||
Square,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct WorkspaceConfig {
|
||||
/// Name
|
||||
@@ -231,7 +222,7 @@ impl From<&Monitor> for MonitorConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.24`
|
||||
/// The `komorebi.json` static configuration file reference for `v0.1.25`
|
||||
pub struct StaticConfig {
|
||||
/// DEPRECATED from v0.1.22: no longer required
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
@@ -313,30 +304,31 @@ pub struct StaticConfig {
|
||||
/// Set display index preferences
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub display_index_preferences: Option<HashMap<usize, String>>,
|
||||
/// Stackbar configuration options
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stackbar: Option<StackbarConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum StackbarMode {
|
||||
Always,
|
||||
Never,
|
||||
OnStack,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct TabsConfig {
|
||||
/// Width of a stackbar tab
|
||||
width: Option<i32>,
|
||||
/// Focused tab text colour
|
||||
focused_text: Option<Colour>,
|
||||
/// Unfocused tab text colour
|
||||
unfocused_text: Option<Colour>,
|
||||
/// Tab background colour
|
||||
background: Option<Colour>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct StackbarConfig {
|
||||
height: Option<i32>,
|
||||
mode: Option<StackbarMode>,
|
||||
tabs: Option<TabsConfig>,
|
||||
/// Stackbar height
|
||||
pub height: Option<i32>,
|
||||
/// Stackbar mode
|
||||
pub mode: Option<StackbarMode>,
|
||||
/// Stackbar tab configuration options
|
||||
pub tabs: Option<TabsConfig>,
|
||||
}
|
||||
|
||||
impl From<&WindowManager> for StaticConfig {
|
||||
@@ -534,10 +526,12 @@ impl StaticConfig {
|
||||
if let Some(height) = &stackbar.height {
|
||||
STACKBAR_TAB_HEIGHT.store(*height, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(mode) = &stackbar.mode {
|
||||
let mut stackbar_mode = STACKBAR_MODE.lock();
|
||||
*stackbar_mode = *mode;
|
||||
}
|
||||
|
||||
if let Some(tabs) = &stackbar.tabs {
|
||||
if let Some(background) = &tabs.background {
|
||||
STACKBAR_TAB_BACKGROUND_COLOUR.store((*background).into(), Ordering::SeqCst);
|
||||
@@ -741,6 +735,16 @@ impl StaticConfig {
|
||||
|
||||
value.apply_globals()?;
|
||||
|
||||
let stackbar_mode = *STACKBAR_MODE.lock();
|
||||
|
||||
for m in wm.monitors_mut() {
|
||||
for w in m.workspaces_mut() {
|
||||
for c in w.containers_mut() {
|
||||
c.set_stackbar_mode(stackbar_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(monitors) = value.monitors {
|
||||
for (i, monitor) in monitors.iter().enumerate() {
|
||||
if let Some(m) = wm.monitors_mut().get_mut(i) {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use bitflags::bitflags;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_BORDER;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_CAPTION;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_CHILD;
|
||||
@@ -56,7 +58,7 @@ use windows::Win32::UI::WindowsAndMessaging::WS_VSCROLL;
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct WindowStyle: u32 {
|
||||
const BORDER = WS_BORDER.0;
|
||||
const CAPTION = WS_CAPTION.0;
|
||||
@@ -90,7 +92,7 @@ bitflags! {
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct ExtendedWindowStyle: u32 {
|
||||
const ACCEPTFILES = WS_EX_ACCEPTFILES.0;
|
||||
const APPWINDOW = WS_EX_APPWINDOW.0;
|
||||
|
||||
@@ -41,7 +41,7 @@ use crate::WSL2_UI_PROCESSES;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, JsonSchema)]
|
||||
pub struct Window {
|
||||
pub(crate) hwnd: isize,
|
||||
pub hwnd: isize,
|
||||
}
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
@@ -125,7 +125,7 @@ impl Window {
|
||||
HWND(self.hwnd)
|
||||
}
|
||||
|
||||
pub fn center(&mut self, work_area: &Rect) -> Result<()> {
|
||||
pub fn center(&self, work_area: &Rect) -> Result<()> {
|
||||
let half_width = work_area.right / 2;
|
||||
let half_weight = work_area.bottom / 2;
|
||||
|
||||
@@ -140,7 +140,7 @@ impl Window {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, layout: &Rect, top: bool) -> Result<()> {
|
||||
pub fn set_position(&self, layout: &Rect, top: bool) -> Result<()> {
|
||||
let rect = *layout;
|
||||
WindowsApi::position_window(self.hwnd(), &rect, top)
|
||||
}
|
||||
@@ -153,6 +153,10 @@ impl Window {
|
||||
WindowsApi::is_iconic(self.hwnd())
|
||||
}
|
||||
|
||||
pub fn is_visible(self) -> bool {
|
||||
WindowsApi::is_window_visible(self.hwnd())
|
||||
}
|
||||
|
||||
pub fn hide(self) {
|
||||
let mut programmatically_hidden_hwnds = HIDDEN_HWNDS.lock();
|
||||
if !programmatically_hidden_hwnds.contains(&self.hwnd) {
|
||||
@@ -218,77 +222,20 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn focus(self, mouse_follows_focus: bool) -> Result<()> {
|
||||
// Attach komorebi thread to Window thread
|
||||
let (_, window_thread_id) = WindowsApi::window_thread_process_id(self.hwnd());
|
||||
let current_thread_id = WindowsApi::current_thread_id();
|
||||
|
||||
// This can be allowed to fail if a window doesn't have a message queue or if a journal record
|
||||
// hook has been installed
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-attachthreadinput#remarks
|
||||
match WindowsApi::attach_thread_input(current_thread_id, window_thread_id, true) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not attach to window thread input processing mechanism, but continuing execution of focus(): {}",
|
||||
error
|
||||
);
|
||||
// If the target window is already focused, do nothing.
|
||||
if let Ok(ihwnd) = WindowsApi::foreground_window() {
|
||||
if HWND(ihwnd) == self.hwnd() {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// Raise Window to foreground
|
||||
let mut foregrounded = false;
|
||||
let mut tried_resetting_foreground_access = false;
|
||||
let mut max_attempts = 10;
|
||||
|
||||
while !foregrounded && max_attempts > 0 {
|
||||
match WindowsApi::set_foreground_window(self.hwnd()) {
|
||||
Ok(()) => {
|
||||
foregrounded = true;
|
||||
}
|
||||
Err(error) => {
|
||||
max_attempts -= 1;
|
||||
tracing::error!(
|
||||
"could not set as foreground window, but continuing execution of focus(): {}",
|
||||
error
|
||||
);
|
||||
|
||||
// If this still doesn't work then maybe try https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-locksetforegroundwindow
|
||||
if !tried_resetting_foreground_access {
|
||||
let process_id = WindowsApi::current_process_id();
|
||||
if WindowsApi::allow_set_foreground_window(process_id).is_ok() {
|
||||
tried_resetting_foreground_access = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
WindowsApi::raise_and_focus_window(self.hwnd())?;
|
||||
|
||||
// Center cursor in Window
|
||||
if mouse_follows_focus {
|
||||
WindowsApi::center_cursor_in_rect(&WindowsApi::window_rect(self.hwnd())?)?;
|
||||
}
|
||||
|
||||
// This isn't really needed when the above command works as expected via AHK
|
||||
match WindowsApi::set_focus(self.hwnd()) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not set focus, but continuing execution of focus(): {}",
|
||||
error
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
match WindowsApi::attach_thread_input(current_thread_id, window_thread_id, false) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
"could not detach from window thread input processing mechanism, but continuing execution of focus(): {}",
|
||||
error
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -370,18 +317,27 @@ impl Window {
|
||||
self.update_style(&style)
|
||||
}
|
||||
|
||||
#[tracing::instrument(fields(exe, title))]
|
||||
pub fn should_manage(self, event: Option<WindowManagerEvent>) -> Result<bool> {
|
||||
if let Some(WindowManagerEvent::DisplayChange(_)) = event {
|
||||
return Ok(true);
|
||||
#[tracing::instrument(fields(exe, title), skip(debug))]
|
||||
pub fn should_manage(
|
||||
self,
|
||||
event: Option<WindowManagerEvent>,
|
||||
debug: &mut RuleDebug,
|
||||
) -> Result<bool> {
|
||||
if !self.is_window() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
#[allow(clippy::question_mark)]
|
||||
debug.is_window = true;
|
||||
|
||||
if self.title().is_err() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let is_cloaked = self.is_cloaked()?;
|
||||
debug.has_title = true;
|
||||
|
||||
let is_cloaked = self.is_cloaked().unwrap_or_default();
|
||||
|
||||
debug.is_cloaked = is_cloaked;
|
||||
|
||||
let mut allow_cloaked = false;
|
||||
|
||||
@@ -394,13 +350,28 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
debug.allow_cloaked = allow_cloaked;
|
||||
|
||||
match (allow_cloaked, is_cloaked) {
|
||||
// If allowing cloaked windows, we don't need to check the cloaked status
|
||||
(true, _) |
|
||||
// If not allowing cloaked windows, we need to ensure the window is not cloaked
|
||||
(false, false) => {
|
||||
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) = (self.title(), self.exe(), self.class(), self.path()) {
|
||||
return Ok(window_is_eligible(&title, &exe_name, &class, &path, &self.style()?, &self.ex_style()?, event));
|
||||
debug.title = Some(title.clone());
|
||||
debug.exe_name = Some(exe_name.clone());
|
||||
debug.class = Some(class.clone());
|
||||
debug.path = Some(path.clone());
|
||||
// calls for styles can fail quite often for events with windows that aren't really "windows"
|
||||
// since we have moved up calls of should_manage to the beginning of the process_event handler,
|
||||
// we should handle failures here gracefully to be able to continue the execution of process_event
|
||||
if let (Ok(style), Ok(ex_style)) = (&self.style(), &self.ex_style()) {
|
||||
debug.window_style = Some(*style);
|
||||
debug.extended_window_style = Some(*ex_style);
|
||||
let eligible = window_is_eligible(&title, &exe_name, &class, &path, style, ex_style, event, debug);
|
||||
debug.should_manage = eligible;
|
||||
return Ok(eligible);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -410,6 +381,28 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct RuleDebug {
|
||||
pub should_manage: bool,
|
||||
pub is_window: bool,
|
||||
pub has_title: bool,
|
||||
pub is_cloaked: bool,
|
||||
pub allow_cloaked: bool,
|
||||
pub window_style: Option<WindowStyle>,
|
||||
pub extended_window_style: Option<ExtendedWindowStyle>,
|
||||
pub title: Option<String>,
|
||||
pub exe_name: Option<String>,
|
||||
pub class: Option<String>,
|
||||
pub path: Option<String>,
|
||||
pub matches_permaignore_class: Option<String>,
|
||||
pub matches_float_identifier: Option<MatchingRule>,
|
||||
pub matches_managed_override: Option<MatchingRule>,
|
||||
pub matches_layered_whitelist: Option<MatchingRule>,
|
||||
pub matches_wsl2_gui: Option<String>,
|
||||
pub matches_no_titlebar: Option<String>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn window_is_eligible(
|
||||
title: &String,
|
||||
exe_name: &String,
|
||||
@@ -418,10 +411,12 @@ fn window_is_eligible(
|
||||
style: &WindowStyle,
|
||||
ex_style: &ExtendedWindowStyle,
|
||||
event: Option<WindowManagerEvent>,
|
||||
debug: &mut RuleDebug,
|
||||
) -> bool {
|
||||
{
|
||||
let permaignore_classes = PERMAIGNORE_CLASSES.lock();
|
||||
if permaignore_classes.contains(class) {
|
||||
debug.matches_permaignore_class = Some(class.clone());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -429,45 +424,65 @@ fn window_is_eligible(
|
||||
let regex_identifiers = REGEX_IDENTIFIERS.lock();
|
||||
|
||||
let float_identifiers = FLOAT_IDENTIFIERS.lock();
|
||||
let should_float = should_act(
|
||||
let should_float = if let Some(rule) = should_act(
|
||||
title,
|
||||
exe_name,
|
||||
class,
|
||||
path,
|
||||
&float_identifiers,
|
||||
®ex_identifiers,
|
||||
);
|
||||
) {
|
||||
debug.matches_float_identifier = Some(rule);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let manage_identifiers = MANAGE_IDENTIFIERS.lock();
|
||||
let managed_override = should_act(
|
||||
let managed_override = if let Some(rule) = should_act(
|
||||
title,
|
||||
exe_name,
|
||||
class,
|
||||
path,
|
||||
&manage_identifiers,
|
||||
®ex_identifiers,
|
||||
);
|
||||
) {
|
||||
debug.matches_managed_override = Some(rule);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if should_float && !managed_override {
|
||||
return false;
|
||||
}
|
||||
|
||||
let layered_whitelist = LAYERED_WHITELIST.lock();
|
||||
let allow_layered = should_act(
|
||||
let allow_layered = if let Some(rule) = should_act(
|
||||
title,
|
||||
exe_name,
|
||||
class,
|
||||
path,
|
||||
&layered_whitelist,
|
||||
®ex_identifiers,
|
||||
);
|
||||
) {
|
||||
debug.matches_layered_whitelist = Some(rule);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// TODO: might need this for transparency
|
||||
// let allow_layered = true;
|
||||
|
||||
let allow_wsl2_gui = {
|
||||
let wsl2_ui_processes = WSL2_UI_PROCESSES.lock();
|
||||
wsl2_ui_processes.contains(exe_name)
|
||||
let allow = wsl2_ui_processes.contains(exe_name);
|
||||
if allow {
|
||||
debug.matches_wsl2_gui = Some(exe_name.clone())
|
||||
}
|
||||
|
||||
allow
|
||||
};
|
||||
|
||||
let allow_titlebar_removed = {
|
||||
@@ -509,10 +524,10 @@ pub fn should_act(
|
||||
path: &str,
|
||||
identifiers: &[MatchingRule],
|
||||
regex_identifiers: &HashMap<String, Regex>,
|
||||
) -> bool {
|
||||
let mut should_act = false;
|
||||
for identifier in identifiers {
|
||||
match identifier {
|
||||
) -> Option<MatchingRule> {
|
||||
let mut matching_rule = None;
|
||||
for rule in identifiers {
|
||||
match rule {
|
||||
MatchingRule::Simple(identifier) => {
|
||||
if should_act_individual(
|
||||
title,
|
||||
@@ -522,7 +537,7 @@ pub fn should_act(
|
||||
identifier,
|
||||
regex_identifiers,
|
||||
) {
|
||||
should_act = true
|
||||
matching_rule = Some(rule.clone());
|
||||
};
|
||||
}
|
||||
MatchingRule::Composite(identifiers) => {
|
||||
@@ -539,13 +554,13 @@ pub fn should_act(
|
||||
}
|
||||
|
||||
if composite_results.iter().all(|&x| x) {
|
||||
should_act = true;
|
||||
matching_rule = Some(rule.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
should_act
|
||||
matching_rule
|
||||
}
|
||||
|
||||
pub fn should_act_individual(
|
||||
|
||||
@@ -16,6 +16,7 @@ use hotwatch::notify::ErrorKind as NotifyErrorKind;
|
||||
use hotwatch::EventKind;
|
||||
use hotwatch::Hotwatch;
|
||||
use parking_lot::Mutex;
|
||||
use regex::Regex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
@@ -23,11 +24,13 @@ use uds_windows::UnixListener;
|
||||
|
||||
use komorebi_core::config_generation::MatchingRule;
|
||||
use komorebi_core::custom_layout::CustomLayout;
|
||||
use komorebi_core::ActiveWindowBorderStyle;
|
||||
use komorebi_core::Arrangement;
|
||||
use komorebi_core::Axis;
|
||||
use komorebi_core::CycleDirection;
|
||||
use komorebi_core::DefaultLayout;
|
||||
use komorebi_core::FocusFollowsMouseImplementation;
|
||||
use komorebi_core::HidingBehaviour;
|
||||
use komorebi_core::Layout;
|
||||
use komorebi_core::MoveBehaviour;
|
||||
use komorebi_core::OperationBehaviour;
|
||||
@@ -48,10 +51,23 @@ use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::winevent_listener;
|
||||
use crate::workspace::Workspace;
|
||||
use crate::ActiveWindowBorderColours;
|
||||
use crate::Colour;
|
||||
use crate::Rgb;
|
||||
use crate::WorkspaceRule;
|
||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
||||
use crate::BORDER_COLOUR_MONOCLE;
|
||||
use crate::BORDER_COLOUR_SINGLE;
|
||||
use crate::BORDER_COLOUR_STACK;
|
||||
use crate::BORDER_ENABLED;
|
||||
use crate::BORDER_HWND;
|
||||
use crate::BORDER_OFFSET;
|
||||
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::HOME_DIR;
|
||||
use crate::LAYERED_WHITELIST;
|
||||
use crate::MANAGE_IDENTIFIERS;
|
||||
@@ -59,8 +75,15 @@ use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::NO_TITLEBAR;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::REMOVE_TITLEBARS;
|
||||
use crate::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::STACKBAR_MODE;
|
||||
use crate::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::STACKBAR_TAB_HEIGHT;
|
||||
use crate::STACKBAR_TAB_WIDTH;
|
||||
use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WORKSPACE_RULES;
|
||||
use komorebi_core::StackbarMode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WindowManager {
|
||||
@@ -91,10 +114,27 @@ pub struct State {
|
||||
pub resize_delta: i32,
|
||||
pub new_window_behaviour: WindowContainerBehaviour,
|
||||
pub cross_monitor_move_behaviour: MoveBehaviour,
|
||||
pub unmanaged_window_operation_behaviour: OperationBehaviour,
|
||||
pub work_area_offset: Option<Rect>,
|
||||
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
||||
pub mouse_follows_focus: bool,
|
||||
pub has_pending_raise_op: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GlobalState {
|
||||
pub active_window_border_enabled: bool,
|
||||
pub active_window_border_colours: ActiveWindowBorderColours,
|
||||
pub active_window_border_style: ActiveWindowBorderStyle,
|
||||
pub border_offset: i32,
|
||||
pub border_width: i32,
|
||||
pub stackbar_mode: StackbarMode,
|
||||
pub stackbar_focused_text_colour: Colour,
|
||||
pub stackbar_unfocused_text_colour: Colour,
|
||||
pub stackbar_tab_background_colour: Colour,
|
||||
pub stackbar_tab_width: i32,
|
||||
pub stackbar_height: i32,
|
||||
pub remove_titlebars: bool,
|
||||
pub float_identifiers: Vec<MatchingRule>,
|
||||
pub manage_identifiers: Vec<MatchingRule>,
|
||||
@@ -103,6 +143,52 @@ pub struct State {
|
||||
pub name_change_on_launch_identifiers: Vec<MatchingRule>,
|
||||
pub monitor_index_preferences: HashMap<usize, Rect>,
|
||||
pub display_index_preferences: HashMap<usize, String>,
|
||||
pub workspace_rules: HashMap<String, WorkspaceRule>,
|
||||
pub window_hiding_behaviour: HidingBehaviour,
|
||||
pub configuration_dir: PathBuf,
|
||||
pub data_dir: PathBuf,
|
||||
pub custom_ffm: bool,
|
||||
}
|
||||
|
||||
impl Default for GlobalState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
active_window_border_enabled: BORDER_ENABLED.load(Ordering::SeqCst),
|
||||
active_window_border_colours: ActiveWindowBorderColours {
|
||||
single: Colour::Rgb(Rgb::from(BORDER_COLOUR_SINGLE.load(Ordering::SeqCst))),
|
||||
stack: Colour::Rgb(Rgb::from(BORDER_COLOUR_STACK.load(Ordering::SeqCst))),
|
||||
monocle: Colour::Rgb(Rgb::from(BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst))),
|
||||
},
|
||||
active_window_border_style: *ACTIVE_WINDOW_BORDER_STYLE.lock(),
|
||||
border_offset: BORDER_OFFSET.load(Ordering::SeqCst),
|
||||
border_width: BORDER_WIDTH.load(Ordering::SeqCst),
|
||||
stackbar_mode: *STACKBAR_MODE.lock(),
|
||||
stackbar_focused_text_colour: Colour::Rgb(Rgb::from(
|
||||
STACKBAR_FOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
|
||||
)),
|
||||
stackbar_unfocused_text_colour: Colour::Rgb(Rgb::from(
|
||||
STACKBAR_UNFOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
|
||||
)),
|
||||
stackbar_tab_background_colour: Colour::Rgb(Rgb::from(
|
||||
STACKBAR_TAB_BACKGROUND_COLOUR.load(Ordering::SeqCst),
|
||||
)),
|
||||
stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst),
|
||||
stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst),
|
||||
remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst),
|
||||
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
||||
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
|
||||
layered_whitelist: LAYERED_WHITELIST.lock().clone(),
|
||||
tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_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(),
|
||||
workspace_rules: WORKSPACE_RULES.lock().clone(),
|
||||
window_hiding_behaviour: *HIDING_BEHAVIOUR.lock(),
|
||||
configuration_dir: HOME_DIR.clone(),
|
||||
data_dir: DATA_DIR.clone(),
|
||||
custom_ffm: CUSTOM_FFM.load(Ordering::SeqCst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Self> for WindowManager {
|
||||
@@ -123,14 +209,7 @@ impl From<&WindowManager> for State {
|
||||
focus_follows_mouse: wm.focus_follows_mouse,
|
||||
mouse_follows_focus: wm.mouse_follows_focus,
|
||||
has_pending_raise_op: wm.has_pending_raise_op,
|
||||
remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst),
|
||||
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
||||
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
|
||||
layered_whitelist: LAYERED_WHITELIST.lock().clone(),
|
||||
tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_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(),
|
||||
unmanaged_window_operation_behaviour: wm.unmanaged_window_operation_behaviour,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -522,11 +601,36 @@ impl WindowManager {
|
||||
// And all the visible windows (at the top of a container)
|
||||
for window in workspace.visible_windows().into_iter().flatten() {
|
||||
let mut already_moved_window_handles = self.already_moved_window_handles.lock();
|
||||
let exe_name = window.exe()?;
|
||||
let title = window.title()?;
|
||||
let class = window.class()?;
|
||||
|
||||
let mut found_workspace_rule = workspace_rules.get(&window.exe()?);
|
||||
let mut found_workspace_rule = workspace_rules.get(&exe_name);
|
||||
|
||||
if found_workspace_rule.is_none() {
|
||||
found_workspace_rule = workspace_rules.get(&window.title()?);
|
||||
found_workspace_rule = workspace_rules.get(&title);
|
||||
}
|
||||
|
||||
if found_workspace_rule.is_none() {
|
||||
found_workspace_rule = workspace_rules.get(&class);
|
||||
}
|
||||
|
||||
if found_workspace_rule.is_none() {
|
||||
for (k, v) in workspace_rules.iter() {
|
||||
if let Ok(re) = Regex::new(k) {
|
||||
if re.is_match(&exe_name) {
|
||||
found_workspace_rule = Some(v);
|
||||
}
|
||||
|
||||
if re.is_match(&title) {
|
||||
found_workspace_rule = Some(v);
|
||||
}
|
||||
|
||||
if re.is_match(&class) {
|
||||
found_workspace_rule = Some(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the executable names or titles of any of those windows are in our rules map
|
||||
@@ -617,7 +721,7 @@ impl WindowManager {
|
||||
|
||||
// Only re-tile the focused workspace if we need to
|
||||
if should_update_focused_workspace {
|
||||
self.update_focused_workspace(false)?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -670,14 +774,11 @@ impl WindowManager {
|
||||
pub fn raise_window_at_cursor_pos(&mut self) -> Result<()> {
|
||||
let mut hwnd = None;
|
||||
|
||||
for monitor in self.monitors() {
|
||||
for workspace in monitor.workspaces() {
|
||||
if let Some(container_idx) = workspace.container_idx_from_current_point() {
|
||||
if let Some(container) = workspace.containers().get(container_idx) {
|
||||
if let Some(window) = container.focused_window() {
|
||||
hwnd = Some(window.hwnd);
|
||||
}
|
||||
}
|
||||
let workspace = self.focused_workspace()?;
|
||||
if let Some(container_idx) = workspace.container_idx_from_current_point() {
|
||||
if let Some(container) = workspace.containers().get(container_idx) {
|
||||
if let Some(window) = container.focused_window() {
|
||||
hwnd = Some(window.hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,7 +897,11 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn update_focused_workspace(&mut self, follow_focus: bool) -> Result<()> {
|
||||
pub fn update_focused_workspace(
|
||||
&mut self,
|
||||
follow_focus: bool,
|
||||
trigger_focus: bool,
|
||||
) -> Result<()> {
|
||||
tracing::info!("updating");
|
||||
|
||||
let offset = self.work_area_offset;
|
||||
@@ -807,13 +912,19 @@ impl WindowManager {
|
||||
|
||||
if follow_focus {
|
||||
if let Some(window) = self.focused_workspace()?.maximized_window() {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
} else if let Some(container) = self.focused_workspace()?.monocle_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
} else if let Some(container) = self.focused_workspace()?.monocle_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
}
|
||||
} else if let Ok(window) = self.focused_window_mut() {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
} else {
|
||||
let desktop_window = Window {
|
||||
hwnd: WindowsApi::desktop_window()?,
|
||||
@@ -822,10 +933,7 @@ impl WindowManager {
|
||||
let rect = self.focused_monitor_size()?;
|
||||
WindowsApi::center_cursor_in_rect(&rect)?;
|
||||
|
||||
// Calling this directly instead of the window.focus() wrapper because trying to
|
||||
// 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()) {
|
||||
match WindowsApi::raise_and_focus_window(desktop_window.hwnd()) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::warn!("{} {}:{}", error, file!(), line!());
|
||||
@@ -844,7 +952,9 @@ impl WindowManager {
|
||||
&& self.focused_workspace()?.monocle_container().is_none()
|
||||
{
|
||||
if let Ok(window) = self.focused_window_mut() {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -854,7 +964,9 @@ impl WindowManager {
|
||||
if !follow_focus {
|
||||
if let Some(window) = self.focused_workspace()?.maximized_window() {
|
||||
window.restore();
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +1049,7 @@ impl WindowManager {
|
||||
workspace.resize_dimensions_mut()[focused_idx] = resize;
|
||||
|
||||
return if update {
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
@@ -1073,7 +1185,7 @@ impl WindowManager {
|
||||
|
||||
self.swap_monitor_workspaces(focused_monitor_idx, idx)?;
|
||||
|
||||
self.update_focused_workspace(mouse_follows_focus)
|
||||
self.update_focused_workspace(mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1120,7 +1232,7 @@ impl WindowManager {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1137,7 +1249,7 @@ impl WindowManager {
|
||||
monitor.move_container_to_workspace(idx, follow)?;
|
||||
monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
|
||||
self.update_focused_workspace(mouse_follows_focus)
|
||||
self.update_focused_workspace(mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
pub fn remove_focused_workspace(&mut self) -> Option<Workspace> {
|
||||
@@ -1166,7 +1278,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
self.focus_monitor(idx)?;
|
||||
self.update_focused_workspace(mouse_follows_focus)
|
||||
self.update_focused_workspace(mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1327,7 +1439,7 @@ impl WindowManager {
|
||||
.id();
|
||||
|
||||
if !WindowsApi::monitors_have_same_dpi(a, b)? {
|
||||
self.update_focused_workspace(self.mouse_follows_focus)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)?;
|
||||
}
|
||||
}
|
||||
Some(new_idx) => {
|
||||
@@ -1337,7 +1449,7 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1395,7 +1507,7 @@ impl WindowManager {
|
||||
|
||||
workspace.swap_containers(current_idx, new_idx);
|
||||
workspace.focus_container(new_idx);
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1419,7 +1531,7 @@ impl WindowManager {
|
||||
container.focus_window(next_idx);
|
||||
container.load_focused_window();
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1456,7 +1568,7 @@ impl WindowManager {
|
||||
};
|
||||
|
||||
workspace.move_window_to_container(adjusted_new_index)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus)?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -1476,7 +1588,7 @@ impl WindowManager {
|
||||
tracing::info!("promoting container");
|
||||
|
||||
workspace.promote_container()?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1499,7 +1611,7 @@ impl WindowManager {
|
||||
};
|
||||
|
||||
workspace.focus_container(target_idx);
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1515,14 +1627,14 @@ impl WindowManager {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
workspace.new_container_for_focused_window()?;
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn toggle_tiling(&mut self) -> Result<()> {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
workspace.set_tile(!*workspace.tile());
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1544,7 +1656,7 @@ impl WindowManager {
|
||||
self.float_window()?;
|
||||
}
|
||||
|
||||
self.update_focused_workspace(is_floating_window)
|
||||
self.update_focused_workspace(is_floating_window, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1579,14 +1691,25 @@ impl WindowManager {
|
||||
pub fn toggle_monocle(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let workspace = self.focused_workspace()?;
|
||||
match workspace.monocle_container() {
|
||||
None => self.monocle_on()?,
|
||||
Some(_) => self.monocle_off()?,
|
||||
}
|
||||
|
||||
self.update_focused_workspace(true)
|
||||
self.update_focused_workspace(true, true)?;
|
||||
|
||||
// TODO: fix this ugly hack to restore stackbar after monocle is toggled off
|
||||
let workspace = self.focused_workspace()?;
|
||||
if workspace.monocle_container().is_none() {
|
||||
if let Some(container) = workspace.focused_container() {
|
||||
if container.stackbar().is_some() {
|
||||
self.retile_all(true)?;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1616,7 +1739,7 @@ impl WindowManager {
|
||||
Some(_) => self.unmaximize_window()?,
|
||||
}
|
||||
|
||||
self.update_focused_workspace(true)
|
||||
self.update_focused_workspace(true, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1675,7 +1798,7 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1700,7 +1823,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
workspace.set_layout(Layout::Default(layout));
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1723,7 +1846,7 @@ impl WindowManager {
|
||||
Layout::Custom(_) => {}
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1753,7 +1876,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_layout(Layout::Custom(layout));
|
||||
workspace.set_layout_flip(None);
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1768,7 +1891,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_workspace_padding(Option::from(sizing.adjust_by(padding, adjustment)));
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1783,7 +1906,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_container_padding(Option::from(sizing.adjust_by(padding, adjustment)));
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1805,7 +1928,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_tile(tile);
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -1849,7 +1972,7 @@ impl WindowManager {
|
||||
workspace.update(&work_area, offset)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(self.update_focused_workspace(false)?)
|
||||
Ok(self.update_focused_workspace(false, false)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1899,7 +2022,7 @@ impl WindowManager {
|
||||
workspace.update(&work_area, offset)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(self.update_focused_workspace(false)?)
|
||||
Ok(self.update_focused_workspace(false, false)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1940,7 +2063,7 @@ impl WindowManager {
|
||||
workspace.update(&work_area, offset)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(self.update_focused_workspace(false)?)
|
||||
Ok(self.update_focused_workspace(false, false)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1981,7 +2104,7 @@ impl WindowManager {
|
||||
workspace.update(&work_area, offset)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(self.update_focused_workspace(false)?)
|
||||
Ok(self.update_focused_workspace(false, false)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2026,7 +2149,7 @@ impl WindowManager {
|
||||
workspace.update(&work_area, offset)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(self.update_focused_workspace(false)?)
|
||||
Ok(self.update_focused_workspace(false, false)?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2093,7 +2216,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_workspace_padding(Option::from(size));
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -2142,7 +2265,7 @@ impl WindowManager {
|
||||
|
||||
workspace.set_container_padding(Option::from(size));
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, false)
|
||||
}
|
||||
|
||||
pub fn focused_monitor_size(&self) -> Result<Rect> {
|
||||
@@ -2246,7 +2369,7 @@ impl WindowManager {
|
||||
monitor.focus_workspace(idx)?;
|
||||
monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
|
||||
self.update_focused_workspace(false)
|
||||
self.update_focused_workspace(false, true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -2278,7 +2401,7 @@ impl WindowManager {
|
||||
monitor.focus_workspace(monitor.new_workspace_idx())?;
|
||||
monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus)
|
||||
self.update_focused_workspace(self.mouse_follows_focus, false)
|
||||
}
|
||||
|
||||
pub fn focused_container(&self) -> Result<&Container> {
|
||||
|
||||
@@ -153,7 +153,8 @@ impl WindowManagerEvent {
|
||||
path,
|
||||
&object_name_change_on_launch,
|
||||
®ex_identifiers,
|
||||
);
|
||||
)
|
||||
.is_some();
|
||||
|
||||
if should_trigger {
|
||||
Option::from(Self::Show(winevent, window))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::size_of;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
@@ -47,9 +48,7 @@ use windows::Win32::Graphics::Gdi::MONITORINFOEXW;
|
||||
use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST;
|
||||
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
|
||||
use windows::Win32::System::RemoteDesktop::ProcessIdToSessionId;
|
||||
use windows::Win32::System::Threading::AttachThreadInput;
|
||||
use windows::Win32::System::Threading::GetCurrentProcessId;
|
||||
use windows::Win32::System::Threading::GetCurrentThreadId;
|
||||
use windows::Win32::System::Threading::OpenProcess;
|
||||
use windows::Win32::System::Threading::QueryFullProcessImageNameW;
|
||||
use windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS;
|
||||
@@ -61,7 +60,6 @@ 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;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_0;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_MOUSE;
|
||||
@@ -104,7 +102,6 @@ use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_NOTOPMOST;
|
||||
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
|
||||
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
|
||||
@@ -115,6 +112,9 @@ use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_GETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETFOREGROUNDLOCKTIMEOUT;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE;
|
||||
use windows::Win32::UI::WindowsAndMessaging::SW_MINIMIZE;
|
||||
@@ -347,12 +347,19 @@ impl WindowsApi {
|
||||
/// the layout to account for any window shadow borders (the window painted
|
||||
/// region will match layout on completion).
|
||||
pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> {
|
||||
let flags = SetWindowPosition::NO_ACTIVATE
|
||||
let mut flags = SetWindowPosition::NO_ACTIVATE
|
||||
| SetWindowPosition::NO_SEND_CHANGING
|
||||
| SetWindowPosition::NO_COPY_BITS
|
||||
| SetWindowPosition::FRAME_CHANGED;
|
||||
|
||||
let shadow_rect = Self::shadow_rect(hwnd)?;
|
||||
// If the request is to place the window on top, then HWND_TOP will take
|
||||
// effect, otherwise pass NO_Z_ORDER that will cause set_window_pos to
|
||||
// ignore the z-order paramter.
|
||||
if !top {
|
||||
flags |= SetWindowPosition::NO_Z_ORDER;
|
||||
}
|
||||
|
||||
let shadow_rect = Self::shadow_rect(hwnd).unwrap_or_default();
|
||||
let rect = Rect {
|
||||
left: layout.left + shadow_rect.left,
|
||||
top: layout.top + shadow_rect.top,
|
||||
@@ -360,16 +367,29 @@ impl WindowsApi {
|
||||
bottom: layout.bottom + shadow_rect.bottom,
|
||||
};
|
||||
|
||||
let position = if top { HWND_TOP } else { HWND_NOTOPMOST };
|
||||
Self::set_window_pos(hwnd, &rect, position, flags.bits())
|
||||
// Note: earlier code had set HWND_TOPMOST here, but we should not do
|
||||
// that. HWND_TOPMOST is a sticky z-order change, rather than a regular
|
||||
// z-order reordering. Programs will use TOPMOST themselves to do things
|
||||
// such as making sure that their tool windows or dialog pop-ups are
|
||||
// above their main window. If any such windows are unmanaged, they must
|
||||
// still remian topmost, so we set HWND_TOP here, which will cause the
|
||||
// managed window to come to the front, but if the managed window has a
|
||||
// child that is TOPMOST it will still be rendered above, in the proper
|
||||
// order expected by the application. It's also important to understand
|
||||
// that TOPMOST is somewhat viral, in that when you set a window to
|
||||
// TOPMOST all of its owned windows are also made TOPMOST.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos#remarks
|
||||
Self::set_window_pos(hwnd, &rect, HWND_TOP, flags.bits())
|
||||
}
|
||||
|
||||
pub fn bring_window_to_top(hwnd: HWND) -> Result<()> {
|
||||
unsafe { BringWindowToTop(hwnd) }.process()
|
||||
}
|
||||
|
||||
// Raise the window to the top of the Z order, but do not activate or focus
|
||||
// it. Use raise_and_focus_window to activate and focus a window.
|
||||
pub fn raise_window(hwnd: HWND) -> Result<()> {
|
||||
let flags = SetWindowPosition::NO_MOVE;
|
||||
let flags = SetWindowPosition::NO_MOVE | SetWindowPosition::NO_ACTIVATE;
|
||||
|
||||
let position = HWND_TOP;
|
||||
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
|
||||
@@ -394,8 +414,7 @@ impl WindowsApi {
|
||||
// top of other pop-up dialogs such as a file picker dialog from
|
||||
// Firefox. When adjusting this in the future, it's important to check
|
||||
// those dialog cases.
|
||||
let position = HWND_NOTOPMOST;
|
||||
Self::set_window_pos(hwnd, layout, position, flags.bits())
|
||||
Self::set_window_pos(hwnd, layout, HWND_TOP, flags.bits())
|
||||
}
|
||||
|
||||
pub fn hide_border_window(hwnd: HWND) -> Result<()> {
|
||||
@@ -462,8 +481,31 @@ impl WindowsApi {
|
||||
unsafe { GetForegroundWindow() }.process()
|
||||
}
|
||||
|
||||
pub fn set_foreground_window(hwnd: HWND) -> Result<()> {
|
||||
unsafe { SetForegroundWindow(hwnd) }.ok().process()
|
||||
pub fn raise_and_focus_window(hwnd: HWND) -> Result<()> {
|
||||
let event = [INPUT {
|
||||
r#type: INPUT_MOUSE,
|
||||
..Default::default()
|
||||
}];
|
||||
|
||||
unsafe {
|
||||
// Send an input event to our own process first so that we pass the
|
||||
// foreground lock check
|
||||
SendInput(&event, size_of::<INPUT>() as i32);
|
||||
// Error ignored, as the operation is not always necessary.
|
||||
let _ = SetWindowPos(
|
||||
hwnd,
|
||||
HWND_TOP,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW,
|
||||
)
|
||||
.process();
|
||||
SetForegroundWindow(hwnd)
|
||||
}
|
||||
.ok()
|
||||
.process()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -583,10 +625,6 @@ impl WindowsApi {
|
||||
(process_id, thread_id)
|
||||
}
|
||||
|
||||
pub fn current_thread_id() -> u32 {
|
||||
unsafe { GetCurrentThreadId() }
|
||||
}
|
||||
|
||||
pub fn current_process_id() -> u32 {
|
||||
unsafe { GetCurrentProcessId() }
|
||||
}
|
||||
@@ -604,16 +642,6 @@ impl WindowsApi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach_thread_input(thread_id: u32, target_thread_id: u32, attach: bool) -> Result<()> {
|
||||
unsafe { AttachThreadInput(thread_id, target_thread_id, attach) }
|
||||
.ok()
|
||||
.process()
|
||||
}
|
||||
|
||||
pub fn set_focus(hwnd: HWND) -> Result<()> {
|
||||
unsafe { SetFocus(hwnd) }.process().map(|_| ())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_window_long_ptr_w(
|
||||
hwnd: HWND,
|
||||
|
||||
@@ -36,12 +36,12 @@ use windows::Win32::UI::WindowsAndMessaging::WM_SETTINGCHANGE;
|
||||
use crate::container::Container;
|
||||
use crate::monitor::Monitor;
|
||||
use crate::ring::Ring;
|
||||
use crate::window::RuleDebug;
|
||||
use crate::window::Window;
|
||||
use crate::window_manager_event::WindowManagerEvent;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::winevent::WinEvent;
|
||||
use crate::winevent_listener;
|
||||
use crate::ActiveWindowBorderStyle;
|
||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
||||
use crate::BORDER_COLOUR_CURRENT;
|
||||
use crate::BORDER_RECT;
|
||||
@@ -50,6 +50,7 @@ use crate::DISPLAY_INDEX_PREFERENCES;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::TRANSPARENCY_COLOUR;
|
||||
use crate::WINDOWS_11;
|
||||
use komorebi_core::ActiveWindowBorderStyle;
|
||||
|
||||
pub extern "system" fn valid_display_monitors(
|
||||
hmonitor: HMONITOR,
|
||||
@@ -157,7 +158,7 @@ pub extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
if is_visible && is_window && !is_minimized {
|
||||
let window = Window { hwnd: hwnd.0 };
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(None) {
|
||||
if let Ok(should_manage) = window.should_manage(None, &mut RuleDebug::default()) {
|
||||
if should_manage {
|
||||
if is_maximized {
|
||||
WindowsApi::restore_window(hwnd);
|
||||
@@ -198,13 +199,9 @@ pub extern "system" fn win_event_hook(
|
||||
Some(event) => event,
|
||||
};
|
||||
|
||||
if let Ok(should_manage) = window.should_manage(Option::from(event_type)) {
|
||||
if should_manage {
|
||||
winevent_listener::event_tx()
|
||||
.send(event_type)
|
||||
.expect("could not send message on winevent_listener::event_tx");
|
||||
}
|
||||
}
|
||||
winevent_listener::event_tx()
|
||||
.send(event_type)
|
||||
.expect("could not send message on winevent_listener::event_tx");
|
||||
}
|
||||
|
||||
pub extern "system" fn border_window(
|
||||
|
||||
@@ -131,6 +131,8 @@ impl Workspace {
|
||||
}
|
||||
|
||||
self.set_layout_rules(all_rules);
|
||||
|
||||
self.tile = true;
|
||||
}
|
||||
|
||||
if let Some(layout_rules) = &config.custom_layout_rules {
|
||||
@@ -139,6 +141,8 @@ impl Workspace {
|
||||
let rule = CustomLayout::from_path(pathbuf)?;
|
||||
rules.push((*count, Layout::Custom(rule)));
|
||||
}
|
||||
|
||||
self.tile = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -299,8 +303,10 @@ impl Workspace {
|
||||
let containers = self.containers_mut();
|
||||
|
||||
for (i, container) in containers.iter_mut().enumerate() {
|
||||
container.renew_stackbar();
|
||||
|
||||
let container_windows = container.windows().clone();
|
||||
let container_topbar = container.stackbar().clone();
|
||||
let container_stackbar = container.stackbar().clone();
|
||||
|
||||
if let (Some(window), Some(layout)) =
|
||||
(container.focused_window_mut(), layouts.get(i))
|
||||
@@ -326,18 +332,21 @@ impl Workspace {
|
||||
rect.add_padding(width);
|
||||
}
|
||||
|
||||
if let Some(stackbar) = container_topbar {
|
||||
stackbar.set_position(
|
||||
&stackbar.get_position_from_container_layout(layout),
|
||||
false,
|
||||
)?;
|
||||
if let Some(stackbar) = container_stackbar {
|
||||
if stackbar
|
||||
.set_position(
|
||||
&stackbar.get_position_from_container_layout(layout),
|
||||
false,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
stackbar.update(&container_windows, focused_hwnd)?;
|
||||
let tab_height = STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst);
|
||||
let total_height = tab_height + container_padding;
|
||||
|
||||
stackbar.update(&container_windows, focused_hwnd)?;
|
||||
let tab_height = STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst);
|
||||
let total_height = tab_height + container_padding;
|
||||
|
||||
rect.top += total_height;
|
||||
rect.bottom -= total_height;
|
||||
rect.top += total_height;
|
||||
rect.bottom -= total_height;
|
||||
}
|
||||
}
|
||||
|
||||
window.set_position(&rect, false)?;
|
||||
@@ -357,6 +366,33 @@ impl Workspace {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// focus_changed performs updates in response to the fact that a focus
|
||||
// change event has occurred. The focus change is assumed to be valid, and
|
||||
// should not result in a new focus change - the intent here is to update
|
||||
// focus-reactive elements, such as the stackbar.
|
||||
pub fn focus_changed(&mut self, hwnd: isize) -> Result<()> {
|
||||
if !self.tile() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let containers = self.containers_mut();
|
||||
|
||||
for container in containers.iter_mut() {
|
||||
let container_windows = container.windows().clone();
|
||||
let container_topbar = container.stackbar().clone();
|
||||
|
||||
if let Some(idx) = container.idx_for_window(hwnd) {
|
||||
container.focus_window(idx);
|
||||
container.restore();
|
||||
}
|
||||
|
||||
if let Some(stackbar) = container_topbar {
|
||||
stackbar.update(&container_windows, hwnd)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reap_orphans(&mut self) -> Result<(usize, usize)> {
|
||||
let mut hwnds = vec![];
|
||||
let mut floating_hwnds = vec![];
|
||||
@@ -844,7 +880,7 @@ impl Workspace {
|
||||
self.containers_mut().remove(focused_idx);
|
||||
self.resize_dimensions_mut().remove(focused_idx);
|
||||
|
||||
if focused_idx == self.containers().len() {
|
||||
if focused_idx == self.containers().len() && focused_idx != 0 {
|
||||
self.focus_container(focused_idx - 1);
|
||||
}
|
||||
} else {
|
||||
@@ -862,6 +898,17 @@ impl Workspace {
|
||||
fn enforce_resize_constraints(&mut self) {
|
||||
match self.layout {
|
||||
Layout::Default(DefaultLayout::BSP) => self.enforce_resize_constraints_for_bsp(),
|
||||
Layout::Default(DefaultLayout::Columns) => self.enforce_resize_for_columns(),
|
||||
Layout::Default(DefaultLayout::Rows) => self.enforce_resize_for_rows(),
|
||||
Layout::Default(DefaultLayout::VerticalStack) => {
|
||||
self.enforce_resize_for_vertical_stack();
|
||||
}
|
||||
Layout::Default(DefaultLayout::RightMainVerticalStack) => {
|
||||
self.enforce_resize_for_right_vertical_stack();
|
||||
}
|
||||
Layout::Default(DefaultLayout::HorizontalStack) => {
|
||||
self.enforce_resize_for_horizontal_stack();
|
||||
}
|
||||
Layout::Default(DefaultLayout::UltrawideVerticalStack) => {
|
||||
self.enforce_resize_for_ultrawide();
|
||||
}
|
||||
@@ -895,6 +942,146 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_columns(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
let len = resize_dimensions.len();
|
||||
for (i, rect) in resize_dimensions.iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
rect.top = 0;
|
||||
rect.bottom = 0;
|
||||
|
||||
if i == 0 {
|
||||
rect.left = 0;
|
||||
}
|
||||
if i == len - 1 {
|
||||
rect.right = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_rows(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
let len = resize_dimensions.len();
|
||||
for (i, rect) in resize_dimensions.iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
rect.left = 0;
|
||||
rect.right = 0;
|
||||
|
||||
if i == 0 {
|
||||
rect.top = 0;
|
||||
}
|
||||
if i == len - 1 {
|
||||
rect.bottom = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_vertical_stack(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
// Single window can not be resized at all
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
// Zero is actually on the left
|
||||
if let Some(mut left) = resize_dimensions[0] {
|
||||
left.top = 0;
|
||||
left.bottom = 0;
|
||||
left.left = 0;
|
||||
}
|
||||
|
||||
// Handle stack on the right
|
||||
let stack_size = resize_dimensions[1..].len();
|
||||
for (i, rect) in resize_dimensions[1..].iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
// No containers can resize to the right
|
||||
rect.right = 0;
|
||||
|
||||
// First container in stack cant resize up
|
||||
if i == 0 {
|
||||
rect.top = 0;
|
||||
} else if i == stack_size - 1 {
|
||||
// Last cant be resized to the bottom
|
||||
rect.bottom = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_right_vertical_stack(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
// Single window can not be resized at all
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
// Zero is actually on the right
|
||||
if let Some(mut left) = resize_dimensions[1] {
|
||||
left.top = 0;
|
||||
left.bottom = 0;
|
||||
left.right = 0;
|
||||
}
|
||||
|
||||
// Handle stack on the right
|
||||
let stack_size = resize_dimensions[1..].len();
|
||||
for (i, rect) in resize_dimensions[1..].iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
// No containers can resize to the left
|
||||
rect.left = 0;
|
||||
|
||||
// First container in stack cant resize up
|
||||
if i == 0 {
|
||||
rect.top = 0;
|
||||
} else if i == stack_size - 1 {
|
||||
// Last cant be resized to the bottom
|
||||
rect.bottom = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_horizontal_stack(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
if let Some(mut left) = resize_dimensions[0] {
|
||||
left.top = 0;
|
||||
left.left = 0;
|
||||
left.right = 0;
|
||||
}
|
||||
|
||||
let stack_size = resize_dimensions[1..].len();
|
||||
for (i, rect) in resize_dimensions[1..].iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
rect.bottom = 0;
|
||||
|
||||
if i == 0 {
|
||||
rect.left = 0;
|
||||
}
|
||||
if i == stack_size - 1 {
|
||||
rect.right = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_ultrawide(&mut self) {
|
||||
let resize_dimensions = self.resize_dimensions_mut();
|
||||
match resize_dimensions.len() {
|
||||
@@ -995,7 +1182,7 @@ impl Workspace {
|
||||
.ok_or_else(|| anyhow!("there is no monocle container"))?;
|
||||
|
||||
let container = container.clone();
|
||||
if restore_idx > self.containers().len() - 1 {
|
||||
if restore_idx >= self.containers().len() {
|
||||
self.containers_mut()
|
||||
.resize(restore_idx, Container::default());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebic-no-console"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "The command-line interface (without a console) for Komorebi, a tiling window manager for Windows"
|
||||
categories = ["cli", "tiling-window-manager", "windows"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; Generated by komorebic.exe
|
||||
#Requires AutoHotkey v2.0.2
|
||||
|
||||
Start(ffm, await_configuration, tcp_port) {
|
||||
RunWait("komorebic.exe start " ffm " --await-configuration " await_configuration " --tcp-port " tcp_port, , "Hide")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "komorebic"
|
||||
version = "0.1.25-dev.0"
|
||||
version = "0.1.25"
|
||||
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
|
||||
description = "The command-line interface for Komorebi, a tiling window manager for Windows"
|
||||
categories = ["cli", "tiling-window-manager", "windows"]
|
||||
@@ -13,6 +13,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
derive-ahk = { path = "../derive-ahk" }
|
||||
komorebi-core = { path = "../komorebi-core" }
|
||||
komorebi-client = { path = "../komorebi-client" }
|
||||
|
||||
clap = { version = "4", features = ["derive", "wrap_help"] }
|
||||
color-eyre = { workspace = true }
|
||||
@@ -28,7 +29,7 @@ reqwest = { version = "0.12", features = ["blocking"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = "0.9"
|
||||
sysinfo = "0.30"
|
||||
sysinfo = { workspace = true }
|
||||
thiserror = "1"
|
||||
uds_windows = "1"
|
||||
which = "6"
|
||||
|
||||
@@ -478,6 +478,14 @@ pub struct SendToMonitorWorkspace {
|
||||
target_workspace: usize,
|
||||
}
|
||||
|
||||
#[derive(Parser, AhkFunction)]
|
||||
pub struct MoveToMonitorWorkspace {
|
||||
/// Target monitor index (zero-indexed)
|
||||
target_monitor: usize,
|
||||
/// Workspace index on the target monitor (zero-indexed)
|
||||
target_workspace: usize,
|
||||
}
|
||||
|
||||
macro_rules! gen_focused_workspace_padding_subcommand_args {
|
||||
// SubCommand Pattern
|
||||
( $( $name:ident ),+ $(,)? ) => {
|
||||
@@ -815,6 +823,8 @@ enum SubCommand {
|
||||
Whkdrc,
|
||||
/// Show a JSON representation of the current window manager state
|
||||
State,
|
||||
/// Show a JSON representation of the current global state
|
||||
GlobalState,
|
||||
/// Show a JSON representation of visible windows
|
||||
VisibleWindows,
|
||||
/// Query the current window manager state
|
||||
@@ -916,6 +926,9 @@ enum SubCommand {
|
||||
/// Send the focused window to the specified monitor workspace
|
||||
#[clap(arg_required_else_help = true)]
|
||||
SendToMonitorWorkspace(SendToMonitorWorkspace),
|
||||
/// Move the focused window to the specified monitor workspace
|
||||
#[clap(arg_required_else_help = true)]
|
||||
MoveToMonitorWorkspace(MoveToMonitorWorkspace),
|
||||
/// Focus the specified monitor
|
||||
#[clap(arg_required_else_help = true)]
|
||||
FocusMonitor(FocusMonitor),
|
||||
@@ -1244,9 +1257,15 @@ fn main() -> Result<()> {
|
||||
let subcommands = cli.get_subcommands_mut();
|
||||
std::fs::create_dir_all("docs/cli")?;
|
||||
|
||||
let ignore = [
|
||||
"docgen",
|
||||
"alt-focus-hack",
|
||||
"identify-border-overflow-application",
|
||||
];
|
||||
|
||||
for cmd in subcommands {
|
||||
let name = cmd.get_name().to_string();
|
||||
if name != "docgen" {
|
||||
if !ignore.contains(&name.as_str()) {
|
||||
let help_text = cmd.render_long_help().to_string();
|
||||
let outpath = format!("docs/cli/{name}.md");
|
||||
let markdown = format!("# {name}\n\n```\n{help_text}\n```");
|
||||
@@ -1389,6 +1408,11 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this file adheres to the schema static config schema as the last step,
|
||||
// so that more basic errors above can be shown to the error before schema-specific
|
||||
// errors
|
||||
let _ = serde_json::from_str::<komorebi_client::StaticConfig>(&config_source)?;
|
||||
|
||||
if config_whkd.exists() {
|
||||
println!("Found {}; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag\n", config_whkd.to_string_lossy());
|
||||
} else {
|
||||
@@ -1543,6 +1567,15 @@ fn main() -> Result<()> {
|
||||
.as_bytes()?,
|
||||
)?;
|
||||
}
|
||||
SubCommand::MoveToMonitorWorkspace(arg) => {
|
||||
send_message(
|
||||
&SocketMessage::MoveContainerToMonitorWorkspaceNumber(
|
||||
arg.target_monitor,
|
||||
arg.target_workspace,
|
||||
)
|
||||
.as_bytes()?,
|
||||
)?;
|
||||
}
|
||||
SubCommand::MoveWorkspaceToMonitor(arg) => {
|
||||
send_message(&SocketMessage::MoveWorkspaceToMonitorNumber(arg.target).as_bytes()?)?;
|
||||
}
|
||||
@@ -1773,7 +1806,7 @@ fn main() -> Result<()> {
|
||||
};
|
||||
|
||||
let mut flags = vec![];
|
||||
if let Some(config) = arg.config {
|
||||
if let Some(config) = &arg.config {
|
||||
let path = resolve_home_path(config)?;
|
||||
if !path.is_file() {
|
||||
bail!("could not find file: {}", path.display());
|
||||
@@ -1808,9 +1841,10 @@ fn main() -> Result<()> {
|
||||
)
|
||||
};
|
||||
|
||||
let mut attempts = 0;
|
||||
let mut running = false;
|
||||
|
||||
while !running {
|
||||
while !running && attempts <= 2 {
|
||||
match powershell_script::run(&script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
@@ -1831,9 +1865,27 @@ fn main() -> Result<()> {
|
||||
running = true;
|
||||
} else {
|
||||
println!("komorebi.exe did not start... Trying again");
|
||||
attempts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if !running {
|
||||
println!("\nRunning komorebi.exe directly for detailed error output\n");
|
||||
if let Some(config) = arg.config {
|
||||
let path = resolve_home_path(config)?;
|
||||
if let Ok(output) = Command::new("komorebi.exe")
|
||||
.arg(format!("'--config=\"{}\"'", path.display()))
|
||||
.output()
|
||||
{
|
||||
println!("{}", String::from_utf8(output.stderr)?);
|
||||
}
|
||||
} else if let Ok(output) = Command::new("komorebi.exe").output() {
|
||||
println!("{}", String::from_utf8(output.stderr)?);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if arg.whkd {
|
||||
let script = r"
|
||||
if (!(Get-Process whkd -ErrorAction SilentlyContinue))
|
||||
@@ -1895,6 +1947,34 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
send_message(&SocketMessage::Stop.as_bytes()?)?;
|
||||
let mut system = sysinfo::System::new_all();
|
||||
system.refresh_processes();
|
||||
|
||||
if system.processes_by_name("komorebi.exe").count() >= 1 {
|
||||
println!("komorebi is still running, attempting to force-quit");
|
||||
|
||||
let script = r"
|
||||
Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
|
||||
";
|
||||
match powershell_script::run(script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
|
||||
let hwnd_json = DATA_DIR.join("komorebi.hwnd.json");
|
||||
|
||||
let file = File::open(hwnd_json)?;
|
||||
let reader = BufReader::new(file);
|
||||
let hwnds: Vec<isize> = serde_json::from_reader(reader)?;
|
||||
|
||||
for hwnd in hwnds {
|
||||
restore_window(HWND(hwnd));
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
println!("Error: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SubCommand::FloatRule(arg) => {
|
||||
send_message(&SocketMessage::FloatRule(arg.identifier, arg.id).as_bytes()?)?;
|
||||
@@ -2025,6 +2105,9 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
|
||||
SubCommand::State => {
|
||||
print_query(&SocketMessage::State.as_bytes()?);
|
||||
}
|
||||
SubCommand::GlobalState => {
|
||||
print_query(&SocketMessage::GlobalState.as_bytes()?);
|
||||
}
|
||||
SubCommand::VisibleWindows => {
|
||||
print_query(&SocketMessage::VisibleWindows.as_bytes()?);
|
||||
}
|
||||
@@ -2139,10 +2222,10 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
|
||||
)?;
|
||||
}
|
||||
SubCommand::ActiveWindowBorderWidth(arg) => {
|
||||
send_message(&SocketMessage::ActiveWindowBorderWidth(arg.width).as_bytes()?)?;
|
||||
send_message(&SocketMessage::BorderWidth(arg.width).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::ActiveWindowBorderOffset(arg) => {
|
||||
send_message(&SocketMessage::ActiveWindowBorderOffset(arg.offset).as_bytes()?)?;
|
||||
send_message(&SocketMessage::BorderOffset(arg.offset).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::ResizeDelta(arg) => {
|
||||
send_message(&SocketMessage::ResizeDelta(arg.pixels).as_bytes()?)?;
|
||||
|
||||
306
mkdocs.yml
306
mkdocs.yml
@@ -45,160 +45,162 @@ plugins:
|
||||
|
||||
nav:
|
||||
- Komorebi:
|
||||
- index.md
|
||||
- Design: design.md
|
||||
- index.md
|
||||
- Design: design.md
|
||||
- Getting started:
|
||||
- Installation: installation.md
|
||||
- Example configurations: example-configurations.md
|
||||
- Installation: installation.md
|
||||
- Example configurations: example-configurations.md
|
||||
- Common workflows:
|
||||
- common-workflows/komorebi-config-home.md
|
||||
- common-workflows/active-window-border.md
|
||||
- common-workflows/stackbar.md
|
||||
- common-workflows/remove-gaps.md
|
||||
- common-workflows/ignore-windows.md
|
||||
- common-workflows/force-manage-windows.md
|
||||
- common-workflows/tray-and-multi-window-applications.md
|
||||
- common-workflows/focus-follows-mouse.md
|
||||
- common-workflows/mouse-follows-focus.md
|
||||
- common-workflows/custom-layouts.md
|
||||
- common-workflows/dynamic-layout-switching.md
|
||||
# - common-workflows/autohotkey.md
|
||||
- common-workflows/komorebi-config-home.md
|
||||
- common-workflows/active-window-border.md
|
||||
- common-workflows/stackbar.md
|
||||
- common-workflows/remove-gaps.md
|
||||
- common-workflows/ignore-windows.md
|
||||
- common-workflows/force-manage-windows.md
|
||||
- common-workflows/tray-and-multi-window-applications.md
|
||||
- common-workflows/focus-follows-mouse.md
|
||||
- common-workflows/mouse-follows-focus.md
|
||||
- common-workflows/custom-layouts.md
|
||||
- common-workflows/dynamic-layout-switching.md
|
||||
# - common-workflows/autohotkey.md
|
||||
- Release notes:
|
||||
- release/v0-1-22.md
|
||||
- release/v0-1-22.md
|
||||
- Configuration reference: https://komorebi.lgug2z.com/schema
|
||||
- CLI reference:
|
||||
- cli/quickstart.md
|
||||
- cli/start.md
|
||||
- cli/stop.md
|
||||
- cli/check.md
|
||||
- cli/configuration.md
|
||||
- cli/whkdrc.md
|
||||
- cli/state.md
|
||||
- cli/visible-windows.md
|
||||
- cli/query.md
|
||||
- cli/subscribe-socket.md
|
||||
- cli/unsubscribe-socket.md
|
||||
- cli/subscribe-pipe.md
|
||||
- cli/unsubscribe-pipe.md
|
||||
- cli/log.md
|
||||
- cli/quick-save-resize.md
|
||||
- cli/quick-load-resize.md
|
||||
- cli/save-resize.md
|
||||
- cli/load-resize.md
|
||||
- cli/focus.md
|
||||
- cli/move.md
|
||||
- cli/minimize.md
|
||||
- cli/close.md
|
||||
- cli/force-focus.md
|
||||
- cli/cycle-focus.md
|
||||
- cli/cycle-move.md
|
||||
- cli/stack.md
|
||||
- cli/resize-edge.md
|
||||
- cli/resize-axis.md
|
||||
- cli/unstack.md
|
||||
- cli/cycle-stack.md
|
||||
- cli/move-to-monitor.md
|
||||
- cli/cycle-move-to-monitor.md
|
||||
- cli/move-to-workspace.md
|
||||
- cli/move-to-named-workspace.md
|
||||
- cli/cycle-move-to-workspace.md
|
||||
- cli/send-to-monitor.md
|
||||
- cli/cycle-send-to-monitor.md
|
||||
- cli/send-to-workspace.md
|
||||
- cli/send-to-named-workspace.md
|
||||
- cli/cycle-send-to-workspace.md
|
||||
- cli/send-to-monitor-workspace.md
|
||||
- cli/focus-monitor.md
|
||||
- cli/focus-last-workspace.md
|
||||
- cli/focus-workspace.md
|
||||
- cli/focus-workspaces.md
|
||||
- cli/focus-monitor-workspace.md
|
||||
- cli/focus-named-workspace.md
|
||||
- cli/cycle-monitor.md
|
||||
- cli/cycle-workspace.md
|
||||
- cli/move-workspace-to-monitor.md
|
||||
- cli/swap-workspaces-with-monitor.md
|
||||
- cli/new-workspace.md
|
||||
- cli/resize-delta.md
|
||||
- cli/invisible-borders.md
|
||||
- cli/global-work-area-offset.md
|
||||
- cli/monitor-work-area-offset.md
|
||||
- cli/focused-workspace-container-padding.md
|
||||
- cli/focused-workspace-padding.md
|
||||
- cli/adjust-container-padding.md
|
||||
- cli/adjust-workspace-padding.md
|
||||
- cli/change-layout.md
|
||||
- cli/cycle-layout.md
|
||||
- cli/load-custom-layout.md
|
||||
- cli/flip-layout.md
|
||||
- cli/promote.md
|
||||
- cli/promote-focus.md
|
||||
- cli/retile.md
|
||||
- cli/monitor-index-preference.md
|
||||
- cli/display-index-preference.md
|
||||
- cli/ensure-workspaces.md
|
||||
- cli/ensure-named-workspaces.md
|
||||
- cli/container-padding.md
|
||||
- cli/named-workspace-container-padding.md
|
||||
- cli/workspace-padding.md
|
||||
- cli/named-workspace-padding.md
|
||||
- cli/workspace-layout.md
|
||||
- cli/named-workspace-layout.md
|
||||
- cli/workspace-custom-layout.md
|
||||
- cli/named-workspace-custom-layout.md
|
||||
- cli/workspace-layout-rule.md
|
||||
- cli/named-workspace-layout-rule.md
|
||||
- cli/workspace-custom-layout-rule.md
|
||||
- cli/named-workspace-custom-layout-rule.md
|
||||
- cli/clear-workspace-layout-rules.md
|
||||
- cli/clear-named-workspace-layout-rules.md
|
||||
- cli/workspace-tiling.md
|
||||
- cli/named-workspace-tiling.md
|
||||
- cli/workspace-name.md
|
||||
- cli/toggle-window-container-behaviour.md
|
||||
- cli/toggle-pause.md
|
||||
- cli/toggle-tiling.md
|
||||
- cli/toggle-float.md
|
||||
- cli/toggle-monocle.md
|
||||
- cli/toggle-maximize.md
|
||||
- cli/restore-windows.md
|
||||
- cli/manage.md
|
||||
- cli/unmanage.md
|
||||
- cli/reload-configuration.md
|
||||
- cli/watch-configuration.md
|
||||
- cli/complete-configuration.md
|
||||
- cli/window-hiding-behaviour.md
|
||||
- cli/cross-monitor-move-behaviour.md
|
||||
- cli/toggle-cross-monitor-move-behaviour.md
|
||||
- cli/unmanaged-window-operation-behaviour.md
|
||||
- cli/float-rule.md
|
||||
- cli/manage-rule.md
|
||||
- cli/initial-workspace-rule.md
|
||||
- cli/initial-named-workspace-rule.md
|
||||
- cli/workspace-rule.md
|
||||
- cli/named-workspace-rule.md
|
||||
- cli/identify-object-name-change-application.md
|
||||
- cli/identify-tray-application.md
|
||||
- cli/identify-layered-application.md
|
||||
- cli/remove-title-bar.md
|
||||
- cli/toggle-title-bars.md
|
||||
- cli/active-window-border.md
|
||||
- cli/active-window-border-colour.md
|
||||
- cli/active-window-border-width.md
|
||||
- cli/active-window-border-offset.md
|
||||
- cli/focus-follows-mouse.md
|
||||
- cli/toggle-focus-follows-mouse.md
|
||||
- cli/mouse-follows-focus.md
|
||||
- cli/toggle-mouse-follows-focus.md
|
||||
- cli/ahk-library.md
|
||||
- cli/ahk-app-specific-configuration.md
|
||||
- cli/pwsh-app-specific-configuration.md
|
||||
- cli/format-app-specific-configuration.md
|
||||
- cli/fetch-app-specific-configuration.md
|
||||
- cli/application-specific-configuration-schema.md
|
||||
- cli/notification-schema.md
|
||||
- cli/socket-schema.md
|
||||
- cli/static-config-schema.md
|
||||
- cli/generate-static-config.md
|
||||
- cli/enable-autostart.md
|
||||
- cli/disable-autostart.md
|
||||
- cli/quickstart.md
|
||||
- cli/start.md
|
||||
- cli/stop.md
|
||||
- cli/check.md
|
||||
- cli/configuration.md
|
||||
- cli/whkdrc.md
|
||||
- cli/state.md
|
||||
- cli/global-state.md
|
||||
- cli/visible-windows.md
|
||||
- cli/query.md
|
||||
- cli/subscribe-socket.md
|
||||
- cli/unsubscribe-socket.md
|
||||
- cli/subscribe-pipe.md
|
||||
- cli/unsubscribe-pipe.md
|
||||
- cli/log.md
|
||||
- cli/quick-save-resize.md
|
||||
- cli/quick-load-resize.md
|
||||
- cli/save-resize.md
|
||||
- cli/load-resize.md
|
||||
- cli/focus.md
|
||||
- cli/move.md
|
||||
- cli/minimize.md
|
||||
- cli/close.md
|
||||
- cli/force-focus.md
|
||||
- cli/cycle-focus.md
|
||||
- cli/cycle-move.md
|
||||
- cli/stack.md
|
||||
- cli/resize-edge.md
|
||||
- cli/resize-axis.md
|
||||
- cli/unstack.md
|
||||
- cli/cycle-stack.md
|
||||
- cli/move-to-monitor.md
|
||||
- cli/cycle-move-to-monitor.md
|
||||
- cli/move-to-workspace.md
|
||||
- cli/move-to-named-workspace.md
|
||||
- cli/cycle-move-to-workspace.md
|
||||
- cli/send-to-monitor.md
|
||||
- cli/cycle-send-to-monitor.md
|
||||
- cli/send-to-workspace.md
|
||||
- cli/send-to-named-workspace.md
|
||||
- cli/cycle-send-to-workspace.md
|
||||
- cli/send-to-monitor-workspace.md
|
||||
- cli/move-to-monitor-workspace.md
|
||||
- cli/focus-monitor.md
|
||||
- cli/focus-last-workspace.md
|
||||
- cli/focus-workspace.md
|
||||
- cli/focus-workspaces.md
|
||||
- cli/focus-monitor-workspace.md
|
||||
- cli/focus-named-workspace.md
|
||||
- cli/cycle-monitor.md
|
||||
- cli/cycle-workspace.md
|
||||
- cli/move-workspace-to-monitor.md
|
||||
- cli/swap-workspaces-with-monitor.md
|
||||
- cli/new-workspace.md
|
||||
- cli/resize-delta.md
|
||||
- cli/invisible-borders.md
|
||||
- cli/global-work-area-offset.md
|
||||
- cli/monitor-work-area-offset.md
|
||||
- cli/focused-workspace-container-padding.md
|
||||
- cli/focused-workspace-padding.md
|
||||
- cli/adjust-container-padding.md
|
||||
- cli/adjust-workspace-padding.md
|
||||
- cli/change-layout.md
|
||||
- cli/cycle-layout.md
|
||||
- cli/load-custom-layout.md
|
||||
- cli/flip-layout.md
|
||||
- cli/promote.md
|
||||
- cli/promote-focus.md
|
||||
- cli/retile.md
|
||||
- cli/monitor-index-preference.md
|
||||
- cli/display-index-preference.md
|
||||
- cli/ensure-workspaces.md
|
||||
- cli/ensure-named-workspaces.md
|
||||
- cli/container-padding.md
|
||||
- cli/named-workspace-container-padding.md
|
||||
- cli/workspace-padding.md
|
||||
- cli/named-workspace-padding.md
|
||||
- cli/workspace-layout.md
|
||||
- cli/named-workspace-layout.md
|
||||
- cli/workspace-custom-layout.md
|
||||
- cli/named-workspace-custom-layout.md
|
||||
- cli/workspace-layout-rule.md
|
||||
- cli/named-workspace-layout-rule.md
|
||||
- cli/workspace-custom-layout-rule.md
|
||||
- cli/named-workspace-custom-layout-rule.md
|
||||
- cli/clear-workspace-layout-rules.md
|
||||
- cli/clear-named-workspace-layout-rules.md
|
||||
- cli/workspace-tiling.md
|
||||
- cli/named-workspace-tiling.md
|
||||
- cli/workspace-name.md
|
||||
- cli/toggle-window-container-behaviour.md
|
||||
- cli/toggle-pause.md
|
||||
- cli/toggle-tiling.md
|
||||
- cli/toggle-float.md
|
||||
- cli/toggle-monocle.md
|
||||
- cli/toggle-maximize.md
|
||||
- cli/restore-windows.md
|
||||
- cli/manage.md
|
||||
- cli/unmanage.md
|
||||
- cli/reload-configuration.md
|
||||
- cli/watch-configuration.md
|
||||
- cli/complete-configuration.md
|
||||
- cli/window-hiding-behaviour.md
|
||||
- cli/cross-monitor-move-behaviour.md
|
||||
- cli/toggle-cross-monitor-move-behaviour.md
|
||||
- cli/unmanaged-window-operation-behaviour.md
|
||||
- cli/float-rule.md
|
||||
- cli/manage-rule.md
|
||||
- cli/initial-workspace-rule.md
|
||||
- cli/initial-named-workspace-rule.md
|
||||
- cli/workspace-rule.md
|
||||
- cli/named-workspace-rule.md
|
||||
- cli/identify-object-name-change-application.md
|
||||
- cli/identify-tray-application.md
|
||||
- cli/identify-layered-application.md
|
||||
- cli/remove-title-bar.md
|
||||
- cli/toggle-title-bars.md
|
||||
- cli/active-window-border.md
|
||||
- cli/active-window-border-colour.md
|
||||
- cli/active-window-border-width.md
|
||||
- cli/active-window-border-offset.md
|
||||
- cli/focus-follows-mouse.md
|
||||
- cli/toggle-focus-follows-mouse.md
|
||||
- cli/mouse-follows-focus.md
|
||||
- cli/toggle-mouse-follows-focus.md
|
||||
- cli/ahk-library.md
|
||||
- cli/ahk-app-specific-configuration.md
|
||||
- cli/pwsh-app-specific-configuration.md
|
||||
- cli/format-app-specific-configuration.md
|
||||
- cli/fetch-app-specific-configuration.md
|
||||
- cli/application-specific-configuration-schema.md
|
||||
- cli/notification-schema.md
|
||||
- cli/socket-schema.md
|
||||
- cli/static-config-schema.md
|
||||
- cli/generate-static-config.md
|
||||
- cli/enable-autostart.md
|
||||
- cli/disable-autostart.md
|
||||
|
||||
16
schema.json
16
schema.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "StaticConfig",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.20`",
|
||||
"description": "The `komorebi.json` static configuration file reference for `v0.1.25`",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"active_window_border": {
|
||||
@@ -775,7 +775,8 @@
|
||||
"VerticalStack",
|
||||
"HorizontalStack",
|
||||
"UltrawideVerticalStack",
|
||||
"Grid"
|
||||
"Grid",
|
||||
"RightMainVerticalStack"
|
||||
]
|
||||
},
|
||||
"layout_rules": {
|
||||
@@ -790,7 +791,8 @@
|
||||
"VerticalStack",
|
||||
"HorizontalStack",
|
||||
"UltrawideVerticalStack",
|
||||
"Grid"
|
||||
"Grid",
|
||||
"RightMainVerticalStack"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -942,13 +944,16 @@
|
||||
"format": "int32"
|
||||
},
|
||||
"stackbar": {
|
||||
"description": "Stackbar configuration options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"height": {
|
||||
"description": "Stackbar height",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"mode": {
|
||||
"description": "Stackbar mode",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Always",
|
||||
@@ -957,9 +962,11 @@
|
||||
]
|
||||
},
|
||||
"tabs": {
|
||||
"description": "Stackbar tab configuration options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"background": {
|
||||
"description": "Tab background colour",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Colour represented as RGB",
|
||||
@@ -997,6 +1004,7 @@
|
||||
]
|
||||
},
|
||||
"focused_text": {
|
||||
"description": "Focused tab text colour",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Colour represented as RGB",
|
||||
@@ -1034,6 +1042,7 @@
|
||||
]
|
||||
},
|
||||
"unfocused_text": {
|
||||
"description": "Unfocused tab text colour",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Colour represented as RGB",
|
||||
@@ -1071,6 +1080,7 @@
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"description": "Width of a stackbar tab",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user