Commit Graph
100 Commits
Author SHA1 Message Date
LGUG2Z 9fd4dbf044 fix(wm): handle empty vd reg values gracefully
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.
2021-12-03 22:24:50 -08:00
LGUG2Z 9be248bc03 feat(wm): add cmd to focus ws on target monitor
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
2021-12-03 14:52:14 -08:00
LGUG2Z 85fe20ebba refactor(wm): validate virtual desktops via reg
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
2021-12-02 18:44:44 -08:00
LGUG2Z 409d374b72 fix(wm): enforce virtual desktop validation
This commit fixes a regression introduced in
https://github.com/LGUG2Z/komorebi/commit/2e86b607b257e9905900f69072790f32b3d3c19f
which broke virtual desktop id validation on Windows 10.
2021-12-02 15:59:09 -08:00
LGUG2Z f9785bef55 feat(wm): add option to either minimize or hide
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
2021-11-20 15:18:45 -08:00
LGUG2Z 0519ebddbf fix(wm): ignore mstsc.exe helper classes on w11
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
2021-11-20 08:32:43 -08:00
LGUG2Z b1ca0a3e3c feat(wm): enforce last known layout on unpause
This commit ensures that the last known layout is restored on a
workspace when a command to unpause has been received.
2021-11-19 16:34:38 -08:00
LGUG2Z 84ccfedad4 chore(deps): bump windows-rs from 0.26 to 0.28 2021-11-18 14:09:54 -08:00
LGUG2Z adcb38fed9 chore(deps): bump windows-rs from 0.25 to 0.26 2021-11-15 12:49:51 -08:00
LGUG2Z 4a19edaab2 feat(wm): impl drag to move in append mode
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
2021-11-15 12:42:49 -08:00
LGUG2Z 676b643faf feat(wm): add cmd to toggle new window behaviour
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
2021-11-13 14:31:02 -08:00
LGUG2Z 7f74640dbd chore(deps): bump windows-rs and serde-json 2021-11-05 15:22:45 -07:00
LGUG2Z c247426b8e ci(artifacts): include .pdb files in archives
resolve #70
2021-11-03 11:10:32 -07:00
LGUG2Z 4d7ccc5519 feat(wm): allow resize-axis for custom primary col
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.
2021-11-03 10:04:51 -07:00
LGUG2Z 71e28b33e3 feat(wm): add resize-delta 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.
2021-11-02 14:16:29 -07:00
LGUG2Z 40226a2bbd refactor(wm): update cmds & keep compat w/ aliases
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.
2021-11-02 14:16:29 -07:00
LGUG2Z 2814349228 feat(wm): add cmd to resize by axis
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.
2021-11-02 14:16:29 -07:00
LGUG2Z d627a1a771 chore(deps): bump windows-rs from 0.23 to 0.24 2021-11-02 13:24:23 -07:00
LGUG2Z 78683ce7b3 chore(deps): bump clap from 3.0.0-beta.4 to beta.5 2021-11-01 14:56:42 -07:00
LGUG2Z a1ca4f03c3 chore(deps): bump tracing-subscriber and tracing-appender 2021-11-01 14:45:36 -07:00
LGUG2Z 127254b7ac feat(wm): disable windows ffm on stop and ctrl-c
This commit disables the native Windows ffm implementation as part of
the stop command and the ctrl-c handler.

resolve #69
2021-11-01 13:59:40 -07:00
LGUG2Z 4e6e2b3aa8 feat(wm): mouse follows focus enable/disable cmd
This commit adds a command to explicitly specify the desired state of
mouse follows focus to complement the previously added toggle command.
2021-10-30 16:05:04 -07:00
LGUG2Z a55069df48 feat(wm): add mouse follows focus toggle
This commit adds a toggle for the mouse follows focus behaviour that has
been the default for komorebi until now.

