Commit Graph
88 Commits
Author SHA1 Message Date
LGUG2Z 63cf48daa5 fix(wm): ensure idx < len before container removal
fix #38
2021-09-19 11:05:09 -07:00
LGUG2Z a2b49845ac chore(release): v0.1.4 2021-09-17 08:05:59 -07:00
LGUG2Z 5b923a135c feat(wm): adapt to scaling and resolution changes
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
2021-09-16 14:53:07 -07:00
LGUG2Z b8a27a93fe feat(ffm): explicitly require flag to enable
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
2021-09-16 09:42:13 -07:00
LGUG2Z 28a641609c fix(wm): update target monitor after send op
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
2021-09-15 07:18:10 -07:00
LGUG2Z f1ee5ea194 feat(wm): make invisible borders configurable
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
2021-09-14 21:26:18 -07:00
LGUG2Z ff53533da0 feat(wm): add cmd to id apps that overflow borders
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
2021-09-13 09:03:40 -07:00
LGUG2Z c4c8bd7d4b feat(wm): reconcile monitor state
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
2021-09-13 07:24:09 -07:00
LGUG2Z e1bd0e9fcb fix(ffm): handle multiple overlay window classes
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.
2021-09-07 08:38:41 -07:00
LGUG2Z 368d41e3e0 fix(ffm): raise when switching focus from anywhere
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.
2021-09-07 08:38:41 -07:00
LGUG2Z 2b7c51b87b refactor(ffm): add selection of ffm implementation
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
2021-09-07 08:38:41 -07:00
LGUG2Z ce3c742e09 feat(ffm): add custom ffm/autoraise implementation
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
2021-09-07 08:38:41 -07:00
LGUG2Z 2a4e6fa6da feat(wm): get monitor idx from cursor on ws switch
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
2021-09-07 08:33:53 -07:00
LGUG2Z 2d19109fb6 feat(wm): allow direct querying of focused objects
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
2021-09-02 12:58:14 -07:00
LGUG2Z a9a0ecd49d chore(deps): bump cc and object crates 2021-09-01 08:12:52 -07:00
LGUG2Z 752dde2288 docs(readme): add link to zh translation on wiki
Adding a section under ##About for links to translations of the document
in other languages, starting with @crosstyan's Chinese translation.

resolve #21
2021-08-29 07:30:25 -07:00
LGUG2Z dc771a104d build(cargo): update dependencies 2021-08-26 09:58:18 -07:00
LGUG2Z e5a7c140ff refactor(macros): add trailing commas 2021-08-26 09:53:15 -07:00
LGUG2Z 61b231be28 docs(readme): fix some bad copypasta 2021-08-24 11:05:33 -07:00
LGUG2Z cab8b4ad52 chore(release): v0.1.3 2021-08-24 08:28:44 -07:00
LGUG2Z 05777c34b9 fix(wm): ensure removal of max + monocle windows
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
2021-08-24 07:21:13 -07:00
LGUG2Z 5094001862 feat(wm): add send-to-workspace/monitor cmds
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
2021-08-24 06:52:56 -07:00
LGUG2Z bc08e177a1 fix(komorebic): add missing help annotations 2021-08-23 15:14:16 -07:00
LGUG2Z 87fe718754 feat(wm): add toggle-focus-follows-mouse cmd
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
2021-08-23 14:08:40 -07:00
LGUG2Z fb4fe4d9c3 refactor(derive-ahk): enforce no_implicit_prelude
Starting to implement the feedback I got from this post on Reddit
https://old.reddit.com/r/rust/comments/pa2997/code_review_request_first_derive_macro/.
2021-08-23 11:16:58 -07:00
LGUG2Z b61b03b1c9 refactor(eyre): handle options with combinators
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.
2021-08-23 09:52:13 -07:00
LGUG2Z a02cd699a0 refactor(derive-ahk): push up generation logic
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.
2021-08-23 07:49:37 -07:00
LGUG2Z 2c876701d8 feat(ahk): add cmd to generate helper lib
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.
2021-08-22 18:54:44 -07:00
LGUG2Z c42739591f build(windows-rs): upgrade to 0.19.0 2021-08-22 07:19:34 -07:00
LGUG2Z 381253da20 fix(wm): switch to correct ws when following links
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.
2021-08-20 17:16:16 -07:00
LGUG2Z cf7532330b chore(release): prepare v0.1.1 2021-08-20 14:00:06 -07:00
LGUG2Z ffb86458f0 build(cargo): set -Ctarget-feature=+crt-static
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.
2021-08-20 13:47:48 -07:00
LGUG2Z 292bdb282f refactor(clippy): apply all super pedantic lints
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.
2021-08-20 13:26:16 -07:00
LGUG2Z 1625ca6e5d feat(wm): allow all app identifiers for all rules
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.
2021-08-20 12:49:37 -07:00
LGUG2Z df07409a2f refactor(workspace): extract fns for container focusing 2021-08-20 12:01:11 -07:00
LGUG2Z 2e86b607b2 refactor(wm): improve data consistency + scoping
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.
2021-08-19 17:18:24 -07:00
LGUG2Z 6f7e87799b fix(wm): handle winvd errors gracefully
Of course, the crate built to interact with an undocumented COM API is
not the best candidate for unwrap and expect calls...

