Compare commits

..

9 Commits

Author SHA1 Message Date
LGUG2Z
0cdce8fc2a chore(release): v0.1.28 2024-07-15 08:59:42 -07:00
LGUG2Z
67f14730d0 ci(github): rm nightly tag before running kokai 2024-07-15 08:58:38 -07:00
LGUG2Z
ef9e734680 fix(wm): handle "rdpudd chained dd" edge case
This commit builds on these changes in win32-display-data:
32a45cebf1p

With the addition of lenient fallbacks when looking up display device
information for "RDPUDD Chained DD" virtual display adapters, komorebi
will now set Monitor.device and Monitor.device_id to "UNKNOWN" as this
virtual mirror display driver will never have a reported DeviceID.

This limitation for "RDPUDD Chained DD" devices is also noted in a
Chromium issue: https://codereview.chromium.org/2557513005/

fix #883
2024-07-13 21:37:59 -07:00
LGUG2Z
faa7786979 docs(mkdocs): add updates for v0.1.28 features 2024-07-13 16:12:35 -07:00
LGUG2Z
3c8a6cb7bd chore(deps): bump win32-display-data 2024-07-13 16:12:34 -07:00
LGUG2Z
50a279239a fix(animation): disable on cross-monitor ops
There are quite a lot of janky animation bugs when moving window
containers across monitor and workspace boundaries.

This commit disables animation on all of the main cross-border window
container operations, meaning that animations should now only happen
within the context of a single workspace.

fix #912
2024-07-12 09:21:50 -07:00
LGUG2Z
2c8f25ef82 fix(animation): add async focus manager for mff
This commit adds a new focus manager module to be used to trigger async
focus changes with mouse follows focus updates. Currently this should
only need to be used with animations as all other focus calls are
synchronous.

fix #910
2024-07-11 18:29:46 -07:00
LGUG2Z
bdc1cad597 feat(config): add "color-hex" format to jsonschema
This commit specifies "color-hex" as the "format" when implementing
JsonSchema for Hex.

resolve #911
2024-07-11 15:20:20 -07:00
LGUG2Z
e2f2d6b919 feat(animation): add window animations
Work on this feature was first started by @thearturca in November 2023
before komorebi v0.1.21 in #597 and has undergone numerous revisions
to reach the point of this commit.

Although this is a single squashed commit, almost all of the heavy
lifting for this feature was done by @thearturca, which is where all of
the kudos and gratitude should be directed.

This commit adds a new static configuration block for animations, where
they can be enabled, and have their style, fps and duration set.
Corresponding SocketMessages and komorebic cli commands have also been
exposed.

There are some caveats to the use of this feature, which revolve around
the quality of the Windows compositor (it is not very good):

* There will be visual artifacts with various apps when animations are
  taking place - komorebi can't do anything about this as it is a
  limitation of the Windows compositor
* Since komorebi's borders are implemented as independent windows are
  are not a part of the windows they are drawn around, these borders
  will be hidden while animations are in progress
* If you wish to use borders with this feature, you'll probably better
  off using BorderImplementation::Windows, which uses the native thin
  "accent" borders, which are part of the windows they are drawn around,
  and can be moved with those windows during animations

As a result of these and other caveats, this feature will be marked as
"experimental" for the foreseeable future and will be off-by-default.

Below, a number of now-squashed commits that contributed to the
stabilization of this feature are referenced to help with code
archeology in the future.

fix(animation): Fixed cancelling logic
(57e9b2f4bcaedb4fdfa71adf785d661690d81dfc)

Added static animation state manager for tracking "in_progress" and
"is_cancelled" states. The idea is not to have states in Animation
struct but to keep them in HashMap<hwnd, AnimationState> behind
reference (Arc<Mutex<>>). So we each animation frame we have access to
state and can cancel animation if we have to.

Need review and testings

refactor(animation): avoid unwrap
(fa6d5bbc77c1882f85ee1ce73733ff7e53b39eaa)

fix(animation): Move cancel call to Animation struct
(306513f5dbe5f6bd6ce817f3edca0bfda13d9442)

