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 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 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 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
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.
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
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
This commit removes the unnecessary eyre dependency and instead uses the
relevant imports from color-eyre.
Additionally, after reading the eyre readme a little more closely, I
have switched out .compat() for the ok_or() combinator function as
suggested here: https://github.com/yaahc/eyre#compatibility-with-anyhow.
Woke up today and thought this would be a cool way to learn more about
deriving functionality with proc macros.
Hopefully having this wrapper/helper library will make first time
configuration for new users easier.
Silly boolean error meant that if a link was clicked in one
monitor/workspace, the browser, if not on the same workspace, would be
brought into the workspace the link was clicked in.
This was because I was checking if the focused monitor != the known
monitor && the focused workspace != the known workspace, when in fact,
we don't need both of those conditions to be true in order to switch to
where the browser is, we only need one of them to be true.
After changing the && (and) to a || (or), the behaviour is now as
expected, and clicking a link will switch to the workspace where the
browser is open.
This feature allows users to specify which monitor/workspace an
application's window, identified either by executable name or window
class name, should be assigned to.
A new fn, WindowManager.enforce_workspace_rules, is called whenever a
new rule is added, and periodically whenever an event is processed by
komorebi (just after orphan windows are repead, before the matching and
processing of the specific event).
Both class and exe identifiers are stored in the same HashMap for the
sake of simplicity, as I couldn't think of any situations where there
might be a clash between the two identifiers.
Did some light refactoring of window_manager.rs to make the new()
constructor a static method on the WindowManager struct.
Also fixed a bug in Workspace.new_container_for_window where the focused
index was not getting set correctly when the workspace had no
containers.
An issue was reported in which switching between Windows Virtual
Desktops was causing issues with the layout generation. This was due to
WinEvents being emitted from other Virtual Desktops ending up in the WM
state when they shouldn't.
This commit introduces a check to ensure that the WM will only listen to
events and commands emitted from the Windows Virtual Desktop that it was
started on.
fix#15
I used a parking_lot to detect what I suspected to be the deadlock
resulting in issue #13.
I was pleasantly surprised by the alternative to std::sync::Mutex
provided by parking_lot, especially not having to unlock it to use it,
and of course the excellent and intuitive (even if experimental)
deadlock detector.
I have decided to use parking_lot::Mutex as an almost-drop-in
replacement for std::sync::Mutex, as I expect that this isn't the last
time komorebi will have a deadlocking issue, and I have put the deadlock
detection code which runs in a separate thread behind a
"deadlock_detection" feature.
The actual deadlock itself was solved by scoping the first lock in the
handler for WindowManagerEvent::Hide and then executing any required
operations (some of which, like window.maximize(), may require another
lock on HIDDEN_HWNDS) in a separate scope once the previous lock has
been dropped.
In the future I should look at integrating globals like HIDDEN_HWNDS
into WindowManager in a way that won't lead to double-mutable-borrow
issues.
fix#13
This commit adds a log command directly to the komorebic cli to make it
easier for users to check the logs if they don't have tail installed or
are not familiar with it.
A separate logfile with ANSI color codes is now being written to the
user's tempdir, which is tailed by the log command until the process is
halted by a Ctrl-C signal.
The latest clap beta introduced a lot of breaking changes for komorebic,
so I decided it was a good time to refactor a little and add
documentation to all of the cli commands.
The primary change for komorebic is that subcommands now only take
structs as arguments, so every enum must be wrapped in a struct. Some
macros have been introduced to ease this.
Using on|off alongside enable|disable for BooleanState arguments has
been deprecated, going forward only enable|disable will be supported.
The commands to introduce float rules have been refactored to make use
of ApplicationTarget, and a single command 'float-rule' has been
introduced in the cli.
Finally I took some time to standardise the sample AHK config a little,
primarily making sure that command prompt windows are never shown for
any of the configuration commands.
BREAKING CHANGE: float-exe, float-class, and float-title have been
deprecated in favour of float-rule in komorebic. workspace-tiling now
only accepts enable|disable as valid inputs to the final arg,
deprecating the previously also valid on|off.
re #8
Adds two new commands that enable the manual reloading of an AHK config
file in the default location and the watching and automatic reloading of
an AHK config file in the default location.
When AutoHotKey is detected, and %USERPROFILE%\komorebi.ahk exists,
komorebi.exe will now try to run the ahk script after starting the
command listener.
For this to work smoothly, it is important to set the #SingleInstance
directive to Force in komorebi.ahk, which will ensure that duplicates of
the script are not run, and a new version of the script is loaded
without displaying a GUI confirmation prompt.
resolve#3
This commit introduces the getset crate to reduce a lot of the
boilerplate, especially in workspace.rs, around different variations of
getters. Hopefully this will make the codebase easier to navigate for
contributors in the future.
Also trying to avoid pinning to patch versions and minor versions
wherever possible.
Using macros to generate common type-specific Ring element accessors.
Should make codebase navigation a little easier my making logic-heavy
functions more visible in impl blocks.
The last remaining feature to bring komorebi to feature parity with
yatta. Implementing this in komorebi was a lot harder because I had to
make sure that resizing worked even when the layout is flipped (in any
one of the three possible ways).
In yatta, resize dimension information was stored on the window. In
komorebi, I initially tried storing this information on the Container
itself, but eventually decided to store it for all Containers in the
Workspace.
There is some additional work required to ensure that this Vec is kept
up to date whenever containers are added or destroyed, but it all seems
to be working fairly well.
I got rid of the iterative fibonacci code that I adapted from leftwm and
went back and reworked the recursive code that I was using in yatta
(originally from umberwm I think) to integrate layout flipping. At least
for me, it is much easier to reason about.
This stores a constantly updated list of known HWNDs at
~/komorebi.hwnd.json which can be used to restore windows that may
disappear into a permanently hidden state during development using a new
'restore-windows' command with komorebic.
Added a query command to komorebic to return the WindowManager struct
serialized to JSON to help with debugging and maybe help others to build
tools like stackline for yabai in the future.
This commit fixes issues with toggling on and off Monocle and Floating
Window mode by ensuring that the relevant windows are always at the top
of the Z order, and in the latter case, ensuring that the top visible
window is used to search the local floating window state of the process.
After some experimenting I seem to have been able to adjust to remove
all of the invisible window borders by default, so if desired, a user
can now have no gaps at all.
Also upgraded to the latest version of the windows-rs crate since I saw
it was available. Thankfully no breaking changes.