fix #15
2021-08-19 14:52:04 -07:00
LGUG2Z 4e9b294835 feat(wm): add additional manage rules
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
2021-08-19 14:35:02 -07:00
LGUG2Z 8ffe6f78b7 feat(wm): forcibly manage and unmanage windows
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
2021-08-19 13:31:49 -07:00
LGUG2Z 42b9305dfe refactor(windows_callbacks): push logic further up
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.
2021-08-19 09:25:10 -07:00
LGUG2Z 1eba8aa01d feat(wm): add workspace rules
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.
2021-08-19 08:19:34 -07:00
LGUG2Z 74811fbe13 fix(wm): limit to a single virtual desktop
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
2021-08-19 07:52:44 -07:00
LGUG2Z 209cd82892 fix(wm): prevent hidden_hwnds deadlock
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
2021-08-19 06:31:02 -07:00
LGUG2Z 98f731ba13 feat(komorebic): add change-layout command
The handler for this was already hooked up in process_command.rs, but I
had forgotten to add the command to the cli.

resolve #14
2021-08-18 16:39:04 -07:00
LGUG2Z c7bf09e34b fix(wm): restore focus to monocle on ws switch 2021-08-18 10:22:58 -07:00
LGUG2Z 0725549d45 feat(wm): add native window maximization toggle
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
2021-08-18 09:49:05 -07:00
LGUG2Z 13b335cecc feat(komorebic): add log command
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.
2021-08-18 06:21:19 -07:00
LGUG2Z 23aada05d0 refactor(komorebic): inject metadata from cargo 2021-08-17 14:15:13 -07:00
LGUG2Z f11dcbc0cb ci(dependabot): add configuration file 2021-08-17 11:53:29 -07:00
LGUG2Z 564ee89c84 ci(scoop): stop proc if running before updates
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
2021-08-17 11:21:40 -07:00
LGUG2Z 4dadffabf1 feat(ahk): add support for ahk2
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
2021-08-17 09:20:19 -07:00
LGUG2Z 2e955973f0 ci(goreleaser): automate releases on tag push
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.
2021-08-17 08:27:44 -07:00
LGUG2Z 4dff452c1f refactor(komorebic): gen more clap boilerplate
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.
2021-08-16 15:21:12 -07:00
LGUG2Z 9c55545600 refactor(komorebic): update clap, add cli docs
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
2021-08-16 11:23:41 -07:00
LGUG2Z 7ede5a2dbc docs(readme): update install cmd to use lockfile
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
2021-08-15 21:16:24 -07:00
LGUG2Z b2ab893e77 feat(wm): add cmd to identify 'close to tray' apps
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
2021-08-15 18:42:23 -07:00
LGUG2Z b6ff862705 feat(ahk): add config watching + reloading cmds
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.
2021-08-15 14:26:46 -07:00
LGUG2Z 126eee49ca fix(wm): don't duplicate windows across workspaces
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).
2021-08-15 07:31:44 -07:00
LGUG2Z a59bbacb29 feat(tracing): use hook to log errors on panics
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
2021-08-15 06:42:10 -07:00
LGUG2Z a53b2cc28c fix(wm): skip layout calc for empty workspaces
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
2021-08-15 06:27:54 -07:00
LGUG2Z a550c088dc fix(wm): don't attach to the desktop window thread
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.
2021-08-14 21:39:20 -07:00
LGUG2Z 820432f9d4 feat(wm): add per-workspace tiling config + toggle
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
2021-08-14 10:19:32 -07:00
LGUG2Z b8929cbead feat(wm): add command to create new workspace
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
2021-08-14 09:42:12 -07:00
LGUG2Z 91ddb2c22b feat(ahk): autoload config on start
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
2021-08-14 07:53:40 -07:00
LGUG2Z 55b62c2bc9 fix(wm): check resize_dimensions before removing
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
2021-08-14 07:02:12 -07:00
LGUG2Z 0d3751a7cc refactor(wm): reduce boilerplate with getset
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.
2021-08-13 10:38:11 -07:00
LGUG2Z c15f1e1d7b ci(windows): add basic build pipeline
Adding a basic MSVC build pipeline based on the workflows used in the
rustup repo.
2021-08-10 12:48:15 -07:00
LGUG2Z 579a5556cc refactor(ring): gen element impls using macro
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.
2021-08-10 08:10:56 -07:00
LGUG2Z be1d07e397 fix(wm): enforce resize constraints universally
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.
2021-08-09 12:27:03 -07:00
LGUG2Z f3661325d9 feat(wm): add focus follows mouse toggle 2021-08-09 07:49:00 -07:00
LGUG2Z 8b4ce48a66 feat(wm): add container resizing
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.
2021-08-08 23:04:35 -07:00
LGUG2Z ca27730b01 fix(operation_direction): adjust for layout flips
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.
2021-08-06 14:57:18 -07:00
LGUG2Z f97cdf7c15 refactor(windows_api): gen from impls using macro
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.
2021-08-06 11:16:14 -07:00
LGUG2Z 88d6eee7af fix(wm): clean stale floating windows from state
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.
2021-08-06 08:23:26 -07:00
LGUG2Z bebf2f791a docs(readme): add screenshot, features and debugging info 2021-08-06 07:57:49 -07:00
LGUG2Z b456097ca2 fix(wm): track programmatically hidden hwnds
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.
2021-08-05 19:49:12 -07:00
LGUG2Z b96a302451 docs(readme): initial readme, license and sample config 2021-08-05 18:16:49 -07:00
LGUG2Z 0ca3320939 refactor(logging): make use of tracing::instrument 2021-08-05 13:46:22 -07:00
LGUG2Z 77aa4c0d21 feat(debug): track and hard-restore hwnds
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.
2021-08-05 11:36:07 -07:00
LGUG2Z da8214cdc7 fix(wm): switch only to different workspaces
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.
2021-08-05 09:52:03 -07:00
LGUG2Z 73568922d5 fix(workspaces): let set_foreground_window fail
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.
2021-07-30 21:05:02 -07:00
LGUG2Z b867db1900 fix(wm): switch to focused workspace
This commit fixes corruption of workspace state when clicking a link
brings to the foreground a window in a different workspace, and also
ensures that the workspace containing the window coming to the
foreground will be focused and switched to as part of the Show event.
2021-07-30 14:41:59 -07:00
LGUG2Z 230b534735 feat(wm): add query command to cli
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.
2021-07-30 14:11:09 -07:00
LGUG2Z 793ba51695 fix(wm): add settings to multi-window exes 2021-07-30 12:29:28 -07:00
LGUG2Z 8c939328d1 feat(wm): ensure workspace count
Allow the number of workspaces for a given monitor to be pre-created, so
that configuration options can be sent (name, padding, layout) before
the workspace has ever been activated.
2021-07-30 12:06:31 -07:00
LGUG2Z d8a717950c fix(wm): unmanage multi-window exes on hide
Looks like explorer.exe is not the only one. Making the comparison
against a list instead.
2021-07-30 10:59:23 -07:00
LGUG2Z b0c3480262 fix(wm): float/monocle toggle, invisible borders
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.
2021-07-30 10:44:31 -07:00
LGUG2Z 61cee458a1 feat(wm): initial commit
One week of blissful, in-the-zone coding, applying all of the lessons
learnt from the development of yatta.
2021-07-29 16:23:42 -07:00