Only focused window was cancelling its animation because we call cancel
in window::set_position and waiting for its cancelling. And because we
waiting for cancelling second window is still moving. Second window will stop
moving only after the first window. So I moved `cancel` call to
Animation struct so its happening in its own thread and doesn't block
others animation moves and cancels.

refactor(animation): renamed args parameters and variables names
(8abb4b9618bbb3823b868fc37551f0a70b98281e)

refactor(animation): inverse if-statement in `window::animate_position`
(3de2c6e932614651892da4a8c626946e427375dd)

There is was a bug when ease function generates `t` greater the
`SetWindowPos` function will be called instead of `move_window`.
`SetWindowPos` is only for last frame of animation.

fix(wm): add shadow rect to `move_window` calls
(b58620fb4de36d8e422a80541bedf9c1c1579a31)

This fixes a bug when windows get shunk during the animation
2024-07-10 13:28:31 -07:00
29 changed files with 460 additions and 117 deletions

View File

@@ -134,6 +134,7 @@ jobs:
shell: bash
run: |
if ! type kokai >/dev/null; then cargo install --locked kokai --force; fi
git tag -d nightly
kokai release --no-emoji --add-links github:commits,issues --ref "$(git tag --points-at HEAD)" >"CHANGELOG.md"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3

130
Cargo.lock generated
View File

