Compare commits

...

78 Commits

Author SHA1 Message Date
LGUG2Z
6308414129 chore(release): v0.1.14 2022-11-09 13:38:57 -08:00
LGUG2Z
035e77bd25 fix(wm): don't reconcile monitors during drag
This commit ensures that monitor reconciliation doesn't get triggered
eagerly when a cross-monitor mouse drag/move of a window is taking
place.
2022-11-09 06:25:21 -08:00
dependabot[bot]
7b98b563eb chore(deps): bump clap from 4.0.18 to 4.0.20
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.18 to 4.0.20.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.18...v4.0.20)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-07 09:51:04 -08:00
LGUG2Z
5fda4a39b8 docs(readme): convert badges to html 2022-11-03 09:34:25 -07:00
LGUG2Z
3ad0ae6aca feat(wm): introduce lazy monitor cache
This commit introduces a lazy monitor cache that only gets populated
with a monitor has been disconnected, before the monitor is removed from
the state. If and when the same monitor is reconnected and identified by
its size on the virtual screen, the cached monitor state will be used to
repopulate layout options, avoiding a potentially expensive full
configuration reload.

re #275
2022-10-31 12:38:59 -07:00
LGUG2Z
2575ca2da4 feat(wm): add monitor index preference cmd
This commit adds a new komorebic command, monitor-index-preference,
which allows the user to set the index preference within the VecDeque of
monitors based on the "size" of a display.

This works as the size Rect identifies a unique display on the greater
virtual screen and persists across display connections and
disconnections unless the user deliberately changes the positioning of
the display monitor on the virtual screen.

When a new monitor is added to the state, the monitor preferences will
be checked, and if a preference exists, the new monitor will be inserted
at that index, otherwise, it will be pushed to the back of the VecDeque.

resolve #275
2022-10-31 12:38:59 -07:00
LGUG2Z
37f1a163cc fix(wm): match display name / avoid id volatility
This commit replaces all usages of MONITORINFO with MONITORINFOEX in
order to retrieve a name for each connected display device.

This display device name makes for easier deduping during monitor
reconciliation, so that matching display monitor names can simply have
their hmonitor id updated instead of trying to figure out which id
corresponds to which monitor by looking at the windows currently visible
on each.

fix #267
2022-10-31 12:38:59 -07:00
LGUG2Z
91c532d9b1 fix(wm): listen to settingchange + devicechange
This commit adds listeners on two more events, WM_SETTINGCHANGE and
WM_DEVICECHANGE, in the hope of more reliably catching monitor
attachments and detachments based on info in an SO answer.

fix #267
2022-10-31 12:38:59 -07:00
LGUG2Z
75d72522a2 fix(wm): listen to displaychange w/ hidden hwnd
This commit removes the previous polling strategy on ObjectCreate events
and uses a hidden window to listen to WM_DISPLAYCHANGE.

Unfortunately, as all monitors change HMONITOR values on monitor
attach/detach, even if the monitor remains attached, the only real
choice we have when a monitor which previously held windows is detached
is to read the entire monitor and workspace state again, as we do when
we initialise the window manager for the first time.

Since it's possible that the "wrong" monitor in the state has its
HMONITOR value updated, we also have to load the configuration again.

This commit deprecates WindowManagerEvent::MonitorPoll.

fix #267
2022-10-31 12:38:59 -07:00
dependabot[bot]
438bfc86ff chore(deps): bump windows from 0.42.0 to 0.43.0
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.42.0 to 0.43.0.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/compare/0.42.0...0.43.0)

---
updated-dependencies:
- dependency-name: windows
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-31 09:23:01 -07:00
dependabot[bot]
ca86418e3c chore(deps): bump sysinfo from 0.26.4 to 0.26.7
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.26.4 to 0.26.7.
- [Release notes](https://github.com/GuillaumeGomez/sysinfo/releases)
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/commits)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-31 09:01:45 -07:00
dependabot[bot]
d8c76b97a9 chore(deps): bump serde from 1.0.145 to 1.0.147
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.145 to 1.0.147.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.145...v1.0.147)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-31 09:01:19 -07:00
dependabot[bot]
a4be1b95e0 chore(deps): bump net2 from 0.2.37 to 0.2.38
Bumps [net2](https://github.com/deprecrated/net2-rs) from 0.2.37 to 0.2.38.
- [Release notes](https://github.com/deprecrated/net2-rs/releases)
- [Commits](https://github.com/deprecrated/net2-rs/compare/0.2.37...0.2.38)

---
updated-dependencies:
- dependency-name: net2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-24 08:38:58 -07:00
dependabot[bot]
6e666bc4d8 chore(deps): bump serde_json from 1.0.86 to 1.0.87
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.86 to 1.0.87.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.86...v1.0.87)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-24 08:38:48 -07:00
dependabot[bot]
857b3c9ccf chore(deps): bump syn from 1.0.102 to 1.0.103
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.102 to 1.0.103.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.102...1.0.103)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-24 08:38:36 -07:00
dependabot[bot]
9b916c0c21 chore(deps): bump clap from 4.0.15 to 4.0.18
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.15 to 4.0.18.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.0.15...v4.0.18)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-24 08:38:22 -07:00
dependabot[bot]
b642eddb96 chore(deps): bump serde_yaml from 0.9.13 to 0.9.14
Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.9.13 to 0.9.14.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.9.13...0.9.14)

---
updated-dependencies:
- dependency-name: serde_yaml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-24 08:37:55 -07:00
LGUG2Z
1229c65580 fix(ahk): prefer runwait for ahk lib wrappers
This commit ensures that the generated AHK library for komorebic uses
RunWait instead of Run, as the latter is asynchronous and can result in
an unexpected order of calls when used in a komorebi.ahk configuration
file.

re #269
2022-10-21 15:24:31 -07:00
LGUG2Z
b25cc1c8bf fix(wm): reset foreground access when calls fail 2022-10-21 14:10:12 -07:00
LGUG2Z
e02ddd47cc fix(wm): eagerly set new active border position
This commit adds SocketMessage::FocusWindow as a target to update the
border position on at the end of the command handler. There are some
occasions where the EVENT_SYSTEM_FOREGROUND notification isn't being
sent (on newer versions of Win11, I think), so we can't count on the
border being updated when that event is received by the event handler.
2022-10-21 12:13:06 -07:00
LGUG2Z
e20b4aabc3 fix(clap): address deprecations 2022-10-20 14:21:27 -07:00
dependabot[bot]
acaee5595d chore(deps): bump clap from 3.2.22 to 4.0.15
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.22 to 4.0.15.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.22...v4.0.15)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-20 14:21:27 -07:00
dependabot[bot]
083a142597 chore(deps): bump proc-macro2 from 1.0.46 to 1.0.47
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.46 to 1.0.47.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.46...1.0.47)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-17 09:17:02 -07:00
Max Bane
1633a5ebc2 fix(config): call ActiveWindowBorderColour correctly
The sample config only provided three of the four required arguments in
the example call to ActiveWindowBorderColour. Uncommenting the line as
it was would raise an error from AuthoHotKey.
2022-10-14 11:40:17 -07:00
Yusuf007R
352c010021 feat(wm): manage return bool of PostMessage + update ahk library
this commit makes a small refactor to the way PostMessageW is used so now be able to handle the
returned bool, as well as adding a custom error message to WindowsApi::close_window and updating the
ahk generated library

#259
2022-10-13 01:08:35 -07:00
Yusuf007R
33965f92ad feat(wm): add close and minimize cmd
this commit adds the ability to close and minimize the current focused window via SocketMessages and
komorebic commands

resolve #189
2022-10-13 01:08:35 -07:00
Yusuf007R
635272fc10 feat(wm): add max number of attempts to set foreground
this commits adds a max number of attempts (5) to the call of set_foreground_window inside
Window:Focus
2022-10-13 01:06:58 -07:00
dependabot[bot]
5354e9c7a4 chore(deps): bump tracing-subscriber from 0.3.15 to 0.3.16
Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.15 to 0.3.16.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.15...tracing-subscriber-0.3.16)

---
updated-dependencies:
- dependency-name: tracing-subscriber
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 08:27:26 -07:00
dependabot[bot]
e35164f106 chore(deps): bump tracing from 0.1.36 to 0.1.37
Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.36 to 0.1.37.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.36...tracing-0.1.37)

