This commit removes all stackbar-related code from Container, Workspace,
process_command, process_event etc. and centralizes it in the new
stackbar_manager module.
Instead of trying to figure out where in process_event and
process_command we should make stackbar-related changes, a notification
gets sent to a channel that stackbar_manager listens to whenever an
event or command has finished processing.
The stackbar_manager listener, upon receiving a notification, acquires a
lock on the WindowManager instance and updates stackbars for the focused
workspace on every monitor; this allows us to centralize all edge case
handling within the stackbar_manager listener's loop.
Global state related to stackbars has also been moved into the
stackbar_manager module, which also tracks the state of stackbar objects
(STACKBAR_STATE), mappings between stackbars and containers
(STACKBARS_CONTAINERS) and the mappings between stackbars and monitors
(STACKBARS_MONITORS).
A number of edge cases around stackbar behaviour have been addressed in
this commit (re #832), and stackbars now respect the "border_style"
configuration option.
This commit adds the monitor_reconciliator module which uses a tightly
bounded channel (cap: 1) to handle monitor connection and disconnection
events, as well as resolution and work area change events.
Before, all this logic lived in a the WindowManager.reconcile_monitors
function, which ran on pretty much every process_event iteration, and
sometimes led to undesirable behaviour, but now the logic is split up to
only run when the appropriate notifications are dispatched from the
hidden window which listens for monitor and display-related events.
The monitor cache has been moved out of WindowManager and into the
monitor_reconciliator module, and in addition to the previous behaviour
of attempting to cache monitors which had been identified as
disconnected, now when the static configuration file is loaded, if the
user has set display_index_preferences, the device IDs will be used to
pre-populate the cache for the event where a known monitor is connected
later in a session.
The monitor cache itself now uses the unique device ID as a key rather
than the hmonitor which is known to be inconsistent.
This commit also delegates all display monitor-related Win32 calls to
the "win32-display-data" crate, which was extracted from the larger
"brightness" crate for its use in komorebi.
As a result of these changes, "device" and "device_id" on Monitor have
been changed from Option<String> to String types, as failures in
retrieving these values with directly attached monitors has not been
possible to reproduce. However, it remains to be seen if this will
adversely impact users who use display docks which may prevent display
monitor device IDs from being read and stored by the operating system.
WindowManagerEvent::DisplayChange has been removed in favour of
the monitor_reconciliator::Notification enum, as these events are no
longer being handled in process_events.
Attempts are now made to eagerly update hmonitors both within the
monitor_reconciliator loop on DisplayConnectionChange notifications and
when failing to find a matching hmonitor in functions like
monitor_idx_from_current_pos and monitor_idx_from_window.
This commit adds hiding and restoring of other containers on a workspace
with monocle on/off, and exits early when a monocle container is found
on workspace restores to avoid flashing of other containers before the
workspace focus operation completes.
Focus is also restored when focusing a monocle container on another
monitor as part of a cross-monitor focus operation.
The border rendering for monocle containers has also been tightened up.
re #819
This commit addresses two visual artifacts with monocle mode:
* Flashing of background windows when switching to a monocle container
on another monitor is now gone
* Stackbars are automatically disabled whenever a container enters
monocle mode
re #819
This commit fixes a number of monocle container-related regressions.
* Monocle container on one monitor preventing border updates on another
* Cross-monitor focus changes towards a monitor w/ a monocle container
* Cross-monitor move towards a monitor w/ a monocle container
re #819
This commit handles the EVENT_OBJECT_NAMECHANGE WinEvent which is
emitted when window titles change to update Stackbar labels in real-time
when StackbarLabel::Title is used.
re #826
This commit fixes a small regression that was introduced with the
addition of the Grid layout, where stacking right from index 0 on the
UltrawideVerticalStack layout would actually end up stacking to the
left.
This commit introduces a new stackbar label configuration option backed
by the StackbarLabel enum, which now has two variants, Process and
Title.
The state tracker for this option is kept in an AtomicCell, and the
state tracker for StackbarMode has also been changed from an
Arc<Mutex<T>> to an AtomicCell to match.
resolve#826
This commit adds a new cli command, cycle-move-workspace-to-monitor.
After the introduction of the monitor reconciliator module in
combination with display_index_preferences, this command should never
really be necessary, however it is worth having as a backup.
resolve#718
This commit renames a number of border-related code refs, removing the
ActiveWindow prefix since these borders are no longer just for the
active window.
Aliases have been added to preserve backwards compat for existing
configs.
An example AHK configuration file has been added to the Common Workflows
section of the docs site.
A link to the docs site has been added to the output of komorebic start.
A note has been added recommending that users disable system animations
for the best experience in the Getting Started guide.
This commit updates the initial design of single_window_work_area_offset
to window_based_work_area_offset where the user can set
window_based_work_area_offset_limit to determine the limit of windows on
the screen that this offset should apply to.
By default this is 1, and in the most extreme case of someone using a
super ultrawide monitor this might be 2.
This commit fixes a regression which led to the adjusted work area for a
monitor not being respected when applying additional window-based work
area offsets.
re #811
This commit adds a new monitor configuration option, single_window_work_area_offset, which will
apply to a monitor when only a single window is open on a workspace. This is implemented as a Rect
to enable its use on both horizontally and vertically positioned monitors. This option will be
particularly useful for ultrawide monitor users, where a single window taking up the full width of
the work area can often hinder usability.
resolve#434
This commit ensures that both windows and borders will make a comparison
to the current values returned by WindowRect before attempting to make
update calls to SetWindowPos. This should greatly reduce visual
flickering in both the borders and sensitive apps like JetBrains IDEs.
This commit adds some rough heuristics to workspace_reconciliator which
should help with having the correct window focused after reconciliation
in the majority of, but probably not all, cases.
EnumWindows generally returns HWNDs according to z order, and a window
selected by alt-tab will almost always be put on the top of the z order.
Before sending a workspace_reconciliator::Notification, we store this
HWND along with an Instant and an AtomicBool telling us that we have a
candidate to focus after the workspace switch.
This commit ensures that if and when either the border_manager or
workspace_reconciliator notification handlers crash in their respective
threads, they will be restarted instead of killing the whole thread.
This is acheived via a loop running in the spawned threads of both
listeners, which will report whichever error killed the notification
handler functions.
Clippy annotations to deny expect and unwrap calls have been added to
these two modules.
Calls to DestroyWindow for expired borders were sporadically failing in
unpredictable circumstances, so these have been switched out with calls
to CloseWindow which has been working well so far with the stackbar
feature.
This commit ensures that even border hwnds that may now be untracked as
a result of events such as monitor changes will now be reaped in the
destroy_all_borders function.
This commit ensures that if a user uses index-based commands to switch
workspaces, workspace layout update code paths will not be run if the
user is already on the desired monitor and workspace indices.
resolve#647
This commit adds a new "NoOp" MoveBehaviour for users who don't want any
moves to happen across monitor boundaries. The
toggle-cross-monitor-move-behaviour will only toggle between Swap and
Insert, and will do nothing if NoOp is the selected MoveBehaviour.
resolve#667
This commit adds the workspace_reconciliator module which uses a tightly
bounded channel (cap: 1) to update the focused workspace in situations
where the user or another process has foregrounded a window that is on a
different workspace.
This most often happens via Alt-Tab, or by clicking a link which opens
in another application.
workspace_reconciliator::Notification contains the target monitor and
workspace indices, which when received allows for the correct workspace to
be focused.
These notifications are sent in process_event.rs when handling
WindowManagerEvent::Show, Manage and Uncloak events.
All previous logic pertaining to workspace reconciliation which lived in
the handler for these events has been removed and replaced with
notifications sent to the reconciliator.
As the notifications channel is tightly capped and any notifications
which overflow the cap will never be delivered, we are able to avoid the
infinite workspace switching loops which happened when using the
previous logic, which ran on every single event.
This commit removes all border-related code from process_command,
process_event etc. and centralizes it in the new border_manager module.
Instead of trying to figure out where in process_event and
process_command we should make border-related changes, a notification
gets sent to a channel that border_manager listens to whenever an event
or command has finished processing.
The border_manager listener, upon receiving a notification, acquires a
lock on the WindowManager instance and updates borders for the focused
workspace on every monitor; this allows us to centralize all edge case
handling within the border_manager listener's loop.
Borders on workspaces that lose focus are now destroyed and recreated
when those workspaces regain focus, instead of trying to share
individual border instances across workspaces.
A number of common edge cases that have been addressed in this commit
are:
* Paused window manager
* Floating workspaces
* Maximized windows
* Fullscreen videos
* Monocle containers
* Ghost borders on workspace switching
* Incorrect focused window border colours
Global state related to borders has also been moved into the
border_manager module, which also tracks the state of border objects
(BORDER_STATE), their rects (RECT_STATE) and their focus kinds
(FOCUS_STATE).
This allows us to now track multiple borders per-container, enabling
unfocused border windows for the first time.
Additionally, the Z-Order for border windows is now also configurable.
ActiveWindowBorderColours has been expanded to include Unfocused, but in
order to not introduce a breaking configuration change for end users,
all members of this struct have been made Option<Colour>.
This commit ensures that in situations where the last container on a
monitor is moved to an adjacent monitor, the focused container index of
the origin monitor will be appropriately decremented.
When adding selective handling of Uncloak events, a regression was
introduced where, for example, when clicking a link from Discord on
Workspace 2, a Firefox instance on Workspace 1 would be moved to
Workspace 2 to open the link, but when moving back to Workspace 1, a
ghost tile would be left, and the Firefox instance would be duplicated
across two workspaces.
This commit fixes this regression and makes the handler a bit easier to
reason about while also removing unnecessary early return statements
which prevent notifcations from getting sent to subscribers.
This commit adds selective handling for WindowManagerEvent::Uncloak
alongside Show and Manage, avoiding the workspace-switching logic that
is known to cause infinite workspace loops.
This commit ensures that if a window is moved to a workspace on another
monitor which is not the currently focused workspace on that monitor,
the target workspace will be focused as part of the operation.
This commit completely removes the custom Clone and Drop trait
implementation for Stackbar, and moves the handling to be explicit
within container.rs, which helps us to avoid unintentional drops when
the Stackbar struct is cloned for Notification events sent to
subscribers such as Zebar.
re #746
This commit ensures that when we call methods to change
Container.stackbar we are not unintentionally invoking a Drop which
kills a stackbar window that already exists.
Checks have been added to make sure that we not change the value of the
stackbar variable if it is already an Option::Some.
re #746 re #792
This commit ensures that tiling on a workspace will be enabled if a user
specifies layout rules or custom layout rules without providing an
option to the "layout" key.
This commit adds a new RightMainVerticalStack layout, adapting code from
the similarly named LeftWM layout.
It turns out that the horizontal axis flip on the VerticalStack does not
play well with resize offsets.
It was ultimately easier to implement this layout and the logic for
resizing both VerticalStack and RightMainVerticalStack independently
than to make resize offsets and horizontal axis flips work together.
I still have no idea why resize offsets and horizontal axis flips aren't
working properly together.
Horizontal axis flips have been disabled for both the VerticalStack and
RightMainVerticalStack layouts.
re #789
This commit ensures that when floating the sole window visible on a
workspace that the focused container index for the workspace will not be
decremented below 0.
re #787
This commit ensures that the wm's mouse_follows_mouse state is respected when handling FocusChange
WindowManagerEvents, so that applications opened on empty workspaces do not automatically center the
cursor unless configured to do so.
fix#782
This commit ensures that if a container stack has a stackbar, when
toggling off monocle mode, the stackbar will be restored as expected.
This requires an additional retile which it would be nice to avoid in
the future.
This commit adds a move-to-monitor-workspace command, which, following
the existing convention, does the same action as
send-to-monitor-workspace, but sets the focused monitor, workspace and
container to the window container once it is inserted into the target
monitor and workspace indices.
This commit ensures that after 3 failures to start komorebi with
'komorebic start', 'komorebi.exe' will be run directly in order to show
the detailed error output to the end user.
This commit ensures that enforce_workspace_rules() will try to match
exact exe names, classes and titles, and then against any potential
regexes that may have been used as keys to index matching rules against
the current window's exe, title and class.
Support for other matchers isn't implemented yet. Not sure it's worth
adding while using a HashMap to store the workspace rules, probably need
to rethink the data structure first.
This commit ensures that when the stackbar mode is updated via a
SocketMessage or static config update, any visible stackbars will have
their mode updated immediately without having to wait for user
interaction.
This commit adds support for debugging windows and emitting information
about how they go through komorebi's decision making pipeline and rules
engines which ultimately decide how they are or aren't managed.
This commit ensures that new features such as stackbar, particularly
where the configuration is located in the global state, can be
configured via SocketMessages.
A few structs had to be moved to komorebi-core to make this possible.
I've also cleaned up a bunch of strum snake_case attrs which seemed to
be unused.
A new GlobalState SocketMessage has been introduced, and going forward
we should make sure that this can send all global state to a requester,
and move global state out of the State handler, which should only handle
window manager state.
This commit ensures that a window is restored before a focus call is
made on it when switching windows in a stack by using a window's tab in
the stackbar.
This handles the issue where two clicks are required to trigger a layout
update the first time a window that is not currently at the top of the
stack is brought to the front via a stackbar click.
This commit fixes a small regression and ensures that the active window
border, when enabled, will be drawn as expected when a container stack
has a stackbar active.
This commit ensures that the focused container index on a workspace is
updated appropriately if the user calls toggle-float on the last
Container in a Ring. Previously, doing this would leave a ghost tile.
Now that we check if the focused_idx is still valid after removing an
empty Container from the workspace, users will no longer be left with a
ghost tile.
This commit ensures that the MoveResizeEnd handler will only proceed if
the window triggering the event is a managed window on the focused
workspace.
fix#733
This commit ensures that if an applications.yaml revision is passed
which includes the now-deprecated border_overflow option, komorebi will
gracefully handle it instead of crashing on an unknown enum variant
error.
A user reported in an issue that their komorebi data dir did not persist
across reboots. While there have not been any other reports of this type
of system behaviour, it's worth just doing a mkdir -p equivalent call
whenever komorebi.exe is starting to ensure that the socket files can
always be created no matter what.
re #731
This commit adds a new active window border style configuration option
to komorebi.json, allowing users to explicitly opt in to square or
rounded active window borders to match whatever patches they may have
made at the system / dwm.exe level.
This commit introduces the stackbar feature through careful extracting
and refactoring of code from the Komorebi-UI hard-fork.
Unfortunately on the fork, this feature was not implemented using atomic
commits, which resulted in the implementation here being more of a
"reinterpretation" than a lift-and-shit of the referenced code.
Nevertheless, this commit represents a working version of the stackbar
feature.
resolve#681
This commit adds support for composite rules in the static configuration
file, and for float_identifiers in the applications.yaml file.
A new enum, MatchingRule provides two variants, Simple and Composite,
and is now used in place of IdWithIdentifier throughout komorebi.
In order to keep this new enum lean, a variant for
IdWithIdentifierAndComment has not been added, and references to it in
the old config generation code have been replaced with MatchingRule.
resolve#462, resolve#715, resolve#237
This commit adds a 10 millisecond thread sleep specifically for Firefox
as an interim solution for the race condition which results in new
windows often not being tiled correctly until interacted with.
The idea to add a sleep instead of spamming the output with dbg! calls
comes from @kornel@mastodon.social:
https://mastodon.social/@kornel/112125851048707993
This commit ensures that ApplicationFrameHost.exe applications developed
by Microsoft are raised correctly when a user has the custom komorebi
ffm implementation enabled.
The Win32 API calls EnumWindows and WindowFromPoint return different
HWNDs for the same windows because of some jank in how the
ApplicationFrameHost apps are developed.
To avoid this inconsistency on the Win32 API level, komorebi now queries
its own state when looking up HWNDs for windows at any given cursor
position.
This commit swaps out the old "raise" fn for the more up-to-date and
tested "focus" fn when raising a window for focus when the "komorebi"
implementation of focus follows mouse is enabled.
It seems like when we use the bottom flag, Rainmeter widgets will be
drawn on top of windows that are managed by komorebi. After looking at
the GlazeWM codebase, where this issue does not occur, it seems like the
difference is made by the use of the notopmost flag.
resolve#679
This commit ensures that workspace change events get emitted even when
changing to workspaces with no window containers. Previously these were
failing due to early returns triggered when the workspace focused did
not have a focused container.
This commit fixes a regression that was most likely introduced in #678
which changed a bunch of stuff related to window and border dimension
calculation.
See commit 4e98d7d36d for more information
as the same approach to fix the behaviour there has been applied here.
This commit switches out the serde_json crate with the
serde_json_lenient crate, forked by Google, which allows for JSON files
with comments to be parsed properly.
Users can set the format of komorebi.json to "jsonc" in their editors in
order to write // comments without being faced with lint errors.
The expected file extension remains the same (json). komorebi and
komorebic will not look for files with the "jsonc" file extension or any
other JSON-variant file extension.
resolve#693
This commit fixes a regression that was most likely introduced in #678
which changed a bunch of stuff related to window and border dimension
calculation.
While we could previously assume that the points resize.right and
resize.bottom would always be 0 if we were dealing with a move rather
than a resize, these two points now depend on the values of BORDER_WIDTH
and BORDER_OFFSET. The code has been updated to reflect this and
calculate this constant just-in-time.
This commit introduces the komorebi-client library crate for other Rust
applications to interact with a running instance of komorebi over Unix
Domain Sockets.
Currently the crate re-exports everything one might find in the
komorebi::State struct and everything that is publicly exposed in
komorebi-core.
Public types and methods are still lacking documentation, and this crate
should not be published on crates.io until this is no longer the case.
This commit adds some contribution guidelines and updates the "Window
Manager Event Subscriptions" section with information on using
subscribe-socket and komorebi-client.
This commit includes backwards-compatible renames of
active_window_border_offset and active_window_border_width to
border_offset and border_width respectively.
Since the invisible window border adjustments were removed in #678, the
invisible window borders set by the OS can now also be adjusted via
border_offset and border_width, which is the primary reason for the
rename.
invisible_borders has been marked as deprecated and the previously
deprecated alt_focus_hack option has been removed.
This commit adds the "komorebic whkdrc" command to go along with the
"komorebic configuration" command introduced in
608ec03047, aimed it making it easier to
edit this file using a command line editor.
The "config" command has been renamed in the code to Configuration, with
an alias of "config". The Whkdrc command similarly comes with the "whkd"
alias.
This commit introduces the ability for users to specify colours in the
static config file in either RGB or Hex format.
This is done by introducing a new enum, Colour, which provides variants
wrapping the internal Rgb type, and the HexColour type from the
hex_colour crate. HexColour itself is wrapped in a new struct, Hex, in
order to allow the implementation of the JsonSchema trait.
A number of From<T> implementations have been done in order to make
working with the Colour enum more ergonomic.
Ultimately, the core representation for colours in komorebi remains the
Rgb struct, any and Hex-specified colours will be converted to this Rgb
type before being converted to u32 to pass them on to various Win32 API
calls.