@@ -422,7 +422,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -451,13 +451,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
version = "0.1.80"
version = "0.1.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -699,7 +699,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -710,9 +710,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
[[package]]
name = "calloop"
@@ -742,9 +742,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.104"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
checksum = "9711f33475c22aab363b05564a17d7b789bf3dfec5ebabb586adee56f0e271b5"
dependencies = [
"jobserver",
"libc",
@@ -800,9 +800,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.8"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
dependencies = [
"clap_builder",
"clap_derive",
@@ -810,9 +810,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.8"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
dependencies = [
"anstream",
"anstyle",
@@ -830,7 +830,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -841,9 +841,9 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "clipboard-win"
version = "5.3.1"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
dependencies = [
"error-code",
]
@@ -1153,9 +1153,9 @@ dependencies = [
[[package]]
name = "document-features"
version = "0.2.8"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
dependencies = [
"litrs",
]
@@ -1350,7 +1350,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -1371,7 +1371,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -1382,7 +1382,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -1566,7 +1566,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -2006,9 +2006,9 @@ dependencies = [
[[package]]
name = "http-body"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
@@ -2035,9 +2035,9 @@ checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
[[package]]
name = "hyper"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc"
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
dependencies = [
"bytes",
"futures-channel",
@@ -2316,7 +2316,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "komorebi"
version = "0.1.28-dev.0"
version = "0.1.28"
dependencies = [
"bitflags 2.6.0",
"clap",
@@ -2359,7 +2359,7 @@ dependencies = [
[[package]]
name = "komorebi-client"
version = "0.1.28-dev.0"
version = "0.1.28"
dependencies = [
"komorebi",
"komorebi-core",
@@ -2369,7 +2369,7 @@ dependencies = [
[[package]]
name = "komorebi-core"
version = "0.1.28-dev.0"
version = "0.1.28"
dependencies = [
"clap",
"color-eyre",
@@ -2385,7 +2385,7 @@ dependencies = [
[[package]]
name = "komorebi-gui"
version = "0.1.28-dev.0"
version = "0.1.28"
dependencies = [
"eframe",
"egui_extras",
@@ -2397,7 +2397,7 @@ dependencies = [
[[package]]
name = "komorebic"
version = "0.1.28-dev.0"
version = "0.1.28"
dependencies = [
"chrono",
"clap",
@@ -2426,7 +2426,7 @@ dependencies = [
[[package]]
name = "komorebic-no-console"
version = "0.1.28-dev.0"
version = "0.1.28"
[[package]]
name = "kqueue"
@@ -2653,7 +2653,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -2906,7 +2906,7 @@ dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3106,7 +3106,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3261,7 +3261,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3701,9 +3701,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.10"
version = "0.23.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0"
dependencies = [
"once_cell",
"rustls-pki-types",
@@ -3790,7 +3790,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3820,9 +3820,9 @@ dependencies = [
[[package]]
name = "security-framework"
version = "2.11.0"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.6.0",
"core-foundation",
@@ -3833,9 +3833,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.11.0"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
dependencies = [
"core-foundation-sys",
"libc",
@@ -3858,7 +3858,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3869,7 +3869,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -3902,7 +3902,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -4125,7 +4125,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -4168,9 +4168,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.68"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
@@ -4185,9 +4185,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "sysinfo"
version = "0.30.12"
version = "0.30.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
@@ -4263,22 +4263,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.61"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.61"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -4361,9 +4361,9 @@ dependencies = [
[[package]]
name = "tinyvec"
version = "1.6.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82"
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
dependencies = [
"tinyvec_macros",
]
@@ -4509,7 +4509,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -4781,7 +4781,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
"wasm-bindgen-shared",
]
@@ -4815,7 +4815,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -5098,7 +5098,7 @@ checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]]
name = "win32-display-data"
version = "0.1.0"
source = "git+https://github.com/LGUG2Z/win32-display-data?rev=2a0f7166da154880a1750b91829b1186d9c6a00c#2a0f7166da154880a1750b91829b1186d9c6a00c"
source = "git+https://github.com/LGUG2Z/win32-display-data?rev=32a45cebf132c3d651ee22c0c40033a6b7edc945#32a45cebf132c3d651ee22c0c40033a6b7edc945"
dependencies = [
"itertools",
"thiserror",
@@ -5207,7 +5207,7 @@ checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -5229,7 +5229,7 @@ checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]
@@ -5685,7 +5685,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
"syn 2.0.71",
]
[[package]]

View File

@@ -18,7 +18,7 @@ serde = { version = "1", features = ["derive"] }
serde_json = { package = "serde_json_lenient", version = "0.2" }
sysinfo = "0.30"
uds_windows = "1"
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "2a0f7166da154880a1750b91829b1186d9c6a00c" }
win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev = "32a45cebf132c3d651ee22c0c40033a6b7edc945" }
windows-implement = { version = "0.53" }
windows-interface = { version = "0.53" }
shadow-rs = "0.29"

View File

@@ -99,7 +99,7 @@ video will answer the majority of your questions.
# Demonstrations
[@amnweb](https://github.com/amnweb) showing _komorebi_ `v0.1.28-dev.0` running on Windows 11 with window borders,
[@amnweb](https://github.com/amnweb) showing _komorebi_ `v0.1.28` running on Windows 11 with window borders,
unfocused window transparency and animations enabled, using a custom status bar integrated using
_komorebi_'s [Window Manager Event Subscriptions](https://github.com/LGUG2Z/komorebi?tab=readme-ov-file#window-manager-event-subscriptions).
@@ -358,7 +358,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.25"}
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.28"}
use anyhow::Result;
use komorebi_client::Notification;

View File

@@ -1,12 +0,0 @@
# ahk-library
```
Generate a library of AutoHotKey helper functions
Usage: komorebic.exe komorebic.exe ahk-library
Options:
-h, --help
Print help
```

View File

@@ -0,0 +1,20 @@
# border-implementation
```
Set the border implementation
Usage: komorebic.exe border-implementation <STYLE>
Arguments:
<STYLE>
Desired border implementation
Possible values:
- komorebi: Use the adjustable komorebi border implementation
- windows: Use the thin Windows accent border implementation
Options:
-h, --help
Print help (see a summary with '-h')
```

21
docs/cli/border-style.md Normal file
View File

@@ -0,0 +1,21 @@
# border-style
```
Set the border style
Usage: komorebic.exe border-style <STYLE>
Arguments:
<STYLE>
Desired border style
Possible values:
- system: Use the system border style
- rounded: Use the Windows 11-style rounded borders
- square: Use the Windows 10-style square borders
Options:
-h, --help
Print help (see a summary with '-h')
```

View File

@@ -0,0 +1,12 @@
# clear-all-workspace-rules
```
Remove all application association rules for all workspaces
Usage: komorebic.exe clear-all-workspace-rules
Options:
-h, --help
Print help
```

View File

@@ -0,0 +1,16 @@
# clear-named-workspace-rules
```
Remove all application association rules for a named workspace
Usage: komorebic.exe clear-named-workspace-rules <WORKSPACE>
Arguments:
<WORKSPACE>
Name of a workspace
Options:
-h, --help
Print help
```

View File

@@ -0,0 +1,19 @@
# clear-workspace-rules
```
Remove all application association rules for a workspace by monitor and workspace index
Usage: komorebic.exe clear-workspace-rules <MONITOR> <WORKSPACE>
Arguments:
<MONITOR>
Monitor index (zero-indexed)
<WORKSPACE>
Workspace index on the specified monitor (zero-indexed)
Options:
-h, --help
Print help
```

View File

@@ -10,7 +10,7 @@ Arguments:
Possible values:
- hide: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)
- minimize: Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)
- cloak: Use the undocumented SetCloak Win32 function to hide windows when switching workspaces (has foregrounding issues)
- cloak: Use the undocumented SetCloak Win32 function to hide windows when switching workspaces
Options:
-h, --help

View File

@@ -0,0 +1,25 @@
# Animations
If you would like to add window movement animations, ensure the following options are
defined in the `komorebi.json` configuration file.
```json
{
"animation": {
"enabled": true
}
}
```
Window movement animations only apply to actions taking place within the same monitor
workspace.
You can optionally set a custom duration in ms with `animation.duration` (default: `250`),
a custom style with `animation.style` (default: `Linear`), and a custom FPS value with
`animation.fps` (default: `60`).
It is important to note that higher `fps` and a longer `duration` settings will result
in increased CPU usage.
This feature is not considered stable, and you may encounter visual artifacts
from time to time.

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.25/schema.json",
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.28/schema.json",
"app_specific_configuration_path": "$Env:USERPROFILE/applications.yaml",
"window_hiding_behaviour": "Cloak",
"cross_monitor_move_behaviour": "Insert",

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-client"
version = "0.1.28-dev.0"
version = "0.1.28"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-core"
version = "0.1.28-dev.0"
version = "0.1.28"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi-gui"
version = "0.1.28-dev.0"
version = "0.1.28"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi"
version = "0.1.28-dev.0"
version = "0.1.28"
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
description = "A tiling window manager for Windows"
categories = ["tiling-window-manager", "windows"]

View File

@@ -39,6 +39,7 @@ impl JsonSchema for Hex {
fn json_schema(_: &mut SchemaGenerator) -> Schema {
SchemaObject {
instance_type: Some(InstanceType::String.into()),
format: Some("color-hex".to_string()),
..Default::default()
}
.into()

View File

@@ -0,0 +1,70 @@
#![deny(clippy::unwrap_used, clippy::expect_used)]
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use parking_lot::Mutex;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::Window;
use crate::WindowManager;
pub struct Notification(isize);
impl Deref for Notification {
type Target = isize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
}
fn event_tx() -> Sender<Notification> {
channel().0.clone()
}
fn event_rx() -> Receiver<Notification> {
channel().1.clone()
}
// Currently this should only be used for async focus updates, such as
// when an animation finishes and we need to focus to set the cursor
// position if the user has mouse follows focus enabled
pub fn send_notification(hwnd: isize) {
if event_tx().try_send(Notification(hwnd)).is_err() {
tracing::warn!("channel is full; dropping notification")
}
}
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
std::thread::spawn(move || loop {
match handle_notifications(wm.clone()) {
Ok(()) => {
tracing::warn!("restarting finished thread");
}
Err(error) => {
tracing::warn!("restarting failed thread: {}", error);
}
}
});
}
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
tracing::info!("listening");
let receiver = event_rx();
for notification in receiver {
let mouse_follows_focus = wm.lock().mouse_follows_focus;
let _ = Window::from(*notification).focus(mouse_follows_focus);
}
Ok(())
}

View File

@@ -8,6 +8,7 @@ pub mod com;
pub mod ring;
pub mod colour;
pub mod container;
pub mod focus_manager;
pub mod monitor;
pub mod monitor_reconciliator;
pub mod process_command;
@@ -227,6 +228,7 @@ pub static SESSION_ID: AtomicU32 = AtomicU32::new(0);
pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false);
pub static ANIMATION_TEMPORARY_DISABLED: AtomicBool = AtomicBool::new(false);
pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250);
#[must_use]

View File

@@ -25,6 +25,7 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::EnvFilter;
use komorebi::border_manager;
use komorebi::focus_manager;
use komorebi::load_configuration;
use komorebi::monitor_reconciliator;
use komorebi::process_command::listen_for_commands;
@@ -265,6 +266,7 @@ fn main() -> Result<()> {
workspace_reconciliator::listen_for_notifications(wm.clone());
monitor_reconciliator::listen_for_notifications(wm.clone())?;
reaper::watch_for_orphans(wm.clone());
focus_manager::listen_for_notifications(wm.clone());
let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1);
ctrlc::set_handler(move || {

View File

@@ -67,11 +67,17 @@ pub fn attached_display_devices() -> color_eyre::Result<Vec<Monitor>> {
.flatten()
.map(|display| {
let path = display.device_path;
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
let (device, device_id) = if path.is_empty() {
(String::from("UNKNOWN"), String::from("UNKNOWN"))
} else {
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
(device, device_id)
};
let name = display.device_name.trim_start_matches(r"\\.\").to_string();
let name = name.split('\\').collect::<Vec<_>>()[0].to_string();

View File

@@ -1,9 +1,11 @@
use crate::border_manager;
use crate::com::SetCloak;
use crate::focus_manager;
use crate::stackbar_manager;
use crate::ANIMATIONS_IN_PROGRESS;
use crate::ANIMATION_DURATION;
use crate::ANIMATION_ENABLED;
use crate::ANIMATION_TEMPORARY_DISABLED;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::fmt::Display;
@@ -53,6 +55,7 @@ pub static MINIMUM_HEIGHT: AtomicI32 = AtomicI32::new(0);
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema, PartialEq)]
pub struct Window {
pub hwnd: isize,
#[serde(skip)]
animation: Animation,
}
@@ -189,6 +192,9 @@ impl Window {
if progress == 1.0 {
WindowsApi::position_window(hwnd, &new_rect, top)?;
if WindowsApi::foreground_window().unwrap_or_default() == hwnd.0 {
focus_manager::send_notification(hwnd.0)
}
if ANIMATIONS_IN_PROGRESS.load(Ordering::Acquire) == 0 {
border_manager::BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst);
@@ -219,7 +225,9 @@ impl Window {
return Ok(());
}
if ANIMATION_ENABLED.load(Ordering::SeqCst) {
if ANIMATION_ENABLED.load(Ordering::SeqCst)
&& !ANIMATION_TEMPORARY_DISABLED.load(Ordering::SeqCst)
{
self.animate_position(layout, top)
} else {
WindowsApi::position_window(self.hwnd(), layout, top)

View File

@@ -65,6 +65,7 @@ use crate::BorderColours;
use crate::Colour;
use crate::Rgb;
use crate::WorkspaceRule;
use crate::ANIMATION_TEMPORARY_DISABLED;
use crate::CUSTOM_FFM;
use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES;
@@ -1108,6 +1109,7 @@ impl WindowManager {
follow: bool,
) -> Result<()> {
self.handle_unmanaged_window_behaviour()?;
ANIMATION_TEMPORARY_DISABLED.store(true, Ordering::SeqCst);
tracing::info!("moving container");
@@ -1177,12 +1179,17 @@ impl WindowManager {
self.focus_monitor(monitor_idx)?;
}
self.update_focused_workspace(self.mouse_follows_focus, true)
self.update_focused_workspace(self.mouse_follows_focus, true)?;
ANIMATION_TEMPORARY_DISABLED.store(false, Ordering::SeqCst);
Ok(())
}
#[tracing::instrument(skip(self))]
pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> {
self.handle_unmanaged_window_behaviour()?;
ANIMATION_TEMPORARY_DISABLED.store(true, Ordering::SeqCst);
tracing::info!("moving container");
@@ -1194,7 +1201,11 @@ impl WindowManager {
monitor.move_container_to_workspace(idx, follow)?;
monitor.load_focused_workspace(mouse_follows_focus)?;
self.update_focused_workspace(mouse_follows_focus, true)
self.update_focused_workspace(mouse_follows_focus, true)?;
ANIMATION_TEMPORARY_DISABLED.store(false, Ordering::SeqCst);
Ok(())
}
pub fn remove_focused_workspace(&mut self) -> Option<Workspace> {
@@ -1297,6 +1308,13 @@ impl WindowManager {
let origin_monitor_idx = self.focused_monitor_idx();
let target_container_idx = workspace.new_idx_for_direction(direction);
let animation_temporarily_disabled = if target_container_idx.is_none() {
ANIMATION_TEMPORARY_DISABLED.store(true, Ordering::SeqCst);
true
} else {
false
};
match target_container_idx {
// If there is nowhere to move on the current workspace, try to move it onto the monitor
// in that direction if there is one
@@ -1421,7 +1439,13 @@ impl WindowManager {
}
}
self.update_focused_workspace(self.mouse_follows_focus, true)
self.update_focused_workspace(self.mouse_follows_focus, true)?;
if animation_temporarily_disabled {
ANIMATION_TEMPORARY_DISABLED.store(false, Ordering::SeqCst);
}
Ok(())
}
#[tracing::instrument(skip(self))]

View File

@@ -239,11 +239,17 @@ impl WindowsApi {
pub fn load_monitor_information(monitors: &mut Ring<Monitor>) -> Result<()> {
'read: for display in win32_display_data::connected_displays_all().flatten() {
let path = display.device_path.clone();
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
let (device, device_id) = if path.is_empty() {
(String::from("UNKNOWN"), String::from("UNKNOWN"))
} else {
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
(device, device_id)
};
let name = display.device_name.trim_start_matches(r"\\.\").to_string();
let name = name.split('\\').collect::<Vec<_>>()[0].to_string();
@@ -809,11 +815,17 @@ impl WindowsApi {
for display in win32_display_data::connected_displays_all().flatten() {
if display.hmonitor == hmonitor {
let path = display.device_path;
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
let (device, device_id) = if path.is_empty() {
(String::from("UNKNOWN"), String::from("UNKNOWN"))
} else {
let mut split: Vec<_> = path.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);
let device = split[0].to_string();
let device_id = split.join("-");
(device, device_id)
};
let name = display.device_name.trim_start_matches(r"\\.\").to_string();
let name = name.split('\\').collect::<Vec<_>>()[0].to_string();

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebic-no-console"
version = "0.1.28-dev.0"
version = "0.1.28"
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"]

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebic"
version = "0.1.28-dev.0"
version = "0.1.28"
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"]

View File

@@ -57,6 +57,7 @@ nav:
- Troubleshooting: troubleshooting.md
- Common workflows:
- common-workflows/komorebi-config-home.md
- common-workflows/animations.md
- common-workflows/autohotkey.md
- common-workflows/borders.md
- common-workflows/stackbar.md
@@ -191,6 +192,9 @@ nav:
- cli/initial-named-workspace-rule.md
- cli/workspace-rule.md
- cli/named-workspace-rule.md
- cli/clear-workspace-rules.md
- cli/clear-named-workspace-rules.md
- cli/clear-all-workspace-rules.md
- cli/identify-object-name-change-application.md
- cli/identify-tray-application.md
- cli/identify-layered-application.md
@@ -200,6 +204,8 @@ nav:
- cli/border-colour.md
- cli/border-width.md
- cli/border-offset.md
- cli/border-style.md
- cli/border-implementation.md
- cli/transparency.md
- cli/transparency-alpha.md
- cli/focus-follows-mouse.md

View File

@@ -1,9 +1,70 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "StaticConfig",
"description": "The `komorebi.json` static configuration file reference for `v0.1.27`",
"description": "The `komorebi.json` static configuration file reference for `v0.1.28`",
"type": "object",
"properties": {
"animation": {
"description": "Animations configuration options",
"type": "object",
"required": [
"enabled"
],
"properties": {
"duration": {
"description": "Set the animation duration in ms (default: 250)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"enabled": {
"description": "Enable or disable animations (default: false)",
"type": "boolean"
},
"fps": {
"description": "Set the animation FPS (default: 60)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"style": {
"description": "Set the animation style (default: Linear)",
"type": "string",
"enum": [
"Linear",
"EaseInSine",
"EaseOutSine",
"EaseInOutSine",
"EaseInQuad",
"EaseOutQuad",
"EaseInOutQuad",
"EaseInCubic",
"EaseInOutCubic",
"EaseInQuart",
"EaseOutQuart",
"EaseInOutQuart",
"EaseInQuint",
"EaseOutQuint",
"EaseInOutQuint",
"EaseInExpo",
"EaseOutExpo",
"EaseInOutExpo",
"EaseInCirc",
"EaseOutCirc",
"EaseInOutCirc",
"EaseInBack",
"EaseOutBack",
"EaseInOutBack",
"EaseInElastic",
"EaseOutElastic",
"EaseInOutElastic",
"EaseInBounce",
"EaseOutBounce",
"EaseInOutBounce"
]
}
}
},
"app_specific_configuration_path": {
"description": "Path to applications.yaml from komorebi-application-specific-configurations (default: None)",
"type": "string"
@@ -50,7 +111,8 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
@@ -88,7 +150,8 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
@@ -126,7 +189,8 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
@@ -164,12 +228,32 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
}
}
},
"border_implementation": {
"description": "Display an active window border (default: false)",
"oneOf": [
{
"description": "Use the adjustable komorebi border implementation",
"type": "string",
"enum": [
"Komorebi"
]
},
{
"description": "Use the thin Windows accent border implementation",
"type": "string",
"enum": [
"Windows"
]
}
]
},
"border_offset": {
"description": "Offset of the window border (default: -1)",
"type": "integer",
@@ -674,6 +758,16 @@
]
}
},
"minimum_window_height": {
"description": "DISCOURAGED: Minimum height for a window to be eligible for tiling",
"type": "integer",
"format": "int32"
},
"minimum_window_width": {
"description": "DISCOURAGED: Minimum width for a window to be eligible for tiling",
"type": "integer",
"format": "int32"
},
"monitor_index_preferences": {
"description": "Set monitor index preferences",
"type": "object",
@@ -796,6 +890,10 @@
"name"
],
"properties": {
"apply_window_based_work_area_offset": {
"description": "Apply this monitor's window-based work area offset (default: true)",
"type": "boolean"
},
"container_padding": {
"description": "Container padding (default: global)",
"type": "integer",
@@ -1094,7 +1192,8 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
@@ -1132,10 +1231,20 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
"font_family": {
"description": "Font family",
"type": "string"
},
"font_size": {
"description": "Font size",
"type": "integer",
"format": "int32"
},
"unfocused_text": {
"description": "Unfocused tab text colour",
"anyOf": [
@@ -1170,7 +1279,8 @@
},
{
"description": "Colour represented as Hex",
"type": "string"
"type": "string",
"format": "color-hex"
}
]
},
@@ -1315,7 +1425,7 @@
]
},
"window_hiding_behaviour": {
"description": "Which Windows signal to use when hiding windows (default: minimize)",
"description": "Which Windows signal to use when hiding windows (default: Cloak)",
"oneOf": [
{
"description": "Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)",
@@ -1332,7 +1442,7 @@
]
},
{
"description": "Use the undocumented SetCloak Win32 function to hide windows when switching workspaces (has foregrounding issues)",
"description": "Use the undocumented SetCloak Win32 function to hide windows when switching workspaces",
"type": "string",
"enum": [
"Cloak"