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
Previously, the implementation of maximized and monocle windows assumed
that the only valid state for them to transition to would be to restore
them to the index that they were maximized/monocle-d from in their host
workspace.
This is not exclusively the case as it is also possible for them to be
closed when they are in a maximized or monocle state.
This commit updates the Workspace.remove_window() fn to also look for
the hwnd to be removed in the monocle container and maximized window, if
they exist.
fix#19
This commit adds two commands to allow the user to send the currently
focused container to a different workspace or monitor as a background
operation, without following the moved container to the destination
workspace or monitor.
resolve#20
Decided there should be a quick way to toggle the native ffm
functionality, it gets especially annoying when trying to click drop
downs from the system tray etc.
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.
This commit pushes as much of the generation logic as possible to the
derive-ahk crate, so that when it is used in komorebic, we only need to
do an as_bytes() call to prepare it for being written to a file.
Besides that, this commit changes the generation command name to
'ahk-library' for clarity, and adds both additional samples and
instructions in the readme file and Scoop post-install hook.
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.
I tried running prebuilt binaries from GitHub Actions on a fresh Windows
11 VM and was faced with the error "The code execution cannot proceed
because VCRUNTIME140.dll was not found."
After Googling around a little I think this may help with that issue;
definitely don't want to have to troubleshoot this for non-developers
who just want to use a tiling window manager.
Realised that I hadn't turned on super pedantic mode for clippy in the
komorebi-core and komorebic crates. This commit ensures the same clippy
config across all crates and applies the lint suggestions that arose as
a result of turning on the same config everywhere.
This commit removes the restriction on adding title rules for tray
applications and forcibly managed applications since there wasn't any
good reason for disallowing them.
Also updated the sample config and the readme to add a section for
common first time tips and to remove the big JSON blob showing an
outdated example of output from the state command.
Just a little bit of clean up to make sure that the float rule data
structures match the same emerging pattern as the data structures for
other kinds of rules.
Also some refactoring of Window.should_manage to ensure stricter scoping
where locks are gained on global static variables.
Following on from 8ffe6f78b7, this commit
introduces a command to add rules to forcibly manage windows that don't
get picked up by the rough heuristics that are able to target most
windows for management in Window.should_manage.
Since there is again no overlap (or at least, no undesired overlap)
between executable names and classes, I'll keep both class and exe names
in a single lookup vec.
re #16
Added commands to forcibly manage and unmanage windows if they don't get
picked up for tiling automatically. This commit adds support for running
those operations on the currently focused window, but if there is a need
to specify a hwnd to operate on, that could be added pretty easily too
in the future, though I'd like to keep the complexity of looking up and
passing hwnds to a command out of the CLI if possible.
This commit also fixes an issue with restoring floating windows. I'm not
sure what happened, but at some point, for me at least,
WindowsApi::top_visible_window started returning explorer.exe all the
time, so I've switched this out for WindowsApi::foreground_window.
I have a feeling I was using TopWindow before, thinking it was
GetForegroundWindow, which it isn't, and it wasn't reliable, so I
created the top_visible_window abstraction on top of it, which also
turned out to be unreliable. Anyway, it's working now.
I think the next step will be to create a manage-rule command to
compliment the float-rule command which users can use to handle edge
cases with their apps in their configuration.
re #16
The win_event_hook was still just a messy copy-paste from the yatta
days.
This commit pushes the logic around deciding if we should emit a
WindowManagerEvent::Show from a WinEvent::ObjectNameChange up to the
WindowManagerEvent::from_win_event method.
Now, the win_event_hook is just calling other functions that decide what
to do with the window and passing on the results.
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
Windows that have been maximized do not retain their maximized state
across workspaces as workspaces are built on top of sending SW_HIDE and
SW_SHOW events which at various points of the event loop end up
overriding SW_SHOWMAXIMIZED and SW_SHOWMAXIMIZE.
To handle this use case, I have added a new 'komorebic toggle-maximize'
command which sends SW_MAXIMIZE for a window and keeps a record of the
window in the focused workspace in the same way that monocle windows are
tracked.
In this way, komorebi can know when switching to a workspace if it has
to restore a window to a native maximized state.
Some additional edge cases are caught in this commit in showing and
hiding workspaces, to also account for floating windows and monocle
containers.
resolve#12
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.
For future upgrades of komorebi via Scoop, the proc will most likely be
running on the user's system. This commit adds a pre_install hook to run
'komorebi stop' if komorebi is running at the time of the upgrade.
resolve#11
Some users prefer to use AutoHotKey v2, so this commit adds a check for
both komorebi.ahk and komorebi.akh2 files, and the corresponding AHK
executables, whenever commands around configuration loading are run (on
startup, when manually reloading, and when watching for changes).
If both files exist in the home directory, komorebi.ahk will be
preferred (at least until AHKv2 is out of beta).
An example of a configuration file compatible with AHKv2 by @crosstyan
has been added to the documentation.
resolve#10
This commit adapts a basic GoReleaser configuration to work for Rust
projects, allowing us to automatically create releases on GitHub via
GitHub Actions whenever a semantic version tag (vX.Y.Z) is pushed, with
custom changelogs generated by kokai, and zipped binaries attached to
the release.
Those zipped binaries are then used to create a Scoop release in a
custom bucket.
Due to the way that Scoop uses shims, when running the 'komorebic start'
command, there needs to be an explicit check to try and determine if
komorebi has been installed via Scoop. This is done by checking for a
komorebi.ps1 shim in the Path.
Scoop shims cannot be used with the Start-Process PS command, so
instead, we replicate in code what the komorebi.ps1 script is doing
(finding the path to the current version of the executable), and then
passing the entire path to the Start-Process command that gets called to
start komorebi.
The README has been updated to reflect the availability of prebuilt
binaries and how to get started with them.
Following on from the last commit, I jumped on the Rust Community
Discord and @danielhenrymantilla was kind enough to show me a working
example of how an optional macro argument can be used together with
cfg_attr to conditionally add a doc comment.
I took his example and reworked it a little, in the process refactoring
all the macros in the komorebic crate to give them a sense of internal
consistency.
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
Clap just released a new beta which breaks a bunch of stuff. Not looking
forward to digging through the changes to do that update.
For now, users can run 'cargo install --locked' to ensure that the
previous beta of Clap is used, thus allowing them to continue compiling
from source.
resolve#8
Issue #6 highlighted a workflow that I don't personally use, but I am
sure is common among other Windows users, which is to use the Close
button to minimize an application to the tray.
Since this is largely a configurable option in those applications
(Discord etc.), I have implemented a command for the user to identify
those applications themselves when configuring the window manager,
instead of adding them to the previous Vec of known multi-window
applications that need to be identified by default.
Close/minimize to tray applications can be identified either by their
class or their executable name.
I figure it is pretty important to know the rules defined on the window
manager instance, so I have exposed these on a new window_manager::State
struct which is now what get returns from the 'komorebic.exe state'
command.
resolve#6
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.
There are some applications such as Firefox where, if they are focused
when a workspace switch takes place, an additional Show event will be
fired. This results in the window being associated with both the
original workspace and the workspace being switched to.
This commit adds a check when handling WindowManagerEvent::Show to try
and ignore events from windows that are already known to be associated
with other workspaces (which are not the currently focused workspace).
The two bugs raised in issues #1 and #2 were due to panics that were not
visible in the logs, which left the process hanging and unresponsive,
ultimately needing to be force killed with a command like 'Stop-Process
-Name komorebi'.
The only way to even verify that a panic had taken place and what the
panic related to, was to run '$env:RUST_BACKTRACE ='full';
komorebi.exe', wait for the panic, then restore the now-hidden window
with 'komorebic restore-windows' to finally see the panic message.
This commit integrates an example from the 'tracing' repo, which
through the addition of a panic hook, logs out panics as errors.
Hopefully this will debugging much easier in the future.
re #1, re #2
While investigating issue #2 I was able to reproduce it and view the
panic that causes the komorebi process to become non-responsive.
When switching to a columnar layout (which is the default for the 2nd
workspace in the sample ahk config), there is the possibility to cause a
divide by zero panic if the len passed to Layout::calculate is 0.
I have remedied this by changing the type of len from usize to
NonZeroUsize, and also by ensuring that Layout::calculate is only called
from within the komorebi crate if the workspace has at least one
container.
While moving containers around I also noticed that creating a new
container for a window may also cause a panic if focused_idx + 1 is
greater than the length of the VecDeque of containers, so this was
addressed by pushing to the back of the VecDeque in that case.
re #2
Noticed in the logs when looking at issue #2 that an "Access is denied.
(os error 5)" error was being reported when trying to attach to the
thread of the special Desktop Window, which only happens when switching
to a workspace which doesn't contain any windows. Calling
WindowsApi::set_foreground_window on the HWND directly seems to be the
better option here.
Added two commands, 'komorebic toggle-tiling' and 'komorebic
workspace-tiling MONITOR_IDX WORKSPACE_IDX on|off' which allow for
tiling on the currently focused workspace to be toggled on and off, and
for the tiling for a specific workspace to be set to on or off (useful
if you want a specific workspace to always have tiling set to off at
startup).
resolve#5
This commit adds a new command, 'komorebic.exe new-workspace', which
will append a new, empty workspace, to the list of workspaces on the
currently focused monitor, and then switch focus to it.
Also took the opportunity to clean up some unnecessary unwraps in
komorebic/src/main.rs.
resolve#4
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
A user, possibly using multiple monitors, reported a panic on startup
which I traced back to an unchecked remove op on a Vec. Spent so much
time working with VecDeque that I forgot that removing from a Vec panics
instead of returning an Option<T>.
This change ensures that when trying to remove a container's resize
dimensions in a workspace, we check that the container actually has a
corresponding resize dimension before calling remove.
Similarly, in order to ensure consistency with workspace updates which
always resize the length of the resize dimensions to match the length of
the number of container layouts, sets the length of the resize
dimensions array when initialising a workspace in
WindowsApi::load_workspace_information.
fix#1
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.
Previously resize constraints on odd and even container numbers were not
being enforced consistently. Now, instead of trying to enforce them on
individual operations, every time an update operation is called for a
workspace, the resize constraints will be enforced before trying to
calculate and apply an updated layout.
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.
If the BSP layout was flipped on the X or Y axis (or both),
OperationDirection commands would not adjust their directions
accordingly and prevent the user from focusing, moving etc in a valid
direction on the flipped layout.
This commit addresses that bug by ensuring that we always try to apply
any axis adjustments to an OperationDirection before calling the
is_valid or new_idx functions.
My first time writing a macro. Figured I could clean up the repetition a
little by using a macro to generate From impls for WindowsResult on the
primative integer types that various windows-rs functions return.
Floating windows that were minimised or destroyed remained in the
Workspace state because the call to workspace.remove_window() was only
checking containers for a matching hwnd.
This commit ensures that floating windows are checked before other
window containers and removes the window from the Workspace state if
necessary.
This commit also adds steam.exe to the MULTI_WINDOW_EXES list to ensure
the expected behaviour when responding to an ObjectHide event.
Introducing another global Vec to keep track of HWNDs that have been
hidden by komorebi, so that when responding to ObjectHide WinEvents, we
don't stop managing windows that we have hidden when cycling through
container stacks.
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.
Previously a Show event when clicking Firefox tabs would trigger a
refocusing of monitors and workspaces every time for a known hwnd, which
meant that in practice, the tab would be taken out of the current window
and a new window would be created.
This commit ensures that the workspace switch is only done if it would
be to a different monitor/workspace combination.
When hiding/restoring windows as part of workspace switching, calls to
SetForegroundWindow fail, and if they fail, other hidden windows get
lost forever in hidden mode when the error is returned up the call chain
using the ? operator.
This commit separates out the focus() calls from the loops restoring
windows when switching workspaces, and also ensures that calls to
SetForegroundWindow will log an error, but ultimately continue to the
end of the focus() function call.