---
updated-dependencies:
- dependency-name: tracing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 08:27:16 -07:00
dependabot[bot]
a637eefd82 chore(deps): bump syn from 1.0.101 to 1.0.102
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.101 to 1.0.102.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.101...1.0.102)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 08:27:01 -07:00
dependabot[bot]
db361f36db chore(deps): bump serde_json from 1.0.85 to 1.0.86
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.85 to 1.0.86.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.85...v1.0.86)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 08:26:43 -07:00
LGUG2Z
577fa0a97f fix(wm): retry foreground calls on focus change
For the past few weeks since upgrading the windows-rs crate I've seen
sporadic failures when calling SetForegroundWindow which require a full
restart to get the wm working as expected again. Adding in a retry loop
here seems to help when the issue comes up for me on Windows 11.
2022-10-07 06:57:37 -07:00
dependabot[bot]
f8ada73739 chore(deps): bump proc-macro2 from 1.0.44 to 1.0.46
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.44 to 1.0.46.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.44...1.0.46)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 07:58:29 -07:00
dependabot[bot]
ffcc2f71d1 chore(deps): bump crossbeam-utils from 0.8.11 to 0.8.12
Bumps [crossbeam-utils](https://github.com/crossbeam-rs/crossbeam) from 0.8.11 to 0.8.12.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-utils-0.8.11...crossbeam-utils-0.8.12)

---
updated-dependencies:
- dependency-name: crossbeam-utils
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 07:58:10 -07:00
dependabot[bot]
ed79793002 chore(deps): bump schemars from 0.8.10 to 0.8.11
Bumps [schemars](https://github.com/GREsau/schemars) from 0.8.10 to 0.8.11.
- [Release notes](https://github.com/GREsau/schemars/releases)
- [Changelog](https://github.com/GREsau/schemars/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GREsau/schemars/compare/v0.8.10...v0.8.11)

---
updated-dependencies:
- dependency-name: schemars
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 07:57:52 -07:00
sitiom
afb819a383 ci(winget): update workflow 2022-09-29 08:16:10 -07:00
LGUG2Z
3438818999 chore(deps): cargo update 2022-09-27 09:54:34 -07:00
LGUG2Z
611e4cc4a8 chore(deps): bump windows from 0.40 to 0.42 2022-09-27 09:53:43 -07:00
dependabot[bot]
27490de0d1 chore(deps): bump windows from 0.39.0 to 0.40.0
Bumps [windows](https://github.com/microsoft/windows-rs) from 0.39.0 to 0.40.0.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/compare/0.39.0...0.40.0)

---
updated-dependencies:
- dependency-name: windows
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-20 08:28:02 -07:00
dependabot[bot]
5112a8f39d chore(deps): bump syn from 1.0.99 to 1.0.100
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.99 to 1.0.100.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.99...1.0.100)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-19 07:37:14 -07:00
LGUG2Z
c3f77ef4f8 chore(deps): cargo update 2022-09-18 08:37:24 -07:00
LGUG2Z
33520a46b5 fix(cli): open resp sock before sending query
This commit ensures that a response socket is opened before sending a
query request from komorebic to komorebi. Additionally, I have taken
this opportunity to ensure that all socket files are created in
DATA_DIR.

fix #218
2022-09-18 08:30:09 -07:00
LGUG2Z
0903be7931 fix(cli): pass correct tcp flag to start cmd 2022-09-13 15:53:57 -07:00
dependabot[bot]
e78e6b1382 chore(deps): bump paste from 1.0.8 to 1.0.9
Bumps [paste](https://github.com/dtolnay/paste) from 1.0.8 to 1.0.9.
- [Release notes](https://github.com/dtolnay/paste/releases)
- [Commits](https://github.com/dtolnay/paste/compare/1.0.8...1.0.9)

---
updated-dependencies:
- dependency-name: paste
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 13:13:24 -07:00
dependabot[bot]
adafa32488 chore(deps): bump sysinfo from 0.26.0 to 0.26.2
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.26.0 to 0.26.2.
- [Release notes](https://github.com/GuillaumeGomez/sysinfo/releases)
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/commits)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 13:13:14 -07:00
dependabot[bot]
329b3052a4 chore(deps): bump clap from 3.2.17 to 3.2.20
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.17 to 3.2.20.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/v3.2.20/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.17...v3.2.20)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 13:12:54 -07:00
dependabot[bot]
b25662fea2 chore(deps): bump which from 4.2.5 to 4.3.0
Bumps [which](https://github.com/harryfei/which-rs) from 4.2.5 to 4.3.0.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Commits](https://github.com/harryfei/which-rs/compare/4.2.5...4.3.0)

---
updated-dependencies:
- dependency-name: which
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 13:12:34 -07:00
dependabot[bot]
edc9b0cd3d chore(deps): bump serde_yaml from 0.9.10 to 0.9.11
Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.9.10 to 0.9.11.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.9.10...0.9.11)

---
updated-dependencies:
- dependency-name: serde_yaml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 13:12:01 -07:00
sitiom
a43eb8fbf5 docs(readme): add winget installation reference 2022-09-05 07:47:58 -07:00
Ryan Caezar Itang
8b0f1d007f ci(windows): add winget releaser workflow 2022-08-30 12:46:06 -07:00
dependabot[bot]
83a502f199 chore(deps): bump sysinfo from 0.25.3 to 0.26.0
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.25.3 to 0.26.0.
- [Release notes](https://github.com/GuillaumeGomez/sysinfo/releases)
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/commits)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-29 07:50:20 -07:00
LGUG2Z
5006aa9009 fix(wm): give focus priority to monocle containers
This commit ensures that monocle containers are given priority when
handling WindowManagerEvent::FocusChange.

This is especially important when switching workspaces to ensure that
the keyboard input focus stays with the monocle container's focused
window when returning to a workspace with a monocle container activated.

fix #219
2022-08-28 08:09:10 -07:00
LGUG2Z
e4a8117a94 docs(readme): add link to blog by omochice 2022-08-27 19:08:12 -07:00
LGUG2Z
748c389b34 chore(release): v0.1.13 2022-08-27 15:12:23 -07:00
LGUG2Z
26a18adeb4 fix(wm): restore monocle border on ws change
This commit ensures that when navigating away from and then back to a
workspace with a monocle window container, that the monocle window
container will be properly focused when navigating back, including
having the focus of the active window border.

fix #219
2022-08-27 15:00:23 -07:00
LGUG2Z
5d094f601f fix(wm): enforce valid hwnd check for border fns
This commit ensures that the active window border has non-zero HWND
before attempting to either hide it or set the border position. This is
required as the border is only initialized when a komorebic command is
received, meaning that the default value of 0 will never change if a
user decides to use komorebi without the active window border.

Most notably this commit fixes an issue where users who did not have the
active window border enabled would not be able to move away from an
empty workspace using a komorebic command.

fix #217
2022-08-27 14:56:47 -07:00
LGUG2Z
5a0ba4cdbb fix(wm): detach thread inputs explicitly
This commit ensures that any calls to AttachThreadInput which are used
to allow the focusing or raising of a window are paired with a closing
call to detach the thread input.

Although undocumented, it seems that when attaching the input thread of
a window to an admin/sudo process, this prevents that window from
handling inputs from any unelevated processes (including regular
keyboard and mouse inputs), until the input thread is detached.

fix #86
2022-08-27 13:20:37 -07:00
LGUG2Z
7c41460b14 fix(wm): remove mstsc.exe from wsl2 ui proc list
This commit removes mstsc.exe from WSL2_UI_PROCESSES. Recent changes to
WSLg unfortunately mean that even with this exe being included in the
override list, WSLg windows once again no longer tile correctly. On top
of that, mstsc.exe is also used for traditional Windows RDP connections,
so leaving this in the override list results in ghost window tiles for
users connecting to other machines via RDP.

Users who wish to keep mstsc.exe included in WSL2_UI_PROCESSES are
welcome to maintain a fork of komorebi.

My official recommendation for users wishing to run Linux GUI
applications from WSL on Windows is to use VcXsrv, which is fully
compatible with komorebi, and generall just a very mature, stable, tried
and tested piece of software.

fix #216
2022-08-23 07:06:37 -07:00
dependabot[bot]
d34a561753 chore(deps): bump serde_json from 1.0.83 to 1.0.85
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.83 to 1.0.85.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.83...v1.0.85)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-22 11:57:57 -07:00
dependabot[bot]
04146a3ce9 chore(deps): bump serde_yaml from 0.9.9 to 0.9.10
Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.9.9 to 0.9.10.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.9.9...0.9.10)

---
updated-dependencies:
- dependency-name: serde_yaml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-22 11:57:46 -07:00
dependabot[bot]
09a544b45b chore(deps): bump serde from 1.0.143 to 1.0.144
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.143 to 1.0.144.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.143...v1.0.144)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-22 11:57:26 -07:00
dependabot[bot]
0e1ad164d4 chore(deps): bump sysinfo from 0.25.2 to 0.25.3
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.25.2 to 0.25.3.
- [Release notes](https://github.com/GuillaumeGomez/sysinfo/releases)
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/commits)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-22 11:57:11 -07:00
LGUG2Z
cec8b04ffd docs(readme): add charitable donations section 2022-08-20 08:29:03 -07:00
LGUG2Z
f4b3d568ee fix(wm): add bounds checking in move cmd
This commit ensures that when there is only one container on the target
workspace in a cross-monitor move, meaning that there won't be one
swapped back, we only decrement the focused container index on the
origin workspace if there is a focused container at an index greater
than 0.

fix #209
2022-08-18 14:51:39 -07:00
LGUG2Z
d3dc193d29 feat(tcp): add listener + export socket schema
This commit adds a TCP listener that can be optionally exposed on a port
provided by the user using the --tcp-port flag. If the flag is not
provided, the TCP listener will not be started.

Client state is tracked using the connecting address, and clients are
purged if they send unrecognised messages.

A JSON Schema of the SocketMessage enum can be exported via komorebic
and be used to generate type definitions in various programming
languages.

This commit also makes some improvements to the handling of 'komorebic
start'.

The previous backoff approach was not working as once the Windows API
denies access to the process for any call, no amount of retries with the
same process id will result in approval.

Therefore, 'komorebic start' now checks if the process has been started,
and if it hasn't (ie. it has errored out because of an access denied
error), it will continue to restart the process until all the komorebi
startup calls to the Windows API succeed.

resolve #176
2022-08-15 09:35:08 -07:00
LGUG2Z
441bfce053 fix(wm): update border on hide events 2022-08-13 17:41:28 -07:00
LGUG2Z
458d1ef80a feat(wm): add promote-focus command
This commit adds a promote-focus command to complement the promote
command.

resolve #203
2022-08-13 17:10:55 -07:00
LGUG2Z
be5945c64b fix(wm): create active border only on command 2022-08-13 16:36:23 -07:00
LGUG2Z
38ce38d65c fix(wm): improve startup reliability
This commit wraps calls to the Windows API which may intermittently fail
in backoff blocks, reducing the potential of early exits from errors
returned by the Windows API before the tiling has even started.
Hopefully this makes calls to 'komorebic start' more relible for use at
login time.
2022-08-13 14:40:10 -07:00
LGUG2Z
6ed52c9387 fix(wm): reduce floating window border jank
This commit reduces some of the jank when the active border window deals
with windows that have been floated by the wm.

- The border on a floated window is always on top of all other windows,
  just like the floated window itself
- When a floated window is moved by the mouse, it retains its border
- When a floated window loses and then regains focus via mouse
  interactions, it regains its border

Note that now border changes are handled afer the main match block in
process_event.rs, early returns should be avoided unless absolutely
necessary, as this will prevent the border state from being updated
until the next event is received.
2022-08-13 14:20:57 -07:00
LGUG2Z
e466a17877 feat(wm): restrict border window to outline
This commit moves the border window drawing logic into the WNDPROC
callback and uses BeginPaint -> Rectangle -> Endpaint to draw a
rectangle around the outside of the window in a specific colour that is
not black, which is used as the transparency colour with
SetLayeredWindowAttributes.

All of this results in a non-filled border rect and a much nicer
experience for users who are using transparency or translucent effects
on their windows.

This commit also introduces an optional second active border colour when
the user is focused on a stack of windows. If this is not set, the
default colour for single windows will be used.

Finally, a bunch of small issues relating to the border window staying
drawn on the screen even when there are no active windows on a workspace
have been addressed.

resolve #201
2022-08-13 08:16:27 -07:00
LGUG2Z
f5def84010 fix(ahk): gen multi-word + multiple flags correctly 2022-08-12 13:04:01 -07:00
LGUG2Z
12473aa41c chore(editor): remove jetbrains iml file from repo 2022-08-12 11:21:51 -07:00
dependabot[bot]
33d1c0edbc chore(deps): bump powershell_script from 1.0.2 to 1.0.4
Bumps [powershell_script](https://github.com/cfsamson/powershell-script) from 1.0.2 to 1.0.4.
- [Release notes](https://github.com/cfsamson/powershell-script/releases)
- [Commits](https://github.com/cfsamson/powershell-script/commits)

---
updated-dependencies:
- dependency-name: powershell_script
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 11:19:31 -07:00
dependabot[bot]
8d346627d5 chore(deps): bump clap from 3.2.16 to 3.2.17
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.16 to 3.2.17.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/v3.2.17/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.16...v3.2.17)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 11:19:21 -07:00
LGUG2Z
be83b4b5f2 docs(config): provide basic sample with lib + gen
This commit introduces a new komorebi.sample.ahk in the repository root,
as well as adding the latest generated versions of komorebic.lib.ahk and
komorebi.generated.ahk.

Pushing new users to use the AHK library by default will significantly
simplify the process of building a new configuration, and including the
application-specific configuration generated from the configuration
repository will result in a better first impression of komorebi where
more and more applications "just work".

This new sample is focused on setting a few sane configuration defaults,
and as few keybinds as possible, really just enough to allow the user to
switch focus and move windows around. This significantly reduces the
possibility of the first-time user accidentally triggering a command
that leaves them confused, frustrated and would probably end in them
killing the komorebi.exe proc from the task manager.

The new sample configuration will no longer be bundled with scoop
starting from the next release, which is also expected to introduce
support for installation via winget.

Instead, instructions have been added for users to download the latest
example configuration and generated libs from GitHub in the getting
started section.

resolve #62
2022-08-12 10:29:18 -07:00
LGUG2Z
f7ac1d0ece ci(artifacts): add msi to release artifacts
These changes to the GitHub actions workflows will include an MSI
installer in the artifacts that are uploaded at the end of each
successful build, and also attach an MSI installer to a release when the
job runs on a tag that creates a new release version.

re #152
2022-08-12 09:45:36 -07:00
LGUG2Z
2ba3ca4f31 build(msi): add configuration for cargo wix 2022-08-12 09:45:36 -07:00
37 changed files with 2607 additions and 1538 deletions

View File

@@ -13,7 +13,7 @@ updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "monthly"
interval: "weekly"
assignees:
- "LGUG2Z"
commit-message:

View File

@@ -76,6 +76,10 @@ jobs:
- name: Run a full build
run: |
cargo build --locked --release --target ${{ matrix.target }}
- name: Create MSI installer
run: |
cargo install cargo-wix
cargo wix -p komorebi --nocapture -I .\wix\main.wxs --target x86_64-pc-windows-msvc
- name: Upload the built artifacts
uses: actions/upload-artifact@v3
with:
@@ -85,19 +89,39 @@ jobs:
target/${{ matrix.target }}/release/komorebic.exe
target/${{ matrix.target }}/release/komorebi.pdb
target/${{ matrix.target }}/release/komorebic.pdb
target/wix/komorebi-*.msi
retention-days: 7
# Release
- name: Generate changelog
if: startsWith(github.ref, 'refs/tags/')
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
run: |
if ! type kokai >/dev/null; then cargo install --locked kokai --force; fi
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
if: startsWith(github.ref, 'refs/tags/')
if: startsWith(github.ref, 'refs/tags/v')
with:
version: latest
args: release --skip-validate --rm-dist --release-notes=CHANGELOG.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SCOOP_TOKEN: ${{ secrets.SCOOP_TOKEN }}
- name: Add MSI to release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/v')
with:
files: "target/wix/komorebi-*.msi"
winget:
name: Publish to WinGet
runs-on: windows-latest
needs: build
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: vedantmgoyal2009/winget-releaser@v1
with:
identifier: LGUG2Z.komorebi
token: ${{ secrets.WINGET_TOKEN }}

View File

@@ -35,11 +35,10 @@ archives:
name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Arch }}-{{ .Os }}"
files:
- LICENSE
- komorebi.sample.ahk
- CHANGELOG.md
checksum:
name_template: checksums.txt
changelog:
sort: asc
sort: asc

419
Cargo.lock generated
View File

@@ -17,15 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "atty"
version = "0.2.14"
@@ -66,9 +57,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.73"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
[[package]]
name = "cfg-if"
@@ -84,27 +75,25 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.2.16"
version = "4.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
checksum = "91b9970d7505127a162fdaa9b96428d28a479ba78c9ec7550a63a5d9863db682"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"once_cell",
"strsim",
"termcolor",
"terminal_size",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.2.15"
version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
@@ -115,9 +104,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.2.4"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
@@ -178,33 +167,31 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.10"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [
"cfg-if 1.0.0",
"once_cell",
]
[[package]]
name = "ctrlc"
version = "3.2.2"
version = "3.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865"
checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173"
dependencies = [
"nix",
"winapi 0.3.9",
@@ -212,7 +199,7 @@ dependencies = [
[[package]]
name = "derive-ahk"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"proc-macro2",
"quote",
@@ -247,9 +234,30 @@ checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2"
[[package]]
name = "either"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "eyre"
@@ -272,14 +280,14 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.17"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"windows-sys 0.36.1",
"windows-sys 0.42.0",
]
[[package]]
@@ -334,9 +342,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "getrandom"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if 1.0.0",
"libc",
@@ -437,6 +445,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "io-lifetimes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074"
[[package]]
name = "iovec"
version = "0.1.4"
@@ -448,9 +462,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "kernel32-sys"
@@ -464,7 +478,7 @@ dependencies = [
[[package]]
name = "komorebi"
version = "0.1.12"
version = "0.1.14"
dependencies = [
"bitflags",
"clap",
@@ -479,6 +493,7 @@ dependencies = [
"lazy_static",
"miow 0.4.0",
"nanoid",
"net2",
"os_info",
"parking_lot",
"paste",
@@ -499,7 +514,7 @@ dependencies = [
[[package]]
name = "komorebi-core"
version = "0.1.12"
version = "0.1.14"
dependencies = [
"clap",
"color-eyre",
@@ -513,7 +528,7 @@ dependencies = [
[[package]]
name = "komorebic"
version = "0.1.12"
version = "0.1.14"
dependencies = [
"clap",
"color-eyre",
@@ -528,6 +543,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
"sysinfo",
"uds_windows",
"windows",
]
@@ -546,15 +562,21 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.129"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
[[package]]
name = "lock_api"
version = "0.4.7"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
@@ -595,9 +617,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
"adler",
]
@@ -665,9 +687,9 @@ dependencies = [
[[package]]
name = "net2"
version = "0.2.37"
version = "0.2.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631"
dependencies = [
"cfg-if 0.1.10",
"libc",
@@ -676,10 +698,11 @@ dependencies = [
[[package]]
name = "nix"
version = "0.24.2"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
dependencies = [
"autocfg",
"bitflags",
"cfg-if 1.0.0",
"libc",
@@ -705,29 +728,30 @@ dependencies = [
[[package]]
name = "ntapi"
version = "0.3.7"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"hermit-abi",
"libc",
"overload",
"winapi 0.3.9",
]
[[package]]
name = "num_threads"
version = "0.1.6"
name = "num_cpus"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
dependencies = [
"hermit-abi",
"libc",
]
@@ -742,15 +766,15 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.13.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "os_info"
version = "3.5.0"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399"
checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f"
dependencies = [
"log",
"serde",
@@ -759,15 +783,21 @@ dependencies = [
[[package]]
name = "os_str_bytes"
version = "6.2.0"
version = "6.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owo-colors"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "parking_lot"
@@ -781,9 +811,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
dependencies = [
"backtrace",
"cfg-if 1.0.0",
@@ -792,14 +822,14 @@ dependencies = [
"redox_syscall",
"smallvec",
"thread-id",
"windows-sys 0.36.1",
"windows-sys 0.42.0",
]
[[package]]
name = "paste"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
[[package]]
name = "petgraph"
@@ -819,15 +849,15 @@ checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "powershell_script"
version = "1.0.2"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5c8599ccb442b80c8c04437bcbcac2f76ff34d7b658b759fb26744dcab6c03"
checksum = "54bde2e1a395c0aee9423072d781610da37b7b120edf17d4da99f83d04f2cd54"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-error"
@@ -855,9 +885,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
@@ -894,9 +924,9 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
@@ -947,9 +977,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"regex-syntax",
]
@@ -965,9 +995,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.27"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
@@ -984,6 +1014,20 @@ version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustix"
version = "0.35.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.42.0",
]
[[package]]
name = "rustversion"
version = "1.0.9"
@@ -1007,9 +1051,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed"
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -1019,9 +1063,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.10"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743"
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
dependencies = [
"proc-macro2",
"quote",
@@ -1037,18 +1081,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.143"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.143"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [
"proc-macro2",
"quote",
@@ -1068,9 +1112,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.83"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
dependencies = [
"itoa",
"ryu",
@@ -1079,9 +1123,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
version = "0.9.4"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b7c9017c64a49806c6e8df8ef99b92446d09c92457f85f91835b01a8064ae0"
checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da"
dependencies = [
"indexmap",
"itoa",
@@ -1110,9 +1154,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "strsim"
@@ -1144,9 +1188,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.99"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
dependencies = [
"proc-macro2",
"quote",
@@ -1155,9 +1199,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.25.2"
version = "0.26.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1594a36887d0f70096702bffadfb67dfbfe76ad4bf84605e86157dc9fce9961a"
checksum = "c375d5fd899e32847b8566e10598d6e9f1d9b55ec6de3cdf9e7da4bdc51371bc"
dependencies = [
"cfg-if 1.0.0",
"core-foundation-sys",
@@ -1193,37 +1237,28 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.1.17"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
checksum = "40ca90c434fd12083d1a6bdcbe9f92a14f96c8a1ba600ba451734ac334521f7a"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [
"terminal_size",
"rustix",
"windows-sys 0.42.0",
]
[[package]]
name = "thiserror"
version = "1.0.32"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.32"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
@@ -1252,20 +1287,36 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.13"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45"
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [
"itoa",
"libc",
"num_threads",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
[[package]]
name = "time-macros"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
dependencies = [
"time-core",
]
[[package]]
name = "tracing"
version = "0.1.36"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
@@ -1286,9 +1337,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.22"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
@@ -1297,9 +1348,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.29"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
"valuable",
@@ -1328,12 +1379,12 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.15"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
dependencies = [
"ansi_term",
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
@@ -1356,15 +1407,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.3"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unsafe-libyaml"
version = "0.2.2"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0"
checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68"
[[package]]
name = "valuable"
@@ -1397,13 +1448,13 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.2.5"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
dependencies = [
"either",
"lazy_static",
"libc",
"once_cell",
]
[[package]]
@@ -1451,15 +1502,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.39.0"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
dependencies = [
"windows_aarch64_msvc 0.39.0",
"windows_i686_gnu 0.39.0",
"windows_i686_msvc 0.39.0",
"windows_x86_64_gnu 0.39.0",
"windows_x86_64_msvc 0.39.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.0",
]
[[package]]
@@ -1477,17 +1530,25 @@ dependencies = [
[[package]]
name = "windows-sys"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_msvc 0.36.1",
"windows_i686_gnu 0.36.1",
"windows_i686_msvc 0.36.1",
"windows_x86_64_gnu 0.36.1",
"windows_x86_64_msvc 0.36.1",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.28.0"
@@ -1496,15 +1557,9 @@ checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
@@ -1514,15 +1569,9 @@ checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
@@ -1532,15 +1581,9 @@ checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
@@ -1550,15 +1593,15 @@ checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnu"
version = "0.39.0"
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
@@ -1568,15 +1611,9 @@ checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "winput"

179
README.md
View File

@@ -2,12 +2,27 @@
Tiling Window Management for Windows.
![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/LGUG2Z/komorebi/Windows/master)
![GitHub](https://img.shields.io/github/license/LGUG2Z/komorebi)
![GitHub all releases](https://img.shields.io/github/downloads/LGUG2Z/komorebi/total)
![GitHub commits since latest release (by date) for a branch](https://img.shields.io/github/commits-since/LGUG2Z/komorebi/latest/master)
![Discord](https://img.shields.io/discord/898554690126630914?label=discord)
![GitHub Sponsors](https://img.shields.io/github/sponsors/LGUG2Z)
<p>
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/LGUG2Z/komorebi/Windows">
<img alt="GitHub" src="https://img.shields.io/github/license/LGUG2Z/komorebi">
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/LGUG2Z/komorebi/total">
<img alt="GitHub commits since latest release (by date) for a branch" src="https://img.shields.io/github/commits-since/LGUG2Z/komorebi/latest">
<a href="https://discord.gg/mGkn66PHkx">
<img alt="Discord" src="https://img.shields.io/discord/898554690126630914">
</a>
<a href="https://github.com/sponsors/LGUG2Z">
<img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/LGUG2Z">
</a>
<a href="https://notado.app/feeds/jado/software-development">
<img alt="Notado Feed" src="https://img.shields.io/badge/Notado-Subscribe-informational">
</a>
<a href="https://jeezy.substack.com">
<img alt="Substack Read" src="https://img.shields.io/badge/Substack-Read-orange">
</a>
<a href="https://twitter.com/LGUG2Z">
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/LGUG2Z">
</a>
</p>
![screenshot](https://user-images.githubusercontent.com/13164844/184027064-f5a6cec2-2865-4d65-a549-a1f1da589abf.png)
@@ -33,6 +48,7 @@ Articles, blog posts, demos, and videos about _komorebi_ can be added to this li
- [Moving to Windows from Linux Pt 1](https://kvwu.io/posts/moving-to-windows/)
- [Windows 下的现代化平铺窗口管理器 komorebi](https://zhuanlan.zhihu.com/p/455064481)
- [komorebi を導入してみる](https://zenn.dev/omochice/articles/50f42a3df8f426)
## GitHub Sponsors Early Access
@@ -46,6 +62,15 @@ available for free in the public repository once it meets the requisite level of
Features-in-progress that are available in early access will be tagged in the issues with
an ["early access" label](https://github.com/LGUG2Z/komorebi/issues?q=is%3Aopen+is%3Aissue+label%3A%22early+access%22).
## Charitable Donations
`komorebi`, like `vim`, is a free and open-source project, and one that encourages you to make charitable donations if
you find the software to be useful and have the financial means.
I encourage you to make a charitable donation
to [Fresh Start Refugee](https://www.freshstartrefugee.org/donate) before
you consider sponsoring me on GitHub.
## Demonstrations
[@haxibami](https://github.com/haxibami) showing _komorebi_ running on Windows
@@ -119,6 +144,14 @@ using [`setx`](https://docs.microsoft.com/en-us/windows-server/administration/wi
Variables pop up in System Properties Advanced (which can be launched with `SystemPropertiesAdvanced.exe` at a
PowerShell prompt), and then move the binaries to that directory.
### Winget
You can use the builtin package manager from Windows to install the latest komorebi release:
```powershell
winget install LGUG2Z.komorebi
```
### Scoop
If you use the [Scoop](https://scoop.sh/) command line installer, you can run the following commands to install the
@@ -127,10 +160,14 @@ binaries from the latest GitHub Release:
```powershell
scoop bucket add extras
scoop install komorebi
# To download the example configuration
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebi.sample.ahk -OutFile $Env:USERPROFILE\komorebi.ahk
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebic.lib.ahk -OutFile $Env:USERPROFILE\komorebic.lib.ahk
iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebi.generated.ahk -OutFile $Env:USERPROFILE\komorebi.generated.ahk
```
If you install _komorebi_ using Scoop, the binaries will automatically be added to your `Path` and a command will be
shown for you to run in order to get started using the sample configuration file.
If you install _komorebi_ using Scoop, the binaries will automatically be added to your `Path`.
Thanks to [@sitiom](https://github.com/sitiom) for getting _komorebi_ added to the popular Scoop Extras bucket.
@@ -152,7 +189,7 @@ cargo install --path komorebic --locked
Once you have either the prebuilt binaries in your `Path`, or have compiled the binaries from source (these will already
be in your `Path` if you installed Rust with [rustup](https://rustup.rs), which you absolutely should), you can
run `komorebic start` at a Powershell prompt, and you will see the following output:
run `komorebic start --await-configuration` at a Powershell prompt, and you will see the following output:
```
Start-Process komorebi -WindowStyle hidden
@@ -264,7 +301,10 @@ If you would like to add a visual border around the currently focused window, tw
```powershell
komorebic.exe active-window-border [enable|disable]
komorebic.exe active-window-border-colour [R G B]
komorebic.exe active-window-border-colour [R G B] --window-kind single
# optionally, if you want a different colour for stacks of windows
komorebic.exe active-window-border-colour [R G B] --window-kind stack
```
It is important to note that the active window border will only apply to windows managed by `komorebi`.
@@ -480,95 +520,6 @@ You can run `komorebic.exe` to get a full list of the commands that you can use
keybindings with. You can run `komorebic.exe <COMMAND> --help` to get a full explanation of the arguments required for
each command.
```
start Start komorebi.exe as a background process
stop Stop the komorebi.exe process and restore all hidden windows
state Show a JSON representation of the current window manager state
query Query the current window manager state
subscribe Subscribe to komorebi events
unsubscribe Unsubscribe from komorebi events
log Tail komorebi.exe's process logs (cancel with Ctrl-C)
quick-save-resize Quicksave the current resize layout dimensions
quick-load-resize Load the last quicksaved resize layout dimensions
save-resize Save the current resize layout dimensions to a file
load-resize Load the resize layout dimensions from a file
focus Change focus to the window in the specified direction
move Move the focused window in the specified direction
cycle-focus Change focus to the window in the specified cycle direction
cycle-move Move the focused window in the specified cycle direction
stack Stack the focused window in the specified direction
resize-edge Resize the focused window in the specified direction
resize-axis Resize the focused window or primary column along the specified axis
unstack Unstack the focused window
cycle-stack Cycle the focused stack in the specified cycle direction
move-to-monitor Move the focused window to the specified monitor
move-to-workspace Move the focused window to the specified workspace
send-to-monitor Send the focused window to the specified monitor
send-to-workspace Send the focused window to the specified workspace
send-to-monitor-workspace Send the focused window to the specified monitor workspace
focus-monitor Focus the specified monitor
focus-workspace Focus the specified workspace on the focused monitor
focus-monitor-workspace Focus the specified workspace on the target monitor
cycle-monitor Focus the monitor in the given cycle direction
cycle-workspace Focus the workspace in the given cycle direction
move-workspace-to-monitor Move the focused workspace to the specified monitor
new-workspace Create and append a new workspace on the focused monitor
resize-delta Set the resize delta (used by resize-edge and resize-axis)
invisible-borders Set the invisible border dimensions around each window
work-area-offset Set offsets to exclude parts of the work area from tiling
adjust-container-padding Adjust container padding on the focused workspace
adjust-workspace-padding Adjust workspace padding on the focused workspace
change-layout Set the layout on the focused workspace
load-custom-layout Load a custom layout from file for the focused workspace
flip-layout Flip the layout on the focused workspace (BSP only)
promote Promote the focused window to the top of the tree
retile Force the retiling of all managed windows
ensure-workspaces Create at least this many workspaces for the specified monitor
container-padding Set the container padding for the specified workspace
workspace-padding Set the workspace padding for the specified workspace
workspace-layout Set the layout for the specified workspace
workspace-custom-layout Set a custom layout for the specified workspace
workspace-layout-rule Add a dynamic layout rule for the specified workspace
workspace-custom-layout-rule Add a dynamic custom layout for the specified workspace
clear-workspace-layout-rules Clear all dynamic layout rules for the specified workspace
workspace-tiling Enable or disable window tiling for the specified workspace
workspace-name Set the workspace name for the specified workspace
toggle-window-container-behaviour Toggle the behaviour for new windows (stacking or dynamic tiling)
toggle-pause Toggle window tiling on the focused workspace
toggle-tiling Toggle window tiling on the focused workspace
toggle-float Toggle floating mode for the focused window
toggle-monocle Toggle monocle mode for the focused container
toggle-maximize Toggle native maximization for the focused window
restore-windows Restore all hidden windows (debugging command)
manage Force komorebi to manage the focused window
unmanage Unmanage a window that was forcibly managed
reload-configuration Reload ~/komorebi.ahk (if it exists)
watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists)
complete-configuration Signal that the final configuration option has been sent
window-hiding-behaviour Set the window behaviour when switching workspaces / cycling stacks
cross-monitor-move-behaviour Set the behaviour when moving windows across monitor boundaries
toggle-cross-monitor-move-behaviour Toggle the behaviour when moving windows across monitor boundaries
unmanaged-window-operation-behaviour Set the operation behaviour when the focused window is not managed
float-rule Add a rule to always float the specified application
manage-rule Add a rule to always manage the specified application
workspace-rule Add a rule to associate an application with a workspace
identify-object-name-change-application Identify an application that sends EVENT_OBJECT_NAMECHANGE on launch
identify-tray-application Identify an application that closes to the system tray
identify-layered-application Identify an application that has WS_EX_LAYERED, but should still be managed
identify-border-overflow-application Identify an application that has overflowing borders
active-window-border Enable or disable the active window border
active-window-border-colour Set the colour for the active window border
focus-follows-mouse Enable or disable focus follows mouse for the operating system
toggle-focus-follows-mouse Toggle focus follows mouse for the operating system
mouse-follows-focus Enable or disable mouse follows focus on all workspaces
toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces
ahk-library Generate a library of AutoHotKey helper functions
ahk-app-specific-configuration Generate common app-specific configurations and fixes to use in komorebi.ahk
format-app-specific-configuration Format a YAML file for use with the 'ahk-app-specific-configuration' command
notification-schema Generate a JSON Schema of subscription notifications
help Print this message or the help of the given subcommand(s)
```
### AutoHotKey Helper Library for `komorebic`
Additionally, you may run `komorebic.exe ahk-library` to
@@ -598,7 +549,7 @@ used [is available here](komorebi.sample.with.lib.ahk).
- [x] Resize window container in direction
- [x] Resize window container on axis
- [x] Set custom resize delta
- [ ] Resize child window containers by split ratio
- [x] Active window border
- [x] Quicksave and quickload layouts with resize dimensions
- [x] Save and load layouts with resize dimensions to/from specific files
- [x] Mouse drag to swap window container position
@@ -619,7 +570,7 @@ used [is available here](komorebi.sample.with.lib.ahk).
- [x] Identify applications which overflow their borders by exe name and class
- [x] Identify 'close/minimize to tray' applications by exe name and class
- [x] Configure work area offsets to preserve space for custom taskbars
- [x] Configure and compensate for the size of Windows 10's invisible borders
- [x] Configure and compensate for the size of Windows invisible borders
- [x] Toggle floating windows
- [x] Toggle monocle window
- [x] Toggle native maximization
@@ -729,9 +680,35 @@ An example of how to create a named pipe and a subscription to `komorebi`'s hand
by [@denBot](https://github.com/denBot) can be
found [here](https://gist.github.com/denBot/4136279812f87819f86d99eba77c1ee0).
An example of how to create a named pipe and a subscription to `komorebi`'s handled events in Rust can also be found
in the [`komokana`](https://github.com/LGUG2Z/komokana) repository.
### Subscription Event Notification Schema
A [JSON Schema](https://json-schema.org/) of the event notifications emitted to subscribers can be generated with
the `komorebic notification-schema` command. The output of this command can be redirected to the clipboard or a file,
which can be used with services such as [Quicktype](https://app.quicktype.io/) to generate type definitions in different
programming languages.
### Communication over TCP
A TCP listener can optionally be exposed on a port of your choosing with the `--tcp-port=N` flag. If this flag is not
provided to `komorebi` or `komorebic start`, no TCP listener will be created.
Once created, your client may send
any [SocketMessage](https://github.com/LGUG2Z/komorebi/blob/master/komorebi-core/src/lib.rs#L37) to `komorebi` in the
same way that `komorebic` would.
This can be used if you would like to create your own alternative to `komorebic` which incorporates scripting and
various middleware layers, and similarly it can be used if you would like to integrate `komorebi` with
a [custom input handler](https://github.com/LGUG2Z/komorebi/issues/176#issue-1302643961).
If a client sends an unrecognized message, it will be disconnected and have to reconnect before trying to communicate
again.
### Socket Message Schema
A [JSON Schema](https://json-schema.org/) of socket messages used to send instructions to `komorebi` can be generated
with the `komorebic socket-schema` command. The output of this command can be redirected to the clipboard or a file,
which can be used with services such as [Quicktype](https://app.quicktype.io/) to generate type definitions in different
programming languages.

View File

@@ -1,6 +1,6 @@
[package]
name = "derive-ahk"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
[lib]

View File

@@ -5,12 +5,15 @@
use ::std::clone::Clone;
use ::std::convert::From;
use ::std::convert::Into;
use ::std::format;
use ::std::iter::Extend;
use ::std::iter::Iterator;
use ::std::matches;
use ::std::option::Option::Some;
use ::std::string::String;
use ::std::string::ToString;
use ::std::unreachable;
use ::std::vec::Vec;
use ::quote::quote;
use ::syn::parse_macro_input;
@@ -102,7 +105,8 @@ pub fn ahk_function(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStre
let flag_idents_clone = flag_idents.clone();
let flags = quote! {#(--#flag_idents_clone) *}
.to_string()
.replace("- - ", "--");
.replace("- - ", "--")
.replace('_', "-");
let called_flag_arguments = quote! {#(%#flag_idents%) *}
.to_string()
@@ -110,19 +114,28 @@ pub fn ahk_function(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStre
.replace("% ", "%")
.replace("%%", "% %");
let flags_split: Vec<_> = flags.split(' ').collect();
let flag_args_split: Vec<_> = called_flag_arguments.split(' ').collect();
let mut consolidated_flags: Vec<String> = Vec::new();
for (idx, flag) in flags_split.iter().enumerate() {
consolidated_flags.push(format!("{} {}", flag, flag_args_split[idx]));
}
let all_flags = consolidated_flags.join(" ");
quote! {
impl AhkFunction for #name {
fn generate_ahk_function() -> String {
::std::format!(r#"
{}({}) {{
Run, komorebic.exe {} {} {} {}, , Hide
RunWait, komorebic.exe {} {} {}, , Hide
}}"#,
::std::stringify!(#name),
#all_arguments,
::std::stringify!(#name).to_kebab_case(),
#called_arguments,
#flags,
#called_flag_arguments
#all_flags,
)
}
}
@@ -135,7 +148,7 @@ pub fn ahk_function(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStre
fn generate_ahk_function() -> String {
::std::format!(r#"
{}({}) {{
Run, komorebic.exe {} {}, , Hide
RunWait, komorebic.exe {} {}, , Hide
}}"#,
::std::stringify!(#name),
#arguments,
@@ -181,7 +194,7 @@ pub fn ahk_library(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStrea
stream.extend(quote! {
v.push(::std::format!(r#"
{}() {{
Run, komorebic.exe {}, , Hide
RunWait, komorebic.exe {}, , Hide
}}"#,
::std::stringify!(#name),
::std::stringify!(#name).to_kebab_case()

View File

@@ -8,6 +8,10 @@ fmt:
cargo +nightly fmt
cargo +stable clippy
prettier --write README.md
prettier --write .goreleaser.yml
prettier --write .github/dependabot.yml
prettier --write .github/FUNDING.yml
prettier --write .github/workflows/windows.yaml
install-komorebic:
cargo +stable install --path komorebic --locked
@@ -19,7 +23,8 @@ install:
just install-komorebic
just install-komorebi
komorebic ahk-library
cat '%USERPROFILE%\.config\komorebi\komorebic.lib.ahk' > komorebic.lib.sample.ahk
cat '%USERPROFILE%\.config\komorebi\komorebic.lib.ahk' > komorebic.lib.ahk
cat '%USERPROFILE%\.config\komorebi\komorebi.generated.ahk' > komorebi.generated.ahk
run:
just install-komorebic

View File

@@ -1,12 +1,12 @@
[package]
name = "komorebi-core"
version = "0.1.12"
version = "0.1.14"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3", features = ["derive"] }
clap = { version = "4", features = ["derive"] }
color-eyre = "0.6"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@@ -15,7 +15,7 @@ strum = { version = "0.24", features = ["derive"] }
schemars = "0.8"
[dependencies.windows]
version = "0.39"
version = "0.43"
features = [
"Win32_Foundation",
]

View File

@@ -1,6 +1,6 @@
use std::num::NonZeroUsize;
use clap::ArgEnum;
use clap::ValueEnum;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -342,7 +342,9 @@ impl Arrangement for CustomLayout {
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum Axis {
Horizontal,

View File

@@ -1,4 +1,4 @@
use clap::ArgEnum;
use clap::ValueEnum;
use color_eyre::Result;
use schemars::JsonSchema;
use serde::Deserialize;
@@ -8,7 +8,7 @@ use strum::EnumString;
use crate::ApplicationIdentifier;
#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum ApplicationOptions {

View File

@@ -1,13 +1,15 @@
use std::num::NonZeroUsize;
use clap::ArgEnum;
use clap::ValueEnum;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use strum::Display;
use strum::EnumString;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum CycleDirection {
Previous,

View File

@@ -1,4 +1,4 @@
use clap::ArgEnum;
use clap::ValueEnum;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -9,7 +9,9 @@ use crate::OperationDirection;
use crate::Rect;
use crate::Sizing;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum DefaultLayout {
BSP,

View File

@@ -4,7 +4,7 @@
use std::path::PathBuf;
use std::str::FromStr;
use clap::ArgEnum;
use clap::ValueEnum;
use color_eyre::Result;
use schemars::JsonSchema;
use serde::Deserialize;
@@ -51,7 +51,10 @@ pub enum SocketMessage {
SendContainerToWorkspaceNumber(usize),
SendContainerToMonitorWorkspaceNumber(usize, usize),
MoveWorkspaceToMonitorNumber(usize),
Close,
Minimize,
Promote,
PromoteFocus,
ToggleFloat,
ToggleMonocle,
ToggleMaximize,
@@ -69,6 +72,7 @@ pub enum SocketMessage {
ChangeLayoutCustom(PathBuf),
FlipLayout(Axis),
// Monitor and Workspace Commands
MonitorIndexPreference(usize, i32, i32, i32, i32),
EnsureWorkspaces(usize, usize),
NewWorkspace,
ToggleTiling,
@@ -98,7 +102,7 @@ pub enum SocketMessage {
WatchConfiguration(bool),
CompleteConfiguration,
ActiveWindowBorder(bool),
ActiveWindowBorderColour(u32, u32, u32),
ActiveWindowBorderColour(WindowKind, u32, u32, u32),
InvisibleBorders(Rect),
WorkAreaOffset(Rect),
ResizeDelta(i32),
@@ -118,6 +122,7 @@ pub enum SocketMessage {
AddSubscriber(String),
RemoveSubscriber(String),
NotificationSchema,
SocketSchema,
}
impl SocketMessage {
@@ -134,7 +139,18 @@ impl FromStr for SocketMessage {
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum WindowKind {
Single,
Stack,
}
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum StateQuery {
FocusedMonitorIndex,
@@ -143,7 +159,9 @@ pub enum StateQuery {
FocusedWindowIndex,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum ApplicationIdentifier {
@@ -152,42 +170,54 @@ pub enum ApplicationIdentifier {
Title,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum FocusFollowsMouseImplementation {
Komorebi,
Windows,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum WindowContainerBehaviour {
Create,
Append,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum MoveBehaviour {
Swap,
Insert,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum HidingBehaviour {
Hide,
Minimize,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum OperationBehaviour {
Op,
NoOp,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum Sizing {
Increase,

View File

@@ -1,6 +1,6 @@
use std::num::NonZeroUsize;
use clap::ArgEnum;
use clap::ValueEnum;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -10,7 +10,9 @@ use strum::EnumString;
use crate::direction::Direction;
use crate::Axis;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
#[strum(serialize_all = "snake_case")]
pub enum OperationDirection {
Left,

394
komorebi.generated.ahk Normal file
View File

@@ -0,0 +1,394 @@
; Generated by komorebic.exe
; To use this file, add the line below to the top of your komorebi.ahk configuration file
; #Include %A_ScriptDir%\komorebi.generated.ahk
; 1Password
Run, komorebic.exe float-rule exe "1Password.exe", , Hide
; Adobe Creative Cloud
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application class "CreativeCloudDesktopWindowClass", , Hide
; ArmCord
Run, komorebic.exe identify-border-overflow-application exe "ArmCord.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ArmCord.exe", , Hide
; AutoHotkey
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "AutoHotkeyU64.exe", , Hide
Run, komorebic.exe float-rule title "Window Spy", , Hide
; Beeper
Run, komorebic.exe identify-border-overflow-application exe "Beeper.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Beeper.exe", , Hide
; Bitwarden
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Bitwarden.exe", , Hide
; Calculator
Run, komorebic.exe float-rule title "Calculator", , Hide
; Credential Manager UI Host
; Targets the Windows popup prompting you for a PIN instead of a password on 1Password etc.
Run, komorebic.exe float-rule exe "CredentialUIBroker.exe", , Hide
; Cron
Run, komorebic.exe identify-border-overflow-application exe "Cron.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Cron.exe", , Hide
; Discord
Run, komorebic.exe identify-border-overflow-application exe "Discord.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Discord.exe", , Hide
; DiscordCanary
Run, komorebic.exe identify-border-overflow-application exe "DiscordCanary.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "DiscordCanary.exe", , Hide
; DiscordDevelopment
Run, komorebic.exe identify-border-overflow-application exe "DiscordDevelopment.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "DiscordDevelopment.exe", , Hide
; DiscordPTB
Run, komorebic.exe identify-border-overflow-application exe "DiscordPTB.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "DiscordPTB.exe", , Hide
; ElectronMail
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ElectronMail.exe", , Hide
; Element
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Element.exe", , Hide
; ElevenClock
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ElevenClock.exe", , Hide
; Elgato Camera Hub
Run, komorebic.exe float-rule exe "Camera Hub.exe", , Hide
; Elgato Control Center
Run, komorebic.exe float-rule exe "ControlCenter.exe", , Hide
; Elgato Wave Link
Run, komorebic.exe float-rule exe "WaveLink.exe", , Hide
; Epic Games Launcher
Run, komorebic.exe identify-border-overflow-application exe "EpicGamesLauncher.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "EpicGamesLauncher.exe", , Hide
; Flow Launcher
Run, komorebic.exe identify-border-overflow-application exe "Flow.Launcher.exe", , Hide
; GOG Galaxy
Run, komorebic.exe identify-border-overflow-application exe "GalaxyClient.exe", , Hide
Run, komorebic.exe manage-rule exe "GalaxyClient.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "GalaxyClient.exe", , Hide
; Targets a hidden window spawned by GOG Galaxy
Run, komorebic.exe float-rule class "Chrome_RenderWidgetHostHWND", , Hide
; GoPro Webcam
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application class "GoPro Webcam", , Hide
; Google Chrome
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "chrome.exe", , Hide
; Google Drive
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "GoogleDriveFS.exe", , Hide
; Houdoku
Run, komorebic.exe identify-border-overflow-application exe "Houdoku.exe", , Hide
; Inno Setup
; Target hidden window spawned by Inno Setup applications
Run, komorebic.exe float-rule class "TApplication", , Hide
; Target Inno Setup installers
Run, komorebic.exe float-rule class "TWizardForm", , Hide
; IntelliJ IDEA
Run, komorebic.exe identify-object-name-change-application exe "idea64.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "idea64.exe", , Hide
; Targets JetBrains IDE popups and floating windows
Run, komorebic.exe float-rule class "SunAwtDialog", , Hide
; Kleopatra
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "kleopatra.exe", , Hide
; Kotatogram
Run, komorebic.exe identify-border-overflow-application exe "Kotatogram.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Kotatogram.exe", , Hide
; Logi Bolt
Run, komorebic.exe float-rule exe "LogiBolt.exe", , Hide
; LogiTune
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "LogiTune.exe", , Hide
Run, komorebic.exe float-rule exe "LogiTune.exe", , Hide
; Logitech G HUB
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "lghub.exe", , Hide
Run, komorebic.exe identify-border-overflow-application exe "lghub.exe", , Hide
; Logitech Options
Run, komorebic.exe float-rule exe "LogiOptionsUI.exe", , Hide
; Mailspring
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "mailspring.exe", , Hide
; ManyCam
Run, komorebic.exe identify-border-overflow-application exe "ManyCam.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ManyCam.exe", , Hide
; Mica For Everyone
; Microsoft Excel
Run, komorebic.exe identify-border-overflow-application exe "EXCEL.EXE", , Hide
Run, komorebic.exe identify-layered-application exe "EXCEL.EXE", , Hide
; Targets a hidden window spawned by Microsoft Office applications
Run, komorebic.exe float-rule class "_WwB", , Hide
; Microsoft Outlook
Run, komorebic.exe identify-border-overflow-application exe "OUTLOOK.EXE", , Hide
Run, komorebic.exe identify-layered-application exe "OUTLOOK.EXE", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "OUTLOOK.EXE", , Hide
; Microsoft PowerPoint
Run, komorebic.exe identify-border-overflow-application exe "POWERPNT.EXE", , Hide
Run, komorebic.exe identify-layered-application exe "POWERPNT.EXE", , Hide
; Microsoft Teams
; Target Teams pop-up notification windows
Run, komorebic.exe float-rule title "Microsoft Teams Notifications", , Hide
; Microsoft Word
Run, komorebic.exe identify-border-overflow-application exe "WINWORD.EXE", , Hide
Run, komorebic.exe identify-layered-application exe "WINWORD.EXE", , Hide
; Modern Flyouts
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ModernFlyoutsHost.exe", , Hide
; Mozilla Firefox
Run, komorebic.exe identify-object-name-change-application exe "firefox.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "firefox.exe", , Hide
; Targets invisible windows spawned by Firefox to show tab previews in the taskbar
Run, komorebic.exe float-rule class "MozillaTaskbarPreviewClass", , Hide
; NVIDIA GeForce Experience
Run, komorebic.exe identify-border-overflow-application exe "NVIDIA GeForce Experience.exe", , Hide
; NiceHash Miner
Run, komorebic.exe identify-border-overflow-application exe "nhm_app.exe", , Hide
Run, komorebic.exe manage-rule exe "nhm_app.exe", , Hide
; NohBoard
Run, komorebic.exe float-rule exe "NohBoard.exe", , Hide
; Notion Enhanced
Run, komorebic.exe identify-border-overflow-application exe "Notion Enhanced.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Notion Enhanced.exe", , Hide
; OBS Studio (32-bit)
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "obs32.exe", , Hide
; OBS Studio (64-bit)
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "obs64.exe", , Hide
; ONLYOFFICE Editors
Run, komorebic.exe identify-border-overflow-application class "DocEditorsWindowClass", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application class "DocEditorsWindowClass", , Hide
; Obsidian
Run, komorebic.exe identify-border-overflow-application exe "Obsidian.exe", , Hide
Run, komorebic.exe manage-rule exe "Obsidian.exe", , Hide
; OpenRGB
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "OpenRGB.exe", , Hide
; Paradox Launcher
Run, komorebic.exe float-rule exe "Paradox Launcher.exe", , Hide
; PowerToys
; Target color picker dialog
Run, komorebic.exe float-rule exe "PowerToys.ColorPickerUI.exe", , Hide
; Target image resizer dialog
Run, komorebic.exe float-rule exe "PowerToys.ImageResizer.exe", , Hide
; Process Hacker
Run, komorebic.exe identify-border-overflow-application exe "ProcessHacker.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ProcessHacker.exe", , Hide
Run, komorebic.exe float-rule exe "ProcessHacker.exe", , Hide
; ProtonVPN
Run, komorebic.exe identify-border-overflow-application exe "ProtonVPN.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ProtonVPN.exe", , Hide
; PyCharm
Run, komorebic.exe identify-object-name-change-application exe "pycharm64.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "pycharm64.exe", , Hide
; QuickLook
Run, komorebic.exe float-rule exe "QuickLook.exe", , Hide
; RepoZ
Run, komorebic.exe float-rule exe "RepoZ.exe", , Hide
; Roblox FPS Unlocker
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "rbxfpsunlocker.exe", , Hide
; RoundedTB
Run, komorebic.exe float-rule exe "RoundedTB.exe", , Hide
; RoundedTB
Run, komorebic.exe identify-border-overflow-application exe "RoundedTB.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "RoundedTB.exe", , Hide
; ShareX
Run, komorebic.exe identify-border-overflow-application exe "ShareX.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ShareX.exe", , Hide
; Signal
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "signal.exe", , Hide
; SiriKali
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "sirikali.exe", , Hide
; Slack
Run, komorebic.exe identify-border-overflow-application exe "Slack.exe", , Hide
Run, komorebic.exe manage-rule exe "Slack.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Slack.exe", , Hide
; Slack
Run, komorebic.exe identify-border-overflow-application exe "slack.exe", , Hide
Run, komorebic.exe manage-rule exe "slack.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "slack.exe", , Hide
; SoulseekQt
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "SoulseekQt.exe", , Hide
; Spotify
Run, komorebic.exe identify-border-overflow-application exe "Spotify.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Spotify.exe", , Hide
; Steam
Run, komorebic.exe identify-border-overflow-application class "vguiPopupWindow", , Hide
; SystemSettings
Run, komorebic.exe float-rule class "Shell_Dialog", , Hide
; Task Manager
Run, komorebic.exe float-rule class "TaskManagerWindow", , Hide
; Telegram
Run, komorebic.exe identify-border-overflow-application exe "Telegram.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "Telegram.exe", , Hide
; TouchCursor
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "tcconfig.exe", , Hide
Run, komorebic.exe float-rule exe "tcconfig.exe", , Hide
; TranslucentTB
Run, komorebic.exe float-rule exe "TranslucentTB.exe", , Hide
; TranslucentTB
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "TranslucentTB.exe", , Hide
; Unreal Editor
Run, komorebic.exe identify-border-overflow-application exe "UnrealEditor.exe", , Hide
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "UnrealEditor.exe", , Hide
; Visual Studio
Run, komorebic.exe manage-rule exe "devenv.exe", , Hide
Run, komorebic.exe float-rule class "GenericPane", , Hide
; Visual Studio Code
Run, komorebic.exe identify-border-overflow-application exe "Code.exe", , Hide
; WebTorrent Desktop
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "WebTorrent.exe", , Hide
; Windows Console (conhost.exe)
Run, komorebic.exe manage-rule class "ConsoleWindowClass", , Hide
; Windows Explorer
; Targets copy/move operation windows
Run, komorebic.exe float-rule class "OperationStatusWindow", , Hide
Run, komorebic.exe float-rule title "Control Panel", , Hide
; Windows Installer
; Targets MSI Installers
Run, komorebic.exe float-rule class "MsiDialogCloseClass", , Hide
; WingetUI
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "WingetUI.exe", , Hide
; WingetUI
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "wingetui.exe", , Hide
; Wox
; Targets a hidden window spawned by Wox
Run, komorebic.exe float-rule title "Hotkey sink", , Hide
; Zoom
Run, komorebic.exe float-rule exe "Zoom.exe", , Hide
; mpv.net
Run, komorebic.exe identify-object-name-change-application exe "mpvnet.exe", , Hide
; paint.net
Run, komorebic.exe float-rule exe "paintdotnet.exe", , Hide
; qBittorrent
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "qbittorrent.exe", , Hide
; ueli
; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line
Run, komorebic.exe identify-tray-application exe "ueli.exe", , Hide
Run, komorebic.exe float-rule exe "ueli.exe", , Hide

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUST_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/bindings/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/komorebi-core/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/komorebi/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/komorebic/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,225 +1,93 @@
#SingleInstance Force
; You can generate a fresh version of this file with "komorebic ahk-library"
#Include %A_ScriptDir%\komorebic.lib.ahk
; https://github.com/LGUG2Z/komorebi/#generating-common-application-specific-configurations
#Include %A_ScriptDir%\komorebi.generated.ahk
; Default to minimizing windows when switching workspaces
WindowHidingBehaviour("minimize")
; Set cross-monitor move behaviour to insert instead of swap
CrossMonitorMoveBehaviour("insert")
; Enable hot reloading of changes to this file
Run, komorebic.exe watch-configuration enable, , Hide
WatchConfiguration("enable")
; Ensure there is 1 workspace created on monitor 0
EnsureWorkspaces(0, 1)
; Configure the invisible border dimensions
Run, komorebic.exe invisible-borders 7 0 14 7, , Hide
InvisibleBorders(7, 0, 14, 7)
; Enable focus follows mouse
Run, komorebic.exe focus-follows-mouse enable, , Hide
; Configure the 1st workspace
WorkspaceName(0, 0, "I")
; Ensure there are 3 workspaces created on monitor 0
Run, komorebic.exe ensure-workspaces 0 5, , Hide
; Uncomment the next two lines if you want a visual border drawn around the focused window
; ActiveWindowBorderColour(66, 165, 245, "single") ; this is a nice blue colour
; ActiveWindowBorder("enable")
; Give the workspaces some optional names
Run, komorebic.exe workspace-name 0 0 bsp, , Hide
Run, komorebic.exe workspace-name 0 1 columns, , Hide
Run, komorebic.exe workspace-name 0 2 thicc, , Hide
Run, komorebic.exe workspace-name 0 3 matrix, , Hide
Run, komorebic.exe workspace-name 0 4 floaty, , Hide
; Allow komorebi to start managing windows
CompleteConfiguration()
; Set the padding of the different workspaces
Run, komorebic.exe workspace-padding 0 1 30, , Hide
Run, komorebic.exe container-padding 0 1 30, , Hide
Run, komorebic.exe workspace-padding 0 2 200, , Hide
Run, komorebic.exe workspace-padding 0 3 0, , Hide
Run, komorebic.exe container-padding 0 3 0, , Hide
; Set the layouts of different workspaces
Run, komorebic.exe workspace-layout 0 1 columns, , Hide
; Set the floaty layout to not tile any windows
Run, komorebic.exe workspace-tiling 0 4 disable, , Hide
; Always show chat apps on the second workspace
Run, komorebic.exe workspace-rule exe slack.exe 0 1, , Hide
Run, komorebic.exe workspace-rule exe Discord.exe 0 1, , Hide
; Always float IntelliJ popups, matching on class
Run, komorebic.exe float-rule class SunAwtDialog, , Hide
; Always float Control Panel, matching on title
Run, komorebic.exe float-rule title "Control Panel", , Hide
; Always float Task Manager, matching on class
Run, komorebic.exe float-rule class TaskManagerWindow, , Hide
; Always float Wally, matching on executable name
Run, komorebic.exe float-rule exe Wally.exe, , Hide
Run, komorebic.exe float-rule exe wincompose.exe, , Hide
; Always float Calculator app, matching on window title
Run, komorebic.exe float-rule title Calculator, , Hide
Run, komorebic.exe float-rule exe 1Password.exe, , Hide
; Always manage forcibly these applications that don't automatically get picked up by komorebi
Run, komorebic.exe manage-rule exe TIM.exe, , Hide
; Identify applications that close to the tray
Run, komorebic.exe identify-tray-application exe Discord.exe, , Hide
; Identify applications that have overflowing borders
Run, komorebic.exe identify-border-overflow exe Discord.exe, , Hide
; Change the focused window, Alt + Vim direction keys
; Change the focused window, Alt + Vim direction keys (HJKL)
!h::
Run, komorebic.exe focus left, , Hide
Focus("left")
return
!j::
Run, komorebic.exe focus down, , Hide
Focus("down")
return
!k::
Run, komorebic.exe focus up, , Hide
Focus("up")
return
!l::
Run, komorebic.exe focus right, , Hide
Focus("right")
return
; Move the focused window in a given direction, Alt + Shift + Vim direction keys
; Move the focused window in a given direction, Alt + Shift + Vim direction keys (HJKL)
!+h::
Run, komorebic.exe move left, , Hide
Move("left")
return
!+j::
Run, komorebic.exe move down, , Hide
Move("down")
return
!+k::
Run, komorebic.exe move up, , Hide
Move("up")
return
!+l::
Run, komorebic.exe move right, , Hide
Move("right")
return
; Stack the focused window in a given direction, Alt + Shift + direction keys
!+Left::
Run, komorebic.exe stack left, , Hide
return
!+Down::
Run, komorebic.exe stack down, , Hide
return
!+Up::
Run, komorebic.exe stack up, , Hide
return
!+Right::
Run, komorebic.exe stack right, , Hide
return
!]::
Run, komorebic.exe cycle-stack next, , Hide
return
![::
Run, komorebic.exe cycle-stack previous, , Hide
return
; Unstack the focused window, Alt + Shift + D
!+d::
Run, komorebic.exe unstack, , Hide
return
; Promote the focused window to the top of the tree, Alt + Shift + Enter
!+Enter::
Run, komorebic.exe promote, , Hide
return
; Switch to an equal-width, max-height column layout on the main workspace, Alt + Shift + C
!+c::
Run, komorebic.exe workspace-layout 0 0 columns, , Hide
return
; Switch to the default bsp tiling layout on the main workspace, Alt + Shift + T
!+t::
Run, komorebic.exe workspace-layout 0 0 bsp, , Hide
return
; Toggle the Monocle layout for the focused window, Alt + Shift + F
!+f::
Run, komorebic.exe toggle-monocle, , Hide
return
; Toggle native maximize for the focused window, Alt + Shift + =
!+=::
Run, komorebic.exe toggle-maximize, , Hide
return
; Flip horizontally, Alt + X
!x::
Run, komorebic.exe flip-layout horizontal, , Hide
return
; Flip vertically, Alt + Y
!y::
Run, komorebic.exe flip-layout vertical, , Hide
return
; Force a retile if things get janky, Alt + Shift + R
!+r::
Run, komorebic.exe retile, , Hide
return
; Float the focused window, Alt + T
!t::
Run, komorebic.exe toggle-float, , Hide
return
; Reload ~/komorebi.ahk, Alt + O
!o::
Run, komorebic.exe reload-configuration, , Hide
return
; Pause responding to any window events or komorebic commands, Alt + P
!p::
Run, komorebic.exe toggle-pause, , Hide
return
; Switch to workspace
!1::
Send !
Run, komorebic.exe focus-workspace 0, , Hide
return
!2::
Send !
Run, komorebic.exe focus-workspace 1, , Hide
return
!3::
Send !
Run, komorebic.exe focus-workspace 2, , Hide
return
!4::
Send !
Run, komorebic.exe focus-workspace 3, , Hide
return
!5::
Send !
Run, komorebic.exe focus-workspace 4, , Hide
return
; Move window to workspace
!+1::
Run, komorebic.exe move-to-workspace 0, , Hide
return
!+2::
Run, komorebic.exe move-to-workspace 1, , Hide
return
!+3::
Run, komorebic.exe move-to-workspace 2, , Hide
return
!+4::
Run, komorebic.exe move-to-workspace 3, , Hide
return
!+5::
Run, komorebic.exe move-to-workspace 4, , Hide
return
; There are many more commands that you can bind to whatever keys combinations you want!
;
; Have a look at the komorebic.lib.ahk file to see which arguments are required by different commands
;
; If you want more information about a command, you can run every komorebic command with "--help"
;
; For example, if you see this in komorebic.lib.ahk
;
; WorkspaceLayout(monitor, workspace, value) {
; Run, komorebic.exe workspace-layout %monitor% %workspace% %value%, , Hide
; }
;
; Just run "komorebic.exe workspace-layout --help" and you'll get all the information you need to use the command
;
; komorebic.exe-workspace-layout
; Set the layout for the specified workspace
;
; USAGE:
; komorebic.exe workspace-layout <MONITOR> <WORKSPACE> <VALUE>
;
; ARGS:
; <MONITOR> Monitor index (zero-indexed)
; <WORKSPACE> Workspace index on the specified monitor (zero-indexed)
; <VALUE> [possible values: bsp, columns, rows, vertical-stack, horizontal-stack, ultrawide-vertical-stack]
;
; OPTIONS:
; -h, --help Print help information

View File

@@ -1,243 +0,0 @@
#SingleInstance Force
#Include %A_ScriptDir%\komorebic.lib.ahk
; Default to minimizing windows when switching workspaces
WindowHidingBehaviour("minimize")
; Enable hot reloading of changes to this file
WatchConfiguration("enable")
; Ensure there are 5 workspaces created on monitor 0
EnsureWorkspaces(0, 5)
; Configure the invisible border dimensions
InvisibleBorders(7, 0, 14, 7)
; Configure the 1st workspace
WorkspaceName(0, 0, "bsp")
; Configure the 2nd workspace
WorkspaceName(0, 1, "columns") ; Optionally set the name of the workspace
WorkspacePadding(0, 1, 30) ; Set the padding around the edge of the screen
ContainerPadding(0, 1, 30) ; Set the padding between the containers on the screen
WorkspaceRule("exe", "slack.exe", 0, 1) ; Always show chat apps on this workspace
; Configure the 3rd workspace
WorkspaceName(0, 2, "thicc")
WorkspacePadding(0, 2, 200) ; Set some super thicc padding
; Configure the 4th workspace
WorkspaceName(0, 3, "matrix")
WorkspacePadding(0, 3, 0) ; No padding at all
ContainerPadding(0, 3, 0) ; Matrix-y hacker vibes
; Configure the 5th workspace
WorkspaceName(0, 4, "floaty")
WorkspaceTiling(0, 4, "disable") ; Everything floats here
; Configure floating rules
FloatRule("class", "SunAwtDialog") ; All the IntelliJ popups
FloatRule("title", "Control Panel")
FloatRule("class", "TaskManagerWindow")
FloatRule("exe", "Wally.exe")
FloatRule("exe", "wincompose.exe")
FloatRule("exe", "1Password.exe")
FloatRule("exe", "Wox.exe")
FloatRule("exe", "ddm.exe")
FloatRule("class", "Chrome_RenderWidgetHostHWND") ; GOG Electron invisible overlay
FloatRule("class", "CEFCLIENT")
; Identify Minimize-to-Tray Applications
IdentifyTrayApplication("exe", "Discord.exe")
IdentifyTrayApplication("exe", "Spotify.exe")
IdentifyTrayApplication("exe", "GalaxyClient.exe")
; Identify Electron applications with overflowing borders
IdentifyBorderOverflow("exe", "Discord.exe")
IdentifyBorderOverflow("exe", "Spotify.exe")
IdentifyBorderOverflow("exe", "GalaxyClient.exe")
IdentifyBorderOverflow("class", "ZPFTEWndClass")
; Identify applications to be forcibly managed
ManageRule("exe", "GalaxyClient.exe")
; Change the focused window, Alt + Vim direction keys
!h::
Focus("left")
return
!j::
Focus("down")
return
!k::
Focus("up")
return
!l::
Focus("right")
return
; Move the focused window in a given direction, Alt + Shift + Vim direction keys
!+h::
Move("left")
return
!+j::
Move("down")
return
!+k::
Move("up")
return
!+l::
Move("right")
return
; Stack the focused window in a given direction, Alt + Shift + direction keys
!+Left::
Stack("left")
return
!+Down::
Stack("down")
return
!+Up::
Stack("up")
return
!+Right::
Stack("right")
return
!]::
CycleStack("next")
return
![::
CycleStack("previous")
return
; Unstack the focused window, Alt + Shift + D
!+d::
Unstack()
return
; Promote the focused window to the top of the tree, Alt + Shift + Enter
!+Enter::
Promote()
return
; Manage the focused window
!=::
Manage()
return
; Unmanage the focused window
!-::
Unmanage()
return
; Switch to an equal-width, max-height column layout on the main workspace, Alt + Shift + C
!+c::
ChangeLayout("columns")
return
; Switch to the default bsp tiling layout on the main workspace, Alt + Shift + T
!+t::
ChangeLayout("bsp")
return
; Toggle the Monocle layout for the focused window, Alt + Shift + F
!+f::
ToggleMonocle()
return
; Toggle native maximize for the focused window, Alt + Shift + =
!+=::
ToggleMaximize()
return
; Flip horizontally, Alt + X
!x::
FlipLayout("horizontal")
return
; Flip vertically, Alt + Y
!y::
FlipLayout("vertical")
return
; Force a retile if things get janky, Alt + Shift + R
!+r::
Retile()
return
; Float the focused window, Alt + T
!t::
ToggleFloat()
return
; Reload ~/komorebi.ahk, Alt + O
!o::
ReloadConfiguration()
return
; Pause responding to any window events or komorebic commands, Alt + P
!p::
TogglePause()
return
; Enable focus follows mouse
!0::
ToggleFocusFollowsMouse("komorebi")
return
; Switch to workspace
!1::
Send !
FocusWorkspace(0)
return
!2::
Send !
FocusWorkspace(1)
return
!3::
Send !
FocusWorkspace(2)
return
!4::
Send !
FocusWorkspace(3)
return
!5::
Send !
FocusWorkspace(4)
return
; Move window to workspace
!+1::
MoveToWorkspace(0)
return
!+2::
MoveToWorkspace(1)
return
!+3::
MoveToWorkspace(2)
return
!+4::
MoveToWorkspace(3)
return
!+5::
MoveToWorkspace(4)
return

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebi"
version = "0.1.12"
version = "0.1.14"
authors = ["Jade Iqbal <jadeiqbal@fastmail.com>"]
description = "A tiling window manager for Windows"
categories = ["tiling-window-manager", "windows"]
@@ -14,7 +14,7 @@ edition = "2021"
komorebi-core = { path = "../komorebi-core" }
bitflags = "1"
clap = { version = "3", features = ["derive"] }
clap = { version = "4", features = ["derive"] }
color-eyre = "0.6"
crossbeam-channel = "0.5"
crossbeam-utils = "0.8"
@@ -25,6 +25,7 @@ hotwatch = "0.4"
lazy_static = "1"
miow = "0.4"
nanoid = "0.4"
net2 = "0.2"
os_info = "3.4"
parking_lot = { version = "0.12", features = ["deadlock_detection"] }
paste = "1"
@@ -32,7 +33,7 @@ schemars = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
strum = { version = "0.24", features = ["derive"] }
sysinfo = "0.25"
sysinfo = "0.26"
tracing = "0.1"
tracing-appender = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
@@ -42,7 +43,7 @@ winput = "0.2"
winreg = "0.10"
[dependencies.windows]
version = "0.39"
version = "0.43"
features = [
"Win32_Foundation",
"Win32_Graphics_Dwm",
@@ -55,7 +56,8 @@ features = [
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Shell",
"Win32_UI_Shell_Common",
"Win32_UI_WindowsAndMessaging"
"Win32_UI_WindowsAndMessaging",
"Win32_System_SystemServices"
]
[features]

View File

@@ -2,7 +2,6 @@ use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use komorebi_core::Rect;
use windows::core::PCSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
@@ -13,11 +12,15 @@ use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use komorebi_core::Rect;
use crate::window::Window;
use crate::windows_callbacks;
use crate::WindowsApi;
use crate::BORDER_HWND;
use crate::BORDER_OVERFLOW_IDENTIFIERS;
use crate::BORDER_RECT;
use crate::TRANSPARENCY_COLOUR;
use crate::WINDOWS_11;
#[derive(Debug, Clone, Copy)]
@@ -40,7 +43,7 @@ impl Border {
let name = format!("{name}\0");
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(255, 140, 0);
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
hInstance: instance,
lpszClassName: class_name,
@@ -84,7 +87,11 @@ impl Border {
}
pub fn hide(self) -> Result<()> {
WindowsApi::hide_border_window(self.hwnd())
if self.hwnd == 0 {
Ok(())
} else {
WindowsApi::hide_border_window(self.hwnd())
}
}
pub fn set_position(
@@ -93,27 +100,33 @@ impl Border {
invisible_borders: &Rect,
activate: bool,
) -> Result<()> {
let mut should_expand_border = false;
if self.hwnd == 0 {
Ok(())
} else {
let mut should_expand_border = false;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= invisible_borders.bottom;
rect.bottom += invisible_borders.bottom;
let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock();
if border_overflows.contains(&window.title()?)
|| border_overflows.contains(&window.exe()?)
|| border_overflows.contains(&window.class()?)
{
should_expand_border = true;
}
if should_expand_border {
rect.left -= invisible_borders.left;
rect.top -= invisible_borders.top;
rect.right += invisible_borders.right;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= invisible_borders.bottom;
rect.bottom += invisible_borders.bottom;
}
WindowsApi::position_border_window(self.hwnd(), &rect, activate)
let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock();
if border_overflows.contains(&window.title()?)
|| border_overflows.contains(&window.exe()?)
|| border_overflows.contains(&window.class()?)
{
should_expand_border = true;
}
if should_expand_border {
rect.left -= invisible_borders.left;
rect.top -= invisible_borders.top;
rect.right += invisible_borders.right;
rect.bottom += invisible_borders.bottom;
}
*BORDER_RECT.lock() = rect;
WindowsApi::position_border_window(self.hwnd(), &rect, activate)
}
}
}

78
komorebi/src/hidden.rs Normal file
View File

@@ -0,0 +1,78 @@
use std::sync::atomic::Ordering;
use std::time::Duration;
use color_eyre::Result;
use windows::core::PCSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use crate::windows_callbacks;
use crate::WindowsApi;
use crate::HIDDEN_HWND;
use crate::TRANSPARENCY_COLOUR;
#[derive(Debug, Clone, Copy)]
pub struct Hidden {
pub(crate) hwnd: isize,
}
impl From<isize> for Hidden {
fn from(hwnd: isize) -> Self {
Self { hwnd }
}
}
impl Hidden {
pub const fn hwnd(self) -> HWND {
HWND(self.hwnd)
}
pub fn create(name: &str) -> Result<()> {
let name = format!("{name}\0");
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
hInstance: instance,
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(windows_callbacks::hidden_window),
hbrBackground: brush,
..Default::default()
};
let _atom = WindowsApi::register_class_a(&window_class)?;
let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_hidden_window(PCSTR(name_cl.as_ptr()), instance)?;
let hidden = Self::from(hwnd);
let mut message = MSG::default();
unsafe {
while GetMessageA(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
Ok(())
});
let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
}
HIDDEN_HWND.store(hwnd.0, Ordering::SeqCst);
Ok(())
}
}

View File

@@ -4,6 +4,7 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::net::TcpStream;
use std::path::PathBuf;
use std::process::Command;
use std::sync::atomic::AtomicBool;
@@ -37,11 +38,13 @@ use which::which;
use winreg::enums::HKEY_CURRENT_USER;
use winreg::RegKey;
use crate::hidden::Hidden;
use komorebi_core::HidingBehaviour;
use komorebi_core::Rect;
use komorebi_core::SocketMessage;
use crate::border::Border;
use crate::process_command::listen_for_commands;
use crate::process_command::listen_for_commands_tcp;
use crate::process_event::listen_for_events;
use crate::process_movement::listen_for_movements;
use crate::window_manager::State;
@@ -54,6 +57,7 @@ mod ring;
mod border;
mod container;
mod hidden;
mod monitor;
mod process_command;
mod process_event;
@@ -86,6 +90,8 @@ lazy_static! {
"firefox.exe".to_string(),
"idea64.exe".to_string(),
]));
static ref MONITOR_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, Rect>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref WORKSPACE_RULES: Arc<Mutex<HashMap<String, (usize, usize)>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
@@ -98,11 +104,12 @@ lazy_static! {
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
static ref WSL2_UI_PROCESSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"X410.exe".to_string(),
"mstsc.exe".to_string(),
"vcxsrv.exe".to_string(),
]));
static ref SUBSCRIPTION_PIPES: Arc<Mutex<HashMap<String, File>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref TCP_CONNECTIONS: Arc<Mutex<HashMap<String, TcpStream>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref HIDING_BEHAVIOUR: Arc<Mutex<HidingBehaviour>> =
Arc::new(Mutex::new(HidingBehaviour::Minimize));
static ref HOME_DIR: PathBuf = {
@@ -151,6 +158,9 @@ lazy_static! {
Version::Semantic(_, _, x) if x >= &22000
)
};
static ref BORDER_RECT: Arc<Mutex<Rect>> =
Arc::new(Mutex::new(Rect::default()));
}
pub static INITIAL_CONFIGURATION_LOADED: AtomicBool = AtomicBool::new(false);
@@ -159,6 +169,13 @@ pub static SESSION_ID: AtomicU32 = AtomicU32::new(0);
pub static BORDER_ENABLED: AtomicBool = AtomicBool::new(false);
pub static BORDER_HWND: AtomicIsize = AtomicIsize::new(0);
pub static BORDER_HIDDEN: AtomicBool = AtomicBool::new(false);
pub static BORDER_COLOUR_SINGLE: AtomicU32 = AtomicU32::new(0);
pub static BORDER_COLOUR_STACK: AtomicU32 = AtomicU32::new(0);
pub static BORDER_COLOUR_CURRENT: AtomicU32 = AtomicU32::new(0);
// 0 0 0 aka pure black, I doubt anyone will want this as a border colour
pub const TRANSPARENCY_COLOUR: u32 = 0;
pub static HIDDEN_HWND: AtomicIsize = AtomicIsize::new(0);
fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
@@ -383,19 +400,33 @@ struct Opts {
/// Wait for 'komorebic complete-configuration' to be sent before processing events
#[clap(action, short, long)]
await_configuration: bool,
/// Start a TCP server on the given port to allow the direct sending of SocketMessages
#[clap(action, short, long)]
tcp_port: Option<usize>,
}
#[tracing::instrument]
#[allow(clippy::nonminimal_bool)]
fn main() -> Result<()> {
let opts: Opts = Opts::parse();
CUSTOM_FFM.store(opts.focus_follows_mouse, Ordering::SeqCst);
let arg_count = std::env::args().count();
let has_valid_args = arg_count == 1
|| (arg_count == 2 && (opts.await_configuration || opts.focus_follows_mouse))
|| (arg_count == 3 && opts.await_configuration && opts.focus_follows_mouse);
|| (arg_count == 2
&& (opts.await_configuration || opts.focus_follows_mouse || opts.tcp_port.is_some()))
|| (arg_count == 3 && opts.await_configuration && opts.focus_follows_mouse)
|| (arg_count == 3 && opts.tcp_port.is_some() && opts.focus_follows_mouse)
|| (arg_count == 3 && opts.tcp_port.is_some() && opts.await_configuration)
|| (arg_count == 4
&& (opts.focus_follows_mouse && opts.await_configuration && opts.tcp_port.is_some()));
if has_valid_args {
let process_id = WindowsApi::current_process_id();
WindowsApi::allow_set_foreground_window(process_id)?;
WindowsApi::set_process_dpi_awareness_context()?;
let session_id = WindowsApi::process_id_to_session_id()?;
SESSION_ID.store(session_id, Ordering::SeqCst);
@@ -424,17 +455,14 @@ fn main() -> Result<()> {
#[cfg(feature = "deadlock_detection")]
detect_deadlocks();
let process_id = WindowsApi::current_process_id();
WindowsApi::allow_set_foreground_window(process_id)?;
WindowsApi::set_process_dpi_awareness_context()?;
Border::create("komorebi-border-window")?;
let (outgoing, incoming): (Sender<WindowManagerEvent>, Receiver<WindowManagerEvent>) =
crossbeam_channel::unbounded();
let winevent_listener = winevent_listener::new(Arc::new(Mutex::new(outgoing)));
winevent_listener.start();
Hidden::create("komorebi-hidden")?;
let wm = Arc::new(Mutex::new(WindowManager::new(Arc::new(Mutex::new(
incoming,
)))?));
@@ -446,6 +474,10 @@ fn main() -> Result<()> {
INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst);
};
if let Some(port) = opts.tcp_port {
listen_for_commands_tcp(wm.clone(), port);
}
std::thread::spawn(|| {
load_configuration().expect("could not load configuration");
});

View File

@@ -21,6 +21,8 @@ pub struct Monitor {
#[getset(get_copy = "pub", set = "pub")]
id: isize,
#[getset(get = "pub", set = "pub")]
name: String,
#[getset(get = "pub", set = "pub")]
size: Rect,
#[getset(get = "pub", set = "pub")]
work_area_size: Rect,
@@ -32,12 +34,13 @@ pub struct Monitor {
impl_ring_elements!(Monitor, Workspace);
pub fn new(id: isize, size: Rect, work_area_size: Rect) -> Monitor {
pub fn new(id: isize, size: Rect, work_area_size: Rect, name: String) -> Monitor {
let mut workspaces = Ring::default();
workspaces.elements_mut().push_back(Workspace::default());
Monitor {
id,
name,
size,
work_area_size,
workspaces,

View File

@@ -2,15 +2,20 @@ use std::fs::File;
use std::fs::OpenOptions;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use std::io::Write;
use std::net::TcpListener;
use std::net::TcpStream;
use std::num::NonZeroUsize;
use std::str::FromStr;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use miow::pipe::connect;
use net2::TcpStreamExt;
use parking_lot::Mutex;
use schemars::schema_for;
use uds_windows::UnixStream;
@@ -26,6 +31,7 @@ use komorebi_core::Sizing;
use komorebi_core::SocketMessage;
use komorebi_core::StateQuery;
use komorebi_core::WindowContainerBehaviour;
use komorebi_core::WindowKind;
use crate::border::Border;
use crate::current_virtual_desktop;
@@ -36,18 +42,23 @@ use crate::window_manager::WindowManager;
use crate::windows_api::WindowsApi;
use crate::Notification;
use crate::NotificationEvent;
use crate::BORDER_COLOUR_CURRENT;
use crate::BORDER_COLOUR_SINGLE;
use crate::BORDER_COLOUR_STACK;
use crate::BORDER_ENABLED;
use crate::BORDER_HWND;
use crate::BORDER_OVERFLOW_IDENTIFIERS;
use crate::CUSTOM_FFM;
use crate::DATA_DIR;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDING_BEHAVIOUR;
use crate::HOME_DIR;
use crate::INITIAL_CONFIGURATION_LOADED;
use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::SUBSCRIPTION_PIPES;
use crate::TCP_CONNECTIONS;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WORKSPACE_RULES;
@@ -60,10 +71,10 @@ pub fn listen_for_commands(wm: Arc<Mutex<WindowManager>>) {
.expect("could not clone unix listener");
std::thread::spawn(move || {
tracing::info!("listening");
tracing::info!("listening on komorebi.sock");
for client in listener.incoming() {
match client {
Ok(stream) => match wm.lock().read_commands(stream) {
Ok(stream) => match read_commands_uds(&wm, stream) {
Ok(()) => {}
Err(error) => tracing::error!("{}", error),
},
@@ -76,6 +87,48 @@ pub fn listen_for_commands(wm: Arc<Mutex<WindowManager>>) {
});
}
#[tracing::instrument]
pub fn listen_for_commands_tcp(wm: Arc<Mutex<WindowManager>>, port: usize) {
let listener =
TcpListener::bind(format!("0.0.0.0:{}", port)).expect("could not start tcp server");
std::thread::spawn(move || {
tracing::info!("listening on 0.0.0.0:43663");
for client in listener.incoming() {
match client {
Ok(mut stream) => {
stream
.set_keepalive(Some(Duration::from_secs(30)))
.expect("TCP keepalive should be set");
let addr = stream
.peer_addr()
.expect("incoming connection should have an address")
.to_string();
let mut connections = TCP_CONNECTIONS.lock();
connections.insert(
addr.clone(),
stream.try_clone().expect("stream should be cloneable"),
);
tracing::info!("listening for incoming tcp messages from {}", &addr);
match read_commands_tcp(&wm, &mut stream, &addr) {
Ok(()) => {}
Err(error) => tracing::error!("{}", error),
}
}
Err(error) => {
tracing::error!("{}", error);
break;
}
}
}
});
}
impl WindowManager {
#[tracing::instrument(skip(self))]
pub fn process_command(&mut self, message: SocketMessage) -> Result<()> {
@@ -107,6 +160,7 @@ impl WindowManager {
match message {
SocketMessage::Promote => self.promote_container_to_front()?,
SocketMessage::PromoteFocus => self.promote_focus_to_front()?,
SocketMessage::FocusWindow(direction) => {
self.focus_container_in_direction(direction)?;
}
@@ -124,6 +178,8 @@ impl WindowManager {
SocketMessage::CycleStack(direction) => {
self.cycle_container_window_in_direction(direction)?;
}
SocketMessage::Close => self.focused_window()?.close()?,
SocketMessage::Minimize => self.focused_window()?.minimize(),
SocketMessage::ToggleFloat => self.toggle_float()?,
SocketMessage::ToggleMonocle => self.toggle_monocle()?,
SocketMessage::ToggleMaximize => self.toggle_maximize()?,
@@ -347,6 +403,18 @@ impl WindowManager {
std::process::exit(0)
}
SocketMessage::MonitorIndexPreference(index_preference, left, top, right, bottom) => {
let mut monitor_index_preferences = MONITOR_INDEX_PREFERENCES.lock();
monitor_index_preferences.insert(
index_preference,
Rect {
left,
top,
right,
bottom,
},
);
}
SocketMessage::EnsureWorkspaces(monitor_idx, workspace_count) => {
self.ensure_workspaces_for_monitor(monitor_idx, workspace_count)?;
}
@@ -363,7 +431,7 @@ impl WindowManager {
Err(error) => error.to_string(),
};
let mut socket = HOME_DIR.clone();
let mut socket = DATA_DIR.clone();
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -386,7 +454,7 @@ impl WindowManager {
}
.to_string();
let mut socket = HOME_DIR.clone();
let mut socket = DATA_DIR.clone();
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -751,6 +819,10 @@ impl WindowManager {
}
SocketMessage::ActiveWindowBorder(enable) => {
if enable {
if BORDER_HWND.load(Ordering::SeqCst) == 0 {
Border::create("komorebi-border-window")?;
}
BORDER_ENABLED.store(true, Ordering::SeqCst);
self.show_border()?;
} else {
@@ -758,14 +830,33 @@ impl WindowManager {
self.hide_border()?;
}
}
SocketMessage::ActiveWindowBorderColour(r, g, b) => {
let hwnd = BORDER_HWND.load(Ordering::SeqCst);
WindowsApi::change_border_colour(hwnd, r, g, b)?;
SocketMessage::ActiveWindowBorderColour(kind, r, g, b) => {
match kind {
WindowKind::Single => {
BORDER_COLOUR_SINGLE.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
BORDER_COLOUR_CURRENT.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
}
WindowKind::Stack => {
BORDER_COLOUR_STACK.store(r | (g << 8) | (b << 16), Ordering::SeqCst);
}
}
WindowsApi::invalidate_border_rect()?;
}
SocketMessage::NotificationSchema => {
let notification = schema_for!(Notification);
let schema = serde_json::to_string_pretty(&notification)?;
let mut socket = HOME_DIR.clone();
let mut socket = DATA_DIR.clone();
socket.push("komorebic.sock");
let socket = socket.as_path();
let mut stream = UnixStream::connect(&socket)?;
stream.write_all(schema.as_bytes())?;
}
SocketMessage::SocketSchema => {
let socket_message = schema_for!(SocketMessage);
let schema = serde_json::to_string_pretty(&socket_message)?;
let mut socket = DATA_DIR.clone();
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -788,7 +879,14 @@ impl WindowManager {
| SocketMessage::ToggleMonocle
| SocketMessage::ToggleMaximize
| SocketMessage::Promote
| SocketMessage::PromoteFocus
| SocketMessage::Retile
// Adding this one because sometimes EVENT_SYSTEM_FOREGROUND isn't
// getting sent on FocusWindow, meaning the border won't be set
// when processing events
| SocketMessage::FocusWindow(_)
| SocketMessage::InvisibleBorders(_)
| SocketMessage::WorkAreaOffset(_)
| SocketMessage::MoveWindow(_) => {
let foreground = WindowsApi::foreground_window()?;
let foreground_window = Window { hwnd: foreground };
@@ -829,32 +927,87 @@ impl WindowManager {
tracing::info!("processed");
Ok(())
}
}
#[tracing::instrument(skip(self, stream))]
pub fn read_commands(&mut self, stream: UnixStream) -> Result<()> {
let stream = BufReader::new(stream);
for line in stream.lines() {
let message = SocketMessage::from_str(&line?)?;
pub fn read_commands_uds(wm: &Arc<Mutex<WindowManager>>, stream: UnixStream) -> Result<()> {
let stream = BufReader::new(stream);
for line in stream.lines() {
let message = SocketMessage::from_str(&line?)?;
if self.is_paused {
return match message {
SocketMessage::TogglePause | SocketMessage::State | SocketMessage::Stop => {
Ok(self.process_command(message)?)
}
_ => {
tracing::trace!("ignoring while paused");
Ok(())
}
};
}
let mut wm = wm.lock();
self.process_command(message.clone())?;
notify_subscribers(&serde_json::to_string(&Notification {
event: NotificationEvent::Socket(message.clone()),
state: self.as_ref().into(),
})?)?;
if wm.is_paused {
return match message {
SocketMessage::TogglePause | SocketMessage::State | SocketMessage::Stop => {
Ok(wm.process_command(message)?)
}
_ => {
tracing::trace!("ignoring while paused");
Ok(())
}
};
}
Ok(())
wm.process_command(message.clone())?;
notify_subscribers(&serde_json::to_string(&Notification {
event: NotificationEvent::Socket(message.clone()),
state: wm.as_ref().into(),
})?)?;
}
Ok(())
}
pub fn read_commands_tcp(
wm: &Arc<Mutex<WindowManager>>,
stream: &mut TcpStream,
addr: &str,
) -> Result<()> {
let mut stream = BufReader::new(stream);
loop {
let mut buf = vec![0; 1024];
match stream.read(&mut buf) {
Err(..) => {
tracing::warn!("removing disconnected tcp client: {addr}");
let mut connections = TCP_CONNECTIONS.lock();
connections.remove(addr);
break;
}
Ok(size) => {
let message = if let Ok(message) =
SocketMessage::from_str(&String::from_utf8_lossy(&buf[..size]))
{
message
} else {
tracing::warn!("client sent an invalid message, disconnecting: {addr}");
let mut connections = TCP_CONNECTIONS.lock();
connections.remove(addr);
break;
};
let mut wm = wm.lock();
if wm.is_paused {
return match message {
SocketMessage::TogglePause | SocketMessage::State | SocketMessage::Stop => {
Ok(wm.process_command(message)?)
}
_ => {
tracing::trace!("ignoring while paused");
Ok(())
}
};
}
wm.process_command(message.clone())?;
notify_subscribers(&serde_json::to_string(&Notification {
event: NotificationEvent::Socket(message.clone()),
state: wm.as_ref().into(),
})?)?;
}
}
}
Ok(())
}

View File

@@ -20,6 +20,9 @@ use crate::window_manager_event::WindowManagerEvent;
use crate::windows_api::WindowsApi;
use crate::Notification;
use crate::NotificationEvent;
use crate::BORDER_COLOUR_CURRENT;
use crate::BORDER_COLOUR_SINGLE;
use crate::BORDER_COLOUR_STACK;
use crate::BORDER_ENABLED;
use crate::BORDER_HIDDEN;
use crate::BORDER_HWND;
@@ -71,9 +74,9 @@ impl WindowManager {
// Make sure we have the most recently focused monitor from any event
match event {
WindowManagerEvent::MonitorPoll(_, window)
| WindowManagerEvent::FocusChange(_, window)
WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Show(_, window)
| WindowManagerEvent::DisplayChange(window)
| WindowManagerEvent::MoveResizeEnd(_, window) => {
self.reconcile_monitors()?;
@@ -132,7 +135,7 @@ impl WindowManager {
match event {
WindowManagerEvent::Raise(window) => {
window.raise()?;
window.raise();
self.has_pending_raise_op = false;
}
WindowManagerEvent::Destroy(_, window) | WindowManagerEvent::Unmanage(window) => {
@@ -184,22 +187,26 @@ impl WindowManager {
}
WindowManagerEvent::FocusChange(_, window) => {
let workspace = self.focused_workspace_mut()?;
if workspace
if !workspace
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
return Ok(());
}
if let Some(w) = workspace.maximized_window() {
if w.hwnd == window.hwnd {
return Ok(());
}
}
if let Some(w) = workspace.maximized_window() {
if w.hwnd == window.hwnd {
return Ok(());
if let Some(monocle) = workspace.monocle_container() {
if let Some(window) = monocle.focused_window() {
window.focus(false)?;
}
} else {
self.focused_workspace_mut()?
.focus_container_by_window(window.hwnd)?;
}
}
self.focused_workspace_mut()?
.focus_container_by_window(window.hwnd)?;
}
WindowManagerEvent::Show(_, window) | WindowManagerEvent::Manage(window) => {
let mut switch_to = None;
@@ -265,7 +272,7 @@ impl WindowManager {
}
}
}
WindowManagerEvent::MoveResizeStart(_, _) => {
WindowManagerEvent::MoveResizeStart(_, window) => {
let monitor_idx = self.focused_monitor_idx();
let workspace_idx = self
.focused_monitor()
@@ -278,6 +285,8 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no workspace with this idx"))?
.focused_container_idx();
WindowsApi::bring_window_to_top(window.hwnd())?;
self.pending_move_op = Option::from((monitor_idx, workspace_idx, container_idx));
}
WindowManagerEvent::MoveResizeEnd(_, window) => {
@@ -295,147 +304,148 @@ impl WindowManager {
let invisible_borders = self.invisible_borders;
let workspace = self.focused_workspace_mut()?;
if workspace
if !workspace
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
return Ok(());
}
let focused_container_idx = workspace.focused_container_idx();
let focused_container_idx = workspace.focused_container_idx();
let mut new_position = WindowsApi::window_rect(window.hwnd())?;
let mut new_position = WindowsApi::window_rect(window.hwnd())?;
let old_position = *workspace
.latest_layout()
.get(focused_container_idx)
// If the move was to another monitor with an empty workspace, the
// workspace here will refer to that empty workspace, which won't
// have any latest layout set. We fall back to a Default for Rect
// which allows us to make a reasonable guess that the drag has taken
// place across a monitor boundary to an empty workspace
.unwrap_or(&Rect::default());
let old_position = *workspace
.latest_layout()
.get(focused_container_idx)
// If the move was to another monitor with an empty workspace, the
// workspace here will refer to that empty workspace, which won't
// have any latest layout set. We fall back to a Default for Rect
// which allows us to make a reasonable guess that the drag has taken
// place across a monitor boundary to an empty workspace
.unwrap_or(&Rect::default());
// This will be true if we have moved to an empty workspace on another monitor
let mut moved_across_monitors = old_position == Rect::default();
// This will be true if we have moved to an empty workspace on another monitor
let mut moved_across_monitors = old_position == Rect::default();
if let Some((origin_monitor_idx, _, _)) = pending {
// If we didn't move to another monitor with an empty workspace, it is
// still possible that we moved to another monitor with a populated workspace
if !moved_across_monitors {
// So we'll check if the origin monitor index and the target monitor index
// are different, if they are, we can set the override
moved_across_monitors = origin_monitor_idx != target_monitor_idx;
}
}
// Adjust for the invisible borders
new_position.left += invisible_borders.left;
new_position.top += invisible_borders.top;
new_position.right -= invisible_borders.right;
new_position.bottom -= invisible_borders.bottom;
let resize = Rect {
left: new_position.left - old_position.left,
top: new_position.top - old_position.top,
right: new_position.right - old_position.right,
bottom: new_position.bottom - old_position.bottom,
};
// If we have moved across the monitors, use that override, otherwise determine
// if a move has taken place by ruling out a resize
let is_move = moved_across_monitors
|| resize.right == 0 && resize.bottom == 0
|| resize.right.abs() == invisible_borders.right
&& resize.bottom.abs() == invisible_borders.bottom;
if is_move {
tracing::info!("moving with mouse");
if moved_across_monitors {
if let Some((
origin_monitor_idx,
origin_workspace_idx,
origin_container_idx,
)) = pending
{
let target_workspace_idx = self
.monitors()
.get(target_monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
.focused_workspace_idx();
let target_container_idx = self
.monitors()
.get(target_monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
.focused_workspace()
.ok_or_else(|| {
anyhow!("there is no focused workspace for this monitor")
})?
.container_idx_from_current_point()
// Default to 0 in the case of an empty workspace
.unwrap_or(0);
self.transfer_container(
(
origin_monitor_idx,
origin_workspace_idx,
origin_container_idx,
),
(
target_monitor_idx,
target_workspace_idx,
target_container_idx,
),
)?;
// We want to make sure both the origin and target monitors are updated,
// so that we don't have ghost tiles until we force an interaction on
// the origin monitor's focused workspace
self.focus_monitor(origin_monitor_idx)?;
self.focus_workspace(origin_workspace_idx)?;
self.update_focused_workspace(false)?;
self.focus_monitor(target_monitor_idx)?;
self.focus_workspace(target_workspace_idx)?;
self.update_focused_workspace(false)?;
if let Some((origin_monitor_idx, _, _)) = pending {
// If we didn't move to another monitor with an empty workspace, it is
// still possible that we moved to another monitor with a populated workspace
if !moved_across_monitors {
// So we'll check if the origin monitor index and the target monitor index
// are different, if they are, we can set the override
moved_across_monitors = origin_monitor_idx != target_monitor_idx;
}
}
// Adjust for the invisible borders
new_position.left += invisible_borders.left;
new_position.top += invisible_borders.top;
new_position.right -= invisible_borders.right;
new_position.bottom -= invisible_borders.bottom;
let resize = Rect {
left: new_position.left - old_position.left,
top: new_position.top - old_position.top,
right: new_position.right - old_position.right,
bottom: new_position.bottom - old_position.bottom,
};
// If we have moved across the monitors, use that override, otherwise determine
// if a move has taken place by ruling out a resize
let is_move = moved_across_monitors
|| resize.right == 0 && resize.bottom == 0
|| resize.right.abs() == invisible_borders.right
&& resize.bottom.abs() == invisible_borders.bottom;
if is_move {
tracing::info!("moving with mouse");
if moved_across_monitors {
if let Some((
origin_monitor_idx,
origin_workspace_idx,
origin_container_idx,
)) = pending
{
let target_workspace_idx = self
.monitors()
.get(target_monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
.focused_workspace_idx();
let target_container_idx = self
.monitors()
.get(target_monitor_idx)
.ok_or_else(|| anyhow!("there is no monitor at this idx"))?
.focused_workspace()
.ok_or_else(|| {
anyhow!("there is no focused workspace for this monitor")
})?
.container_idx_from_current_point()
// Default to 0 in the case of an empty workspace
.unwrap_or(0);
self.transfer_container(
(
origin_monitor_idx,
origin_workspace_idx,
origin_container_idx,
),
(
target_monitor_idx,
target_workspace_idx,
target_container_idx,
),
)?;
// We want to make sure both the origin and target monitors are updated,
// so that we don't have ghost tiles until we force an interaction on
// the origin monitor's focused workspace
self.focus_monitor(origin_monitor_idx)?;
self.focus_workspace(origin_workspace_idx)?;
self.update_focused_workspace(false)?;
self.focus_monitor(target_monitor_idx)?;
self.focus_workspace(target_workspace_idx)?;
self.update_focused_workspace(false)?;
}
// Here we handle a simple move on the same monitor which is treated as
// a container swap
} else {
match new_window_behaviour {
WindowContainerBehaviour::Create => {
match workspace.container_idx_from_current_point() {
Some(target_idx) => {
workspace
.swap_containers(focused_container_idx, target_idx);
self.update_focused_workspace(false)?;
}
None => {
self.update_focused_workspace(
self.mouse_follows_focus,
)?;
}
}
}
WindowContainerBehaviour::Append => {
match workspace.container_idx_from_current_point() {
Some(target_idx) => {
workspace.move_window_to_container(target_idx)?;
self.update_focused_workspace(false)?;
}
None => {
self.update_focused_workspace(
self.mouse_follows_focus,
)?;
}
}
}
}
}
// Here we handle a simple move on the same monitor which is treated as
// a container swap
} else {
match new_window_behaviour {
WindowContainerBehaviour::Create => {
match workspace.container_idx_from_current_point() {
Some(target_idx) => {
workspace
.swap_containers(focused_container_idx, target_idx);
self.update_focused_workspace(false)?;
}
None => {
self.update_focused_workspace(self.mouse_follows_focus)?;
}
}
}
WindowContainerBehaviour::Append => {
match workspace.container_idx_from_current_point() {
Some(target_idx) => {
workspace.move_window_to_container(target_idx)?;
self.update_focused_workspace(false)?;
}
None => {
self.update_focused_workspace(self.mouse_follows_focus)?;
}
}
}
}
}
} else {
tracing::info!("resizing with mouse");
let mut ops = vec![];
tracing::info!("resizing with mouse");
let mut ops = vec![];
macro_rules! resize_op {
macro_rules! resize_op {
($coordinate:expr, $comparator:tt, $direction:expr) => {{
let adjusted = $coordinate * 2;
let sizing = if adjusted $comparator 0 {
@@ -448,30 +458,31 @@ impl WindowManager {
}};
}
if resize.left != 0 {
ops.push(resize_op!(resize.left, >, OperationDirection::Left));
}
if resize.left != 0 {
ops.push(resize_op!(resize.left, >, OperationDirection::Left));
}
if resize.top != 0 {
ops.push(resize_op!(resize.top, >, OperationDirection::Up));
}
if resize.top != 0 {
ops.push(resize_op!(resize.top, >, OperationDirection::Up));
}
if resize.right != 0 && resize.left == 0 {
ops.push(resize_op!(resize.right, <, OperationDirection::Right));
}
if resize.right != 0 && resize.left == 0 {
ops.push(resize_op!(resize.right, <, OperationDirection::Right));
}
if resize.bottom != 0 && resize.top == 0 {
ops.push(resize_op!(resize.bottom, <, OperationDirection::Down));
}
if resize.bottom != 0 && resize.top == 0 {
ops.push(resize_op!(resize.bottom, <, OperationDirection::Down));
}
for (edge, sizing, delta) in ops {
self.resize_window(edge, sizing, delta, true)?;
}
for (edge, sizing, delta) in ops {
self.resize_window(edge, sizing, delta, true)?;
}
self.update_focused_workspace(false)?;
self.update_focused_workspace(false)?;
}
}
}
WindowManagerEvent::MonitorPoll(..) | WindowManagerEvent::MouseCapture(..) => {}
WindowManagerEvent::DisplayChange(..) | WindowManagerEvent::MouseCapture(..) => {}
};
if *self.focused_workspace()?.tile() && BORDER_ENABLED.load(Ordering::SeqCst) {
@@ -481,21 +492,72 @@ impl WindowManager {
border.hide()?;
BORDER_HIDDEN.store(true, Ordering::SeqCst);
}
WindowManagerEvent::MoveResizeEnd(_, _)
| WindowManagerEvent::Show(_, _)
| WindowManagerEvent::FocusChange(_, _) => {
let window = self.focused_window()?;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= self.invisible_borders.bottom;
rect.bottom += self.invisible_borders.bottom;
let activate = BORDER_HIDDEN.load(Ordering::SeqCst);
WindowManagerEvent::MoveResizeEnd(_, window)
| WindowManagerEvent::Show(_, window)
| WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Hide(_, window)
| WindowManagerEvent::Minimize(_, window) => {
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
border.set_position(*window, &self.invisible_borders, activate)?;
let mut target_window = None;
if self
.focused_workspace()?
.floating_windows()
.iter()
.any(|w| w.hwnd == window.hwnd)
{
target_window = Option::from(*window);
WindowsApi::raise_window(border.hwnd())?;
};
if activate {
BORDER_HIDDEN.store(false, Ordering::SeqCst);
if let Some(monocle_container) = self.focused_workspace()?.monocle_container() {
if let Some(window) = monocle_container.focused_window() {
target_window = Option::from(*window);
}
}
if target_window.is_none() {
match self.focused_container() {
// if there is no focused container, the desktop is empty
Err(..) => {
WindowsApi::hide_border_window(border.hwnd())?;
}
Ok(container) => {
if !(matches!(event, WindowManagerEvent::Minimize(_, _))
&& container.windows().len() == 1)
{
let container_size = self.focused_container()?.windows().len();
target_window = Option::from(*self.focused_window()?);
if container_size > 1 {
BORDER_COLOUR_CURRENT.store(
BORDER_COLOUR_STACK.load(Ordering::SeqCst),
Ordering::SeqCst,
);
} else {
BORDER_COLOUR_CURRENT.store(
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst),
Ordering::SeqCst,
);
}
}
}
}
}
if let Some(target_window) = target_window {
let window = target_window;
let mut rect = WindowsApi::window_rect(window.hwnd())?;
rect.top -= self.invisible_borders.bottom;
rect.bottom += self.invisible_borders.bottom;
let activate = BORDER_HIDDEN.load(Ordering::SeqCst);
WindowsApi::invalidate_border_rect()?;
border.set_position(target_window, &self.invisible_borders, activate)?;
if activate {
BORDER_HIDDEN.store(false, Ordering::SeqCst);
}
}
}
_ => {}

View File

@@ -151,6 +151,14 @@ impl Window {
}
}
pub fn minimize(self) {
WindowsApi::minimize_window(self.hwnd());
}
pub fn close(self) -> Result<()> {
WindowsApi::close_window(self.hwnd())
}
pub fn restore(self) {
let mut programmatically_hidden_hwnds = HIDDEN_HWNDS.lock();
if let Some(idx) = programmatically_hidden_hwnds
@@ -187,25 +195,55 @@ impl Window {
WindowsApi::unmaximize_window(self.hwnd());
}
pub fn raise(self) -> Result<()> {
pub fn raise(self) {
// 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();
WindowsApi::attach_thread_input(current_thread_id, window_thread_id, true)?;
// 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 raise(): {}",
error
);
}
};
// Raise Window to foreground
match WindowsApi::set_foreground_window(self.hwnd()) {
Ok(_) => {}
Err(error) => {
tracing::error!(
"could not set as foreground window, but continuing execution of focus(): {}",
"could not set as foreground window, but continuing execution of raise(): {}",
error
);
}
};
// This isn't really needed when the above command works as expected via AHK
WindowsApi::set_focus(self.hwnd())
match WindowsApi::set_focus(self.hwnd()) {
Ok(_) => {}
Err(error) => {
tracing::error!(
"could not set focus, but continuing execution of raise(): {}",
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 raise(): {}",
error
);
}
};
}
pub fn focus(self, mouse_follows_focus: bool) -> Result<()> {
@@ -227,15 +265,30 @@ impl Window {
};
// Raise Window to foreground
match WindowsApi::set_foreground_window(self.hwnd()) {
Ok(_) => {}
Err(error) => {
tracing::error!(
"could not set as foreground window, but continuing execution of focus(): {}",
error
);
}
};
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();
WindowsApi::allow_set_foreground_window(process_id)?;
tried_resetting_foreground_access = true;
}
}
};
}
// Center cursor in Window
if mouse_follows_focus {
@@ -253,6 +306,16 @@ impl Window {
}
};
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(())
}
@@ -294,7 +357,7 @@ impl Window {
#[tracing::instrument(fields(exe, title))]
pub fn should_manage(self, event: Option<WindowManagerEvent>) -> Result<bool> {
if let Some(WindowManagerEvent::MonitorPoll(_, _)) = event {
if let Some(WindowManagerEvent::DisplayChange(_)) = event {
return Ok(true);
}

View File

@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::collections::VecDeque;
use std::io::ErrorKind;
use std::num::NonZeroUsize;
@@ -15,7 +16,6 @@ use schemars::JsonSchema;
use serde::Serialize;
use uds_windows::UnixListener;
use crate::border::Border;
use komorebi_core::custom_layout::CustomLayout;
use komorebi_core::Arrangement;
use komorebi_core::Axis;
@@ -30,6 +30,7 @@ use komorebi_core::Rect;
use komorebi_core::Sizing;
use komorebi_core::WindowContainerBehaviour;
use crate::border::Border;
use crate::container::Container;
use crate::current_virtual_desktop;
use crate::load_configuration;
@@ -54,6 +55,7 @@ use crate::WORKSPACE_RULES;
#[derive(Debug)]
pub struct WindowManager {
pub monitors: Ring<Monitor>,
pub monitor_cache: HashMap<usize, Monitor>,
pub incoming_events: Arc<Mutex<Receiver<WindowManagerEvent>>>,
pub command_listener: UnixListener,
pub is_paused: bool,
@@ -166,6 +168,7 @@ impl WindowManager {
Ok(Self {
monitors: Ring::default(),
monitor_cache: HashMap::new(),
incoming_events: incoming,
command_listener: listener,
is_paused: false,
@@ -205,7 +208,8 @@ impl WindowManager {
rect.bottom += self.invisible_borders.bottom;
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
border.set_position(foreground_window, &self.invisible_borders, true)
border.set_position(foreground_window, &self.invisible_borders, true)?;
WindowsApi::invalidate_border_rect()
}
#[tracing::instrument(skip(self))]
@@ -325,44 +329,77 @@ impl WindowManager {
#[tracing::instrument(skip(self))]
pub fn reconcile_monitors(&mut self) -> Result<()> {
if self.pending_move_op.is_some() {
return Ok(());
}
let valid_hmonitors = WindowsApi::valid_hmonitors()?;
let mut invalid = vec![];
let mut valid_names = vec![];
let before_count = self.monitors().len();
for monitor in self.monitors_mut() {
if !valid_hmonitors.contains(&monitor.id()) {
let mut mark_as_invalid = true;
// If an invalid hmonitor has at least one window in the window manager state,
// we can attempt to update its hmonitor id in-place so that it doesn't get reaped
if let Some(workspace) = monitor.focused_workspace() {
if let Some(container) = workspace.focused_container() {
if let Some(window) = container.focused_window() {
let actual_hmonitor = WindowsApi::monitor_from_window(window.hwnd());
if actual_hmonitor != monitor.id() {
monitor.set_id(actual_hmonitor);
mark_as_invalid = false;
}
}
}
}
if mark_as_invalid {
invalid.push(monitor.id());
for (valid_name, valid_id) in &valid_hmonitors {
let actual_name = monitor.name().clone();
if actual_name == *valid_name {
monitor.set_id(*valid_id);
valid_names.push(actual_name);
}
}
}
let mut orphaned_containers = vec![];
let mut invalid_indices = vec![];
for (i, invalid) in self
.monitors()
.iter()
.enumerate()
.filter(|(_, m)| !valid_names.contains(m.name()))
{
invalid_indices.push(i);
for workspace in invalid.workspaces() {
for container in workspace.containers() {
// Save the orphaned containers from an invalid monitor
// (which has most likely been disconnected)
orphaned_containers.push(container.clone());
}
}
}
for i in invalid_indices {
if let Some(monitor) = self.monitors().get(i) {
self.monitor_cache.insert(i, monitor.clone());
}
}
// Remove any invalid monitors from our state
self.monitors_mut().retain(|m| !invalid.contains(&m.id()));
self.monitors_mut()
.retain(|m| valid_names.contains(m.name()));
let after_count = self.monitors().len();
if let Some(primary) = self.monitors_mut().front_mut() {
if let Some(focused_ws) = primary.focused_workspace_mut() {
let focused_container_idx = focused_ws.focused_container_idx();
// Put the orphaned containers somewhere visible
for container in orphaned_containers {
focused_ws.add_container(container);
}
// Gotta reset the focus or the movement will feel "off"
focused_ws.focus_container(focused_container_idx);
}
}
let invisible_borders = self.invisible_borders;
let offset = self.work_area_offset;
for monitor in self.monitors_mut() {
let mut should_update = false;
let reference = WindowsApi::monitor(monitor.id())?;
// TODO: If this is different, force a redraw
// If we have lost a monitor, update everything to filter out any jank
let mut should_update = before_count != after_count;
let reference = WindowsApi::monitor(monitor.id())?;
if reference.work_area_size() != monitor.work_area_size() {
monitor.set_work_area_size(Rect {
left: reference.work_area_size().left,
@@ -390,9 +427,51 @@ impl WindowManager {
}
}
#[allow(clippy::needless_collect)]
let old_sizes = self
.monitors()
.iter()
.map(Monitor::size)
.copied()
.collect::<Vec<_>>();
// Check for and add any new monitors that may have been plugged in
WindowsApi::load_monitor_information(&mut self.monitors)?;
let mut check_cache = vec![];
for (i, m) in self.monitors().iter().enumerate() {
if !old_sizes.contains(m.size()) {
check_cache.push(i);
}
}
for i in check_cache {
if let Some(cached) = self.monitor_cache.get(&i).cloned() {
if let Some(monitor) = self.monitors_mut().get_mut(i) {
for (w_idx, workspace) in monitor.workspaces_mut().iter_mut().enumerate() {
if let Some(cached_workspace) = cached.workspaces().get(w_idx) {
workspace.set_layout(cached_workspace.layout().clone());
workspace.set_layout_rules(cached_workspace.layout_rules().clone());
workspace.set_layout_flip(cached_workspace.layout_flip());
workspace.set_workspace_padding(cached_workspace.workspace_padding());
workspace.set_container_padding(cached_workspace.container_padding());
}
}
}
}
}
let final_count = self.monitors().len();
if after_count != final_count {
self.retile_all(true)?;
// Second retile to fix DPI/resolution related jank when a window
// moves between monitors with different resolutions - this doesn't
// really get seen by the user since the screens are flickering anyway
// as a result of the display connections / disconnections
self.retile_all(true)?;
}
Ok(())
}
@@ -1046,8 +1125,10 @@ impl WindowManager {
let origin_workspace =
self.focused_workspace_for_monitor_idx_mut(origin_monitor_idx)?;
origin_workspace
.focus_container(origin_workspace.focused_container_idx() - 1);
if origin_workspace.focused_container_idx() != 0 {
origin_workspace
.focus_container(origin_workspace.focused_container_idx() - 1);
}
}
}
@@ -1250,6 +1331,23 @@ impl WindowManager {
self.update_focused_workspace(self.mouse_follows_focus)
}
#[tracing::instrument(skip(self))]
pub fn promote_focus_to_front(&mut self) -> Result<()> {
self.handle_unmanaged_window_behaviour()?;
tracing::info!("promoting focus");
let workspace = self.focused_workspace_mut()?;
let target_idx = match workspace.layout() {
Layout::Default(_) => 0,
Layout::Custom(custom) => custom
.first_container_idx(custom.primary_idx().map_or(0, |primary_idx| primary_idx)),
};
workspace.focus_container(target_idx);
self.update_focused_workspace(self.mouse_follows_focus)
}
#[tracing::instrument(skip(self))]
pub fn remove_window_from_container(&mut self) -> Result<()> {
self.handle_unmanaged_window_behaviour()?;

View File

@@ -22,7 +22,7 @@ pub enum WindowManagerEvent {
Manage(Window),
Unmanage(Window),
Raise(Window),
MonitorPoll(WinEvent, Window),
DisplayChange(Window),
}
impl Display for WindowManagerEvent {
@@ -77,12 +77,8 @@ impl Display for WindowManagerEvent {
Self::Raise(window) => {
write!(f, "Raise (Window: {})", window)
}
Self::MonitorPoll(winevent, window) => {
write!(
f,
"MonitorPoll (WinEvent: {}, Window: {})",
winevent, window
)
Self::DisplayChange(window) => {
write!(f, "DisplayChange (Window: {})", window)
}
}
}
@@ -99,9 +95,9 @@ impl WindowManagerEvent {
| Self::MoveResizeStart(_, window)
| Self::MoveResizeEnd(_, window)
| Self::MouseCapture(_, window)
| Self::MonitorPoll(_, window)
| Self::Raise(window)
| Self::Manage(window)
| Self::DisplayChange(window)
| Self::Unmanage(window) => window,
}
}
@@ -147,17 +143,6 @@ impl WindowManagerEvent {
None
}
}
WinEvent::ObjectCreate => {
if let Ok(title) = window.title() {
// Hidden COM support mechanism window that fires this event on both DPI/scaling
// changes and resolution changes, a good candidate for polling
if title == "OLEChannelWnd" {
return Option::from(Self::MonitorPoll(winevent, window));
}
}
None
}
_ => None,
}
}

View File

@@ -1,6 +1,9 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::atomic::Ordering;
use color_eyre::eyre::anyhow;
use color_eyre::eyre::Error;
@@ -9,16 +12,16 @@ use windows::core::Result as WindowsCrateResult;
use windows::core::PCSTR;
use windows::core::PWSTR;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::COLORREF;
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Foundation::HINSTANCE;
use windows::Win32::Foundation::HWND;
use windows::Win32::Foundation::LPARAM;
use windows::Win32::Foundation::POINT;
use windows::Win32::Foundation::RECT;
use windows::Win32::Foundation::WPARAM;
use windows::Win32::Graphics::Dwm::DwmGetWindowAttribute;
use windows::Win32::Graphics::Dwm::DwmSetWindowAttribute;
use windows::Win32::Graphics::Dwm::DWMWA_CLOAKED;
use windows::Win32::Graphics::Dwm::DWMWA_EXTENDED_FRAME_BOUNDS;
use windows::Win32::Graphics::Dwm::DWMWA_WINDOW_CORNER_PREFERENCE;
use windows::Win32::Graphics::Dwm::DWMWCP_ROUND;
use windows::Win32::Graphics::Dwm::DWMWINDOWATTRIBUTE;
@@ -28,13 +31,14 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
use windows::Win32::Graphics::Gdi::InvalidateRect;
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
use windows::Win32::Graphics::Gdi::HBRUSH;
use windows::Win32::Graphics::Gdi::HDC;
use windows::Win32::Graphics::Gdi::HMONITOR;
use windows::Win32::Graphics::Gdi::MONITORENUMPROC;
use windows::Win32::Graphics::Gdi::MONITORINFO;
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;
@@ -52,6 +56,7 @@ use windows::Win32::UI::Input::KeyboardAndMouse::SetFocus;
use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR;
use windows::Win32::UI::Shell::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
@@ -66,24 +71,25 @@ use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
use windows::Win32::UI::WindowsAndMessaging::IsIconic;
use windows::Win32::UI::WindowsAndMessaging::IsWindow;
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassA;
use windows::Win32::UI::WindowsAndMessaging::SetClassLongPtrW;
use windows::Win32::UI::WindowsAndMessaging::SetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
use windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
use windows::Win32::UI::WindowsAndMessaging::ShowWindow;
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint;
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT;
use windows::Win32::UI::WindowsAndMessaging::GCLP_HBRBACKGROUND;
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_TOPMOST;
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
use windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
use windows::Win32::UI::WindowsAndMessaging::SPIF_SENDCHANGE;
@@ -97,8 +103,12 @@ use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNOACTIVATE;
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_NOACTIVATE;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOOLWINDOW;
use windows::Win32::UI::WindowsAndMessaging::WS_MAXIMIZEBOX;
use windows::Win32::UI::WindowsAndMessaging::WS_MINIMIZEBOX;
@@ -113,6 +123,8 @@ use crate::monitor::Monitor;
use crate::ring::Ring;
use crate::set_window_position::SetWindowPosition;
use crate::windows_callbacks;
use crate::BORDER_HWND;
use crate::TRANSPARENCY_COLOUR;
pub enum WindowsResult<T, E> {
Err(E),
@@ -187,24 +199,17 @@ impl WindowsApi {
callback: MONITORENUMPROC,
callback_data_address: isize,
) -> Result<()> {
unsafe {
EnumDisplayMonitors(
HDC(0),
std::ptr::null_mut(),
callback,
LPARAM(callback_data_address),
)
}
.ok()
.process()
unsafe { EnumDisplayMonitors(HDC(0), None, callback, LPARAM(callback_data_address)) }
.ok()
.process()
}
pub fn valid_hmonitors() -> Result<Vec<isize>> {
let mut monitors: Vec<isize> = vec![];
let monitors_ref: &mut Vec<isize> = monitors.as_mut();
pub fn valid_hmonitors() -> Result<Vec<(String, isize)>> {
let mut monitors: Vec<(String, isize)> = vec![];
let monitors_ref: &mut Vec<(String, isize)> = monitors.as_mut();
Self::enum_display_monitors(
Option::Some(windows_callbacks::valid_display_monitors),
monitors_ref as *mut Vec<isize> as isize,
monitors_ref as *mut Vec<(String, isize)> as isize,
)?;
Ok(monitors)
@@ -225,7 +230,7 @@ impl WindowsApi {
pub fn load_workspace_information(monitors: &mut Ring<Monitor>) -> Result<()> {
for monitor in monitors.elements_mut() {
let monitor_id = monitor.id();
let monitor_name = monitor.name().clone();
if let Some(workspace) = monitor.workspaces_mut().front_mut() {
// EnumWindows will enumerate through windows on all monitors
Self::enum_windows(
@@ -243,7 +248,7 @@ impl WindowsApi {
for container in workspace.containers_mut() {
for window in container.windows() {
if Self::monitor_from_window(window.hwnd()) != monitor_id {
if Self::monitor_name_from_window(window.hwnd())? != monitor_name {
windows_on_other_monitors.push(window.hwnd().0);
}
}
@@ -270,6 +275,16 @@ impl WindowsApi {
unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) }.0
}
pub fn monitor_name_from_window(hwnd: HWND) -> Result<String> {
// MONITOR_DEFAULTTONEAREST ensures that the return value will never be NULL
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow
Ok(
Self::monitor(unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) }.0)?
.name()
.to_string(),
)
}
pub fn monitor_from_point(point: POINT) -> isize {
// MONITOR_DEFAULTTONEAREST ensures that the return value will never be NULL
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow
@@ -279,10 +294,21 @@ impl WindowsApi {
pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> {
let flags = SetWindowPosition::NO_ACTIVATE;
let position = if top { HWND_TOPMOST } else { HWND_NOTOPMOST };
let position = if top { HWND_TOPMOST } else { HWND_BOTTOM };
Self::set_window_pos(hwnd, layout, position, flags.bits())
}
pub fn bring_window_to_top(hwnd: HWND) -> Result<()> {
unsafe { BringWindowToTop(hwnd) }.ok().process()
}
pub fn raise_window(hwnd: HWND) -> Result<()> {
let flags = SetWindowPosition::NO_MOVE;
let position = HWND_TOPMOST;
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
}
pub fn position_border_window(hwnd: HWND, layout: &Rect, activate: bool) -> Result<()> {
let flags = if activate {
SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE
@@ -290,7 +316,7 @@ impl WindowsApi {
SetWindowPosition::NO_ACTIVATE
};
let position = HWND_BOTTOM;
let position = HWND_NOTOPMOST;
Self::set_window_pos(hwnd, layout, position, flags.bits())
}
@@ -327,6 +353,19 @@ impl WindowsApi {
Self::show_window(hwnd, SW_MINIMIZE);
}
fn post_message(hwnd: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> Result<()> {
unsafe { PostMessageW(hwnd, message, wparam, lparam) }
.ok()
.process()
}
pub fn close_window(hwnd: HWND) -> Result<()> {
match Self::post_message(hwnd, WM_CLOSE, WPARAM(0), LPARAM(0)) {
Ok(_) => Ok(()),
Err(_) => Err(anyhow!("could not close window")),
}
}
pub fn hide_window(hwnd: HWND) {
Self::show_window(hwnd, SW_HIDE);
}
@@ -416,7 +455,9 @@ impl WindowsApi {
// Behaviour is undefined if an invalid HWND is given
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid
let thread_id = unsafe { GetWindowThreadProcessId(hwnd, &mut process_id) };
let thread_id = unsafe {
GetWindowThreadProcessId(hwnd, Option::from(std::ptr::addr_of_mut!(process_id)))
};
(process_id, thread_id)
}
@@ -517,12 +558,7 @@ impl WindowsApi {
let text_ptr = path.as_mut_ptr();
unsafe {
QueryFullProcessImageNameW(
handle,
PROCESS_NAME_WIN32,
PWSTR(text_ptr),
std::ptr::addr_of_mut!(len),
)
QueryFullProcessImageNameW(handle, PROCESS_NAME_WIN32, PWSTR(text_ptr), &mut len)
}
.ok()
.process()?;
@@ -566,14 +602,6 @@ impl WindowsApi {
Ok(())
}
#[allow(dead_code)]
pub fn window_rect_with_extended_frame_bounds(hwnd: HWND) -> Result<Rect> {
let mut rect = RECT::default();
Self::dwm_get_window_attribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &mut rect)?;
Ok(Rect::from(rect))
}
pub fn is_window_cloaked(hwnd: HWND) -> Result<bool> {
let mut cloaked: u32 = 0;
Self::dwm_get_window_attribute(hwnd, DWMWA_CLOAKED, &mut cloaked)?;
@@ -596,24 +624,30 @@ impl WindowsApi {
unsafe { IsIconic(hwnd) }.into()
}
pub fn monitor_info_w(hmonitor: HMONITOR) -> Result<MONITORINFO> {
let mut monitor_info: MONITORINFO = unsafe { std::mem::zeroed() };
monitor_info.cbSize = u32::try_from(std::mem::size_of::<MONITORINFO>())?;
unsafe { GetMonitorInfoW(hmonitor, std::ptr::addr_of_mut!(monitor_info).cast()) }
pub fn monitor_info_w(hmonitor: HMONITOR) -> Result<MONITORINFOEXW> {
let mut ex_info = MONITORINFOEXW::default();
ex_info.monitorInfo.cbSize = u32::try_from(std::mem::size_of::<MONITORINFOEXW>())?;
unsafe { GetMonitorInfoW(hmonitor, &mut ex_info.monitorInfo) }
.ok()
.process()?;
Ok(monitor_info)
Ok(ex_info)
}
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
let monitor_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
let ex_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
let name = OsString::from_wide(&ex_info.szDevice);
let name = name
.to_string_lossy()
.replace('\u{0000}', "")
.trim_start_matches(r"\\.\")
.to_string();
Ok(monitor::new(
hmonitor,
monitor_info.rcMonitor.into(),
monitor_info.rcWork.into(),
ex_info.monitorInfo.rcMonitor.into(),
ex_info.monitorInfo.rcWork.into(),
name,
))
}
@@ -630,7 +664,7 @@ impl WindowsApi {
pv_param: *mut c_void,
update_flags: SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS,
) -> Result<()> {
unsafe { SystemParametersInfoW(action, ui_param, pv_param, update_flags) }
unsafe { SystemParametersInfoW(action, ui_param, Option::from(pv_param), update_flags) }
.ok()
.process()
}
@@ -673,8 +707,8 @@ impl WindowsApi {
unsafe { GetModuleHandleW(None) }.process()
}
pub fn create_solid_brush(r: u32, g: u32, b: u32) -> HBRUSH {
unsafe { CreateSolidBrush(r | (g << 8) | (b << 16)) }
pub fn create_solid_brush(colour: u32) -> HBRUSH {
unsafe { CreateSolidBrush(COLORREF(colour)) }
}
pub fn register_class_a(window_class: &WNDCLASSA) -> Result<u16> {
@@ -692,16 +726,6 @@ impl WindowsApi {
Ok(a == b)
}
pub fn change_border_colour(hwnd: isize, r: u32, g: u32, b: u32) -> Result<usize> {
Result::from(WindowsResult::from(unsafe {
SetClassLongPtrW(
HWND(hwnd),
GCLP_HBRBACKGROUND,
Self::create_solid_brush(r, g, b).0,
)
}))
}
pub fn round_corners(hwnd: isize) -> Result<()> {
let round = DWMWCP_ROUND;
@@ -718,8 +742,8 @@ impl WindowsApi {
pub fn create_border_window(name: PCSTR, instance: HINSTANCE) -> Result<isize> {
unsafe {
CreateWindowExA(
WS_EX_TOOLWINDOW,
let hwnd = CreateWindowExA(
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
name,
name,
WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
@@ -730,9 +754,39 @@ impl WindowsApi {
None,
None,
instance,
std::ptr::null(),
None,
);
SetLayeredWindowAttributes(hwnd, COLORREF(TRANSPARENCY_COLOUR), 0, LWA_COLORKEY);
hwnd
}
.process()
}
pub fn create_hidden_window(name: PCSTR, instance: HINSTANCE) -> Result<isize> {
unsafe {
CreateWindowExA(
WS_EX_NOACTIVATE,
name,
name,
WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None,
None,
instance,
None,
)
}
.process()
}
pub fn invalidate_border_rect() -> Result<()> {
unsafe { InvalidateRect(HWND(BORDER_HWND.load(Ordering::SeqCst)), None, false) }
.ok()
.process()
}
}

View File

@@ -1,19 +1,34 @@
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::COLORREF;
use windows::Win32::Foundation::HWND;
use windows::Win32::Foundation::LPARAM;
use windows::Win32::Foundation::LRESULT;
use windows::Win32::Foundation::RECT;
use windows::Win32::Foundation::WPARAM;
use windows::Win32::Graphics::Gdi::InvalidateRect;
use windows::Win32::Graphics::Gdi::BeginPaint;
use windows::Win32::Graphics::Gdi::CreatePen;
use windows::Win32::Graphics::Gdi::EndPaint;
use windows::Win32::Graphics::Gdi::Rectangle;
use windows::Win32::Graphics::Gdi::SelectObject;
use windows::Win32::Graphics::Gdi::ValidateRect;
use windows::Win32::Graphics::Gdi::HDC;
use windows::Win32::Graphics::Gdi::HMONITOR;
use windows::Win32::Graphics::Gdi::PAINTSTRUCT;
use windows::Win32::Graphics::Gdi::PS_SOLID;
use windows::Win32::System::SystemServices::DBT_DEVNODES_CHANGED;
use windows::Win32::UI::Accessibility::HWINEVENTHOOK;
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
use windows::Win32::UI::WindowsAndMessaging::SPI_ICONVERTICALSPACING;
use windows::Win32::UI::WindowsAndMessaging::SPI_SETWORKAREA;
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
use windows::Win32::UI::WindowsAndMessaging::WM_DEVICECHANGE;
use windows::Win32::UI::WindowsAndMessaging::WM_DISPLAYCHANGE;
use windows::Win32::UI::WindowsAndMessaging::WM_PAINT;
use windows::Win32::UI::WindowsAndMessaging::WM_SETTINGCHANGE;
use crate::container::Container;
use crate::monitor::Monitor;
@@ -22,6 +37,10 @@ use crate::window::Window;
use crate::window_manager_event::WindowManagerEvent;
use crate::windows_api::WindowsApi;
use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL;
use crate::BORDER_COLOUR_CURRENT;
use crate::BORDER_RECT;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::TRANSPARENCY_COLOUR;
pub extern "system" fn valid_display_monitors(
hmonitor: HMONITOR,
@@ -29,8 +48,11 @@ pub extern "system" fn valid_display_monitors(
_: *mut RECT,
lparam: LPARAM,
) -> BOOL {
let monitors = unsafe { &mut *(lparam.0 as *mut Vec<isize>) };
monitors.push(hmonitor.0);
let monitors = unsafe { &mut *(lparam.0 as *mut Vec<(String, isize)>) };
if let Ok(m) = WindowsApi::monitor(hmonitor.0) {
monitors.push((m.name().to_string(), hmonitor.0));
}
true.into()
}
@@ -50,7 +72,24 @@ pub extern "system" fn enum_display_monitor(
}
if let Ok(m) = WindowsApi::monitor(hmonitor.0) {
monitors.elements_mut().push_back(m);
let monitor_index_preferences = MONITOR_INDEX_PREFERENCES.lock();
let mut index_preference = None;
for (index, monitor_size) in &*monitor_index_preferences {
if m.size() == monitor_size {
index_preference = Option::from(index);
}
}
if let Some(preference) = index_preference {
let current_len = monitors.elements().len();
if *preference > current_len {
monitors.elements_mut().reserve(1);
}
monitors.elements_mut().insert(*preference, m);
} else {
monitors.elements_mut().push_back(m);
}
}
true.into()
@@ -120,7 +159,22 @@ pub extern "system" fn border_window(
unsafe {
match message as u32 {
WM_PAINT => {
InvalidateRect(window, std::ptr::null(), true);
let border_rect = *BORDER_RECT.lock();
let mut ps = PAINTSTRUCT::default();
let hdc = BeginPaint(window, &mut ps);
let hpen = CreatePen(
PS_SOLID,
20,
COLORREF(BORDER_COLOUR_CURRENT.load(Ordering::SeqCst)),
);
let hbrush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
SelectObject(hdc, hpen);
SelectObject(hdc, hbrush);
Rectangle(hdc, 0, 0, border_rect.right, border_rect.bottom);
EndPaint(window, &ps);
ValidateRect(window, None);
LRESULT(0)
}
WM_DESTROY => {
@@ -131,3 +185,54 @@ pub extern "system" fn border_window(
}
}
}
pub extern "system" fn hidden_window(
window: HWND,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
unsafe {
match message as u32 {
WM_DISPLAYCHANGE => {
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
WINEVENT_CALLBACK_CHANNEL
.lock()
.0
.send(event_type)
.expect("could not send message on WINEVENT_CALLBACK_CHANNEL");
LRESULT(0)
}
// Added based on this https://stackoverflow.com/a/33762334
WM_SETTINGCHANGE => {
#[allow(clippy::cast_possible_truncation)]
if wparam.0 as u32 == SPI_SETWORKAREA.0
|| wparam.0 as u32 == SPI_ICONVERTICALSPACING.0
{
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
WINEVENT_CALLBACK_CHANNEL
.lock()
.0
.send(event_type)
.expect("could not send message on WINEVENT_CALLBACK_CHANNEL");
}
LRESULT(0)
}
// Added based on this https://stackoverflow.com/a/33762334
WM_DEVICECHANGE => {
#[allow(clippy::cast_possible_truncation)]
if wparam.0 as u32 == DBT_DEVNODES_CHANGED {
let event_type = WindowManagerEvent::DisplayChange(Window { hwnd: window.0 });
WINEVENT_CALLBACK_CHANNEL
.lock()
.0
.send(event_type)
.expect("could not send message on WINEVENT_CALLBACK_CHANNEL");
}
LRESULT(0)
}
_ => DefWindowProcW(window, message, wparam, lparam),
}
}
}

361
komorebic.lib.ahk Normal file
View File

@@ -0,0 +1,361 @@
; Generated by komorebic.exe
Start(ffm, await_configuration, tcp_port) {
RunWait, komorebic.exe start %ffm% --await-configuration %await_configuration% --tcp-port %tcp_port%, , Hide
}
Stop() {
RunWait, komorebic.exe stop, , Hide
}
State() {
RunWait, komorebic.exe state, , Hide
}
Query(state_query) {
RunWait, komorebic.exe query %state_query%, , Hide
}
Subscribe(named_pipe) {
RunWait, komorebic.exe subscribe %named_pipe%, , Hide
}
Unsubscribe(named_pipe) {
RunWait, komorebic.exe unsubscribe %named_pipe%, , Hide
}
Log() {
RunWait, komorebic.exe log, , Hide
}
QuickSaveResize() {
RunWait, komorebic.exe quick-save-resize, , Hide
}
QuickLoadResize() {
RunWait, komorebic.exe quick-load-resize, , Hide
}
SaveResize(path) {
RunWait, komorebic.exe save-resize %path%, , Hide
}
LoadResize(path) {
RunWait, komorebic.exe load-resize %path%, , Hide
}
Focus(operation_direction) {
RunWait, komorebic.exe focus %operation_direction%, , Hide
}
Move(operation_direction) {
RunWait, komorebic.exe move %operation_direction%, , Hide
}
Minimize() {
RunWait, komorebic.exe minimize, , Hide
}
Close() {
RunWait, komorebic.exe close, , Hide
}
CycleFocus(cycle_direction) {
RunWait, komorebic.exe cycle-focus %cycle_direction%, , Hide
}
CycleMove(cycle_direction) {
RunWait, komorebic.exe cycle-move %cycle_direction%, , Hide
}
Stack(operation_direction) {
RunWait, komorebic.exe stack %operation_direction%, , Hide
}
Resize(edge, sizing) {
RunWait, komorebic.exe resize %edge% %sizing%, , Hide
}
ResizeAxis(axis, sizing) {
RunWait, komorebic.exe resize-axis %axis% %sizing%, , Hide
}
Unstack() {
RunWait, komorebic.exe unstack, , Hide
}
CycleStack(cycle_direction) {
RunWait, komorebic.exe cycle-stack %cycle_direction%, , Hide
}
MoveToMonitor(target) {
RunWait, komorebic.exe move-to-monitor %target%, , Hide
}
MoveToWorkspace(target) {
RunWait, komorebic.exe move-to-workspace %target%, , Hide
}
SendToMonitor(target) {
RunWait, komorebic.exe send-to-monitor %target%, , Hide
}
SendToWorkspace(target) {
RunWait, komorebic.exe send-to-workspace %target%, , Hide
}
SendToMonitorWorkspace(target_monitor, target_workspace) {
RunWait, komorebic.exe send-to-monitor-workspace %target_monitor% %target_workspace%, , Hide
}
FocusMonitor(target) {
RunWait, komorebic.exe focus-monitor %target%, , Hide
}
FocusWorkspace(target) {
RunWait, komorebic.exe focus-workspace %target%, , Hide
}
FocusMonitorWorkspace(target_monitor, target_workspace) {
RunWait, komorebic.exe focus-monitor-workspace %target_monitor% %target_workspace%, , Hide
}
CycleMonitor(cycle_direction) {
RunWait, komorebic.exe cycle-monitor %cycle_direction%, , Hide
}
CycleWorkspace(cycle_direction) {
RunWait, komorebic.exe cycle-workspace %cycle_direction%, , Hide
}
MoveWorkspaceToMonitor(target) {
RunWait, komorebic.exe move-workspace-to-monitor %target%, , Hide
}
NewWorkspace() {
RunWait, komorebic.exe new-workspace, , Hide
}
ResizeDelta(pixels) {
RunWait, komorebic.exe resize-delta %pixels%, , Hide
}
InvisibleBorders(left, top, right, bottom) {
RunWait, komorebic.exe invisible-borders %left% %top% %right% %bottom%, , Hide
}
WorkAreaOffset(left, top, right, bottom) {
RunWait, komorebic.exe work-area-offset %left% %top% %right% %bottom%, , Hide
}
AdjustContainerPadding(sizing, adjustment) {
RunWait, komorebic.exe adjust-container-padding %sizing% %adjustment%, , Hide
}
AdjustWorkspacePadding(sizing, adjustment) {
RunWait, komorebic.exe adjust-workspace-padding %sizing% %adjustment%, , Hide
}
ChangeLayout(default_layout) {
RunWait, komorebic.exe change-layout %default_layout%, , Hide
}
LoadCustomLayout(path) {
RunWait, komorebic.exe load-custom-layout %path%, , Hide
}
FlipLayout(axis) {
RunWait, komorebic.exe flip-layout %axis%, , Hide
}
Promote() {
RunWait, komorebic.exe promote, , Hide
}
PromoteFocus() {
RunWait, komorebic.exe promote-focus, , Hide
}
Retile() {
RunWait, komorebic.exe retile, , Hide
}
MonitorIndexPreference(index_preference, left, top, right, bottom) {
RunWait, komorebic.exe monitor-index-preference %index_preference% %left% %top% %right% %bottom%, , Hide
}
EnsureWorkspaces(monitor, workspace_count) {
RunWait, komorebic.exe ensure-workspaces %monitor% %workspace_count%, , Hide
}
ContainerPadding(monitor, workspace, size) {
RunWait, komorebic.exe container-padding %monitor% %workspace% %size%, , Hide
}
WorkspacePadding(monitor, workspace, size) {
RunWait, komorebic.exe workspace-padding %monitor% %workspace% %size%, , Hide
}
WorkspaceLayout(monitor, workspace, value) {
RunWait, komorebic.exe workspace-layout %monitor% %workspace% %value%, , Hide
}
WorkspaceCustomLayout(monitor, workspace, path) {
RunWait, komorebic.exe workspace-custom-layout %monitor% %workspace% %path%, , Hide
}
WorkspaceLayoutRule(monitor, workspace, at_container_count, layout) {
RunWait, komorebic.exe workspace-layout-rule %monitor% %workspace% %at_container_count% %layout%, , Hide
}
WorkspaceCustomLayoutRule(monitor, workspace, at_container_count, path) {
RunWait, komorebic.exe workspace-custom-layout-rule %monitor% %workspace% %at_container_count% %path%, , Hide
}
ClearWorkspaceLayoutRules(monitor, workspace) {
RunWait, komorebic.exe clear-workspace-layout-rules %monitor% %workspace%, , Hide
}
WorkspaceTiling(monitor, workspace, value) {
RunWait, komorebic.exe workspace-tiling %monitor% %workspace% %value%, , Hide
}
WorkspaceName(monitor, workspace, value) {
RunWait, komorebic.exe workspace-name %monitor% %workspace% %value%, , Hide
}
ToggleWindowContainerBehaviour() {
RunWait, komorebic.exe toggle-window-container-behaviour, , Hide
}
TogglePause() {
RunWait, komorebic.exe toggle-pause, , Hide
}
ToggleTiling() {
RunWait, komorebic.exe toggle-tiling, , Hide
}
ToggleFloat() {
RunWait, komorebic.exe toggle-float, , Hide
}
ToggleMonocle() {
RunWait, komorebic.exe toggle-monocle, , Hide
}
ToggleMaximize() {
RunWait, komorebic.exe toggle-maximize, , Hide
}
RestoreWindows() {
RunWait, komorebic.exe restore-windows, , Hide
}
Manage() {
RunWait, komorebic.exe manage, , Hide
}
Unmanage() {
RunWait, komorebic.exe unmanage, , Hide
}
ReloadConfiguration() {
RunWait, komorebic.exe reload-configuration, , Hide
}
WatchConfiguration(boolean_state) {
RunWait, komorebic.exe watch-configuration %boolean_state%, , Hide
}
CompleteConfiguration() {
RunWait, komorebic.exe complete-configuration, , Hide
}
WindowHidingBehaviour(hiding_behaviour) {
RunWait, komorebic.exe window-hiding-behaviour %hiding_behaviour%, , Hide
}
CrossMonitorMoveBehaviour(move_behaviour) {
RunWait, komorebic.exe cross-monitor-move-behaviour %move_behaviour%, , Hide
}
ToggleCrossMonitorMoveBehaviour() {
RunWait, komorebic.exe toggle-cross-monitor-move-behaviour, , Hide
}
UnmanagedWindowOperationBehaviour(operation_behaviour) {
RunWait, komorebic.exe unmanaged-window-operation-behaviour %operation_behaviour%, , Hide
}
FloatRule(identifier, id) {
RunWait, komorebic.exe float-rule %identifier% "%id%", , Hide
}
ManageRule(identifier, id) {
RunWait, komorebic.exe manage-rule %identifier% "%id%", , Hide
}
WorkspaceRule(identifier, id, monitor, workspace) {
RunWait, komorebic.exe workspace-rule %identifier% "%id%" %monitor% %workspace%, , Hide
}
IdentifyObjectNameChangeApplication(identifier, id) {
RunWait, komorebic.exe identify-object-name-change-application %identifier% "%id%", , Hide
}
IdentifyTrayApplication(identifier, id) {
RunWait, komorebic.exe identify-tray-application %identifier% "%id%", , Hide
}
IdentifyLayeredApplication(identifier, id) {
RunWait, komorebic.exe identify-layered-application %identifier% "%id%", , Hide
}
IdentifyBorderOverflowApplication(identifier, id) {
RunWait, komorebic.exe identify-border-overflow-application %identifier% "%id%", , Hide
}
ActiveWindowBorder(boolean_state) {
RunWait, komorebic.exe active-window-border %boolean_state%, , Hide
}
ActiveWindowBorderColour(r, g, b, window_kind) {
RunWait, komorebic.exe active-window-border-colour %r% %g% %b% --window-kind %window_kind%, , Hide
}
FocusFollowsMouse(boolean_state, implementation) {
RunWait, komorebic.exe focus-follows-mouse %boolean_state% --implementation %implementation%, , Hide
}
ToggleFocusFollowsMouse(implementation) {
RunWait, komorebic.exe toggle-focus-follows-mouse --implementation %implementation%, , Hide
}
MouseFollowsFocus(boolean_state) {
RunWait, komorebic.exe mouse-follows-focus %boolean_state%, , Hide
}
ToggleMouseFollowsFocus() {
RunWait, komorebic.exe toggle-mouse-follows-focus, , Hide
}
AhkLibrary() {
RunWait, komorebic.exe ahk-library, , Hide
}
AhkAppSpecificConfiguration(path, override_path) {
RunWait, komorebic.exe ahk-app-specific-configuration %path% %override_path%, , Hide
}
FormatAppSpecificConfiguration(path) {
RunWait, komorebic.exe format-app-specific-configuration %path%, , Hide
}
NotificationSchema() {
RunWait, komorebic.exe notification-schema, , Hide
}
SocketSchema() {
RunWait, komorebic.exe socket-schema, , Hide
}

View File

@@ -1,341 +0,0 @@
; Generated by komorebic.exe
Start(ffm, await_configuration) {
Run, komorebic.exe start %ffm% --await_configuration %await_configuration%, , Hide
}
Stop() {
Run, komorebic.exe stop, , Hide
}
State() {
Run, komorebic.exe state, , Hide
}
Query(state_query) {
Run, komorebic.exe query %state_query%, , Hide
}
Subscribe(named_pipe) {
Run, komorebic.exe subscribe %named_pipe%, , Hide
}
Unsubscribe(named_pipe) {
Run, komorebic.exe unsubscribe %named_pipe%, , Hide
}
Log() {
Run, komorebic.exe log, , Hide
}
QuickSaveResize() {
Run, komorebic.exe quick-save-resize, , Hide
}
QuickLoadResize() {
Run, komorebic.exe quick-load-resize, , Hide
}
SaveResize(path) {
Run, komorebic.exe save-resize %path%, , Hide
}
LoadResize(path) {
Run, komorebic.exe load-resize %path%, , Hide
}
Focus(operation_direction) {
Run, komorebic.exe focus %operation_direction%, , Hide
}
Move(operation_direction) {
Run, komorebic.exe move %operation_direction%, , Hide
}
CycleFocus(cycle_direction) {
Run, komorebic.exe cycle-focus %cycle_direction%, , Hide
}
CycleMove(cycle_direction) {
Run, komorebic.exe cycle-move %cycle_direction%, , Hide
}
Stack(operation_direction) {
Run, komorebic.exe stack %operation_direction%, , Hide
}
Resize(edge, sizing) {
Run, komorebic.exe resize %edge% %sizing%, , Hide
}
ResizeAxis(axis, sizing) {
Run, komorebic.exe resize-axis %axis% %sizing%, , Hide
}
Unstack() {
Run, komorebic.exe unstack, , Hide
}
CycleStack(cycle_direction) {
Run, komorebic.exe cycle-stack %cycle_direction%, , Hide
}
MoveToMonitor(target) {
Run, komorebic.exe move-to-monitor %target%, , Hide
}
MoveToWorkspace(target) {
Run, komorebic.exe move-to-workspace %target%, , Hide
}
SendToMonitor(target) {
Run, komorebic.exe send-to-monitor %target%, , Hide
}
SendToWorkspace(target) {
Run, komorebic.exe send-to-workspace %target%, , Hide
}
SendToMonitorWorkspace(target_monitor, target_workspace) {
Run, komorebic.exe send-to-monitor-workspace %target_monitor% %target_workspace%, , Hide
}
FocusMonitor(target) {
Run, komorebic.exe focus-monitor %target%, , Hide
}
FocusWorkspace(target) {
Run, komorebic.exe focus-workspace %target%, , Hide
}
FocusMonitorWorkspace(target_monitor, target_workspace) {
Run, komorebic.exe focus-monitor-workspace %target_monitor% %target_workspace%, , Hide
}
CycleMonitor(cycle_direction) {
Run, komorebic.exe cycle-monitor %cycle_direction%, , Hide
}
CycleWorkspace(cycle_direction) {
Run, komorebic.exe cycle-workspace %cycle_direction%, , Hide
}
MoveWorkspaceToMonitor(target) {
Run, komorebic.exe move-workspace-to-monitor %target%, , Hide
}
NewWorkspace() {
Run, komorebic.exe new-workspace, , Hide
}
ResizeDelta(pixels) {
Run, komorebic.exe resize-delta %pixels%, , Hide
}
InvisibleBorders(left, top, right, bottom) {
Run, komorebic.exe invisible-borders %left% %top% %right% %bottom%, , Hide
}
WorkAreaOffset(left, top, right, bottom) {
Run, komorebic.exe work-area-offset %left% %top% %right% %bottom%, , Hide
}
AdjustContainerPadding(sizing, adjustment) {
Run, komorebic.exe adjust-container-padding %sizing% %adjustment%, , Hide
}
AdjustWorkspacePadding(sizing, adjustment) {
Run, komorebic.exe adjust-workspace-padding %sizing% %adjustment%, , Hide
}
ChangeLayout(default_layout) {
Run, komorebic.exe change-layout %default_layout%, , Hide
}
LoadCustomLayout(path) {
Run, komorebic.exe load-custom-layout %path%, , Hide
}
FlipLayout(axis) {
Run, komorebic.exe flip-layout %axis%, , Hide
}
Promote() {
Run, komorebic.exe promote, , Hide
}
Retile() {
Run, komorebic.exe retile, , Hide
}
EnsureWorkspaces(monitor, workspace_count) {
Run, komorebic.exe ensure-workspaces %monitor% %workspace_count%, , Hide
}
ContainerPadding(monitor, workspace, size) {
Run, komorebic.exe container-padding %monitor% %workspace% %size%, , Hide
}
WorkspacePadding(monitor, workspace, size) {
Run, komorebic.exe workspace-padding %monitor% %workspace% %size%, , Hide
}
WorkspaceLayout(monitor, workspace, value) {
Run, komorebic.exe workspace-layout %monitor% %workspace% %value%, , Hide
}
WorkspaceCustomLayout(monitor, workspace, path) {
Run, komorebic.exe workspace-custom-layout %monitor% %workspace% %path%, , Hide
}
WorkspaceLayoutRule(monitor, workspace, at_container_count, layout) {
Run, komorebic.exe workspace-layout-rule %monitor% %workspace% %at_container_count% %layout%, , Hide
}
WorkspaceCustomLayoutRule(monitor, workspace, at_container_count, path) {
Run, komorebic.exe workspace-custom-layout-rule %monitor% %workspace% %at_container_count% %path%, , Hide
}
ClearWorkspaceLayoutRules(monitor, workspace) {
Run, komorebic.exe clear-workspace-layout-rules %monitor% %workspace%, , Hide
}
WorkspaceTiling(monitor, workspace, value) {
Run, komorebic.exe workspace-tiling %monitor% %workspace% %value%, , Hide
}
WorkspaceName(monitor, workspace, value) {
Run, komorebic.exe workspace-name %monitor% %workspace% %value%, , Hide
}
ToggleWindowContainerBehaviour() {
Run, komorebic.exe toggle-window-container-behaviour, , Hide
}
TogglePause() {
Run, komorebic.exe toggle-pause, , Hide
}
ToggleTiling() {
Run, komorebic.exe toggle-tiling, , Hide
}
ToggleFloat() {
Run, komorebic.exe toggle-float, , Hide
}
ToggleMonocle() {
Run, komorebic.exe toggle-monocle, , Hide
}
ToggleMaximize() {
Run, komorebic.exe toggle-maximize, , Hide
}
RestoreWindows() {
Run, komorebic.exe restore-windows, , Hide
}
Manage() {
Run, komorebic.exe manage, , Hide
}
Unmanage() {
Run, komorebic.exe unmanage, , Hide
}
ReloadConfiguration() {
Run, komorebic.exe reload-configuration, , Hide
}
WatchConfiguration(boolean_state) {
Run, komorebic.exe watch-configuration %boolean_state%, , Hide
}
CompleteConfiguration() {
Run, komorebic.exe complete-configuration, , Hide
}
WindowHidingBehaviour(hiding_behaviour) {
Run, komorebic.exe window-hiding-behaviour %hiding_behaviour%, , Hide
}
CrossMonitorMoveBehaviour(move_behaviour) {
Run, komorebic.exe cross-monitor-move-behaviour %move_behaviour%, , Hide
}
ToggleCrossMonitorMoveBehaviour() {
Run, komorebic.exe toggle-cross-monitor-move-behaviour, , Hide
}
UnmanagedWindowOperationBehaviour(operation_behaviour) {
Run, komorebic.exe unmanaged-window-operation-behaviour %operation_behaviour%, , Hide
}
FloatRule(identifier, id) {
Run, komorebic.exe float-rule %identifier% "%id%", , Hide
}
ManageRule(identifier, id) {
Run, komorebic.exe manage-rule %identifier% "%id%", , Hide
}
WorkspaceRule(identifier, id, monitor, workspace) {
Run, komorebic.exe workspace-rule %identifier% "%id%" %monitor% %workspace%, , Hide
}
IdentifyObjectNameChangeApplication(identifier, id) {
Run, komorebic.exe identify-object-name-change-application %identifier% "%id%", , Hide
}
IdentifyTrayApplication(identifier, id) {
Run, komorebic.exe identify-tray-application %identifier% "%id%", , Hide
}
IdentifyLayeredApplication(identifier, id) {
Run, komorebic.exe identify-layered-application %identifier% "%id%", , Hide
}
IdentifyBorderOverflowApplication(identifier, id) {
Run, komorebic.exe identify-border-overflow-application %identifier% "%id%", , Hide
}
ActiveWindowBorder(boolean_state) {
Run, komorebic.exe active-window-border %boolean_state%, , Hide
}
ActiveWindowBorderColour(r, g, b) {
Run, komorebic.exe active-window-border-colour %r% %g% %b%, , Hide
}
FocusFollowsMouse(boolean_state, implementation) {
Run, komorebic.exe focus-follows-mouse %boolean_state% --implementation %implementation%, , Hide
}
ToggleFocusFollowsMouse(implementation) {
Run, komorebic.exe toggle-focus-follows-mouse --implementation %implementation%, , Hide
}
MouseFollowsFocus(boolean_state) {
Run, komorebic.exe mouse-follows-focus %boolean_state%, , Hide
}
ToggleMouseFollowsFocus() {
Run, komorebic.exe toggle-mouse-follows-focus, , Hide
}
AhkLibrary() {
Run, komorebic.exe ahk-library, , Hide
}
AhkAppSpecificConfiguration(path, override_path) {
Run, komorebic.exe ahk-app-specific-configuration %path% %override_path%, , Hide
}
FormatAppSpecificConfiguration(path) {
Run, komorebic.exe format-app-specific-configuration %path%, , Hide
}
NotificationSchema() {
Run, komorebic.exe notification-schema, , Hide
}

View File

@@ -1,6 +1,6 @@
[package]
name = "komorebic"
version = "0.1.12"
version = "0.1.14"
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"]
@@ -14,7 +14,7 @@ edition = "2021"
derive-ahk = { path = "../derive-ahk" }
komorebi-core = { path = "../komorebi-core" }
clap = { version = "3", features = ["derive", "wrap_help"] }
clap = { version = "4", features = ["derive", "wrap_help"] }
color-eyre = "0.6"
dirs = "4"
fs-tail = "0.1"
@@ -25,10 +25,11 @@ powershell_script = "1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
sysinfo = "0.26"
uds_windows = "1"
[dependencies.windows]
version = "0.39"
version = "0.43"
features = [
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging"

View File

@@ -10,16 +10,17 @@ use std::io::ErrorKind;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Duration;
use clap::AppSettings;
use clap::ArgEnum;
use clap::Parser;
use clap::ValueEnum;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use fs_tail::TailedFile;
use heck::ToKebabCase;
use lazy_static::lazy_static;
use paste::paste;
use sysinfo::SystemExt;
use uds_windows::UnixListener;
use uds_windows::UnixStream;
use windows::Win32::Foundation::HWND;
@@ -43,6 +44,7 @@ use komorebi_core::Rect;
use komorebi_core::Sizing;
use komorebi_core::SocketMessage;
use komorebi_core::StateQuery;
use komorebi_core::WindowKind;
lazy_static! {
static ref HOME_DIR: PathBuf = {
@@ -74,7 +76,7 @@ trait AhkFunction {
fn generate_ahk_function() -> String;
}
#[derive(Copy, Clone, ArgEnum)]
#[derive(Copy, Clone, ValueEnum)]
enum BooleanState {
Enable,
Disable,
@@ -96,7 +98,7 @@ macro_rules! gen_enum_subcommand_args {
paste! {
#[derive(clap::Parser, derive_ahk::AhkFunction)]
pub struct $name {
#[clap(arg_enum)]
#[clap(value_enum)]
[<$element:snake>]: $element
}
}
@@ -151,7 +153,7 @@ gen_target_subcommand_args! {
macro_rules! gen_workspace_subcommand_args {
// Workspace Property: #[enum] Value Enum (if the value is an Enum)
// Workspace Property: Value Type (if the value is anything else)
( $( $name:ident: $(#[enum] $(@$arg_enum:tt)?)? $value:ty ),+ $(,)? ) => (
( $( $name:ident: $(#[enum] $(@$value_enum:tt)?)? $value:ty ),+ $(,)? ) => (
paste! {
$(
#[derive(clap::Parser, derive_ahk::AhkFunction)]
@@ -162,9 +164,9 @@ macro_rules! gen_workspace_subcommand_args {
/// Workspace index on the specified monitor (zero-indexed)
workspace: usize,
$(#[clap(arg_enum)] $($arg_enum)?)?
$(#[clap(value_enum)] $($value_enum)?)?
#[cfg_attr(
all($(FALSE $($arg_enum)?)?),
all($(FALSE $($value_enum)?)?),
doc = ""$name " of the workspace as a "$value ""
)]
value: $value,
@@ -212,7 +214,7 @@ pub struct WorkspaceLayoutRule {
/// The number of window containers on-screen required to trigger this layout rule
at_container_count: usize,
#[clap(arg_enum)]
#[clap(value_enum)]
layout: DefaultLayout,
}
@@ -233,17 +235,17 @@ pub struct WorkspaceCustomLayoutRule {
#[derive(Parser, AhkFunction)]
struct Resize {
#[clap(arg_enum)]
#[clap(value_enum)]
edge: OperationDirection,
#[clap(arg_enum)]
#[clap(value_enum)]
sizing: Sizing,
}
#[derive(Parser, AhkFunction)]
struct ResizeAxis {
#[clap(arg_enum)]
#[clap(value_enum)]
axis: Axis,
#[clap(arg_enum)]
#[clap(value_enum)]
sizing: Sizing,
}
@@ -277,6 +279,20 @@ struct WorkAreaOffset {
bottom: i32,
}
#[derive(Parser, AhkFunction)]
struct MonitorIndexPreference {
/// Preferred monitor index (zero-indexed)
index_preference: usize,
/// Left value of the monitor's size Rect
left: i32,
/// Top value of the monitor's size Rect
top: i32,
/// Right value of the monitor's size Rect
right: i32,
/// Bottom value of the monitor's size Rect
bottom: i32,
}
#[derive(Parser, AhkFunction)]
struct EnsureWorkspaces {
/// Monitor index (zero-indexed)
@@ -329,7 +345,7 @@ macro_rules! gen_padding_adjustment_subcommand_args {
$(
#[derive(clap::Parser, derive_ahk::AhkFunction)]
pub struct $name {
#[clap(arg_enum)]
#[clap(value_enum)]
sizing: Sizing,
/// Pixels to adjust by as an integer
adjustment: i32,
@@ -349,7 +365,7 @@ macro_rules! gen_application_target_subcommand_args {
$(
#[derive(clap::Parser, derive_ahk::AhkFunction)]
pub struct $name {
#[clap(arg_enum)]
#[clap(value_enum)]
identifier: ApplicationIdentifier,
/// Identifier as a string
id: String,
@@ -369,7 +385,7 @@ gen_application_target_subcommand_args! {
#[derive(Parser, AhkFunction)]
struct WorkspaceRule {
#[clap(arg_enum)]
#[clap(value_enum)]
identifier: ApplicationIdentifier,
/// Identifier as a string
id: String,
@@ -381,26 +397,28 @@ struct WorkspaceRule {
#[derive(Parser, AhkFunction)]
struct ToggleFocusFollowsMouse {
#[clap(arg_enum, short, long, default_value = "windows")]
#[clap(value_enum, short, long, default_value = "windows")]
implementation: FocusFollowsMouseImplementation,
}
#[derive(Parser, AhkFunction)]
struct FocusFollowsMouse {
#[clap(arg_enum, short, long, default_value = "windows")]
#[clap(value_enum, short, long, default_value = "windows")]
implementation: FocusFollowsMouseImplementation,
#[clap(arg_enum)]
#[clap(value_enum)]
boolean_state: BooleanState,
}
#[derive(Parser, AhkFunction)]
struct ActiveWindowBorder {
#[clap(arg_enum)]
#[clap(value_enum)]
boolean_state: BooleanState,
}
#[derive(Parser, AhkFunction)]
struct ActiveWindowBorderColour {
#[clap(value_enum, short, long, default_value = "single")]
window_kind: WindowKind,
/// Red
r: u32,
/// Green
@@ -417,6 +435,9 @@ struct Start {
/// Wait for 'komorebic complete-configuration' to be sent before processing events
#[clap(action, short, long)]
await_configuration: bool,
/// Start a TCP server on the given port to allow the direct sending of SocketMessages
#[clap(action, short, long)]
tcp_port: Option<usize>,
}
#[derive(Parser, AhkFunction)]
@@ -464,7 +485,7 @@ struct FormatAppSpecificConfiguration {
}
#[derive(Parser)]
#[clap(author, about, version, setting = AppSettings::DeriveDisplayOrder)]
#[clap(author, about, version)]
struct Opts {
#[clap(subcommand)]
subcmd: SubCommand,
@@ -509,6 +530,10 @@ enum SubCommand {
/// Move the focused window in the specified direction
#[clap(arg_required_else_help = true)]
Move(Move),
/// Minimize the focused window
Minimize,
/// Close the focused window
Close,
/// Change focus to the window in the specified cycle direction
#[clap(arg_required_else_help = true)]
CycleFocus(CycleFocus),
@@ -591,8 +616,13 @@ enum SubCommand {
FlipLayout(FlipLayout),
/// Promote the focused window to the top of the tree
Promote,
/// Promote the user focus to the top of the tree
PromoteFocus,
/// Force the retiling of all managed windows
Retile,
/// Set the monitor index preference for a monitor identified using its size
#[clap(arg_required_else_help = true)]
MonitorIndexPreference(MonitorIndexPreference),
/// Create at least this many workspaces for the specified monitor
#[clap(arg_required_else_help = true)]
EnsureWorkspaces(EnsureWorkspaces),
@@ -710,6 +740,8 @@ enum SubCommand {
FormatAppSpecificConfiguration(FormatAppSpecificConfiguration),
/// Generate a JSON Schema of subscription notifications
NotificationSchema,
/// Generate a JSON Schema of socket messages
SocketSchema,
}
pub fn send_message(bytes: &[u8]) -> Result<()> {
@@ -763,9 +795,18 @@ fn main() -> Result<()> {
SubCommand::Focus(arg) => {
send_message(&SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?;
}
SubCommand::Close => {
send_message(&SocketMessage::Close.as_bytes()?)?;
}
SubCommand::Minimize => {
send_message(&SocketMessage::Minimize.as_bytes()?)?;
}
SubCommand::Promote => {
send_message(&SocketMessage::Promote.as_bytes()?)?;
}
SubCommand::PromoteFocus => {
send_message(&SocketMessage::PromoteFocus.as_bytes()?)?;
}
SubCommand::TogglePause => {
send_message(&SocketMessage::TogglePause.as_bytes()?)?;
}
@@ -937,16 +978,27 @@ fn main() -> Result<()> {
let script = exec.map_or_else(
|| {
if arg.ffm | arg.await_configuration {
if arg.ffm | arg.await_configuration | arg.tcp_port.is_some() {
format!(
"Start-Process komorebi.exe -ArgumentList {} -WindowStyle hidden",
if arg.ffm && arg.await_configuration {
"'--ffm','--await-configuration'"
} else if arg.ffm {
"'--ffm'"
} else {
"'--await-configuration'"
}
arg.tcp_port.map_or_else(
|| if arg.ffm && arg.await_configuration {
"'--ffm','--await-configuration'".to_string()
} else if arg.ffm {
"'--ffm'".to_string()
} else {
"'--await-configuration'".to_string()
},
|port| if arg.ffm {
format!("'--ffm','--tcp-port={}'", port)
} else if arg.await_configuration {
format!("'--await-configuration','--tcp-port={}'", port)
} else if arg.ffm && arg.await_configuration {
format!("'--ffm','--await-configuration','--tcp-port={}'", port)
} else {
format!("'--tcp-port={}'", port)
}
)
)
} else {
String::from("Start-Process komorebi.exe -WindowStyle hidden")
@@ -957,13 +1009,24 @@ fn main() -> Result<()> {
format!(
"Start-Process '{}' -ArgumentList {} -WindowStyle hidden",
exec,
if arg.ffm && arg.await_configuration {
"'--ffm','--await-configuration'"
} else if arg.ffm {
"'--ffm'"
} else {
"'--await-configuration'"
}
arg.tcp_port.map_or_else(
|| if arg.ffm && arg.await_configuration {
"'--ffm','--await-configuration'".to_string()
} else if arg.ffm {
"'--ffm'".to_string()
} else {
"'--await-configuration'".to_string()
},
|port| if arg.ffm {
format!("'--ffm','--tcp-port={}'", port)
} else if arg.await_configuration {
format!("'--await-configuration','--tcp-port={}'", port)
} else if arg.ffm && arg.await_configuration {
format!("'--ffm','--await-configuration','--tcp-port={}'", port)
} else {
format!("'--tcp-port={}'", port)
}
)
)
} else {
format!("Start-Process '{}' -WindowStyle hidden", exec)
@@ -971,12 +1034,29 @@ fn main() -> Result<()> {
},
);
match powershell_script::run(&script) {
Ok(output) => {
println!("{}", output);
let mut running = false;
while !running {
match powershell_script::run(&script) {
Ok(_) => {
println!("{}", script);
}
Err(error) => {
println!("Error: {}", error);
}
}
Err(error) => {
println!("Error: {}", error);
print!("Waiting for komorebi.exe to start...");
std::thread::sleep(Duration::from_secs(3));
let mut system = sysinfo::System::new_all();
system.refresh_processes();
if system.processes_by_name("komorebi.exe").next().is_some() {
println!("Started!");
running = true;
} else {
println!("komorebi.exe did not start... Trying again");
}
}
}
@@ -1045,6 +1125,18 @@ fn main() -> Result<()> {
.as_bytes()?,
)?;
}
SubCommand::MonitorIndexPreference(arg) => {
send_message(
&SocketMessage::MonitorIndexPreference(
arg.index_preference,
arg.left,
arg.top,
arg.right,
arg.bottom,
)
.as_bytes()?,
)?;
}
SubCommand::EnsureWorkspaces(workspaces) => {
send_message(
&SocketMessage::EnsureWorkspaces(workspaces.monitor, workspaces.workspace_count)
@@ -1052,7 +1144,7 @@ fn main() -> Result<()> {
)?;
}
SubCommand::State => {
let home = HOME_DIR.clone();
let home = DATA_DIR.clone();
let mut socket = home;
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -1068,9 +1160,10 @@ fn main() -> Result<()> {
},
};
let listener = UnixListener::bind(&socket)?;
send_message(&SocketMessage::State.as_bytes()?)?;
let listener = UnixListener::bind(&socket)?;
match listener.accept() {
Ok(incoming) => {
let stream = BufReader::new(incoming.0);
@@ -1086,7 +1179,7 @@ fn main() -> Result<()> {
}
}
SubCommand::Query(arg) => {
let home = HOME_DIR.clone();
let home = DATA_DIR.clone();
let mut socket = home;
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -1102,9 +1195,10 @@ fn main() -> Result<()> {
},
};
let listener = UnixListener::bind(&socket)?;
send_message(&SocketMessage::Query(arg.state_query).as_bytes()?)?;
let listener = UnixListener::bind(&socket)?;
match listener.accept() {
Ok(incoming) => {
let stream = BufReader::new(incoming.0);
@@ -1209,7 +1303,8 @@ fn main() -> Result<()> {
}
SubCommand::ActiveWindowBorderColour(arg) => {
send_message(
&SocketMessage::ActiveWindowBorderColour(arg.r, arg.g, arg.b).as_bytes()?,
&SocketMessage::ActiveWindowBorderColour(arg.window_kind, arg.r, arg.g, arg.b)
.as_bytes()?,
)?;
}
SubCommand::ResizeDelta(arg) => {
@@ -1287,7 +1382,7 @@ fn main() -> Result<()> {
println!("File successfully formatted for PRs to https://github.com/LGUG2Z/komorebi-application-specific-configuration");
}
SubCommand::NotificationSchema => {
let home = HOME_DIR.clone();
let home = DATA_DIR.clone();
let mut socket = home;
socket.push("komorebic.sock");
let socket = socket.as_path();
@@ -1305,6 +1400,40 @@ fn main() -> Result<()> {
send_message(&SocketMessage::NotificationSchema.as_bytes()?)?;
let listener = UnixListener::bind(&socket)?;
match listener.accept() {
Ok(incoming) => {
let stream = BufReader::new(incoming.0);
for line in stream.lines() {
println!("{}", line?);
}
return Ok(());
}
Err(error) => {
panic!("{}", error);
}
}
}
SubCommand::SocketSchema => {
let home = DATA_DIR.clone();
let mut socket = home;
socket.push("komorebic.sock");
let socket = socket.as_path();
match std::fs::remove_file(&socket) {
Ok(_) => {}
Err(error) => match error.kind() {
// Doing this because ::exists() doesn't work reliably on Windows via IntelliJ
ErrorKind::NotFound => {}
_ => {
return Err(error.into());
}
},
};
send_message(&SocketMessage::SocketSchema.as_bytes()?)?;
let listener = UnixListener::bind(&socket)?;
match listener.accept() {
Ok(incoming) => {

BIN
wix/License.rtf Normal file

Binary file not shown.

174
wix/main.wxs Normal file
View File

@@ -0,0 +1,174 @@
<?xml version='1.0' encoding='windows-1252'?>
<!--
Copyright (C) 2017 Christopher R. Field.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
The "cargo wix" subcommand provides a variety of predefined variables available
for customization of this template. The values for each variable are set at
installer creation time. The following variables are available:
TargetTriple = The rustc target triple name.
TargetEnv = The rustc target environment. This is typically either
"msvc" or "gnu" depending on the toolchain downloaded and
installed.
TargetVendor = The rustc target vendor. This is typically "pc", but Rust
does support other vendors, like "uwp".
CargoTargetBinDir = The complete path to the binary (exe). The default would
be "target\release\<BINARY_NAME>.exe" where
"<BINARY_NAME>" is replaced with the name of each binary
target defined in the package's manifest (Cargo.toml). If
a different rustc target triple is used than the host,
i.e. cross-compiling, then the default path would be
"target\<CARGO_TARGET>\<CARGO_PROFILE>\<BINARY_NAME>.exe",
where "<CARGO_TARGET>" is replaced with the "CargoTarget"
variable value and "<CARGO_PROFILE>" is replaced with the
value from the `CargoProfile` variable.
CargoTargetDir = The path to the directory for the build artifacts, i.e.
"target".
CargoProfile = Either "debug" or `release` depending on the build
profile. The default is "release".
Version = The version for the installer. The default is the
"Major.Minor.Fix" semantic versioning number of the Rust
package.
-->
<!--
Please do not remove these pre-processor If-Else blocks. These are used with
the `cargo wix` subcommand to automatically determine the installation
destination for 32-bit versus 64-bit installers. Removal of these lines will
cause installation errors.
-->
<?if $(sys.BUILDARCH) = x64 or $(sys.BUILDARCH) = arm64?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder"?>
<?else ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder"?>
<?endif ?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Id='*' Name='komorebi' UpgradeCode='F8B967B5-7E7B-4E3A-895B-B789EC898B54' Manufacturer='LGUG2Z' Language='1033' Codepage='1252' Version='$(var.Version)'>
<Package Id='*' Keywords='Installer' Description='A tiling window manager for Windows' Manufacturer='LGUG2Z' InstallerVersion='450' Languages='1033' Compressed='yes' InstallScope='perMachine' SummaryCodepage='1252' />
<MajorUpgrade Schedule='afterInstallInitialize' DowngradeErrorMessage='A newer version of [ProductName] is already installed. Setup will now exit.' />
<Media Id='1' Cabinet='media1.cab' EmbedCab='yes' DiskPrompt='CD-ROM #1' />
<Property Id='DiskPrompt' Value='komorebi Installation' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='$(var.PlatformProgramFilesFolder)' Name='PFiles'>
<Directory Id='APPLICATIONFOLDER' Name='komorebi'>
<!--
Disabling the license sidecar file in the installer is a two step process:
1. Comment out or remove the `Component` tag along with its contents.
2. Comment out or remove the `ComponentRef` tag with the "License" Id
attribute value further down in this file.
-->
<Component Id='License' Guid='*'>
<File Id='LicenseFile' Name='License.rtf' DiskId='1' Source='wix\License.rtf' KeyPath='yes' />
</Component>
<Directory Id='Bin' Name='bin'>
<Component Id='Path' Guid='6C6DF276-06C4-4675-BDED-48C5C2BC9BC5' KeyPath='yes'>
<Environment Id='PATH' Name='PATH' Value='[Bin]' Permanent='no' Part='last' Action='set' System='yes' />
</Component>
<Component Id='binary0' Guid='*'>
<File Id='exe0' Name='komorebi.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebi.exe' KeyPath='yes' />
</Component>
<Component Id='binary1' Guid='*'>
<File Id='exe1' Name='komorebic.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\komorebic.exe' KeyPath='yes' />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id='Binaries' Title='Application' Description='Installs all binaries and the license.' Level='1' ConfigurableDirectory='APPLICATIONFOLDER' AllowAdvertise='no' Display='expand' Absent='disallow'>
<!--
Comment out or remove the following `ComponentRef` tag to remove
the license sidecar file from the installer.
-->
<ComponentRef Id='License' />
<ComponentRef Id='binary0' />
<ComponentRef Id='binary1' />
<Feature Id='Environment' Title='PATH Environment Variable' Description='Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location.' Level='1' Absent='allow'>
<ComponentRef Id='Path' />
</Feature>
</Feature>
<SetProperty Id='ARPINSTALLLOCATION' Value='[APPLICATIONFOLDER]' After='CostFinalize' />
<!--
Uncomment the following `Icon` and `Property` tags to change the product icon.
The product icon is the graphic that appears in the Add/Remove
Programs control panel for the application.
-->
<!--<Icon Id='ProductICO' SourceFile='wix\Product.ico'/>-->
<!--<Property Id='ARPPRODUCTICON' Value='ProductICO' />-->
<Property Id='ARPHELPLINK' Value='https://github.com/LGUG2Z/komorebi' />
<UI>
<UIRef Id='WixUI_FeatureTree' />
<!--
Disabling the EULA dialog in the installer is a two step process:
1. Uncomment the following two `Publish` tags
2. Comment out or remove the `<WiXVariable Id='WixUILicenseRtf'...` tag further down
-->
<!--<Publish Dialog='WelcomeDlg' Control='Next' Event='NewDialog' Value='CustomizeDlg' Order='99'>1</Publish>-->
<!--<Publish Dialog='CustomizeDlg' Control='Back' Event='NewDialog' Value='WelcomeDlg' Order='99'>1</Publish>-->
</UI>
<!--
Disabling the EULA dialog in the installer requires commenting out
or removing the following `WixVariable` tag
-->
<WixVariable Id='WixUILicenseRtf' Value='wix\License.rtf' />
<!--
Uncomment the next `WixVaraible` tag to customize the installer's
Graphical User Interface (GUI) and add a custom banner image across
the top of each screen. See the WiX Toolset documentation for details
about customization.
The banner BMP dimensions are 493 x 58 pixels.
-->
<!--<WixVariable Id='WixUIBannerBmp' Value='wix\Banner.bmp'/>-->
<!--
Uncomment the next `WixVariable` tag to customize the installer's
Graphical User Interface (GUI) and add a custom image to the first
dialog, or screen. See the WiX Toolset documentation for details about
customization.
The dialog BMP dimensions are 493 x 312 pixels.
-->
<!--<WixVariable Id='WixUIDialogBmp' Value='wix\Dialog.bmp'/>-->
</Product>
</Wix>