This commit introduces the stackbar feature through careful extracting
and refactoring of code from the Komorebi-UI hard-fork.
Unfortunately on the fork, this feature was not implemented using atomic
commits, which resulted in the implementation here being more of a
"reinterpretation" than a lift-and-shit of the referenced code.
Nevertheless, this commit represents a working version of the stackbar
feature.
resolve#681
This commit adds support for composite rules in the static configuration
file, and for float_identifiers in the applications.yaml file.
A new enum, MatchingRule provides two variants, Simple and Composite,
and is now used in place of IdWithIdentifier throughout komorebi.
In order to keep this new enum lean, a variant for
IdWithIdentifierAndComment has not been added, and references to it in
the old config generation code have been replaced with MatchingRule.
resolve#462, resolve#715, resolve#237
This commit adds a 10 millisecond thread sleep specifically for Firefox
as an interim solution for the race condition which results in new
windows often not being tiled correctly until interacted with.
The idea to add a sleep instead of spamming the output with dbg! calls
comes from @kornel@mastodon.social:
https://mastodon.social/@kornel/112125851048707993
This commit ensures that ApplicationFrameHost.exe applications developed
by Microsoft are raised correctly when a user has the custom komorebi
ffm implementation enabled.
The Win32 API calls EnumWindows and WindowFromPoint return different
HWNDs for the same windows because of some jank in how the
ApplicationFrameHost apps are developed.
To avoid this inconsistency on the Win32 API level, komorebi now queries
its own state when looking up HWNDs for windows at any given cursor
position.
This commit swaps out the old "raise" fn for the more up-to-date and
tested "focus" fn when raising a window for focus when the "komorebi"
implementation of focus follows mouse is enabled.
It seems like when we use the bottom flag, Rainmeter widgets will be
drawn on top of windows that are managed by komorebi. After looking at
the GlazeWM codebase, where this issue does not occur, it seems like the
difference is made by the use of the notopmost flag.
resolve#679
This commit ensures that workspace change events get emitted even when
changing to workspaces with no window containers. Previously these were
failing due to early returns triggered when the workspace focused did
not have a focused container.
This commit fixes a regression that was most likely introduced in #678
which changed a bunch of stuff related to window and border dimension
calculation.
See commit 4e98d7d36d for more information
as the same approach to fix the behaviour there has been applied here.
This commit switches out the serde_json crate with the
serde_json_lenient crate, forked by Google, which allows for JSON files
with comments to be parsed properly.
Users can set the format of komorebi.json to "jsonc" in their editors in
order to write // comments without being faced with lint errors.
The expected file extension remains the same (json). komorebi and
komorebic will not look for files with the "jsonc" file extension or any
other JSON-variant file extension.
resolve#693
This commit fixes a regression that was most likely introduced in #678
which changed a bunch of stuff related to window and border dimension
calculation.
While we could previously assume that the points resize.right and
resize.bottom would always be 0 if we were dealing with a move rather
than a resize, these two points now depend on the values of BORDER_WIDTH
and BORDER_OFFSET. The code has been updated to reflect this and
calculate this constant just-in-time.
This commit introduces the komorebi-client library crate for other Rust
applications to interact with a running instance of komorebi over Unix
Domain Sockets.
Currently the crate re-exports everything one might find in the
komorebi::State struct and everything that is publicly exposed in
komorebi-core.
Public types and methods are still lacking documentation, and this crate
should not be published on crates.io until this is no longer the case.
This commit adds some contribution guidelines and updates the "Window
Manager Event Subscriptions" section with information on using
subscribe-socket and komorebi-client.
This commit includes backwards-compatible renames of
active_window_border_offset and active_window_border_width to
border_offset and border_width respectively.
Since the invisible window border adjustments were removed in #678, the
invisible window borders set by the OS can now also be adjusted via
border_offset and border_width, which is the primary reason for the
rename.
invisible_borders has been marked as deprecated and the previously
deprecated alt_focus_hack option has been removed.
This trades one issue for another, in order of importance:
- Pop-up windows such as a file upload dialog box for Firefox no longer
have a window border drawn over the top - better.
- Opaquely bordered windows without DWM decorations, combined with a -1
offset / single pixel border end up as invisible borders (e.g. EPIC
Games Launcher).
The default window corner rounding is still slightly visible at offset
-1 until this corner radius that completely closes up the transparent
region, without needing to invasively draw over the target window.
topmost has a special meaning, in that it is a sticky raise, which is
not what we want - we don't want to be permanently above all other
windows, as this leads to bugs where for example the windows can end up
stuck above non-topmost windows in a different security context, such as
programs running with administrator priviliges.
In the new border painting strategy, the 20 pixel border is huge. The
border is now offset -1 by default, so as to draw over the standard DWM
1px border (avoiding a "1 pixel see through gap"), and the default width
is 8px.
The SetWindowPos API will inset the provided dimensions by the amount of
space required for window decorations (shadows, etc). Compute the size
of the decorations and add them as padding to the provided size,
resulting in windows being set precisely to the target dimensions.
An active_window_border_width=1, active_window_border_offset=-1 will now
paint over the 1px window decoration consistently.
The border window is always made topmost on resize, so that it paints
over custom borders (e.g. EPIC Games Launcher) as those borders are
opaque and as such a 1px border configuration as above becomes invisible
in that condition.
The layout should leave the space configured for the border, so that the
border always stays within the workspace bounds.
Border offset is cleaned up, as it is no longer a rect, but instead just
a fixed value.
The rect function for adjusting padding now takes a concrete value, as
the optional has no local meaning to the operation, being equivalent to
the default value.
A margin function is added to centralize the notion of increasing the
size of a rect by the given margin, the opposite of the padding
operation.
This fixes a regression from an earlier commit that dropped the DWM
style borders without fixing corner rounding on Windows 11. This is now
fixed for Windows 11 again, while avoiding the extra system border
decorations.
This makes the borders pixel-perfect, and border_overflow can be
disabled on all applications.
Unfortunately this also means we lose the corner rounding, so that may
need to be done differently or the offsets refined in some way to
address that.
Switch to using the DWM API to get Window bounds so as to exclude the
outside of window decorations from the computation.
This is getting close to a precise window size, you can now set an
active border width of 1 and an offset of 1 and get a 1 pixel line
around most windows, except that there's some extra top padding I have
yet to find the cause of.
This implementation needs to be DPI aware, but I haven't yet tested if
the DPI scaling approach is entirely valid - we may instead need to get
the per-monitor DPI scale, identify the monitor the window is on, and
scale to that, rather than using the system wide scale.
Maybe fixes#574
Maybe updates #622
This commit adds the "komorebic whkdrc" command to go along with the
"komorebic configuration" command introduced in
608ec03047, aimed it making it easier to
edit this file using a command line editor.
The "config" command has been renamed in the code to Configuration, with
an alias of "config". The Whkdrc command similarly comes with the "whkd"
alias.
This commit introduces the ability for users to specify colours in the
static config file in either RGB or Hex format.
This is done by introducing a new enum, Colour, which provides variants
wrapping the internal Rgb type, and the HexColour type from the
hex_colour crate. HexColour itself is wrapped in a new struct, Hex, in
order to allow the implementation of the JsonSchema trait.
A number of From<T> implementations have been done in order to make
working with the Colour enum more ergonomic.
Ultimately, the core representation for colours in komorebi remains the
Rgb struct, any and Hex-specified colours will be converted to this Rgb
type before being converted to u32 to pass them on to various Win32 API
calls.
This commit adds the "komorebic config" command as a helper to print the
path to komorebi.json, while respecting the KOMOREBI_CONFIG_HOME
environment variable if it exists.
This is particularly useful for users who wish to edit this file on the
command line, as they can now run commands like:
"lvim $(komorebic config)"
This commit addresses and number of bugs and improves the experience of
working with floating workspaces (ie. Workspace.tile = false).
- When the user moves or resizes a window on a floating workspace,
WindowManagerEvent::MoveResizeStart will no longer trigger, which
prevents the mouse focus from going to the middle of the window rect
after the resize or move action (if mouse_follows_focus = true)
- If active_window_border = true, it will no longer be shown on focused
windows in floating workspaces
- When windows are moved using a komorebic command from a floating
workspace to a tiling workspace and active_window_border = true, the
active window border will be shown again
This commit remove the socket connection retry loop in send_message
which is no longer required after @raggi's changes in
c8f6502b02.
@azinsharaf noticed that when trying to run komorebic commands while
komorebi was not accepting connections, multiple hanging komorebic
instances could be spawned, particularly if commands were retried.
@eythaann proposed an additive fix for this in PR684 but ultimately as
the previous race condition with the query/response commands has been
handed by @raggi we can remove the socket connection retry loop
completely.
This commit addresses a few bugs with regards to maximized window
handling.
- Correctly restoring and focusing when switching to a workspace
containing a window previously maximized with the toggle-maximize
command
- Unmaximizing a window during the initial window scan when the wm
initializes so that windows that are maximized before running komorebi
will no longer have the ugly white bar at the top
- When updating workspace layouts, windows that have been maximized
without using the komorebic toggle-maximize command will be
unmaximized to prevent the wm state drifting out of sync with what is
happening on the screen
This commit ensures that the focus changes to the appropriate window
when a container stack is being cycled through by a user who has
disabled the mouse_follows_focus feature.
fix#680
- Use a single thread to bind the hook, and then start dispatching.
- Use a blocking loop for message dispatching.
- Remove the locks around crossbeam channel, as it's already Send + Sync
This commit splits the komorebi crate into a mixed binary and library
crate.
All types and logic related to window management have been moved under
lib.rs, and are imported from there for use in main.rs, which is now
only responsible for starting and running the window manager process.
In preparation for exposing a new komorebi-client crate in the future,
serde::Deserialize has been derived on Notification and any struct that
may appear in a notification receievd by a process that has subscribed
to event updates.
re #659
This commit adds support for subscriptions via Unix Domain Sockets which
are better suited for IPC between Rust processes compared to Named Pipes
which have issues that I don't want to spend time resolving.
The main motivation for this change is to provide an easy way for the
new zebar project to consume information about komorebi's state in the
Rust backend so that a bar module can be created for komorebi users.
The next step in this process will be to finally refactor the komorebi
crate into a mixed bin/lib crate, and expose all notification-related
structs and maybe some connection helper methods in a new
komorebi-client crate.
The previous "subscribe" and "unsubscribe" komorebic commands have had
the "-pipe" suffix added to them, with aliases in place for the previous
names in order to ensure backwards compat.
Replace the client socket with replies sent on the other side of the
querying stream, for both UDS and TCP clients. This has two results:
unix socket clients such as komorebic no longer race on the socket bind,
fixing the out of order bind error, and the response mixup conditions
that could occur. Queries over TCP now receive replies over TCP, rather
than replies being sent to a future or in-flight command line client.
This commit ensures that the $Env:LOCALAPPDATA/komorebi dir is created
by the quickstart command, as it cannot be assumed that this will always
exist, especially on new machines with recent versions of Windows 11.
fix#671
This commit is a fix that handles a subtle breaking change in
sysinfo::Process:root() which no longer can be used to see if a process
is a scoop shim.
Instead we can stringify the executable path and see if the absolute exe
path contains the substring "shims".
With this fix duplicate process detection is once again working
correctly.
This commit ensures that the KOMOREBI_CONFIG_HOME environment variable is recognized by the
komorebic check command and the static config loader when used to specify the location of the
applications.yaml file.
resolve#660
This commit uses a more reliable Win32 API call to determine the scaling
factor / DPI of user monitors, so that the scale of a window can be
correctly adjusted when moved between monitors with different DPI
settings.
fix#622
This commit adds a new komorebic command, "visible-windows", to make
tracking down ghost windows easier. The returned JSON structure will try
to use the device id to identify a monitor if it is available, or fall
back to the monitor index. Thanks to raggi on Discord for suggesting
this command!
This commit builds on @EBNull's comment shedding light on the uses of
the -A and -W functions in the Win32 API, and standardizes the calling
of the -W functions across the project.
Since UTF-16 String handling is a bit lacking in the Rust standard
library, I have pulled in the widestring crate to use the
from_slice_truncate fn to automagically remove all of the trailing null
chars when handling values returned from the various Win32 -W fns.
Comment ref: 657ac441ae (r135643553)
This commit handles an edge case where the first registered display
monitor has an index preference that is greater than the current length
of the Ring data structure storing the monitors.
re #612
Thanks to @ids1024 for pointing out that the failing system calls were
likely due to optimizations being made with the release profile's
opt-level=3 and to @saethlin for pointing out that in the previous
commit I was returning a pointer to a temporary that was about to be
deallocated.
https://fosstodon.org/@ids1024/111627094548141620https://hachyderm.io/@saethlin/111627135615930244
With this commit, the display ids are now successfully returned from
calls to EnumDisplayDevicesA on release builds.
This commit begins to build on some of the knowledge shared by EBNull in
allowing users to specify monitor index preferences using physical
device identifiers. This does not presently go all the way to EDIDs, but
the display model and what I believe is a port identifier on the display
adapter(s) can be used to uniquely identify a display in most use cases.
However, I believe I may have unfortunately run into a bug in either
windows-rs or Rust itself, as when the code calling EnumDisplayDevices
is called, it always fails when running a release build, and always
succeeds when running a debug build. This needs to be investigated
further.
re #612
This commit attempts to introduce miette to provide users with quick
feedback when there may be syntax errors such as trailing commas in
their komorebi.json configuration file.
The lines and columns reported by serde_json don't actually line up with
the visualization of where we want to indicate a syntax error on the
miette Report. Some hackery has been done, but this should be improved
upon. Notably, this hackery does not accurately reflect the location of
a syntax error when the syntax error is a missing comma after a string
value.
* feat(cli): autostart without a console window
This moves `komorebic` logic into a `lib.rs` file and calls it from `main.rs` (normal behavior) and then there is a second binary `komorebic-no-console` binary that uses `#![windows_subsystem = "windows"]` which tells the linker to not attach a console window to this binary.
* Revert "feat(cli): autostart without a console window"
This reverts commit 08494b46dd.
* feat(cli): autostart without a console window
This creates a second binary `komorebic-no-console` binary that uses `#![windows_subsystem = "windows"]` which tells the linker to not attach a console window to this binary and its only job is to run and pass its args to `komorebic`.
* add behind `--no-console` flag
* reference the new binary in wix
* remove no-console
* fix typo
This commit adds a command to output a JSON Schema for the
applications.yaml file maintained in the
komorebi-application-specific-configuration repo, and also adds an
up-to-date version of the JSON Schema as a file in the root of this
repository so that users can reference it as an autocompletion source.
This commit makes the --config flag on komorebi.exe optional, and
updates the configuration loading logic to try to find a komorebi.json
file in the HOME_DIR, which is either $Env:KOMOREBI_CONFIG_HOME or
$Env:PROFILE.
This unlocks the way for Amr's PR to make the --config flag optional on
the enable-autostart command.
re #596
After another round of deep diving to find a workaround to all of the
mechanisms within Windows that prevent a process from changing the
focused window, I came across this gist which I saw setting
SPI_SETFOREGROUNDLOCKTIMEOUT to 0:
https://gist.github.com/EBNull/1419093
This tentatively seems like it works and it removes the need for the
alt_focus_hack setting.
However, according to this StackOverflow discussion, it seems like on
Win10+ changes to ForegroundLockTimeout in the registry are no longer
respected and changes made via SPI_SETFOREGROUNDLOCKTIMEOUT are not
persisted:
https://stackoverflow.com/questions/73735129/setforegroundwindow-relationship-between-the-foregroundlocktimeout-registry-val
Therefore on starting, komorebi will now check the value with
SPI_GETFOREGROUNDLOCKTIMEOUT and if it is not 0, it will be set to 0.
Logging has been added to inform the user of the changes that are
happening.
This commit ensures that the required calls are made to the system to
enable and disable the Windows focus-follows-mouse implementation when
users make changes to the focus_follows_mouse option in the static
config file.
fix#603
- Avoids unnecessary string allocation when tracing paths
- Replaces `mut path & path.push()` with `path.join()`
- Avoids unncessary cloning of paths where applicable
- Use `dunce` crate to remove `UNC` prefix
- Improve performance of resolving `~` by avoiding unnecessary string allocations
- Resolve `~`, `$Env:USERPROFILE` and `$HOME` consistenly between different code paths
- Use `PathBuf` instead of `String` for paths in CLI args
I may have missed a couple of places but I think I covered 90% of path handling in the codebase
The user dumbhighrank mentioned on Discord that it was not possible to
call enable-autostart with the --ffm flag, as one might expect to be
able to do, given that it is accepted by the start command. This commit
introduces the --ffm flag for the enable-autostart command.
This commit adds a new komorebic quickstart command to handle the
downloading of example configuration files, which is currently done
manually by the user if they are following the quickstart guide on the
README.
re #585
This commit adds a last-second override the string output of the
derive-ahk proc macro for the stop command, which unfortunately ends up
in a broken state in komorebic.lib.ahk with the addition of a 'whkd'
flag in v0.1.19.
fix#578
This commit ensures that when a layout or a custom layout is not defined
for a workspace in the static configuration file, Workspace.tile will be
set to false. Thanks to M. Kichel on Discord for pointing out the need
for this!
This commit fixes a regression introduced in the regex rule matching
refactor.
Invisible borders should be removed from applications that are not
identified as border overflow applications, not vice versa.
This is because applications that are overflowing their borders
effectively erase the invisible borders, while applications that are not
overflowing their borders leave the system's invisible borders
visibility intact.
It is this latter group that we should be targeting with the
should_remove_border variable.
* Command to ToggleLayout
* Just improve logic of figuring out next layout
* Addr review: rename to "Cycle" instead of toggle, and add a small comment
* As per review comments, implement cycle method on DefaultLayout
* I forgot to remove this, my bad
* feat(cli): fixups for cycle-layout cmd
* Update komorebic/src/main.rs
Co-authored-by: Kushashwa Ravi Shrimali <kushashwaravishrimali@gmail.com>
---------
Co-authored-by: LGUG2Z <jadeiqbal@fastmail.com>
Co-authored-by: جاد <LGUG2Z@users.noreply.github.com>
This commit introduce two new commands, enable-autostart and
disable-autostart, to help create shortcuts for users in shell:startup
to automatically start komorebi after logging in.
* Allow different resize constraints for layouts
Change Workspace::enforce_resize_constraints to enforce constraints differently for different layouts
Add enforce_no_resize method for all but bsp layout resize_dimensions
* Add resize constraints for UltrawideVerticalStack layout
Add Workspace::enforce_resize_for_ultrawide method to apply resize
constraints for ultrawide vertical stack layout.
* feat(wm): Use resize_dimensions in calculate for ultrawide layout
Add function calculate_ultrawide_adjustment to calculate adjustments for
individual containers in ultrawide vertical stack layout
Refactor ultrawide layout generation in separate function and use
calculated adjustments
* feat(wm): Enable ultrawide layout in DefaultLayout::resize
* feat(wm): refactor ultrawide resize calculation
Add some helper function and descriptive variable names in calculate_ultrawide_adjustment
Apply clippy lints
This commit ensures that matching strategies can be used wherever
IdWithIdentifier is used, and that they are respected for users opting
to use the static configuration file format.
Some thought and planning needs to go into how this can be backported to
dynamic configurations via the CLI without breaking existing user
configurations.
re #60
This commit is the first in a series of commits which will pave the way
for regex rule matching support in komorebi.
For now, in order to maintain backwards compat and not break anything,
all rules without a matching strategy will get assigned as using the
"Legacy" strategy.
This and the "Equals" strategy are the only two which have been
implemented so far.
There should not be any breaking changes in this commit, not any
functionality lost for users with pre-existing configurations.
re #60
This commit aligns the border option naming and arguments between the
dynamic and static configuration approaches.
The previously named border_width and border_offset options in the
static config will be replaced by active_window_border_width and
active_window_border_offset in v0.1.19.
Similarly the option for the offset will now take a single signed
integer, as it does when using the komorebic command.
re #526
This commit remedies a regression noticed by user @notkvwu in #493,
which results in 'komorebic start' failing, due to an empty ArgumentList
being passed to the PS Start-Process command.
This has been fixed by ensuring that the ArgumentList is only passed
when the user has specified flags on the start command.
fix#493
This commit introduces a new --ahk flag to the start command, which
works similarly to the --whkd, and attempts to load an ahk key binding
configuration script on startup.
The attempt is made from within the komorebic process, rather than the
komorebi process.
resolve#529
This commit adds a '--whkd' flag to the 'komorebic stop' command, which
will also stop any running instance of whkd when stopping the window
manager.
This flag defaults to false, and should not change the existing
behaviour that users are used to.
This commit adds an "monitor_index_preferences" key to the static config
schema, which was missed during the initial rollout of the static
configuration files. To help with testing, these indexes have also been
exposed on the State struct.
resolve#522
This commit is an implementation of a static JSON configuration loader.
An example komorebi.json configuration file has been added.
The application-specific configurations can be loaded directly from a
file, and workspace configuration can be defined declaratively in the
JSON. Individual rules etc. can also be added directly in the static
configuration as one-offs.
A JSONSchema can be generated using komorebic's static-config-schema
command. This should be added to something like SchemaStore later.
Loading from static configuration is significantly faster on startup, as
the lock does not have to be reacquired for every command that is sent
over the socket.
When loading configuration from a static JSON file, a hotwatch instance
will automatically be created to listen to file changes and apply any
updates to both the global and window manager configuration state.
A new --whkd flag has been added to the komorebic start command to
optionally start whkd in a background process.
A new komorebic command 'generate-static-config' has been added to help
existing users migrate to a static JSON config file. Currently, custom
layout file path information can not be automatically populated in the
output of this command and must be added manually by the user if
required.
A new komorebic command 'fetch-asc' has been added to help users update
to the latest version of the application-specific configurations
in-place.
resolve#427
This commit applies a technique shared by Lars from GlazeWM and first
noticed by J.SH on Discord to add the SWP_NOSENDCHANGING flag when
positioning windows to overcome any hard-coded minimum width
restrictions an application might have.
Thanks to @thesobercoder and @olivoil for opening my eyes on this one.
This commit reduces the number of containers required before a custom
layout can be triggered. Please see the closed issue for more discussion
and rationale behind this change.
fix#390
This commit adds a new command, focus-workspaces, to allow the user to
change workspaces across all monitors at the same time. I'm not
convinced of the stability of this command and I would strongly
discourage using komorebi in this manner.
resolve#426
This commit reintroduces some old code from the feature/remove-titlebars
branch. This feature is very unstable and it is strongly advised that
nobody actually uses it. Wherever possible, please use the "remove
titlebar" functionality provided directly within an application.
This commit updates the config generator used by the ahk-asc command to
emit AHKv2 syntax.
An AHKv2 syntax-compatible komorebic.lib.ahk has been (re)introduced to
the repo root as a file to be distributed. This file is created by
taking the AHKv1 syntax output of ahk-library and automatically
converting it to AHKv2 using the automatic script converter by @mmikeww
available on GitHub.
Given that ahk-library is still being used to emit AHKv1 syntax in this
pipeline, it will remain in the repo.
The justfile has been updated to automate as much of this as possible
(the converter still needs to be run manually).
re #324
The whkd process does not start with an s - unless something is wrong or buggy on my computer, it is just "whkd.exe" and so it should be that in this file as well.
A number of people have been tripped up by not having the latest version
of PowerShell installed, which is referenced by the binary "pwsh", so
this commit sets the default .shell in whkdrc.sample to "powershell"
which _should_ come installed with every version of Windows since
Windows 10.
resolve#365
This commit adds a command to generate application-specific
configuration in the format of a PowerShell ps1 file, as well as the
ability to automatically launch a komorebi.ps1 configuration file on
startup.
If a komorebi.ps1 file is found and launched at startup, the
watch-configuration command will watch and hot reload this file when any
changes are made.
A sample komorebi.ps1 file has been added to the root of the repository,
along with a sample whkdrc file, showing how the two can be used
together to replace AHK.
re #339
This commit introduces three new commands, ensure-named-workspaces,
named-workspace-rule, and focus-named-workspace, which email to reduce
the configuration complexity by allowing users to refer to workspace
names instead of monitor and workspace indices.
This commit adds cloaking as a window-hiding-behaviour option.
https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 for
more information on cloaking.
Cloaking is the same mechanism used by the native Virtual Desktops
feature by the Windows team, however it is deliberately hidden from the
public Windows API.
GitHub user Ciantic's VirtualDesktopAccessor crate documents the private
IApplicationView COM interface which contains the hidden and
undocumented SetCloak method, which can be used to cloak and uncloak
application windows by their HWNDs.
With some help from Ciantic and manual exploration to determine the
correct flags values to use, komorebi is now able to use the cloaking
mechanism when switching workspaces, which results in significantly
higher reliability and significantly less jank on workspace transitions.
komorebi's use of this cloaking mechanism also retains the flexibility
of per-monitor workspaces that users have come to know and enjoy.
This has only been tested on Windows 11, it is not yet known if calling
the SetCloak function in IApplicationWindow will cause crashes on
Windows 10.
This commit ensures that when the focus is changed to a monitor with an
empty workspace with the focus-monitor or cycle-monitor commands,
subsequent commands such as focus-workspace will operate successfully on
the chosen monitor.
fix#148
This commit adds an optional focusing hack using simulated ALT key
presses to ensure that focus changes always succeed. As noted in the
documentation for LockSetForegroundWindow, the system automatically
enables calls to SetForegroundWindow if the user presses the ALT key.
This commit ensures that the bounds of the resize_dimensions member on a
workspace are checked before attempting removal when maximizing a window
using the toggle-maximize command or cycle-focus commands.
fix#331
This commit ensures that the force-focus command reads the window
manager state to get the coordinates of the window that should be
currently focused, places the cursor in the middle of that rect, and
then simulates a left-click.
This commit introduces a new command, active-window-border-offset, which
allows the user to offset the starting position of the active window
border, thereby allowing for thicker or thinner active window borders,
when used in conjunction with the active-window-border-width command.
resolve#232
On rare occasions and usually with Firefox, the desired application will
fail to be focused with the regular focus commands. This commit
introduces a new command, force-focus, which can be used to simulate a
left-click on a window that has failed to take focus, since this is what
I have to do to work around the issue anyway.
This commit introduces a new command which lets the user set a custom
width value for the active window border when it is enabled.
Unfortunately a little more width is required when working with rounded
windows on Windows 11 to fill the gap left by the rounding. The default
width remains set at 20.
re #232
This commit introduces two new commands which will allow the user to
move or send the currently focused window to either the next or previous
workspace depending on the cycle direction.
re #297
This commit removes the focused window monocle/maximized check when
trying to focus a container in a direction that requires the focus to
cross a monitor boundary.
Unfortunately, trying to remove the same check from the move command
results in undesired behaviour (the wrong window gets moved, the state
gets funny on both the origin and the destination monitor)
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
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
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
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
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
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
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.
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.
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
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.
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
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
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
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
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
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
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
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
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.
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.
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
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
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
This commit enforces a check to ensure that the active-window-border
configuration is enabled before trying to redraw a border than has been
hidden by a drag or move event.
This commit ensures that active window border updates in the event
processing loop are skipped if the current workspace has tiling
disabled. Previously this check was not enforced so the border would
reappear on a workspace that had disabled tiling after new events had
been processed.
This commit ensures that when the workspace-tiling command is called to
disable tiling for a workspace, that the border is also disabled for the
duration that tiling is diabled. This was previously only implemented
for the toggle-tiling command.
This commit introduces a few changes to reduce border jank, especially
when switching workspaces:
- The border is hidden before the windows start to reorganize when a
workspace switching command is received instead of after
- Avoid unncessary window.focus() call when switching workspace
- Use WindowManager.focused_window() instead of the window received from
the WindowManagerEvent when updating or setting the active border
position as it more accurately matches user expectations when
switching back to a workspace to find the focused window being the one
that you left when you switched away
This commit ensures that failures to focus on the Settings and similar
windows on Windows 11 will allow execution to continue so that the
active window border location can be updated without exiting early from
the command handler with a propagated error.
This commit ensures that when a custom layout is loaded, either manually
or via a workspace layout rule trigger threshold being amtched, any
layout_flip property for the impacted workspace will be removed, to
allow for key bindings to work as expected on the custom layout.
This commit adds an optional active window border with a user-defined
colour. This is achieved by spawning a dedicated "border window" and
constantly placing it behind the focused window, or hiding it whenever
necessary.
Some constraints to note:
- The border will only be applied to windows managed by komorebi
- This means that if you temporarily float a window, it will lose the
active window border
- There are some issues where parts of the border will be broken by
applications like Zoom, even if Zoom is behind the currently focused
window
- You probably want to turn off window shadows globally in Advanced
System Settings -> Performance for the borders to have a consistent
colour all the way around the window
- There is some inevitable jank due to trying to reposition both the
focused window and the "border window" behind it simultaneously
- There are no borders for unfocused windows
resolve#182
This commit introduces a new flag to komorebi and komorebic,
--await-configuration, which when enabled, will stop the process from
processing window manager events and updating the layout until the
'komorebic complete-configuration' command has been sent.
This should typically be added at the end of a user's komorebi.ahk
configuration file if they decide to enable this feature.
resolve#190
This commit ensures that monocle containers and floating windows are
considered validate candidates for the 'toggle-maximize' command and are
handled accordingly if the command is called when they are in the
foreground.
fix#194
This commit ensures that monocle containers and maximized windows are
considered valid candidates for the 'toggle-float' command and are
handled accordingly if the command is called when they are in the
foreground.
fix#193
This commit improves Windows path resolution so that when people run the
ahk-asc command with "applications.yaml" as an argument, without having
".\" prepended, the command will still succeed as expected.
fix#192
This commit ensures that if a window maximized using the 'komorebic
toggle-maximize' is minimized using the UI, on the receipt of the
Minimize WindowManagerEvent, the window will be normalized with
SW_NORMAL before being removed from the window manager state.
This ensures that if the window is later managed again, the user will be
able to toggle-maximize normally again as expected.
This commit ensures that when a window has matched a float rule, the
managed override rule will only apply to that window if the override
identifier is of the same kind (exe, title, class) as the float rule
identifier.
This ensures that the wm isn't constantly trying to allow and disallow
certain windows such as Slack's hidden window, resulting in an infinite
show/hide and retile loop.
This commit fixes a bug with the startup check which tries to ensure
that there is only ever one instance of komorebi running at any given
time.
Previously, only one shim was being checked for, but if a user runs
'komorebic start' multiple times, multiple shims will be active, causing
the check to mistakenly pass.
The changes in this commit now account for N active shims.
This commit ensures that the final argument of the
'workspace-layout-rule' command, which takes a variant of the
DefaultLayout enum, is properly labelled with the #[arg_enum] tag so
that serialization and deserialization works as expected with other
commands that take a DefaultLayout enum variant as an arg.
fix#171
This commit ensures that manage rules have priority over float rules.
This is useful for applications such as Steam, where all windows
including pop-ups have the same class name.
The class name can be used with a float rule to ensure that all Steam
pop-up windows are ignored, and then the title "Steam" can be used with
a manage rule to ensure that the main Steam window does get managed.
fix#163
This commit provides two new commands, to set and toggle the behaviour
(swap, insert) when moving window containers across monitor boundaries.
MoveBehaviour::Swap has been selected as the default as this seems to be
the default on bspwm.
resolve#145
This commit ensures that when moving across a monitor boundary, the
origin window container will be swapped with the last focused window
container on the other side of the monitor boundary.
If there is no window container on the other side of the window
boundary, it will be treated as a move instead of a swap.
re #145
This commit ensures that when focusing across a monitor boundary, the
focus will go to the last focused window container on the focused
workspace on the other side of a given window boundary.
re #145
This commit introduces the ability to operate across monitor boundaries
with the 'move' and 'focus' commands.
When operating down or to the right, the target index of the monitor in
that direction will be 0. When operating up or to the left, the target
index will either be len() - 1 if focusing, or len() if moving.
re #145
This commit ensures that border overflow applications are correctly
identified as being moved instead of being resized when dragged to a new
position using the mouse.
fix#159
This commit introduces two new environment variables to override the exe
name that komorebi uses to verify that AutoHotKey is installed before
launching and reloading 'komorebi.ahk' configuration files.
resolve#147
This commit ensures that a custom layout that is set by a layout rule
will correctly have the width of the primary column increased or
decreased when resize-axis is called with Axis::Horizontal.
re #154
This commit allows the Window.focus() fn to continue execution if
AttachThreadInput fails, as there are valid situations in which this
might fail, but the focusing of the window may/should still succeed.
fix#156
This commit tweaks how float rule matching for titles and classes works.
Previously, they required an exact match to be triggered.
This change allows starts_with and ends_with matches on classes and
window titles to also trigger a float rule for applications that
dynamically change their window titles or window classes.
Exe matches are still required to be exact.
This commit ensures that what monitor reconciliation is triggered from a
MonitorPoll event, the focused monitor is only updated when the HWND
associated with the event is known not to be tied to a specific (in this
case, the primary) monitor.
This ensures that silent state updates do not occur and avoids
unexpected behaviour when performing operations relative to the
currently focused window on a non-primary display (focus, move etc.)
This commit adds a new command, 'unmanaged-window-operation-behaviour'
which allows the user to configure their desired behaviour in situations
when sending window container commands which operate on the focused
window container in the workspace state, but having an unmanaged window
as the foreground hwnd.
The default previously was previously Op (and this remains the default
with these new changes), but the user can now select NoOp, which will
return an error when the focused hwnd is unmanaged and not allow any
write operations to take place on the focused workspace state.
resolve#133
This commit ensures that the origin workspace will be updated after a
container is removed to be sent to a target workspace (specified, or
currently focused) on another monitor.
With this change in place, moving window containers to another monitor
should not result in a ghost container that remains until the next
retile on the origin workspace.
fix#132
@riverar pointed out on Discord that I had my if and else clauses here
mixed up. This commit reintroduces null value checks for HWNDs returned
from Windows API calls.
Previously, generated AHK did not surround with quotes inputs which
could contain spaces such as application titles. This commit ensures
that in any generated AHK code where an application id is passed to a
komorebic.exe command as input, that input will always be quoted.
This fixes bugs related to float rules, manage rules and other
application identification commands not being properly executed via
komorebic called from the generated AHK files when the app id contained
a space.
Small commit to temporarily handle a regression introduced by my changes
when upgrading from 0.34 to 0.35.
Checking for a 0 HWND value results in an Err being propagated in fns
like GetForegroundWindow, while the error message just reads "The
operation completed successfully. (os error 0)".
This behaviour was causing regressions in features such as window
floating which seems to be resolved by removing the 0 HWND check.
This commit adds a second optional argument to the ahk-asc command which
can take an override yaml file. This file can include either entirely
new entries that are not suitable for the asc definitions in the
community repo, or overrides for entries that exist in the community asc
definitions files which will take precedence in the generated ahk file.
This can be useful for example, when the default behaviour for an app is
to minimise to system tray, but that option has been disabled on a
user's computer, making the 'tray_and_multi_window' option no longer
appropriate for their komorebi configuration.
In the case of wanting to override an existing entry, only the "name"
key needs to match; upon a match the entry from the community asc
definitions will be entirely replaced with the entry from the override
definitions.
re #62
This commit adds a fmt command which allows users to prepare PRs to the
configuration repository in a unified way.
The 'custom' formatter basically just ensures that the yaml array is
sorted by application name to make for easier diffs.
Serializing of Option::None has been disabled to keep the yaml file more
concise.
Finally, an option for adding comments to float rules has been included
as some of these rules can be quite esoteric and there is value in
having them annotated with comments in the configuration to preserve and
pass down the knowledge.
The config generation command has been renamed to
'ahk-app-specific-configuration' (with a short alias of 'ahk-asc') to
emphasise that an ahk file is being generated (similar to
'ahk-library').
re #62
This commit introduces a configuration generator for
application-specific config options passed to the cli via a file path.
The hope is to have a public repository that any user can contribute
application-specific configs and fixes to, and for the generated AHK to
be available to any new user as part of the initial setup to make the
onboarding as frictionless as possible.
re #62
Users on Discord noted that Microsoft Office applications were not being
handled correctly by the wm. After some investigation it was clear that
this was because the application windows had WS_EX_LAYERED set.
This had only been seen once before with Steam, and so a whitelist for
layered applications was previously added to the codebase with steam.exe
hard-coded, but this had not been exposed via the cli.
This commit adds a command to allow users to specify layered
applications which should be managed, and also renames the whitelist to
reflect that classes can also be used to identify applications on the
whitelist.
A section has been added to the README to guide Microsoft Office users
to guide Microsoft Office users in configuring komorebi to correctly
handle Office applications with Word given as an example.
This commit also renames the identify-border-overflow command to
identify-border-overflow-application for consistency, while retaining
the previous command as an alias to maintain compatibility with existing
user configurations.
It should be noted however, that those like me who are using the
generated komorebic AHK library, will have to update any AHK function
calls to use IdentifyBorderOverflowApplication().
resolve#124
This commit introduces focus cycling behaviour for a workspace when
either a maximized window or a monocle window exists.
Now, the container in the cycle direction relative to the current window
container will take the maximized or monocle window container space
whenever the cycle-focus command is called.
resolve#97
This commit adds a new feature which allows the user to specify a set of
rules for a specific workspace that will be used to calculate which
layout to apply to that workspace at any given time.
The rule consists of a usize, which identifies the threshold of window
containers which need to be visible on the workspace to activate the
rule, and a layout, which will be applied to the workspace when the rule
is activated.
Both default and custom layouts can be used in workspace layout rules.
When a workspace has layout rules in effect, manually changing the
layout will not work again until the rules for that workspace have been
cleared.
This feature came about after trying but failing to modify the custom
layout code in such a way that the width percentage of a primary column
in a custom layout might be propagated to the fallback columnar layout
when the tertiary column threshold is not met.
Although this new feature introduces more complexity, it is strictly
opt-in and can be completely ignored if the user has no interest in
adjusting layouts based on the visible window count.
re #121
A user on the Discord noted that PyCharm windows were not being managed
as expected when initially launched. After some digging this seems to be
the same issue that was addressed for IntelliJ and Firefox early on in
development, where these applications send EVENT_OBJECT_NAMECHANGE on
launch instead of the regular event when drawing a new window.
The OBJECT_NAME_CHANGE_ON_LAUNCH vec was not previously exposed via
komorebic to allow users to identify other applications that exhibit the
same behaviour. This commit adds a command to allow users to specify
further applications in their configuration files.
This commit introduces the 'notification-schema' command to generate a
JSON schema of the Notification struct which gets sent when notifying
subscribers of updates.
This commit introduces a change to allow users to set a custom
configuration directory for Komorebi to address concerns about $HOME
getting cluttered.
The custom directory can be set with the environment variable
$Env:KOMOREBI_CONFIG_HOME (this should probably be done in $PROFILE).
If this variable is not set, komorebi will default to using
the $HOME directory.
resolve#61
This commit addresses issues that users have been faced with when
installing komorebi with scoop, which resulted in komorebi exiting
almost immediately without providing any feedback as to what had
happened.
Scoop launches komorebi using an exe shim of the same name, which
results in two komorebi.exe named processes running at the same time.
This situation then fails the startup check which attempts to ensure
that only one instance of komorebi.exe ever runs at any given time.
The process startup check has been updated to allow for two komorebi.exe
named processes to be running if one of them is recognised as a Scoop
shim process.
fix#95
This update ensures that whenever a new float rule is added, the focused
workspaces on all monitors will be checked to see if there are any
currently managed windows which match that rule. If so, the matching
window(s) will be removed from the workspace and the workspace will be
updated.
Matching windows on non-focused workspaces will not be removed, as these
windows may be hidden, and removing them could result in these windows
being inaccessible, requiring them to be killed before they can be
relaunched
fix#93
This commit adds a new komorebic command to move the entire focused
workspace and all managed windows and containers to a target monitor
index. Windows that have been excluded from management using various
rules will not be moved as they are not tracked in the window manager
state.
resolve#88
This commit ensures that errors are sent to komorebic in response to the
state command if they occur, so that komorebic is not left hanging
indefinitely waiting for a successful response that will never come.
This commit fixes a regression introduced in
85fe20ebba, where running komorebi before
creating and interacting with virtual desktops via the task view on
Windows 10 would cause komorebi to panic when it could not find the
CurrentVirtualDesktop key in the registry, as it only gets populated
after interacting with virtual desktops via the task view in a new
session.
This commit adds a new command which allows the focusing of workspaces
on monitors other than the currently focused monitor by specifying a
monitor index.
Sending this command to komorebi will make the target monitor index the
currently focused monitor.
resolve#85
This commit refactors the validations that ensure that only commands and
events originating on the same virtual desktop that komorebi was started
on are managed.
This was previously handled by the winvd crate which relied on
undocumented APIs that broke as of Windows 11. This method, while not
very elegant, seems like the best solution for now.
In short, komorebi checks the registry (which has different paths on
Win10 and Win11...) to keep track of the current virtual desktop id.
This is problematic because we just end up comparing byte arrays, and
there is no meaningful representation of the ids that are being
compared, not even a GUID. Nevertheless, it works and it ensures that
komorebi is limited to operating on a single virtual desktop.
resolve#77
This commit adds a command to let the user decide if they want windows
to be hidden with SW_HIDE or minimized with SW_MINIMIZE when workspaces
are changed or window container stacks are cycled.
After a modest amount of local testing, SW_MINIMIZE does not appear to
introduce any regressions, and given that alt-tabbing is a common
workflow on Windows, it makes sense to have minimizing be the default
setting to ease the onboarding experience for new users.
resolve#72
This commit adds OPContainerClass and IHWindowClass to the
FLOAT_IDENTIFIERS global vec, to ignore by default the extra invisible
input and output handling windows created by mstsc.exe when WSL is
launched on Windows 11.
fix#74
This commit ensures that when a window is dragged over another window container while
WindowContainerBehaviour::Append is set, the window will be removed from its current
container and appended to the target container instead of swapping the positions of the two
containers, as would be the case for WindowContainerBehaviour::Create.
re #72
This commit introduces a new command, toggle-new-window-behaviour, which
can be used to toggle how new windows on the screen will be handled.
The default setting is to add a new window in a dedicated container, but
when toggled, new windows will be stacked on top of the currently
focused window container.
This can be useful if you only want to use a certain number of columns,
and when you have enough windows on the screen for them, you can toggle
the new window behaviour to start appending to the existing column
stacks.
This commit also fixes a bug where stacked windows being closed did
cause the next window underneath in the stack to be shown.
re #72
This commit allows the resize-axis cmd on Axis::Horizontal to operate on
the Primary column of a CustomLayout.
Note that this will only operate on a CustomLayout that has met the
window count threshold to enable the tertiary column. If it has not, the
layout will render as DefaultLayout::Columns, which does not support the
resize-axis cmd.
This commit adds a command to set the resize delta used under the hood
by the resize-edge and resize-axis commands. The resize delta defaults
to 50 pixels as was hard-coded previously.
This commit updates a number of komorebic subcommand names while
maintaining their old names as aliases in order to preserve backwards
compatibility.
Resize becomes ResizeEdge, to complement ResizeAxis, and all of the
commands for saving and loading BSP resize adjustments (QuickSave,
QuickLoad, Save, Load) are now post-fixed with "Resize" in order to make
it clear that these commands are not related to custom layout saving and
loading.
This commit adds a new command to resize by axis. Resizing is still
limited to the BSP layout. This command is intended to be bound to mouse
wheel up and down events, with different modified keys determining the
axis to operate on.
This commit ensures that when a window is dragged across a monitor
boundary, the ownership of the window container will be transferred to
the target monitor's currently focused workspace.
In order to achieve this, a new WindowManagerEvent variant has been
added, MoveResizeStart, which will store an optional pending_move_op on
the WindowManager struct. This must be consumed at the beginning of the
handler for MoveResizeEnd.
This is necessary because as soon as the window is dragged across a
monitor boundary, an event is sent (and handled) to update the currently
focused monitor and workspace as the target monitor and workspace, and
we still need to have the information about the original monitor,
workspace and container in order to make comparisons and ultimately
remove the origin container to be able to transfer it.
fix#58
This commit bumps the version of the windows-rs and deprecates the
bindings crate in favour of using the pre-packaged APIs that are
available as of 0.22.
This commit embeds the latest window manager state (as returned from
'komorebic.exe state') as part of the event notifications sent to
subscribers.
Separately, WindowManager.update_focused_workspace has been refactored
to allow a failure to set the foreground window to the default desktop
window on an empty workspace to log a warning instead of returning an
error, allowing messages previously impacted by this to run to
conclusion and be surfaced in the event notifications stream.
resolve#56
I came across some panics when trying to run the custom serialization of
the Window struct for windows that were in the process of being
destroyed recently.
This commit replaces all of the expect() calls in the Serialize
implementation for Window with calls to serde::ser::Error::custom()
which should fail gracefully without rendering the thread that
previously panicked as useless.
fix#55
This commit renames add-subscriber and remove-subscriber to subscribe
and unsubscribe for more semantic consistency in command names, as well
as improving and fixing the cli documentation for these commands.
@denBot's example of how to create named pipes and subscribe to events
has also been added to the readme.
This commit adds two new commands to add and remove subscribers to
WindowManagerEvent and SocketMessage notifications after they have been
handled by komorebi.
Interprocess communication is achieved using Named Pipes; the
subscribing process must first create the Named Pipe, and then run the
'add-subscriber' command, specifying the pipe name as the argument
(without the pipe filesystem path prepended).
Whenever a pipe is closing or has been closed, komorebi will flag this
as a stale subscription and remove it automatically.
resolve#54
This commit adds some documentation around custom layouts as well as a
YAML example.
The load-layout command has been renamed to load-custom-layout for
consistency.
resolve#50
This commit adds support for loading custom layouts from yaml files, and
also moves the custom layout loading and validating logic into the
komorebi-core crate.
re #50
This commit adds a ColumnWidth for Column::Primary which can optionally
be given as a percentage of the total work area of a monitor. The
remaining columns will have their widths calculated by dividing the
remaining work area space evenly.
This commit also fixes a bug with the Promote command, which was not
calculating the primary container index of custom layouts properly, and
was also not using this value to update the focused container index at
the end of the promotion handler.
re #50
This commit introduces a number of refactors to layouts in general in
order to enable navigation across custom layouts and integrate both
default and custom layouts cleanly into komorebi and komorebic.
Layout has been renamed to DefaultLayout, and Layout is now an enum with
the variants Default and Custom, both of which implement the new traits
Arrangement (for layout calculation) and Direction (for operation
destination calculation).
CustomLayout has been simplified to wrap Vec<Column> and no longer
requires the primary column index to be explicitly defined as this can
be looked up at runtime for any valid CustomLayout.
Given the focus on ultrawide layouts for this feature, I have disabled
(and have not yet written the logic for) vertical column splits in
custom layouts.
Since CustomLayouts will be loaded from a file path, a bunch of
clap-related code generation stuff has been removed from the related
enums and structs.
Layout flipping has not yet been worked on for custom layouts.
When switching between Default and Custom layout variants, the primary
column index and the 0 element are swapped to ensure that the same
window container is always at the focal point of every layout.
Resizing/dragging to resize is in a bit of weird spot at the moment
because the logic is only implemented for DefaultLayout::BSP right now
and nothing else. I think eventually this will need to be extracted to a
Resize trait and implemented on everything.
This commit introduces a new Trait, Dimensions, which requires the
implementation of a fn calculate() -> Vec<Rect>, a fn that was
previously limited to the Layout struct.
Dimensions is now implemented both for Layout and the new CustomLayout
struct, the latter being a general adaptive fn which employs a number of
fallbacks to sane defaults when the the layout does not have the minimum
number of required windows on the screen.
The CustomLayout is mainly intended for use on ultra and superultrawide
monitors, and as such uses columns as a basic building block. There are
three Column variants: Primary, Secondary and Tertiary.
The Primary column will typically be somewhere in the middle of the
layout, and will be where a window is placed when promoted using the
komorebic command.
The Secondary column is optional, and can be used one or more times in a
layout, either splitting to accomodate a certain number of windows
horizontally or vertically, or not splitting at all.
The Tertiary window is the final window, which will typically be on the
right of a layout, which must be split either horizontally or vertically
to accomodate as many windows as necessary.
The Tertiary column will only be rendered when the threshold of windows
required to enable it has been met. Until then, the rightmost Primary or
Secondary column will expand to take its place.
If there are less windows than (or a number equal to the) columns
defined in the layout, the windows will be arranged in a basic columnar
layout until the number of windows is greater than the number of columns
defined in the layout.
At this point, although the calculation logic has been completed, work
must be done on the navigation logic before a SocketMessage variant can
be added for loading custom layouts from files.
This commit introduces an allow_wsl2_gui override in
Window.should_manage() which ensures that Linux GUI apps being run
through WSLg, VcXsrv or X410 will be automatically tiled.
For now the exes that trigger this override are kept in a static Vec in
the codebase, but this could be made configurable in the future if there
is a specific feature request.
resolve#52, resolve#53
This commit applies 'cargo fix --edition' to safely migrate the project
to Edition 2021 of Rust.
A rustfmt.toml has also be added to enforce the flattening of use
statements when running 'cargo fmt'.
This commit fixes a boolean logic error with an extra pair of parens to
ensure that apps like Firefox don't end up with their HWNDs reaped by
Workspace.remove_window() when another window is stocked on top of them.
fix#51
This commit extracts independent functions for calculating row and
column layouts in an arbitrary work area. This should be useful in the
future for some ideas I have around custom serializable layouts.
This commit ports the CenterMain, MainAndVertStack, and
MainAndHorizontalStack layouts from LeftWM to komorebi as
UltrawideVerticalStack, VerticalStack and HorizontalStack.
These layouts are fixed-size layouts, meaning that individual containers
cannot be resized. The VerticalStack and UltrawideVerticalStack layouts
support horizontal flipping, whereas the HorizontalStack layout supports
vertical flipping.
resolve#48
This commit adds a new komorebic command to specify offsets for work
areas to be applied across all monitors. The areas covered by these
offsets will be excluded from the tiling area, and can be used for
custom task bars, Rainmeter desktop widgets etc.
When setting an offset at the top, the same offset will need to be
applied to the bottom to ensure that the tiling area is not pushed off
of the screen, but this is not necessary when applying an offset to the
bottom as the top of the work area will never go lower than 0.
resolve#46
This commit adds focusing and moving window containers using cycle
directions when the layout has not been flipped on any axis.
This naive implementation simply increments or decrements the index
number in the desired direction and does not accomodate for axis
flipping.
When the current index number is either at the beginning or the end of
the collection, further operations will loop around.
Ideally I would like an implementation which works coherently on any
LayoutFlip state, but this can be implemented at a later date if
specifically requested in the future.
re #47
This commit expands on the autosave/load functionality to allow saving
and loading layouts from any file.
Handling relative paths and paths with ~ on Windows is a little tricky
so I added a helper fn to komorebic to deal with this, ensuring all the
processing happens in komorebic before the messages get sent to komorebi
for processing.
There will still some lingering uses of ContextCompat around the
codebase which I also took the opportunity to clean up and replace with
ok_or_else + anyhow!().
windows-rs is also updated to 0.20.1 in the lockfile.
resolve#41
This commit adds two new komorebic commands to quicksave and quickload
BSP layouts with custom resize dimensions. The quicksave file is stored
at ${Env:TEMP}/komorebi.quicksave.json, and is a Vec<Option<Rect>>
serialized to JSON.
If a user tries to quickload without a quicksave file being present, an
error will be logged.
At this point there is only one quicksave file which will always be
overwritten whenever the quicksave command is called. Both commands will
only operate on the focused workspace of the focused monitor.
This means that you can quicksave a layout on one workspace, and then
quickload it onto multiple other workspaces (individually) on the same
or other monitors.
If the number of elements in the deserialized Vec is greater than the
number of containers on a workspace, the Vec will be truncated when
Workspace.update is run, and similarly if the number of elements is less
than the number of containers on a workspace, the Vec will be extended
by the difference using None values.
resolve#39
Whatever resize dimensions are at the front of the workspace were
previously being thrown away and overwritten with None whenever a
Promote command was being handled.
This commit preserves any resize dimensions that may already be there
and restores them after the container promotion has been completed.
fix#40
The 0.20.0 release of windows-rs includes a Handle trait which provides
ok() and invalid() fns for implementors, including HWND and HANDLE.
This is pretty cool (and also a big breaking change since the release
takes away is_null() at the same time...), so the code in windows_api.rs
has been updated to make use of this by implementing a
ProcessWindowsCrateResult trait with a process() fn.
When implemented for a windows::Result<T>, it will do any required
processing for T, and ensure that windows::Error is converted to an
eyre-compatible Report.
Switching to this means that I have been able to get rid of some of the
hacky error handling for weird behaviours encountered previously. So
far, they don't seem to be presenting again, but I will run with this
build for a couple of days to see if the false-negative errors are
really gone for good with this update.
This commit expands the reconcile_monitors fn to also update resolution
and work area sizes if they are different from what is stored in the
window manager state.
Another WindowManagerEvent has been added as a polling mechanism for
monitor-related changes (scaling, dpi, resolution etc.), and this will
now also trigger the reconcile_monitors fn in the existing event
pre-processing block.
resolve#36
Following the discovery that the custom FFM implementation significantly
increases CPU usage, and that the underlying library used to track mouse
events is already as optimised as possible for CPU usage, this commit
makes the enabling of custom FFM explicit via a command line flag when
launching the window manager.
The underlying library does not provide for a way to clean up and
recreate a message loop on demand, which means that once it starts,
there is no way of reclaiming those CPU cycles even when FFM is
disabled.
If a user has not started komorebi with the --ffm flag and tries to
enable or toggle custom FFM, a warning will be shown in the logs and
komorebi will override their selection to operate on the Windows FFM
implementation.
In light of this, the default implementation values for komorebic's FFM
commands have been updated to 'windows'.
This commit also takes the opportunity to allow the state and stop
commands to pass when the window manager is in a paused state.
resolve#33
This commit ensures that the focused workspace on the target monitor is
updated with the latest layout after it receives a window via the
send-to-monitor command.
resolve#37
Following the changes I witnessed in the invisible window border size
following an OS update, this commit makes the invisible border offset
configurable via a new komorebic command 'invisible-borders'.
When sending a new set of invisible border offset dimensions via
komorebic, a full retile across all monitors will take place after the
new values have been set.
The default values have been set to what is currently correct for my
machine, and will likely be updated again in the same way in the future
if further changes occur in subsequent OS updates.
This commit also updates some dependencies to their latest releases, and
removes from the CI workflow a line that attempts to delete the
rustup-init.exe binary after installation which has been causing builds
to fail.
resolve#35
Applications like Spotify and Discord draw over the default invisible
borders of Windows 10, which means that when komorebi is setting their
positions, the offset is always off by the amount of pixels of the
invisible borders on each side.
This commit makes it possible to identify applications that have
overflowing borders so that they can be handled appropriately by the
window manager.
This commit also takes the opportunity to consolidate the tray and multi
window identifiers into a single vector instead of spreading them across
multiple vectors by identifier type.
resolve#32
When monitors turn on and off, they do not retain their hmonitor id,
therefore this commit introduces an initial attempt to reconcile invalid
and valid hmonitors after monitor changes based on the windows that are
assigned to them.
If a monitor has at least one window, and has been assigned a new
hmonitor id, komorebi will look up the current hmonitor of that window's
hwnd and update Monitor.id in-place.
When reconciling monitors, any monitor marked as invalid will be purged
from the window manager state.
This commit also applies some of the new clippy lints that come along
with the latest nightly release of Rust.
resolve#31
Explorer windows are made up of multiple different sub-windows which can
make trouble for the ffm implementation if not known about.
This commit pushes up a check to ignore the raise request if the window
are the cursor position is already raised and in the foreground, and
also makes checks against an overlay_classes array to try and look up an
underlying hwnd that should probably be raised by a cursor move.
Previously, when switching focus from unmanaged windows such as the
taskbar and the system tray, komorebi would still recognise its last
known focused window as the currently focused window although that would
not be strictly true, making the ffm functionality stop working until
focus was set to a known window specifically either via a click or an
alt-tab.
This commit fixes that by always also comparing against what the OS has
registered as the current foreground window.
There is another little fix here to reset the pending raise op tracker
whenever ffm is toggled or disabled in the event that it ever gets
stuck.
This commit adds an optional flag to allow users to select the focus
follows mouse implementation that they wish to use (komorebi or
windows). The flag defaults to komorebi.
The ahk-derive crate has been updated to enable the generation of
wrappers fns that require flags.
I pushed the ffm check up to listen_for_movements() so that we don't
even try to listen to the next event from the message loop unless
komorebi-flavoured ffm is enabled.
re #7
This commit implements an initial attempt at a custom focus follows
mouse and autoraise implementation which only responds to hwnds managed
by komorebi.
I was browsing GitHub and came across the winput crate which has a clean
API for tracking both mouse movements and button presses, which seems to
be just enough to get this functionality working.
Once again, Chromium and Electron are the bane of every platform they
run on and Windows is no exception, so I've had to add a hack to work
around the legacy Chrome windows that get drawn on top of Electron apps
with the Chrome_RenderWidgetHostHWND class.
It is fairly naive; it just looks up an alternative (and hopefully
correct) hwnd based on the exe name, but this will no doubt be fragile
when it comes to applications that have multiple windows spawned from
the same exe.
For now I've opted to keep the same komorebic commands for enabling,
disabling and toggling focus-follows-mouse, in order to preserve
backwards compat, but those commands will now enable and disable this
custom implementation instead of the native Windows X-Mouse
implementation.
Perhaps in the future the specific implementation to target could be
specified through the use of an optional flag.
re #7
If a user wants to switch workspace on a secondary monitor which
contains no windows, komorebi doesn't register the monitor as focused
unless the corresponding komorebic command to switch monitor focus is
called explicitly. This generally works fine for users with a
keyboard-heavy workflow.
This commit changes the workspace switching behaviour to look up the
current monitor based on the cursor position just before the switch
takes place, so that the behaviour is still intuitive when trying to
change the monitor focus via the mouse.
re #30
This commit adds a new query command to komorebic, which allows for the
current focused monitor, workspace, container and window indices to be
queried directly without having to use jq run lookups on the entire
output of the state command.
resolve#24
Adding a section under ##About for links to translations of the document
in other languages, starting with @crosstyan's Chinese translation.
resolve#21
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See bug
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots and Videos**
Add screenshots and videos to help explain your problem.
**Operating System**
Provide the output of `systeminfo | grep "^OS Name\|^OS Version"`
For example:
```
OS Name: Microsoft Windows 11 Pro
OS Version: 10.0.22000 N/A Build 22000
```
**`komorebic check` Output**
Provide the output of `komorebic check`
For example:
```
No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\LGUG2Z
Looking for configuration files in C:\Users\LGUG2Z
No komorebi configuration found in C:\Users\LGUG2Z
If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration
```
**Additional context**
Add any other context about the problem here.
In particular, if you have any other AHK scripts or software running that handle any aspect of window management or manipulation
{"event":{"type":"FocusChange","content":["SystemForeground",{"hwnd":329264,"title":"den — Mozilla Firefox","exe":"firefox.exe","class":"MozillaWindowClass","rect":{"left":1539,"top":894,"right":1520,"bottom":821}}]},"state":{}}
in [komokana](https://github.com/LGUG2Z/komokana/blob/feature/komorebi-uds/src/main.rs).
## 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.
# Appreciations
- First and foremost, thank you to my wife, both for naming this project and for her patience throughout its never-ending development
- Thank you to [@sitiom](https://github.com/sitiom) for being [an exemplary open source community leader](https://jeezy.substack.com/p/the-open-source-contributions-i-appreciate)
- Thank you to the developers of [nog](https://github.com/TimUntersberger/nog) who came before me and whose work taught me more than I can ever hope to repay
- Thank you to the developers of [GlazeWM](https://github.com/lars-berger/GlazeWM) for pushing the boundaries of tiling window management on Windows with me and having an excellent spirit of collaboration
- Thank you to [@Ciantic](https://github.com/Ciantic) for helping me bring the [hidden Virtual Desktops cloaking function](https://github.com/Ciantic/AltTabAccessor/issues/1) to `komorebi`
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.