resolve #63
2021-10-29 13:41:55 -07:00
LGUG2Z 7fd545ca35 fix(wm): handle cross-monitor drag/move events
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
2021-10-29 09:32:36 -07:00
LGUG2Z 14e63292e1 chore(deps): bump windows from 0.22 to 0.23 2021-10-28 14:15:21 -07:00
LGUG2Z 18f34babfa chore(deps): bump windows from 0.21 to 0.22
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.
2021-10-28 09:01:10 -07:00
LGUG2Z 2f7ae6f15f build(just): add justfile for common tasks 2021-10-27 19:21:54 -07:00
LGUG2Z 29a6c39084 feat(subscriptions): embed latest state
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
2021-10-26 18:49:53 -07:00
LGUG2Z 5d0806a8c9 fix(serde): gracefully handle window ser errors
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
2021-10-26 08:48:53 -07:00
LGUG2Z 6c53fd7830 refactor(subscriptions): ensure consistent naming
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.
2021-10-25 12:08:59 -07:00
LGUG2Z 6ae59671a2 feat(subscriptions): add and remove subscribers
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
2021-10-25 09:31:59 -07:00
LGUG2Z f17bfe267e docs(readme): add link to custom layout generator 2021-10-23 08:10:46 -07:00
LGUG2Z 840af215a0 docs(readme): add section about custom layouts
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
2021-10-21 16:38:47 -07:00
LGUG2Z 6981d778a9 feat(custom_layout): add yaml file support
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
2021-10-21 16:30:41 -07:00
LGUG2Z 5d6351f48d feat(custom_layout): add opt width for primary col
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
2021-10-21 16:30:41 -07:00
LGUG2Z ac0f33f7ed feat(custom_layout): implement navigation
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.
2021-10-21 16:30:41 -07:00
LGUG2Z f19bd3032b feat(custom_layout): calculate layouts adaptively
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.
2021-10-21 16:30:41 -07:00
LGUG2Z 3f3c2815da feature(wm): manage linux gui apps by default
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
2021-10-21 14:30:58 -07:00
LGUG2Z 7070878f4a chore(rust): migrate to edition 2021
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'.
2021-10-21 12:08:10 -07:00
LGUG2Z d3cb9e07f7 fix(wm): keep multi-window app hwnds when stacking
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
2021-10-18 13:44:01 -07:00
LGUG2Z 6f6181625f refactor(layouts): compose row and column fns
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.
2021-10-15 10:49:04 -07:00
LGUG2Z 80dd07fcde chore(release): v0.1.6 2021-10-15 07:49:55 -07:00
LGUG2Z 09d1d69668 fix(wm): apply container padding in monocle mode
This commit ensures that any configured container padding is also
applied when monocle mode is enabled for containers in any/all layouts.

fix #49
2021-10-14 16:03:56 -07:00
LGUG2Z 786f5e846a feat(wm): add vertical & horizontal stack 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
2021-10-14 11:28:44 -07:00
LGUG2Z 65bc1a966e feat(wm): add cmd to specify work area offsets
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
2021-10-14 11:08:25 -07:00
LGUG2Z ddafe599a2 feat(wm): cycle through monitors and workspaces
This commit adds commands to navigate monitors and workspaces using
cycle directions.

resolve #47
2021-10-12 07:44:47 -07:00
LGUG2Z 7ed6df511f feat(wm): allow focusing and moving by cycle direction
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
2021-10-12 07:44:33 -07:00
LGUG2Z 94e9bb8e9e chore(deps): bump windows-rs, syn and instant 2021-09-25 09:13:43 -07:00
LGUG2Z 644f7ee604 chore(release): v0.1.5 2021-09-22 08:43:51 -07:00
LGUG2Z b9a40924a8 feat(wm): add saving/loading of layouts to file
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
2021-09-22 08:31:50 -07:00
LGUG2Z 80bcb51f75 feat(wm): add quicksaving/loading of sizes/layouts
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
2021-09-21 17:12:18 -07:00
LGUG2Z e10e11d1de fix(wm): preserve resize dimensions on promotion
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
2021-09-21 10:07:15 -07:00
LGUG2Z 2807cafdd0 refactor(windows_api): use handle trait from 0.20
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.
2021-09-20 18:41:31 -07:00
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