This commit makes the `stack-all` command simpler, by simply making a
`VecDeque` with all the tiled windows of the workspace, then it creates
a new container with that `VecDeque` and changes the workspace
containers to be just this new container which has all the windows in
it.
Then and only then do we focus and show the previously focused window
and hide all the rest.
This way we don't have a bunch of `FocusChange`/`Cloak`/`Uncloak` events
coming up which might conflict with each other when the user has
transparency and animations enabled.
With this commit, there will only be one focus event for the focused
window and one cloak event for each of the other windows.
Marking all --ahk flags in the start/stop/kill/enable-autostart commands
as EOL; there are any number of ways that users can manage their own
launching of AutoHotKey scripts and the complexity of the different ways
that AHK can be installed is not worth the maintenance burden for this
project.
This commit adds a new LayoutOptions option, GridLayoutOptions,
currently with a single configurable "rows" opt which can be use to
constrain the grid by number of rows.
This commit adds a new option under layout_options.scrolling -
"center_focused_column", which defaults to false. When
set to true, and when the number of scrolling columns is an odd number
>=3, komorebi will, if there are enough windows being managed on the
workspace, and if the focused window is not too close to either the
beginning or the end of the workspace ring, keep the focused window in a
centered position in the layout
This commit ensures that the default interface for the network widget does not update on every render of the bar.
Some people have experienced the bar being frozen and hopefully this will remediate that issue.
This commit standardizes the codebase to disallow usage of the raw eyre!
macro for creating errors, instead using ok_or_eyre() when constructing
ad-hoc errors from Result and Option types, and otherwise using the
bail! macro in response to failed boolean conditions.
This lets the user enable or disable showing removable or read only
disks in the komorebi-bar storage widget.
Removable disks are set to show by default.
Read-only disks are set not to show by default. Having windows sandbox
installed displays a very long read only disk which could be problematic
for new users.
This commit adds the option to set whether a workspace should be tiled or not by default. It retains
the default behaviour of komorebi, but adds the option to set a workspace to not be tiled by
default, but still be able to change the default layout for that workspace.
This commit makes it so the quickstart command first checks for the existence of the config files.
If they don't exist it writes them, if they do exist it prompts the user to whether or not they want
to overwrite the existing files. Lastly it prints the full path to the files that were written. This
is to prevent users from accidentally overwriting their configs as well as making it clearer where
komorebi places the config files for new users.
Created a test that tests moving a nonexistent container to monocle and
retreiving a nonexistent container from monocle. The test ensures we
receive an error when attempting to use monocle_on or monocle_off when a
container doesn't exist.
Created a test to test toggle monocle when a container doesn't exist in
the monitor. The test ensures that we receive an error when attempting
to call toggle monocle when a monitor doesn't contain a container.
Created a test to test trying to float a nonexistent window. The test
ensures that we receive an error when trying to float a window in an
empty container
Created a test to test cycling windows in an empty container. The test
ensures that when attempting to cycle windows in an empty container it
will push out an error.
Created a test that tests removing a nonexistent window from a
container. The test creates a monitor containing an empty container and
attempts to remove a window from the container. The test ensures that
the result is an error when calling remove_window_from_container.
This commit adds the option to set 'work_area_offset' per workspace. If
no workspace work area offset is set for that workspace it will instead
use the value of the globals.work_area_offset for that workspace.
This commit adds a command to set the work area offset of a workspace
given a monitor index and a workspace index.
This PR significantly refactors the komorebi bar rendering logic,
simplifying state management, and addressing some found bugs. The
primary motivation was to make the codebase more readable and
maintainable.
Key Changes:
- Allocation Reduction: Removed most per-frame structure allocations.
- Runtime Matching Elimination: Replaced runtime pattern matching with
pre-selected function pointers determined at initialization. Widget
validations and configurations are now performed during widget
creation rather than per-frame checks. For example, widget enablement
is now handled by an Option that wraps each ..Bar structure. If a
widget is enabled, its structure is present; otherwise, it is None.
This eliminates the need for runtime enabled checks.
- Widget Modularity: Code is split into smaller parts, reducing
complexity.
Bug Fixes:
- Corrected icon sizing for floating windows following regular
containers, ensuring icons revert correctly from icon_size to
text_size.
- There was also another bug with a floating window positioned above a
monocle container, but I forgot the details 😅
There are currently a number of commands that do not update the previously focused workspace
correctly. The previous method relied on handling each case, this change makes it so that
last_focused_workspace is always updated whenever the focus is changed.
- Removed command filtering logic from the shortcuts UI.
- All hotkey bindings are now shown regardless of command.
- Improved UI with hint text for the filter input.
Key Changes
- Added `locked: bool` field directly to the `Container` struct.
- Removed `locked_containers` from `Workspace`.
- Updated `komorebi_bar` to access `locked` directly
from `Container`.
Insert and swap operations respects `locked` container
indexes in the sequence
Following discussing in #1475, and considering the default of the
komorebi widget in komorebi-bar, this commit updates the default
StackbarLabel from Process to Title.
resolve#1475
This commit ensures that unstack_all is called on a workspace before
attempting to proceed with stack_all to avoid stacking loops that can
occur when there are multiple pre-existing stacks already created on the
workspace.
This commit ensures that the WM_SETCURSOR message is handled by stackbar
windows by setting the cursor to the default IDC_ARROW, which prevents
the spinning "Loading" icon from showing on hover.
re #1456
This commit adds a new DefaultLayout::Scrolling variant, along with a
new LayoutOptions configuration which will initially be used to allow
the user to declaratively specify the number of visible columns for the
Scrolling layout, and a new komorebic "scrolling-layout-columns" command
to allow the user to modify this value for the focused workspace at
runtime.
The Scrolling layout is inspired by the Niri scrolling window manager,
presenting a workspace as an infinite scrollable horizontal strip with a
viewport which includes the focused window + N other windows in columns.
There is no support for splitting columns into multiple rows.
This layout can currently only be applied to single-monitor setups as
the scrolling would result in layout calculations which push the windows
in the columns moving out of the viewport onto adjacent monitors.
This implementation in the current state is enough to be useable for me
personally, but if others want to iterate on this, make it handle
hiding/restoring windows correctly when scrolling the viewport so that
adjacent monitors don't get impacted etc., patches are always welcome.
resolve#1434
Created a test for swapping a container with a container that doesn't
exist, which ensures that we receive an error and that the contents of
the container is still available when attempting to swap a container
with a non-existent one.
A bug was discovered where the origin container was being removed even
though the swap_container function would return an error.
@LGUGZ discovered that the issue was due to the origin container being
removed before verifying that both containers exist. The fix that @LGUGZ
came up with is included.
Created a test for focusing on a monitor that doesn't exist, which
ensures that we receive an error and that we are still focused on the
current monitor when attempting to focus a non-existent monitor.
Created a test for swapping workspaces with a monitor that doesn't
exist, which ensures that we receive an error and that none of the
workspaces were moved when attempting to swap workspaces with a monitor
that doesn't exist.
PR #1439 authored and submitted by @JustForFun88
I understand this PR combines two areas of work — refactoring the
Applications widget and introducing a new icon caching system —
which would ideally be submitted separately.
Originally, I only intended to reduce allocations and simplify icon
loading in `applications.rs`, but as I worked through it, it became
clear that a more general-purpose caching system was needed. One
improvement led to another ... 😄
Apologies for bundling these changes together. If needed, I’m happy to
split this PR into smaller, focused ones.
Key Changes
- Introduced `IconsCache` with unified in-memory image & texture
management.
- Added `ImageIcon` and `ImageIconId` (based on path or HWND) for
caching and reuse.
- `Icon::Image` now wraps `ImageIcon`, decoupled from direct `RgbaImage`
usage.
- Extracted app launch logic into `UserCommand` with built-in cooldown.
- Simplified config parsing and UI hover rendering in `App`.
- Replaced legacy `ICON_CACHE` in
`KomorebiNotificationStateContainerInformation`
→ Now uses the shared `ImageIcon::try_load(hwnd, ..)` with caching and fallback.
Motivation
- Reduce redundant image copies and avoid repeated pixel-to-texture
conversions.
- Cleanly separate concerns for launching and icon handling.
- Reuse icons across `Applications`, Komorebi windows, and potentially
more in the future.
Tested
- Works on Windows 11.
- Verified path/exe/HWND icon loading and fallback.
This commit ensures that the user can't get into a weird state by
attempting to float a monocle container. If a user attempts to call
toggle-float on a monocle container, a warning will be logged and the
command will be ignored.
This commit adds a new StateQuery variant, FocusedContainerKind, which
will will return None if there is not focused container on the current
workspace (ie. it is empty), Single if the focused container contains a
single window, or Stack if the focused container contains more than one
window.
This commit makes it possible to send commands from the bar by using the
mouse/touchpad/touchscreen.
Komorebi or custom commands can be sent by clicking on the mouse's
primary, secondary, middle, back or forward buttons.
As the primary single click is already used by widgets, only primary
double clicks can send commands. This limitation is due to Egui also
triggering 2 single clicks before a double click is triggered. Egui does
not have an implementation for stopping event propagation out of the box
and would be too much work to include.
Similarly, commands can be sent on every "tick" of mouse scrolling,
touchpad or touchscreen swiping in any of the 4 directions. This "tick"
can be adjusted to fit user's preference.
This is due to the fact, that Egui does not have an event for when a
mouse "tick" occurs. It instead gives a number of points that the user
scrolled/swiped on each frame.
PR: #1403
Created a test for the transfer_window function.
The tests attempts to transfer a window to a monitor that doesn't exist,
and checks to see if we return an error. The test successfully gets an
error but there is a bug where the window isn't in the contiainer after
a failed transfer. I wrote a note comment to explain the bug just in
case we need to reference back to it.
Created a test for moving the focused workspace to a monitor that hasn't
been created. The test ensures that we receive an error when moving a
workspace to a monitor that doesn't exist.
Created a test for moving a window to a container that doesn't exist.
The test ensures that we receive an error when moving a window to a
container that doesn't exist.
Created a test for removing a window that doesn't exist.
The test creates a container with a window and then attempts to remove a
window that doesn't exist. The test will check the result to ensure that
the result returned an error and that we still have the expected number
of windows.
Created a test for moving a container to a workspace that doesn't exist.
The test ensures when a container is moved to a workspace that doesn't
exist, the workspace is created and that the workspace contains the
container.
It also checks that there are N workspaces available where N is the
largest workspace number.
Created a test for moving a workspace that doesn't exist. The test
attempts to remove a workspace that doesn't exist and checks to ensure
the removed_workspace variable is None.
This commit adds a simple egui helper application which shows a list of
shortcuts defined in a user's whkdrc file. Parsing AHK files is not
supported.
In addition to listing out shortcuts defined in the whkdrc file, the top
line allows users to add filter a filter to narrow down the list of
commands and key bindings to the ones they are interested in.
A new komorebic command "toggle-shortcuts" has been introduced which
will first attempt to kill "komorebi-shortcuts.exe", and then exit if
the kill signal was successful (ie. a process was closed), or proceed to
open "komorebi-shortcuts.exe" if the kill signal was not successful (ie.
no process was closed, so we should open one).
"komorebi-shortcuts.exe" has been added as a floating application in
lib.rs to allow for users to use the "komorebic move" command to
manipulate its position via their existing keyboard bindings.
This commit ensures that if a user sends one of the various messages
which ultimately call move_container_to_monitor, if the target workspace
on the target monitor currently has a monocle container, it will be
toggled off to allow space for the container being moved to be rendered.
This commit ensures that if a user sends one of the various messages
which ultimately call move_container_to_workspace, if the target
workspace currently has a monocle container, it will be toggled off to
allow space for the container being moved to be rendered.
This startup Win32 API call can sporadically fail, so this commit adds
some retry logic and logging of errors every time it fails. If it
crosses the retry threshold, the application will exit (because you
can't really have a tiling window manager running that doesn't let you
set the foreground window).
This commit ensures that workspace windows that are hidden when the user
is using HidingBehaviour::Hide will not be unintentionally reaped by a
hard-coded workaround for Microsoft Office's continuing
enshittification.
HidingBehaviour::Hide has also been marked in the docs as an EOL
feature, and some dead code that was ultimately migrated to reaper.rs
has been cleaned up.
fix#1426
This commit adds a new VirtualDesktopNotification which is used to
notify subscribers when the user leaves and enters the virtual desktop
associated with komorebi.
komorebi-bar consumes these notifications to minmize and restore the bar
appropriately depending on the currently focused virtual desktop.
re #1420
This commit improves path handling for commands and icons in the new
Application widget by making use of PathExt::replace_env when loading
the user-specified ApplicationsConfig.
Crucially for scoop users, this means that user-agnostic references to
scoop apps can now be made like this:
```
$Env:USERPROFILE/scoop/apps/zed-nightly/current/zed.exe
```
When attempting to look up an icon for a command, we now split the
command on ".exe", and if this is a complete path to a file, we try to
use it to extract an icon, otherwise we try to resolve a complete path
using "which" before doing the same.
This pull request introduces a new Applications widget that displays a
user-defined list of application launchers in the UI. Each app entry
supports an icon, a label, and executes its configured command on click.
The design of this widget is inspired by the Applications Widget of YASB
Reborn. I personally missed this functionality and aimed to bring a
similar experience to komorebi-bar.
Further information is in the text of PR #1415
This commit ensures that all borders will destroyed if komorebi detects
that the user has switched to a Windows Virtual Desktop different from
the one it was launched on and associated with.
There is still some work to be done to forcibly redraw the borders when
a navigation back to the VD associated with komorebi is detected, but
that requires tracking the state of the current VD ID outside of the
process_event handler somewhere.
re #1420
This commit adds a dedicated WindowHandlingBehaviour enum with Sync and
Async variants, and reverts a change to the render fn in window.rs to
use move_window instead of position_window if the
WindowHandlingBehaviour variant is Sync.
Add configuration option for enabling/disabling the asynchronous window
handling. The feature might cause unforeseen issues, so by default it is
off. It can be enabled with setting the option async_window_handling to
true.
Unresponsive windows might cause Komorebi to hang because functions like
SetWindowPos wait for the target window's WindowProc.
I changed most SetWindowPos calls to use the SWP_ASYNCWINDOWPOS flag,
which should avoid hanging, and I changed the one
WindowsApi::move_window call to use position_window instead. I also
changed the ShowWindow to ShowWindowAsync.
The only issue I noticed was that it caused the stackbar to disappear
(and/or flicker), probably because the window is modified right after
moving it, so I disabled the async position_window for that.
Created a simple test for the
add_window_handle_to_move_based_on_workspace_rules function.
The test creates mock data representing window and the movement details.
The test will call the function with an empty vector to hold the
workspace rules and then check that the workspace rules are in the
vector.
Created a test for the ensure_named_workspace_for_monitor function.
The test creates two monitors and holds a list of workspace names.
When calling the ensure_named_workspace_for_monitor_function the test
checks to ensure that the the the monitor contains the length of the
list workspaces and that the workspaces uses the name in the list.
The test adds more names to the list and repeats the check on the other
monitor.
Created tests for the toggle_monocle and toggle_maximize functions. The
test are simialar to the maximize and unmaximize test and the monocle on
and off test.
Created a test for the monocle_on and monocle_off functions.
The test checks to ensure that the focused workspace container becomes a
monocle container when calling the monocle_on function.
The test will also ensure that the container is moved to the workspace's
container ring when the monocle_off function is called.
Created a test for maximizing and unmaximizing a window.
The test ensures that the when calling maximize_window, the focused
window is added to the maximized_window list.
When calling unmaximized window, the checks to ensure that None is
returned to ensure that the maximized window is removed from the list.
The test switches to a different window and performs the same checks.
This commit fixes the default for `CrossBoundaryBehaviour` which was set
to `Monitor` when loading a user configuration but was set to
`Workspace` if starting from fresh without a user config.
The docs also stated that this value was `Monitor` by default.
This commit adds a few more options to combine with the
`FloatingLayerBehaviour` which determine placement in different
situations:
- `"toggle_float_placement"`: the placement to be used by a floating
window when it is forced to float with the `toggle-float` command.
- `"floating_layer_placement"`: the placement to be used by a floating
window when it is spawned on the floating layer and the user has the
floating layer behaviour set to float.
- `"floating_override_placement"`: the placement to be used by a window
that is spawned when float override is active.
- `"float_rule_placement"`: the placement to be used by a window that
matches a 'floating_applications' rule.
Each `Placement` can be one of the following types:
- "None": windows are spawned wherever Windows positions them with
whatever size they had. Komorebi does not change its size or position.
- "Center": windows are centered without changing their size.
- "CenterAndResize": windows are centered and resized according to the
defined aspect ratio.
By default the placements are as follows:
- `"toggle_float_placement"`: `"CenterAndResize"`
- `"floating_layer_placement"`: `"Center"`
- `"floating_override_placement"`: `"None"`
- `"float_rule_placement"`: `"None"`
This commit also adds the `floating_layer_behaviour` as a global config.
When using the eager focus command to focus a window that was hidden on
a stack on an unfocused workspace it would load the workspace focus the
correct window but keep it cloaked with the previously focused window
showing. This would happen because we were focusing the workspace before
focusing the window which would create two window focus events, the
first one for the previously focused window and the second one for the
target window we wanted. The problem was that when the first event was
handled it would again refocus that window and cloak the target window
again so when the target window focus event came it would ignore it
since the `should_manage` function would return `false` because the
window was cloaked and had all its window styles as `None`, unless we
had transparency enabled, in that case it would override it and create a
focus loop.
This commit fixes this by not loading the newly focused workspace
immediately. Instead we first focus the workspace if it is needed
without loading it and mark it as needing to be loaded. Then we focus
the correct target window and only then do we load the workspace. This
way the workspace loads with the correct window already focused.
This is the same approach that is currently being done on the
`perform_reconciliation` function when there is an alt-tab.
This commit adds an option to set the floating layer behaviour for all
workspaces on a monitor.
Overrides set on an individual workspace level will take precedence over
the option set at the monitor level.
Created a test for the toggle_lock function. The test creates a
workspace with multiple containers and checks to see whether the
container was added or removed from the locked containers list when
calling the toggle_lock function.
Created a test for the float_window function. The test checks to ensure
that when calling the float_window function, the window is added to the
floating_windows list and removed from the containers window list. The
test will also check the count and ensure the expected window was added.
This commit removes RetileWithResizeDimensions messages from the batches
that are sent to komorebi when changing workspace.
I'm not really sure why this was added in the first place, but removing
it doesn't seem to impact layouts on workspace switch, and more
important, by removing this message I'm no longer able to reproduce the
sudden exits of komorebi.exe under sustained workspace switching calls
made via the bar.
This commit addresses a deadlock on WINDOW_BORDERS which can occur under
load, particularly when switching workspaces.
When switching workspaces using the komorebi-bar,
RetileWithResizeDimensions is also called, which calls
border_manager::destroy_all_borders.
At the same time, border_manager::window_border is called when hiding
borders from the previous workspace. Both of these functions try to take
locks on WINDOWS_BORDERS and BORDER_STATE.
border_manager::window_border is called in a new thread by hide_border,
so if this has not finished with the lock by the time
destroy_all_borders requests it, we get stuck in a deadlock.
The changes in this commit ensure that the BORDER_STATE lock is dropped
as early as possible in destroy_all_borders, and that we are not holding
the WINDOWS_BORDERS lock in window_border while trying to get the
BORDER_STATE lock to look up BorderInfo.
The logs which show the initial deadlock being detected:
2025-04-08T22:49:37.641888Z WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber
2025-04-08T22:49:38.294952Z WARN komorebi::process_command: could not acquire window manager lock, not processing message: FocusWorkspaceNumber
2025-04-08T22:49:39.225645Z ERROR komorebi: 1 deadlocks detected
2025-04-08T22:49:39.225826Z ERROR komorebi: deadlock #0
2025-04-08T22:49:39.225950Z ERROR komorebi: thread id: 9896
2025-04-08T22:49:39.226072Z ERROR komorebi: 0: 0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99
backtrace::backtrace::trace_unsynchronized<backtrace::capture::impl$1::create::closure_env$0>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66
1: 0x7ff68fd33c87 - backtrace::backtrace::trace<backtrace::capture::impl$1::create::closure_env$0>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53
2: 0x7ff68fd3c03e - backtrace::capture::Backtrace::create
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193
3: 0x7ff68fd3bfae - backtrace::capture::Backtrace::new
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158
4: 0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211
5: 0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144
6: 0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637
7: 0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207
parking_lot_core::parking_lot::park<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600
8: 0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262
9: 0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72
10: 0x7ff68ef05eb3 - lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<isize,alloc::string::String,std::hash::random::RandomState> >::lock<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<isize,alloc::string::Str
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lock_api-0.4.12\src\mutex.rs:223
11: 0x7ff68ef0713d - komorebi::border_manager::destroy_all_borders
at komorebi\src\border_manager\mod.rs:139
12: 0x7ff68f194e61 - komorebi::window_manager::WindowManager::process_command<ref_mut$<uds_windows::stdnet::net::UnixStream> >
at komorebi\src\process_command.rs:918
13: 0x7ff68ef1fdcf - komorebi::process_command::read_commands_uds
at komorebi\src\process_command.rs:2292
14: 0x7ff68f231eb5 - komorebi::process_command::listen_for_commands::closure$0::closure$0::closure$0
at komorebi\src\process_command.rs:123
15: 0x7ff68f32bcf3 - core::hint::black_box
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:477
std::sys::backtrace::__rust_begin_short_backtrace<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152
16: 0x7ff68f00d1b4 - std::thread::impl$0::spawn_unchecked_::closure$1::closure$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:559
17: 0x7ff68f356ea1 - core::panic::unwind_safe::impl$25::call_once<tuple$<>,std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> > >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\panic\unwind_safe.rs:272
18: 0x7ff68f1d1e00 - std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> > >,tuple$<> >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:587
19: 0x7ff68f0102b3 - std::thread::impl$7::drop::closure$0<enum2$<core::result::Result<tuple$<>,eyre::Report> > >
20: 0x7ff68f007be7 - std::panicking::try
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:550
std::panic::catch_unwind
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:358
std::thread::impl$0::spawn_unchecked_::closure$1<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\thread\mod.rs:557
21: 0x7ff68ecfeb8e - core::ops::function::FnOnce::call_once<std::thread::impl$0::spawn_unchecked_::closure_env$1<komorebi::process_command::listen_for_commands::closure$0::closure$0::closure_env$0,tuple$<> >,tuple$<> >
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250
22: 0x7ff68fe84f1d - alloc::boxed::impl$28::call_once
at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976
alloc::boxed::impl$28::call_once
at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\alloc\src\boxed.rs:1976
std::sys::pal::windows::thread::impl$0::new::thread_start
at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\pal\windows\thread.rs:56
23: 0x7ff8ef27257d - BaseThreadInitThunk
24: 0x7ff8f042af28 - RtlUserThreadStart
2025-04-08T22:49:39.228617Z ERROR komorebi: thread id: 62364
2025-04-08T22:49:39.228731Z ERROR komorebi: 0: 0x7ff68fd33dec - backtrace::backtrace::dbghelp64::trace
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\dbghelp64.rs:99
backtrace::backtrace::trace_unsynchronized<backtrace::capture::impl$1::create::closure_env$0>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:66
1: 0x7ff68fd33c87 - backtrace::backtrace::trace<backtrace::capture::impl$1::create::closure_env$0>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\backtrace\mod.rs:53
2: 0x7ff68fd3c03e - backtrace::capture::Backtrace::create
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:193
3: 0x7ff68fd3bfae - backtrace::capture::Backtrace::new
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\backtrace-0.3.71\src\capture.rs:158
4: 0x7ff68f937b54 - parking_lot_core::parking_lot::deadlock_impl::on_unpark
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1211
5: 0x7ff68f921f0e - parking_lot_core::parking_lot::deadlock::on_unpark
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:1144
6: 0x7ff68f92bf88 - parking_lot_core::parking_lot::park::closure$0<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:637
7: 0x7ff68f92a777 - parking_lot_core::parking_lot::with_thread_data
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:207
parking_lot_core::parking_lot::park<parking_lot::raw_mutex::impl$3::lock_slow::closure_env$0,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$1,parking_lot::raw_mutex::impl$3::lock_slow::closure_env$2>
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot_core-0.9.10\src\parking_lot.rs:600
8: 0x7ff68f926fa0 - parking_lot::raw_mutex::RawMutex::lock_slow
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:262
9: 0x7ff68f1daac6 - parking_lot::raw_mutex::impl$0::lock
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\parking_lot-0.12.3\src\raw_mutex.rs:72
10: 0x7ff68ef05d93 - lock_api::mutex::Mutex<parking_lot::raw_mutex::RawMutex,std::collections::hash::map::HashMap<alloc::string::String,alloc::boxed::Box<komorebi::border_manager::border::Border,alloc::alloc::Global>,std::hash::random::RandomState> >::lock<parking_lot::raw_mu
at C:\Users\LGUG2Z\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\lock_api-0.4.12\src\mutex.rs:223
11: 0x7ff68f2064de - komorebi::border_manager::window_border::closure$0
at komorebi\src\border_manager\mod.rs:109
12: 0x7ff68eddeca9 - enum2$<core::option::Option<ref$<alloc::string::String> > >::and_then<ref$<alloc::string::String>,komorebi::border_manager::BorderInfo,komorebi::border_manager::window_border::closure_env$0>
at C:\Users\LGUG2Z\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\option.rs:1452
13: 0x7ff68ef06339 - komorebi::border_manager::window_border
at komorebi\src\border_manager\mod.rs:108
We shouldn't ever have empty containers, but never say never because
someone on the Discord has an empty container with no Windows that
continues to take up a tile. This commit adds a call to drop all
containers without any windows whenever Workspace::update is called.
This commit makes sure the border's width and offset is removed when you
disable the borders.
If you want to still have that size on your gaps when borders are
disabled then you should add it to the `default_container_padding` or to
the per-monitor or per-workspace `container_padding`.
This commit ensures that the replace-configuration command also replaces
bars.
Already running bars are stopped and new bars are started using the new
configuration.
This new implementation allows for expanding any environment variable so
it is not limited to just `~`, `$HOME`, `$Env:USERPROFILE` and
`$Env:KOMOREBI_CONFIG_HOME`.
It expands the follwing formats:
- CMD: `%variable%`
- PowerShell: `$Env:variable`
- Bash: `$variable`
I searched throughout the code base for path and migrate any code that
might need to PathExt::replace_env.
It is possible that I might have missed a few places due to my
unfamiliarity with the code base, so if you find any, please let me
know.
Most of the paths that needed this trait, are in:
- Clap arguments, and that was handled by #[value_parse] attribute and a
helper function.
- SocketMessage and that was handled by custom deserialization with the
help of serde_with crate
Created tests for the ensure_workspace_count function. The function is
tested by calling the function with only the default workspace, after
creating a workspace, and after we already have at least the number of
monitors passed into the funtion.
Created a test for the move_container_to_workspace funtion. The test
creates a workspace with 3 containers and an empty workspace, and
ensuresthat the container is moved to the correct workspace and that if
the workspace focus has changed when setting follow focus to true.
Created a test for the visible_windows function. The test creates two
windows in a workspace and checks to see if the the first created window
is the visible window. The test then maximizes the second window and
checks to ensure both windows are visible.
Expanded visible window test to ensure that a visible window will
display when adding another container.
This commit introduces three new commands, session-float-rule,
session-float-rules, and clear-session-float-rules, which add a
composite float rule for the currently focused window for the duration
of the komorebi session, print the float rules scoped to the current
komorebi session, and clear any float rules scoped to the current
komorebi session respectively.
The composite rule created is fairly strict, using
MatchingStrategy::Equals on the Exe, Class and Title.
Users can run session-float-rule as they are working to avoid having to
break their workflow and edit their configuration file, and when they
are ready, they can run session-float-rules to print out the composite
rules which have been generated and added to the current session to
further refine before adding them to their configuration files.
re #1402
This commit adds the option to set `Wallpaper` per monitor. When
changing workspaces it will first check for a workspace wallpaper, if
there is none it then checks for a monitor wallpaper.
This commit changes the border manager notification to an enum that can
be a `Notification::Update(Option<isize>)` which should work like before
or a `Notification::ForceUpdate` which will always update the borders
and it will also update the border's brushes. To do so, this commit
moved the brush creation from the `create()` function to a new
`update_brushes` function on the `Border` itself and it changed the
`Border` `render_target` from a `OnceLock` to an `Option<RenderTarget>`
so that we can always change it when we need to.
This commit also adds a new function called `send_force_update()` to the
border manager to make it easier to send this notification.
This commit also added a check for `force_update_borders` on the
`process_command` function so that any command that reloads the
configuration, changes the theme or changes any border config can set it
to `true`. When this is true we send the `ForceUpdate` notification, if
false we send the normal `Update` notification as before.
The theme manager now always sends the `ForceUpdate` notification to the
border manager.
This commit adds a new function to the window manager called
`apply_wallpaper_for_monitor_workspace` which in turn calls the
`apply_wallpaper` function for the workspace specified with the
`monitor_idx` and `workspace_idx` given (if the workspace in question
doesn't have a wallpaper defined this won't do anything).
All these changes make it so the wallpaper theme generation colors are
properly applied in all situations.
This commit is changing the icon on the battery widget based on the
current level.
level | icon
------------
100 - 75: discharging
75 - 50: high
50 - 25: medium
25 - 10: low
10 - 0: warning
PR: #1398
This commit adds new settings to some widgets that allows to auto
select/hide them based on their current values.
The cpu/memory/network/storage widgets get a setting that auto selects
the widget if the current value/percentage is over a value.
The battery widget gets a setting that auto selects the widget if the
current percentage is under a value.
The storage widget gets a setting that auto hides the disk widget if the
percentage is under a value.
Also added 2 new settings (auto_select_fill and auto_select_text) to the
theme, in order to select the fill and text colors of an auto selected
widget.
(Easter egg: the network icons change if the value is over the limit)
PR: #1353
This commit adds StateQuery::FocusedWorkspaceLayout variant to allow
queries for focused workspace layout via komorebic query.
This handles floating workspaces returning "None".
This commit adds a new Wallpaper configuration option to the
WorkspaceConfig, allowing the user to specify a path to a wallpaper
image file, and to specify whether to generate a base16 palette from the
colours of that image file.
Theme generation is enabled by default when a wallpaper is selected.
A set of theme options can be given to customize the colours of various
borders and accents.
The themes generated are also plumbed through to the komorebi-bar.
The palette generation algorithm from "flavours" (which has been forked
and updated) is quite slow, so the outputs are cached to file in
DATA_DIR, and keyed by ThemeVariant (Light or Dark).
The Win32 COM API to set the desktop wallpaper is also quite slow,
however this calls is async so it doesn't block komorebi's main thread.
This commit adds a new komorebi widget to indicate whether or not the
focused container is locked.
This commit also includes an icon colour change on the layer and layout
widgets to the accent colour.
The commit also renames the locked_window widget to locked_container as
it is more suitable.
PR: #1394
This commit adds the `unfocused_locked` color to the border_colours so
that users that don't use themes can still customize this color like
they do the others.
This commit adds a new StateQuery::Version, which allows integrators to
make decisions about how to handle different versions of komorebi's
state schema based on the version of komorebi that is running on a
user's machine.
This commit changes the way the alt-tab reconciliation is done.
It no longer uses the `workspace_reconciliator` with the sending of
notifications.
Instead there is a simple function that checks if the shown/uncloaked
window is already handled by komorebi and if it is it will check if it
is on an unfocused workspace and/or if it is an unfocused window of a
stacked container, returning the monitor/workspace index pair of said
window.
If we get this pair then we perform the reconciliation immediately by
focusing the monitor, workspace, container and window indices
corresponding to that window.
Added tests for the focus_container_by_window and
contains_managed_window functions.
test_focus_container_by_window crates two containers with different
distinct windows. The test checks to see if we are focused on the
expected container and window.
test_contains_managed_window creates two containers and checks to ensure
that when calling the function returns the expected result when checking
if a window is available in one of the containers.
Added a test for adding a new floating window. The test creates a
container with three windows and attempts to add one of the windows to
the list of floating windows, then checks to see if the first window in
the container was added to the floating window list and also checks the
list of windows and floating windows to ensure we get the expected
result.
This commit adds a --log-level flag to komorebi.exe which allows the
user to set the logging verbosity without setting the RUST_LOG
environment variable directly. If the RUST_LOG environment variable is
set, it will take precedence over the --log-level flag.
This commit adds a new option to the WorkspaceConfig object,
floating_layer_behaviour, which allows the user to either set
FloatingLayerBehaviour::Tile or FloatingLayerBehaviour::Float. Although
I prefer Float as a default, there was a good enough argument to make
Tile the default based on the fact that the Floating layer is
automatically engaged based on the focused window, and previously when
the focused window was a floating window, new windows would be tiled
unless they matched floating rules.
Added a test for sending a MonitorNotification using the
send_notification function. The test sends a MonitorNotification and
tests that the notification was recieved using event_rx.
Added a test for inserting a monitor into the cache. The test creates
a monitor and uses the insert_in_monitor_cache function to insert the
monitor into cache, and will attempt to retrieve the monitor from the
cache and check to see if it matches the expected value.
Addaded a test for channel capacity. The test will send 20 notifications
and then another notification, then check to ensure that all 20
messages match the notification we sent. The test will also check to
ensure the last notification sent wasn't received.
Added a test for the notification listener. The test will create a
window manager and setup the notification listener, then check to see if
we can send a notification and receive the notification.
Created a Mock Monitor that can be used with testing functions that call
the Win32 API.
Added a test for the attach_display_devices function. The test will
create a Mock Monitor and add the monitor to a closure that simulates a
display_provider. The test passes the display_provider into the
attach_display_devices function and checks to ensure we recieve the
monitor we passed in.
This commit raises and lowers all the floating windows so that they show
up with the smaller windows on top and the bigger windows on the bottom
when we toggle between layers.
This commit tries to focus the floating windows depending on the
direction used. It takes into account the top left corner of each window
and uses that to look for the closest top left corner in the direction
provided.
If there are no windows found in that direction, it then checks if it
can focus across monitor.
This commit changes the `floating_windows` from a `Vec<Window>` to a
`Ring<Window>` which allows us to keep track of the focused floating
window.
This combined with the existing layer switch allows us to know when we
should focus the focused container or the focused floating window.
This commit imports an older revision of my fork of windows-icons to
call when attempting to look up the icon of an application by it's
process id. This needs to be cleaned up before the next release.
This commit adds two new komorebic commands, move-to-last-workspace and
send-to-last-workspace, which move or send the focused window to the
last focused workspace on the focused monitor.
This commit reexports the `win32_display_data` crate so that any 3rd
party app that needs it can get it through the `komorebi-client` without
having to keep manually synchronizing it with the version used by komorebi.
This commit integrates the excellent investigation and work done by
@davor-skontra on the windows-icons repo to enable the retrieval of UWP
applications, including all those annoying Microsoft applications which
all share the ApplicationFrameHost.exe executable and the
ApplicationFrameWindow class.
Since these applications share the same executable, the icon cache in
komorei-bar has been updated to use the window hwnd as a key intead of
the window executable.
resolve#1226
This commit adds some dependency injection to the monitor reconciliator
module to make it easier to test the behaviour when different kinds of
data are returned from win32_display_data.
This commit adds the concept of locked container indexes to komorebi
workspaces.
When a container index is locked, it can only be displaced by manual
user actual - usually when another container is moved there, and when
this happens, that container becomes the locked container.
In the locked state, the container at the locked index should never be
displaced by new windows opening or existing windows around it being
closed.
When the total number of containers on a workspace falls below the
number of the locked index, the locked index will be removed.
A locked index can be identified by a special border color linked to the
new WindowKind::UnfocusedLocked variant.
The implementation of locked container indexes is backed by a new data
structure called a LockedDeque, which is a VecDeque with an auxiliary
HashSet which keeps track of locked indices.
A new komorebic command "toggle-lock" has been added to support
programmatic use of this feature, as well as the
LockMonitorWorkspaceContainer and UnlockMonitorWorkspaceContainer
SocketMessage variants which can be used by status bars.
This commit changes the behaviour of when floating windows are centered
by making them only center when we are on a `WorkspaceLayer::Floating`
and the window doesn't match a `floating_windows` rule and the workspace
is not a floating workspace.
This commit fixes a rare issue, seen exclusively with Acer monitors so
far, where two monitors of the same model can have an identical serial
number id.
If we encounter a system which has two connected monitors with the same
serial id number, the serial id number will be forcefully unset and
blacklisted for the rest of the session.
In this case, users must fall back to using device_id for options like
display_index_preferences.
Possibly a little overkill, but since this has been such a headache I'm
going to opt for this approach over #1368 for now.
This commit ensures that the WM_SETCURSOR message is handled by border
windows by setting the cursor to the default IDC_ARROW, which prevents
the spinning "Loading" icon from showing on hover.
Some credit is due to the user steiner5 on Discord for whining about me
not being interested in working on this while more generally complaining
about komorebi, which consequently made me want to work on this out of
spite since he's probably going to bounce off the software anyway.
Added a test for the cycle_window_in_direction function. The function is
tested by creating 3 windows and cycling in both the next a previous
direction. The test will ensure that the windows were cycled by checking
the window index to ensure it is the expected window.
Created a test for cycling the window by index. This test is similar to
the other cycle window test and performs the same steps as that one,
except it uses the test_cycle_container_index_in_direction function
instead.
This commit removes some workarounds on the `update_focused_workspace`
function that were there to fix issues related to some bugs on the
`workspace.restore()` function.
This commit fixes the bugs on the `restore` function instead. The
`update_focused_workspace` function should be used only to update a
workspace layout.
This commit ensures that when the user switches to the flooating layer
any new spawned window will be spawned floating as if the float override
was set.
This results in a workflow which makes it easier to spawn floating
windows on the fly.
This effectively reverts commit ff2aa5e51a.
This fixes the issue where borders moved to other monitors would
sometimes be removed by their initial monitor because this data wasn't
being updated.
This effectively reverts commit 5919f88b38.
Added a test for moving a workspace from one monitor to another. The
test will ensure that after calling the function, the current monitor
index is the one where the workspace was transfered to. Test also will
check the count to ensure the new workspace was added to the new monitor
and that the old monitor has one less.
Added a test for swapping monitor workspaces. The test will create two
monitors one with a workspace that has a container containing multiple
windows and another with one. The test calls the swap_monitor_workspaces
function and then checks to see if the two workspaces were successfully
swapped.
Added a test to test toggling the tiling state. After each switch the
test will test the current state to ensure that it is the expected
state.
It's very annoying and unclear when enabling the float override to open
the next window as floating to have that window appear immediately over
an existing tile.
This commit sets an explicit behaviour to center windows spawned while
the float override is active.
This commit addresses a border rendering issue when moving a window from
a higher-indexed monitor to a lower-indexed monitor.
Previously, we would do a single render pass across all monitors in
order of their indexes, destroying borders no longer needed, and
creating new borders for new windows.
This resulted in the window being moved to the lower-indexed monitor
still existing in the global border cache when that monitor's borders
were updated, but then being removed when the borders of the origin,
higher-indexed monitor were updated.
With the changes in this commit, if we encounter a situation like this,
an additional render pass will be executed to ensure that the window
will have a corresponding border created on the destination
lower-indexed monitor.
This commit ensures that a workspace float override will also be applied
when the user switches to the floating layer, and removed when the user
switches to the tiling layer. This results in a workflow which makes it
easier to spawn floating windows on the fly.
This commit ensures that if a user switches from a workspace with
managed windows to a workspace without any managed windows but only
floating windows, the focused window from the previous workspace will
lose focus as it should, and the first floating window on the new
workspace will gain focus as it should.
Added a test for removing a window from a container. The test checks to
ensure a new container is created and that the removed window from the
original container is added to the new container. Also ensures that the
old container has one less container after the function is called.
Added a test for removing a workspace. The test keeps track of the
number of workspaces and the current workspace index.
Added test for swapping containers from different monitors. The test
will create two monitors and containers with different amount of
windows. Test will verify that the swap is successful by checking that
the number of windows in the container matches the number of windows it
was created with in the previous monitor. The same will be done with the
other container.
This commit limits the number of times the time and date widgets get a
new state.
Even though having a limit of 1 second on the ui repaint, when the bar
is focused or hovered, this is ignored and state of these widgets were
updated many more times a second.
The time widget looked less accurate and lagging (especially with
multiple showing seconds) so the refresh interval is set to be 500 ms
instead of 1 second.
This commit allows either the single canonical applications.json file,
or multiple files which adhere to the asc scheme to be given to the
app_specific_configuration_path config option.
I thought I had already implemented this earlier, but evidently I
hadn't.
This will be useful for people who want to maintain their own
independent set of asc rules, as they can be kept in a dedicated file
which won't be overwritten by the fetch-asc command.
resolve#736
This commit adds the FocusMonitorAtCursor SocketMessage on all the
toggle buttons as the monitor idx is not sent as a parameter and the
monitor needs to be focused when these buttons are clicked on the bar
(especially for multiple bars).
Use the preferred id set by the user as the key when caching monitors.
This way if a user is having issues with the device_id on their system
they can use the serial_number_id on display_index_preferences.
If instead a user is having issues with the serial_number_id they can
make sure to use the device_id on display_index_preferences. Komorebi
will use the preferred one as a key when caching the monitors.
This PR also includes a change of the DISPLAY_INDEX_PREFERENCES from a
Mutex to RwLock.
I believe the RwLock is better since it allows multiple readers at the
same time, while the mutex blocks on all calls even if you just want to
read or compare some value.
For display index preferences (same thing applies to other existing
mutexes) most times we access it is a read-only access. We only ever
change it when applying a config or when a command is used to change it.
Every other use is a read-only use so it doesn't make sense to block on
those situations
This commit fixes an issue where the move/resize functions for floating
windows weren't properly taking into account the coordinates of
secondary monitors and were only working correctly on the main monitor
where top/left was 0/0.
Implemented drop to ensure that the socket is deleted whenever the
function goes out of scope. This will ensure that if the test fails, the
test socket file will still be removed.
Added a test for cycling to the next and previous container in a
workspace.
Added a test for transfering a window from Monitor 1 to Monitor 2
Added a test for transfering a container to another montior. Also
updated the transfer window test to transfer the window back to the
original container. Both tests will check both monitors to ensure the
expected number of containers are in both.
Previously if we had a stack on a monocle container and tried to cycle
stack or move the window within the stack or even using the focus stack
window from a bar it would focus the wrong window and temporarely show
that wrong window. This commit fixes this.
This commit adds a little Easter egg on the time widget.
Use the `changing_icon` setting to enable this feature.
Based on the current time, the widget will use different icons to
indicate certain activities of the day.
00:00 MOON
06:00 ALARM
06:01 BREAD
06:30 BARBELL
08:00 COFFEE
08:30 CLOCK
12:00 HAMBURGER
12:30 CLOCK_AFTERNOON
18:00 FORK_KNIFE
18:30 MOON_STARS
This commit adds the timezone on the time and date widgets as a new
setting.
In case the timezone is invalid, the output is replaced with an error
message.
Use a custom format to display additional information.
resolve#1312
Created a test that creates the WM instance and ensures the instance is
running. The test creates a custom socket and then cleans up the socket
file after completion.
Created a test that creates a WM instance, monitor instance, and
workpace. The tests checks to ensure that the expected workspace is
focused properly.
Included recommended fixes to ensure that the focus_workspace function
is used correctly and that the test accurately checks the workspaces
length, current workspace index, and switching to an existing workspace.
This commit adds a variation of the cycle-workspace command which will
attempt to focus the next empty workspace in the given direction (with
the usual wraparound). If there are no empty workspaces available, this
command will do nothing.
This commit adds a bit of offset to the time widget's binary clocks so
they are more in the middle.
It also fixes some visual changes that were caused by upgrading to
eframe 0.31
This commit refactors the `border_manager` with the following changes:
- Rework the way the borders are created and their pointer is sent to
the window message handler. Now we also store the same pointer as a
`Box<Border>` on the `border_manager`'s `BORDER_STATE`. This means
that the borders we have are exactly the same ones that the border
window itself is accessing so we can now store the border's info
inside the `Border` struct and all of it will be accessible by the
border window as well. This makes it so the "ACTUAL" border struct is
the one created on the thread of the `Border::create()` function and
when that thread finishes (after the border window closes) it will
handle the drop of the border itself. However this means we need to be
careful with our own stored `Box<Border>` since it will point to the
same memory we can't let the compiler dropped them as usual or
otherwise it would create heap corruption errors. So this commit
creates a special function called `destroy_border()` to actually close
the window border without dropping the border, since it will be later
dropped by the thread that created it.
- Remove `BORDERS_MONITORS`, `FOCUS_STATE` and `RENDER_TARGETS` arc
mutexes, since now this info is stored on the border itself.
- Change the `BORDER_STATE` to now map an id (container or window) to a
`Box<Border>`.
- Change the `WINDOWS_BORDERS` to now map a window hwnd to a border id.
- Create new struct `BorderInfo` which as the border window hwnd and the
border kind. This struct is what is now returned by the function
`window_border()` which checks if some window as a border attached to
it and if it does it returns this info. There is no need to clone the
entire border. If in the future we need more info we can just add it
to this struct.
- Change the way we clear the `BORDER_STATE`. Like mentioned before we
need to be sure we don't drop the `Box<Border>` when removing it, so
now we use the `.drain` function to remove all the borders as an
iterator and we call the `destroy_border()` on each border we are
removing.
- We now check if a border's `tracking_hwnd` has changed and if it does
we simply update it instead of destroying the border and create a new
one.
- Create function `delete_border` so that we can remove a border
properly from outside the `border_manager`.
- Create function `hide_border` which spawns a new thread that searches
if a window hwnd has a border attached to it and if it does it hides
said border window. This function is called on every `window.hide()`.
- Create function `show_border` which spawns a new thread that searches
if a window hwnd has a border attached to it and if it does it restores
said border window. This function is called on every `window.restore()`.
- This commit also changes the previous `window.hide()` and
`window.restore()` functions to be named:
- `window.hide_with_border(hide_border: bool)`: this is the same
function as before but adds a check at the end in case `hide_border`
is true it calls `border_manager::hide_border()`. A new function was
created with the same name as before `window.hide()` which by
default calls this new function with `hide_border = true`.
- `window.restore_with_border(restore_border: bool)`: this is the same
function as before but adds a check at the end in case `hide_border`
is true it calls `border_manager::hide_border()`. A new function was
created with the same name as before `window.hide()` which by
default calls this new function with `hide_border = true`.
- This commit creates a new function on `Container` called
`load_focused_window_ignore_borders()` which performs the same as
`load_focused_window()` but it ignores the borders when hiding and
restoring the windows. This function, along with the
`hide_with_border(false)` and `restore_with_border(false)` are used on
all functions related to changing focus on a stack since if we let the
borders be hidden and restored when cycling or changing focus on a
stack the border would flicker slightly, this prevents that. Ignore
borders when clicking on the stackbar as well.
(P.S. there might still be other places that I forgot to use these new
functions, but if that is the case then what will happen is a simple
flicker of the stack border...)
- The `remove_window` from `Workspace` needs to call the
`border_manager::delete_border()` so that wew make sure we remove that
windows's border window as well if it exists. This is essential when
enforcing workspace rules, otherwise the border would be left behind.
- Lastly, but not least, now that we hide the borders windows along with
their tracking window, we no longer remove the borders when swapping
workspaces or when toggling monocle, etc. Instead we keep all borders
of all workspaces cached and simply hide them. They are only removed
when their tracking window is closed or cloaked on a stack (since on a
stack we only keep one border for all the entire stack container).
This means that when changing between workspaces we no longer see the
borders showing up delayed after the windows show up. Now both the
window and it's border show up as if they are one and the same.
This commit makes all schemars::JsonSchema derives optional. After
analyzing the output of cargo build timings and llvm-lines, it was clear
that the majority of the 2m+ incremental dev build times was taken up by
codegen, and the majority of it by schemars.
Developers can now run cargo commands with --no-default-features to
disable schemars::JsonSchema codegen, and all justfile commands have
been updated to take this flag by default, with the exception of the
jsonschema target, which will compile with all derives required to
export the various jsonschema files.
Incremental dev build times for komorebi.exe on my machine are now at
around ~18s, while clean dev build times for the entire workspace are at
around ~1m.
This commits adds the ability to set icons for the `workspace-layer` with
the `DisplayFormat` and a setting to specify if it should `show_when_tiling`
or not.
collab with @alex-ds13
This commit ensures that the resize dimensions will be reserved for
other monitors and workspaces when the
toggle-window-based-work-area-offset command is used.
This commit fixes a breaking change on the selected_frame that was
introduced by eframe version 0.31.
In this version, the stroke is drawn on the inside of a Frame instead it
being drawn on the outside like before.
This now means that a stroke needs to be added on all the states of the
Frame in order to avoid all the elements to be moving around on hover.
Previously the stacking logic would sometimes change the focused
container without actually changing focus to said container.
This resulted in the stack showing up with an unfocused border even
though we had focus on one windows belonging to the stack (just not the
right one).
Also before it wasn't possible to stack windows on some directions
when we were already on a stack.
This commit fixes both issues.
This commit fixes multiple issues with the borders which were resulting
in multiple borders being created and not completely destroyed which
meant that the amount of borders in memory kept increasing indefinitely
the more we used komorebi. To do so this commit does the following:
- Clear all the maps on `destroy_all_borders`.
- Create function `remove_border` which should always be used when we
want to remove a border since this function destroys the border window
and removes all its related data and clones from all the maps.
- Create function `remove_borders` which should always be used when we
want to remove multiple borders or filter the current existing
borders. It takes in a `condition` function that takes a ref to the
border's container id and a ref to the border and should return a
bool. This function is then applied to each existing border and if it
evaluates to true it will call `remove_border` on it.
- Apply these new functions on all the code that was previously manually
removing borders.
- When a container is a stack, we now check it's unfocused windows, in
case they had borders attached to them we remove them, otherwise these
borders would persist and be drawn below other borders.
- We now check if a container's border was previously tracking a different
window, if it was we destroy that border and remove it's hwnd from the
`FOCUS_STATE` and then we check if its `tracking_hwnd` still points to
the same border and remove it if it does (if it doesn't that means
that a new border was already attached to that window so we don't
remove it).
We don't call `remove_border` here since we don't want to actually
remove the border but instead we replace it with a new one tracking
the correct window. (I've tried updating the `tracking_hwnd` instead
of destroying the border and creating a new one but that didn't work
since it still kept tracking the previous window...).
This commit makes it so when you toggle between workspace layers it
moves all windows of that layer to the top of the z-order.
So if you move to `Floating` layer, then all floating windows are moved
to the top, and if you go back to the `Tiling` layer, all tiled
containers are moved to the top.
This commit makes sure that the accent color is used on certain bar
components, such as active workspace, selected layout and focused
window.
This will now make these components stand out even more for a better
visual indication.
fix#1288
This commit stops the `FocusChange` event from focusing a floating
window when it is the one emitting said `FocusChange` event, since it's
not needed and is the cause of some flicker bugs reported!
If that floating window was the one emitting the `FocusChange` event
then it means it is already the foreground window, and there is no
reason for us to focus the window again (since that will create an
infinite loop of events).
When the window emitting this event is not floating we don't try to
focus the window, we simply set the focus index for the container of
that window and the focused index for the window of that container.
Except in one case, which is if the workspace has a monocle container,
then it does focus a window, it focuses the monocle window to make sure
the monocle keeps showing in front of everything and doesn't let
anything come in front of it.
Previously the reaper at startup would lock it's own `HWNDS_CACHE` and
then try to lock the WM to get its `known_hwnds`.
However if there was an event in the meantime, process_event would lock
the WM first and then it would try to lock the reaper's `HWNDS_CACHE` to
update it. This would deadlock since that would be locked by the reaper
waiting for the WM lock to be released.
This commit now makes it so we pass the `known_hwnds` to the reaper as
an argument at startup and it also rearranges the order of loading the
listeners.
Now komorebi first loads all the manager-type listeners, and only
afterwards does it load the commands and events listeners.
After some testing this seems to be the best order that doesn't cause
any issues at all!
There were some other issues that I've noticed before when starting
komorebi while having other 3rd parties trying to subscribe to it (like
komorebi-bar and YASB), which would make those subscribers lock the
`process_command` thread. This doesn't seem to be happening on my tests
anymore with this new order.
This commit makes sure the bar applies the the `work_area_offset`
correctly after a monitor reconnects; if it is the first time a monitor
is connecting, the cached offset won't exist yet.
This commit fixes an issue where if you started komorebi without a
monitor connected, and then connected it later, it wasn't properly
loading the data returned from `win32-display-data`.
This commit adds an extend_enum! macro and some unit tests to provide
an ergonomic way to specialize configs for specific (sub)widgets.
The macro takes the name of the existing enum, the desired name of the
new, extended enum, and a list of variants which should be added to the
extended enum.
The macro will add new variants to a new enum definition first, before
wrapping the existing enum in an Existing variant and tagging it with
the `#[serde(untagged)]` annotation.
From is also implemented for ergonomic from/into calls between shared
variants of the existing and extended enums.
This commit adds the ability to set container and workspace padding per
monitor.
To do so (and to simplify any future need of changing some value per
monitor), and have it pass through to each workspace a new field was added
to `Workspace` called `globals` which has a new struct called
`WorkspaceGlobals`.
`WorkspaceGlobals` includes any global values that might be needed by
the workspace.
This field is updated by the monitor for all its workspaces whenever the
config is loaded or reloaded. It is also updated on `RetileAll` and on
the function `update_focused_workspace`.
This should make sure that every time a workspace needs to use it's
`update` function, it has all the `globals` up to date!
This also means that now the `update` function from workspaces doesn't
take any argument at all, reducing all the need to get all the
`work_area`, `work_area_offset`, `window_based_work_area_offset` or
`window_based_work_area_offset_limit` simplifying the callers of this
function quite a bit.
Lastly this commit has also (sort of accidentaly) fixed an existing bug
with the `move_workspace_to_monitor` function.
This was previous removing the workspace from a monitor, but wasn't
changing it's `focused_workspace_idx`, meaning that komorebi would get
all messed up after that command. For example, the `border_manager`
would get stuck and the komorebi-bar would crash.
Now, the `remove_focused_workspace` function also focuses the previous
workspace (which in turn will create a new workspace in case the removed
workspace was the last workspace).
Previously if a workspace had any floating windows it would always focus
the first one when restoring. Now it only focus the floating window if
the workspace layer is `Floating`.
This commit introduces an implementation of workspace layers to
komorebi.
Workspace layers change the kinds of windows that certain commands
operate on. This implementation features two variants,
WorkspaceLayer::Tiling and WorkspaceLayer::Floating.
The default behaviour until now has been WorkspaceLayer::Tiling.
When the user sets WorkspaceLayer::Floating, either through the
'toggle-workspace-layer' command or the new bar widget, the 'move',
'focus', 'cycle-focus' and 'resize-axis' commands will operate on
floating windows, if the currently focused window is a floating window.
As I don't have 'cycle-focus' bound to anything, 'focus up' and 'focus
down' double as incrementing and decrementing cycle focus commands,
iterating focus through the floating windows assigned to a workspace.
Floating windows in komorebi belong to specific workspaces, therefore
commands such as 'move' and 'resize-axis' will restrict movement and
resizing to the bounds of their workspace's work area (or more
accurately, the work area of the monitor that the workspace belongs to,
as floating windows are never constrained by workspace-specific work
area restrictions).
This commit changes the way the reaper works.
First this commit changed the `known_hwnds` held by the `WindowManager`
to be a HashMap of window handles (isize) to a pair of monitor_idx,
workspace_idx (usize, usize).
This commit then changes the reaper to have a cache of hwnds which is
updated by the `WindowManager` when they change. The reaper has a thread
that is continuously checking this cache to see if there is any window
handle that no longer exists. When it finds them, the thread sends a
notification to a channel which is then received by the reaper on
another thread that actually does the work on the `WindowManager` by
removing said windows.
This means that the reaper no longer tries to access and lock the
`WindowManager` every second like it used to, but instead it only does
it when it actually needs, when a window actually needs to be reaped.
This means that we can make the thread that checks for orphan windows
run much more frequently since it won't influence the rest of komorebi.
Since now the `known_hwnds` have the monitor/workspace index pair of the
window, we can simply get that info from the map and immediately access
that monitor/workspace or use that index info.
The `WorkspaceConfig` stored on `Workspace` was changed to not be
serialized, however it needs to be serialized and deserialized when
caching a monitor (after a disconnect), so that when it reconnects it is
able to read all the workspace rules, which include:
- initial_workspace_rules
- workspace_rules
- window_container_behaviour_rules
- layout_rules
- custom_layout_rules
This commit changes the serde skip to only skip if is is `None`.
This means that the `komorebic state` command will have all this
information as well and it will send it when notifying subscribers too,
which isn't good at all, so we need to find another way of excluding it
from the state.
This commit introduces a few changes to the bar so that it can handle
the monitor disconnect/reconnect properly and so that it can map the bar
config to the correct monitor.
Previously if you had 3 monitor configs setup on `komorebi.json` with
the `display_index_preferences` set like this:
```
"display_index_preferences": [
"0": "MONITOR_A",
"1": "MONITOR_B",
"2": "MONITOR_C",
]
```
But if you only had connected monitors A and C you would have to
manually change the bar configurations monitor index because now monitor
A would have index 0, but monitor C would have index 1 instead of 2.
Now with this commit this is no longer needed. Now the monitor index
setup on the bar configuration **MUST BE** the index you've used on
`display_index_preferences` for that monitor.
So in the case above you would setup the bar configurations using the
indices 0, 1 and 2 for monitors A, B and C respectively.
As for the changes introduced on this commit they are the following:
- `Komobar.monitor_index` is now an `Option`. When it is `None` it
either means that the bar is starting and has not yet received the
first `State` from komorebi or that the bar is disabled.
- `Komobar.config` is no longer an `Arc`. There was no need for that and
it was creating more issues and difficulties. It was mainly used to
pass the config as an `Arc` to `apply_config` function, but then this
function would actually clone the config itself (not just the `Arc`).
Also this function was passing a `self.config.clone()` most of the
times except once when it received a new config from a hotreload. Now,
on hotreload it first sets `self.config` to the new config and then
calls `apply_config` which now uses its own `self.config` everywhere.
- We only change the `work_area_offset` when the bar is not disabled.
- We update the global `MONITOR` size/coordinates when we receive a
`DisplayConnectionChange` from komorebi.
- We also check if the monitor size/coordinates have changed from the
currently stored ones on every komorebi notification since sometimes
the `DisplayConnectionChange` would be emitted while the state still
had the previous size/coordinates.
This makes sure we always capture a change of size/coordinates, store
the new values, and update the bar.
- The previously mentioned update of the `MONITOR` coordinates also
updates the `config.position.start` since that value is being
overriden on `main.rs` in case the user hasn't set it so we need to
override it again with the new monitor coordinates.
This might mean that users of the old config system might have their
start position changed, but if we didn't do this the bar wouldn't even
show on the screen for them when a monitor disconnected/reconnected.
This is another case for users to start moving into the new config
system, since with that system the bar will still show up with the
correct margins!
This commits adds a few more events that can trigger a
`DisplayConnectionChange` event.
Some of these events are redundant and after a display is
disconnected/reconnected it emits multiple `DisplayConnectionChange`
events.
However, when trying to remove them to have just one it stopped behaving
as it should, as if it was missing the update, while having them
duplicated it works properly.
Therefore it appears to be better to keep them for now, since the
duplicated events will exit early as soon as they see that the monitor
counts match (on the first event the counts don't match so it
adds/removes the monitor and the following events see that the counts
match).
When there is a monitor disconnect/reconnect, usually it produces
multiple monitor events along with it, like the monitor resolution
change and the work area change. With the bound set to 1 it would
sometimes result in missed events.
This commit increases the bound to 20 to prevent this from happening.
This commit makes sure that if the state on file isn't up to date with
the expected `State` struct (maybe after an update) it doesn't panic
komorebi entirely, instead it ignores the state and continues with a
clean state.
This commit changes the MONITOR_CACHE to hold an actual monitor with its
state instead of the config.
This allows us to keep the state of a disconnected monitor, so that when
the monitor reconnects we still have access to all its workspaces and
windows as they were before.
While the monitor is disconnected, all the windows from that monitor are
not considered as handled by komorebi and so they're free to be handled
at any point; if for example the user uses `alt+tab` or presses the
taskbar icon of one of these windows, that window will produce a `Show`
event and will become handled by the currently focused workspace of the
focused monitor.
When the disconnected monitor reconnects it checks all windows and once
it notices that this specific window is now being shown on another
monitor/workspace, it ignores it.
This commit allows a bar to be disabled when it's monitor is
disconnected and re-enabled when said monitor reconnects.
This commit also uses the new `monitor_usr_idx_map` to properly map the
monitor index given by the users on config to the actual monitor index
on the `WindowManager` - in case some middle monitor gets disconnected
the index of the monitors to the "right" of that one will be lowered by
1.
This should allow for the following in cases with monitor A, B and C: if
monitor B disconnects, its bar will be disabled and monitor C will
properly change its monitor index internally to 1 so it still gets the
infos from monitor C (which now will have index 1 on the
`WindowManager`).
This commit creates a new field on the `WindowManager` called
`monitor_usr_idx_map` which contains a map of user intended index for
monitors to their actual monitors' index.
It will be rebuilt on `load_monitor_information` by taking into account
the `display_index_preferences`.
This commit makes sure that any workspace_rules that tried to move a
window to a monitor that has been disconnected are removed.
If the monitor is later reconnected the workspace_rules should be added
from the cached config.
This commit makes use of both `serial_number_id` and `device_id` with
the first taking priority on all monitor reconciliator code, monitor
cache and on postload and reload.
This allows using the serial numbers on the `display_index_preferences`
config, while keeping compatibility with the use of `device_id`.
Using `device_id` should be discouraged since that value can
change on restart while serial number doesn't appear to do so.
When a monitor was disconnected the containers from the removed monitor
were being moved to the primary monitor.
However they weren't restored so containers that were on an unfocused
workspace of the removed monitor would have been cloak and were getting
added to the main monitor still cloaked creating ghost tiles. This
commit fixes that.
If we have display_index_preferences that set a specific config index
for a specific display device, but that device isn't loaded yet, now we
store that config with the corresponding `device_id` on the monitor
cache.
Now when the display is connected it can load the correct config from
the cache.
This commit reworks the way the `postload` and the `reload` functions
apply the monitor configs to the monitors.
Previously it was looping through the monitor configs and applying them
to the monitor with the index corresponding to the config's index.
However this isn't correct, since the user might set the preferred
indices for 3 monitors (like monitor A, B and C), with the preferred
index set to 0 for A, 1 for B and 2 for C, but if only monitors A and C
are connected then komorebi would apply config 0 to A and config 1 to C,
which is wrong it should be 2 for C.
This commit changes the way the configs are applied on those functions.
Now it loops through the existing monitors (already in order), then
checks if the monitor has a preferred config index, if it does it uses
that one, if it doesn't then it uses the first monitor config that isn't
a preferred index for some other monitor and that hasn't been used yet.
For the situation above it means that it would still apply config 2 to
monitor C. And in case there aren't any display_index_preferences set it
will still apply the configs in order.
Store the `WorkspaceConfig` on the `Workspace` itself so that when we
want to cache the workspace as `WorkspaceConfig` on the monitor cache it
properly saves things like the workspace rules and the custom layout and
custom layout rules.
Previously, when caching a workspace config for a monitor it would
simply store the `DefaultLayout` on `layout` even if the original
workspace config had the `layout` as `None`, which makes komorebi create
a workspace with the `layout` as default `BSP` and the `tile` set to
`false`.
This resulted in floating workspaces would becoming tiling `BSP`
workspaces after a monitor disconnect and reconnect.
This commit fixes this by turning the `layout` to `None` when `tile` is
`false`.
System::new_all() pulls all information (processes, cpu, mem, etc) but
we only need process information.
In addition currently it is being polled twice. System::new() creates an
uninitialized struct, then we poll specifically for process info.
This commit is a squashed commit containing the below commits from
PR #1266, which introduces a new "Keyboard" widget, which is used to
display information about the user's currently selected keyboard input
language. This new widget has a data refresh interval of 1 second if not
specified by the user.
721d2ef40858373cd26cce27a76b36fb9054a18b55cc2fd889461a73833e781b8d0bd0fa6bf6ff76
This commit is a squashed commit of all the individual commits that made
up PR #1267 - adding various derives and re-exports aimed at improving
the komorebi integration surface for third party applications.
This commit adds a check which will only allow the focused workspace to
have a full update if the number of managed containers is non-zero.
Previously, this would be triggered in a loop when focusing a workspace
with only focused windows.
Going back in time to the first versions of komorebi and yatta which
didn't have so many different container and window kinds, this was
intended to be called whenever the focus was changed to update the
state.
With the complexity komorebi handles in 2025, there are also many calls
to Win32 APIs when we call self.update_focused_workspace, so we need to
be a bit more careful about when and where we call it.
re #816
This commit ensures that we emit a dedicated border manager event when
WinEvent::SystemForeground is received.
The OS can actually be slower than komorebi when it comes to processing
changed focus state, and in the border manager we rely on
GetForegroundWindow when calculating which the border focus state and
color should be.
This has previously resulted in a situation where there may be no border
with the "focused" color.
This should no longer be a problem because even in the situations where
the OS is slower than komorebi and is still returning an old HWND from
GetForegroundWindow, the new event that we emit to border manager in
response to WinEvent::SystemForeground will ensure that the border focus
colors get updated.
This commit adds a new komorebic command, focus-monitor-at-cursor, which
can optionally be chained with the focus-workspace command in
keybindings to reproduce the previous default behaviour of auto-focusing
whichever monitor the cursor was on before attempting to change the
focused workspace.
This commit makes sure the `layout-rules` and
`window_container_behaviour_rules` are sorted when setting them from the
config. So that the behaviour on workspace update is correct.
This commit ensures that if a user removes an optional block from the
static config file, when reloading a workspace config, the removed
option will also be unset in the window manager workspace configuration
state.
This commit improves the handling of the situation where a user, with
mouse-follows-focus diabled, focuses a secondary monitor with an empty
workspace, either via a komorebic command or by moving the cursor and
clicking on that empty workspace, and then attempts to switch
workspaces.
Previously, if the focus was made by a komorebic command, the mouse
cursor would not move from the previous monitor, and then when trying to
switch the workspace, the previous monitor would be focused against
first. The only way to change focus would be to move the mouse to the
secondary monitor.
With these changes, the following situations all work as expected:
* MFF On + MFF Off: komorebic cmd to focus an empty workspace on a
secondary monitor allows subsequent focus-workspace cmds to execute on
the newly focused secondary monitor
* MFF On + MFF Off: Moving the cursor to an empty workspace on a
secondary monitor allows subsequent focus-workspace cmds to execute on
the newly focused secondary monitor
There is one slight change in behaviour:
* MFF On + MFF Off: When the cursor is on a populated workspace on a
secondary monitor which is not focused, focus-workspace cmds will not
execute on that secondary monitor, but on the currently focused
monitor
resolve#831resolve#1128
This commit adds a new static config option,
window_container_behaviour_rules, which similarly to layout_rules, takes
a map of window container count threshold => window container behaviour.
When the number of window containers on the screen meets a given
threshold, the new window container behaviour is applied to the
workspace.
This can be used to automatically change from creating new window
containers for new windows to appending new windows to existing window
containers when the number of window containers on the screen reaches
more than what can be comfortably laid out and viewed on a user's
screen.
resolve#953
This commit pulls in changes to win32-display-data which provide the
monitor hardware serial number id taken from WmiMonitorID where
available.
No work has yet been done to integrate this with options such as
display_index_preferences.
This commit adds a title regex-based ignore list for applications
identified in object_name_change_applications. When a title change on an
EVENT_OBJECT_NAMECHANGE matches one of these regexes, the event will
never be processed as a Show.
This is an edge case workaround specifically targeting the issue of web
apps in Gecko-based browsers which update their page titles at a fixed
regular interval, which was highlighted in #1235.
resolve#1235
This commit fixes a bug where workspace rules would not be populated
properly on file reloads, leading to issues with the
ReplaceConfiguration message handler.
This commit ensures that floating windows, monocle containers and
maximized windows will be considered when the hide_empty_workspaces
option is enabled for the komorebi widget.
re #1131
This commit introduces a new PathExt trait with a fn replace_env which
can ensure all environemnt variables are loaded for a PathBuf.
As part of the initial rollout this is used in komorebi-bar to look up
environment variables for the configuration switcher widget.
resolve#1131
Added the ability of use modifiers with custom format on the Date widget.
For example if using %U returns 04, you can add a modifier so that bar
date widget shows 05.
This commit adds a new configuration option
"floating_window_aspect_ratio", which users can manipulate to set their
desired window size when using the toggle-float command.
resolve#1230
This commit ensures that Hide events on Layered windows (usually added
when the transparency feature is enabled) will always be considered
eligible for handling.
This will avoid situations where ghost borders are left behind because
the Hide event was ignored.
fix#878
This commit ensures that if mouse-follows-focus is disabled, the cursor
will not follow a focus change to a monocle container on an adjacent
monitor.
fix#1119
This commit removes the code on the workspace `update` on `layout-rules`
where it was setting the `layout-flip` to `None` if the layout was
different from `BSP`. This appears to be some old code when the
layout-flip would only apply to the `BSP` layout. However now it appears
to apply to all layouts so this code shouldn't exist. This commit also
changes the docs from the `FlipLayout` command to remove the statement
that only applied to `BSP` since it is no longer true.
This commit changes the `rx_gui` from receiving just a notification from
komorebi to now receive a new type `KomorebiEvent` which can be either a
`KomorebiEvent::Notification(komorebi_client::Notification)` or a
`KomorebiEvent::Reconnect`.
The `Reconnect` is sent after losing connection with komorebi and then
reconnecting again.
Now on the bar `update` we check for this `rx_gui` if we get a
notification we pass that to the
`KomorebiNotificationState::handle_notification` function just like
before (except now it takes a notification directly instead of taking
the `rx_gui` and checking for some message on the channel).
If instead we get a `Reconnect` we send a `MonitorWorkAreaOffset` socket
message to komorebi to update the work area offset.
This interactively rebased commit is comprised of the subsequent
individual commits listed further below.
At a high level:
- work_area_offset is now automatically calculated by default
- monitor can now take an index in addition to the previous object
- position can largely be replaced by margin and padding for bars that
are positioned at the top of the screen
- frame can now largely be replaced by margin and padding for bars that
are positioned at the top of the screen
- height is now a more intuitive configuration option for setting the
height of the bar
Detailed explainations and examples are included in the body of PR #1224
on GitHub: https://github.com/LGUG2Z/komorebi/pull/1224
fix(bar): add simplified config for bar
This commit creates a few new config options for the bar that should
make it a lot simpler for new users to configure the bar.
- Remove the need for `position`: if a position is given the bar will
still use it with priority over the new config. Instead of position
you can now use the following:
- `height`: defines the height of the bar (50 by default)
- `horizontal_margin`: defines the left and right offset of the bar, it
is the same as setting a `position.start.x` and then remove the same
amount on `position.end.x`.
- `vertical_margin`: defines the top and bottom offset of the bar, it is
the same as setting a `position.start.y` and then add a correct amount
on the `work_area_offset`.
- Remove the need for `frame`: some new configs were added that take
priority over the old `frame`. These are:
- `horizontal_padding`: defines the left and right padding of the bar.
Similar to `frame.inner_margin.x`.
- `vertical_padding`: defines the top and bottom padding of the bar.
Similar to `frame.inner_margin.y`.
- Remove the need for `work_area_offset`: if a `work_area_offset` is
given then it will take priority, if not, then it will calculate the
necessary `work_area_offset` using the bar height, position and
horizontal and vertical margins.
feat(bar): set margin/padding as one or two values
This commit changes the `horizontal_margin`, `vertical_margin`,
`horizontal_padding` and `vertical_padding` to now take a
`SpacingAxisConfig` which can take a single value or two values.
For example, you can set the vertical margin of the bar to add some
spacing above and below like this:
```json
"vertical_margin": 10
```
Which will add a spacing of 10 above and below the bar. Or you can set
it like this:
```json
"vertical_margin": [10, 0]
```
Which will add a spacing of 10 above the bar but no spacing below. You
can even set something like this:
```json
"vertical_margin": [0, -10]
```
To make no spacing above and a negative spacing below to make it so the
tiled windows show right next to the bar. This will basically be
removing the workspace and container padding between the tiled windows
and the bar.
fix(bar): use a right_to_left layout on right side
This commit changes the right area with the right widgets to have a
different layout that is still right_to_left as previously but behaves
much better in regards to its height.
fix(bar): use default bar height
When there is no `work_area_offset` and no `height` on the config it was
using the `BAR_HEIGHT` as default, however the automatica
work_area_offset calculation wasn't being done properly. Now it is!
feat(bar): monitor can be `MonitorConfig` or index
This commit allows the `"monitor":` config to take a `MonitorConfig`
object like it used to or simply a number (index).
docs(schema): update all json schemas
fix(bar): update example bar config
fix(bar): correct work_area_offset on secondary monitors
feat(bar): add multiple options for margin/padding
This commit removes the previous `horizontal_margin`, `vertical_margin`,
`horizontal_padding` and `vertical_padding`, replacing them all with
just `margin` and `padding`.
These new options can be set either with a single value that sets that
spacing on all sides, with an object specifying each individual side or
with an object specifying some "vertical" and/or "horizontal" spacing
which can have a single value, resulting on a symmetric spacing for that
specific axis or two values to define each side of the axis individually.
This commit adds the StateQuery::FocusedWorkspaceName variant to allow
users to query the name of the focused workspace via the komorebic query
command.
re #1238
This commit handles an edge case where minimize events would not be
processed if both transparency and animations were enabled at the same
time.
fix#1231
This commit adds CJK font fallbacks to Microsoft YaHei and Malgun
Gothic. This will be looked up at runtime on the user's system, and only
loaded if the files exist in the default Windows font installation
location.
resolve#1139
This commit is a follow up to 7bf1521363,
ensuring that if a user has changed global padding options, that they
will be preserved from the initialized window manager state and applied
on top of the dumped state which is being restored.
For some reason, when calling the `window.set_position` when creating
the Komobar or even when applying the config on the first frame the
actual EGUI's window size wasn't changing. This commit adds a new field
to `Komobar` called `size_rect` so that we can store the expected size
rect of the window according to the config, so that we don't have to be
calculating it all the time. This field is updated on `apply_config`.
Now on `update` of the bar we check if the current size using the EGUI
Context is the expected `size_rect`, if it is we do nothing, if it is
not we update the bar position. This makes sure that on start the bar
will resize to the users config correctly! Now the resize of the bar
only happens here.
This commit also adds the `hwnd` field to `Komobar` so that we don't
have to be calling `process_hwnd()` all the time.
This commit introduces an if let binding to only process windows which
still exist when attempting to enforce workspace rules.
Previously, calls to functions such as Window::exe might have returned
an error if a window which had been destroyed but not yet removed from
the state was examined by the enforce_workspace_rules fn. Now, such
windows will fail the if let binding and be skipped entirely, eventually
being removed by the core event processing loop.
This commit adds a new widget, "Update", which will check for komorebi
version updates using the cargo package version of the running binary
and the latest release returned from the GitHub API.
If the latest release is newer than the current cargo package version, a
widget will be shown, which can be clicked to open the changelog of the
latest release.
This commit adds an early exit from the border manager's event
processing loop whenever a window which still exists in the state but
has been destroyed is encountered. Instead of returning an error, the
'containers loop will now skip ahead to the next iteration.
This commit also makes an adjustment to the frequency with which the
reaper sends border manager notifications - a single notification is now
sent at the end of each iteration if necessary, rather than one
notification per workspace.
If a user triggers the workspace reconciliator by clicking on an app in
the start bar or via alt-tab, a notification should be sent to
subscribers such as komorebi-bar so that the focused workspace can be
updated.
The various komorebi reconciliators and manager modules don't emit
events to subscribers themselves (yet?), so for now we can pass on the
uncloak event.
Maybe we can look into expanding the Notification enum in the future.
fix#1211
This commit adds mutex lock scoping in
WindowManager::enforce_workspace_rule to avoid a deadlock when
should_update_focused_workspace evaluates to true.
fix#1212
This commit updates various docs with information on the long-promised
individual commercial use license which will be available to purchase
from 01 Jan 2025 onwards.
This commit adds a new komorebic command "eager-focus", which takes a
full case-sensitive exe identifier as an argument. When komorebi
receives this message, it will look through each monitor and workspace
for the first matching managed window and then focus it.
This allows users who have well defined workspaces and rules to bind
semantic hotkeys to commands like "komorebic eager-focus Discord.exe" to
immediately jump to applications instead of mentally looking up their
assigned workspaces or positions within container stacks.
This commit adds a new field to the static config file, "remove_titlebar_applications", which allows
users to now use the full range of matching strategies to identify applications for which titlebars
should be removed. This is heavily discouraged for a number of reasons, and is unlikely to work with
a wide range of applications which now draw their own titlebar regions. The previous advice to use
in-application configuration settings to hide title bars if they exist is still valid.
resolve#805
This commit adds the following new socket messages and commands:
- `EnforceWorkspaceRules`: resets the `already_moved_window_handles` and
calls `enforce_workspace_rules` so that all workspace rules, including
initial workspace rules are applied again
- `enforce-workspace-rules`: cli command which sends the
EnforceWorkspaceRules socket message
Sometimes the bar would randomly stop receiving notifications from
komorebi and would stop updating the `Komorebi` widget.
This feels to me that the reason is the same one that used to happen on
the `process_commands` from `komorebi` where the socket would get stuck
reading an empty connection.
This commit adds a read timeout to the socket to prevent that from
happening and hopefully it should stop those situations where the bar
would stop receiving notifications.
Previously when changing between themes with different backgrounds the
widget's background color was not updating because they take the bg
color from the `RenderConfig` which was only being updated on
`apply_config`, now we also pass the `RenderConfig` to the `apply_theme`
function and update it's `background_color` there as well.
On some computers the context colors were being reset on the very first
frame. So now we try to apply the theme on the first frame and
afterwards we only do it again when there is a config change or a theme
socket message.
There were some cases were the bar was showing some shaking, turns out
that using `ui.with_layout` instead of `ui.horizontal_centered` removes
this shaking, so this commit makes that change and uses the
`right_to_left` layout on the right widgets again, meaning that we need
to reverse them again.
Group roundings were getting lost when applying the theme after a
`komorebi.json` change/save trigger. Now we reapply these groupings on
the `apply_theme` to make sure they are always correct.
Previously when reading the `theme` from `komorebi.json` it was also
getting the transparency_alpha from the `StaticConfig`, this is wrong,
it should use the alpha from the bar config. This commit fixes that.
Previously if we changed/set the theme on `komorebi.json` it would apply
that theme to the bar without taking into account the transparency
alpha, also after removing the `theme` from `komorebi.json` file it
wasn't applying the theme from the bar config. This commit fixes these
issues.
This commit changes the way each of the 3 parts of potential widgets
(left, center and right) is created so that they are all done on the
same way and look the same. It is using `Area` with different anchors
for each part which makes the widgets actually center vertically
properly.
This created an issue with the `Bar` grouping. To fix it we've made the
`Bar` grouping change the outer panel frame instead of creating an
actual group. This has the side effect (or maybe feature!) of losing the
background of the outer frame. Meaning this outer frame will now have
the look of the `Bar` grouping only. Currently it is using a fixed outer
margin but this can be changed in the future to a config option.
This commit creates a new `SocketMessage` called `StopIgnoreRestore`
which makes komorebi stop without calling `window.restore()` on all
windows. This way every maximized window will stay maximized once you
start komorebi again and it is able to use the previous `State`.
If it fails to restore the previous state you might have to call
`komorebic restore-windows` in case you had hidden windows, for example
when when using the `window_hiding_behaviour` as `Hide`, or you can
simply unminimize them if you were using `Cloak` or `Minimize`.
This commit adds two new `DisplayFormat` types:
- `TextAndIconOnSelected`: which displays icon and text for the selected
element and the other elements only have text.
- `IconAndTextOnSelected`: which displays icon and text for the selected
element and the other elements only have icon.
This commit makes the `workspaces` on `Komorebi` widget optional. This
way it allows adding the `workspaces` on one Alignment and the
`focused_window` on another one, for example.
This commit changes the way icons are displayed on the bar.
There was an issue with how app icons were sized using shrink_to_fit.
This has been changed to use fit_to_exact_size instead, relying on the
font size as a starting point and scaling it to 1.4 of its size, making
the icons to appear larger.
The same scaling was done to all the widget icons as well to make them
look unified.
This commit makes sure we focus the previously focused workspace on all
monitors, load it and update it and in the end focus the actual focused
monitor and workspace pair calling `update_focused_workspace` to make
sure it updates the workspace and gives focus to the focused window.
This commit adds changes to the main wm process to dump a state file to
temp_dir() when the process is exited either via komorebic stop or
ctrl-c, and to automatically try to reload that dumped state file if it
exists on the next run.
A new flag "--clean-state" has been added to both komorebi.exe and the
komorebic start command to override this behaviour.
The dumped state file can only be applied if the number of connected
monitors matches the number of monitors recorded in the state, and if
every HWND listed in the state file still exists.
This is validated by calling Window.exe(), which under the hood checks
for the continued existence of the process associated with the HWND.
Only the "workspace" subsection of the state for each matching
connecting monitor will be applied.
This commit adds various transparency related global configuration
values to GlobalState, which is can be queried via the komorebic
global-state command.
resolve#1182
This commit corrects a typo which adds the "--masir" flag to the
autostart shortcut when the user has passed the "--bar" flag to the
enable-autostart command.
fix#1178
This commit makes use of the new `send_batch` function to batch all the
messages in one go when pressing the button to move between workspaces
or when moving between stacked windows.
Since we are creating this messages in one go we won't be mistakenly
changing the value of mff for the user.
It also only batches the mff messages when the mff value it's true, if
it is already false there is no need to be sending those extra messages.
This commit adds a helper function `send_batch` to komorebi-client that
allows sending multiple messages in a batch.
3rd party users of this library could already do this themselves but it
is nice to have this helper to simplify it.
This commit adds an icon cache which is indexed by executable name to
avoid unnecessary calls to windows_icons::get_icon_by_process_id, which
is known to start failing after the komorebi-bar process has been
running for a certain (unknown) period of time.
This commit makes it so a floating window only has the floating border
when it is focused, if not it has the `Unfocused` border. It also makes
the 'focused_container' have the `Unfocused` border when it is not the
foreground window, for example when we have a floating window focused
instead.
This commit also changes the border's `window_kind` so that the stored
borders actually have that value so we can check it later (This value
wasn't being updated).
This commit also makes it so we properly invalidate the borders in the
situations discussed above (for example when changing focus to/from a
floating window we need the floating window border to update its ZOrder
as well as the previously focused window).
Lastly this commit, changes the `WM_PAINT` code part of the border so
that it now sets the position of border so that the border's ZOrder
updates to it's tracking window ZOrder.
This commit introduces a number of changes to the border manager module
to enable borders to track the movements of windows as they are being
animated.
As part of these changes, the code paths for borders to track user
movement of windows have also been overhauled.
The biggest conceptual change introduced here is borrowed from
@lukeyou05's work on tacky-borders, where the primary event listener of
the komorebi process now forwards EVENT_OBJECT_LOCATIONCHANGE and
EVENT_OBJECT_DESTROY messages from application windows directly on to
their borders.
These events are handled directly in the border window callbacks,
outside of the main border manager module event processing loop.
In order to handle these events more performantly in the border window
callbacks, a number of state trackers have been added to the Border
struct.
When handling EVENT_OBJECT_NAMECHANGE, these values are read directly
from the struct, whereas when handling WM_PAINT, which is sent by the
system whenever we invalidate a border window, we update the state
values on the Border structs from the various atomic configuration
variables in the mod.rs file.
Another trick I borrowed from tacky-borders is to store a pointer to the
Border object alongside a border window whenever it is created with
CreateWindowExW, which can be accessed within the callback as
GWLP_USERDATA.
There is some unfortunate introduction of unsafe code to make this
happen, but the callback uses null checks to exit the callback early to
ensure (to the best of my ability) that there are no pointer
dereferencing issues once we start making border changes in the context
of the callback.
There are a few other Direct2D related optimizations throughout this
commit, mainly avoiding the recreation of objects like brush properties
and brushes.
Finally, the border_z_order option is now deprecated as the border
window is now tracking the z-ordering of the application window it is
associated with by default - this should resolve a whole host of subtle
border z-ordering issues, especially when dragging windows around using
the mouse.
This work would not have been possible without the guidance of
@lukeyou05, so if you like this feature, please make sure you thank him
too!
This commit adds a new komorebic command, "kill", to kill background
processes that may be started by "komorebic start", without terminating
the main komorebi process.
This is useful when iterating on changes to external components like the
bar which may require restarts.
This is a small change to the start command which moves the check for
the komorebi processes to come a little bit earlier.
This small change will make running commands like "komorebic start
--bar" around 3s faster when komorebi is already running.
The visual changes include:
* the focused_window section is now indicating the active window in a stack and has hover effect.
* custom icons for all the layouts, including `paused`, `floating`, `monocle` states.
* custom layout/state picker with configurable options.
* display format configuration for the layouts (Icon/Text/IconAndText)
* display format configuration for the focused_window section (Icon/Text/IconAndText)
* display format configuration for the workspaces section (Icon/Text/IconAndText)
This commit fixes an issue where when trying to move floating windows or
windows on a floating workspace across boundaries to another monitor
using the `move_container_in_direction` it wouldn't move the floating
windows physically, although it moved them internally on komorebi,
resulting in weird and wrong behavior.
This commit creates a new method on `Monitor` to
`add_container_with_direction` which takes a move direction and then
uses the same logic that was previously on the
`move_container_in_direction` function.
It changes the `move_container_to_monitor` function to take an optional
move direction which if it is some will have this function call the new
method `add_container_with_direction` instead of just `add_container`.
Lastly the `move_container_in_direction` function now when it realizes
the move will be across monitors simply calls the
`move_container_to_monitor` with the direction that was initially given
to it.
These changes require that all callers of `move_container_to_monitor`
add an direction option, instead of passing `None` on all of them, a new
helper function was created, named `direction_from_monitor_idx` which
calculates the direction a move will have from the currently focused
monitor and the target monitor return `None` if they are the same or
returning `Some(direction)` if not. This way now all commands that call
a move across monitor will use the logic to check from the direction if
it should add the container on front or end.
With these changes now all the code related to moving a window across
monitors using a command should be on one place only making sure that in
the future any change required only needs to be done on one place,
instead of having to do it on `move_container_to_monitor` and
`move_container_in_direction` as before!
This commit is an interactive squashed rebase of the following commits
from PR #1154:
8f4bc101bc
fix(wm): move floats in direction across monitors
This commit fixes an issue where when trying to move floating windows or
windows on a floating workspace across boundaries to another monitor
using the `move_container_in_direction` it wouldn't move the floating
windows physically, although it moved them internally on komorebi,
resulting in weird and wrong behavior.
This commit creates a new method on `Monitor` to
`add_container_with_direction` which takes a move direction and then
uses the same logic that was previously on the
`move_container_in_direction` function.
It changes the `move_container_to_monitor` function to take an optional
move direction which if it is some will have this function call the new
method `add_container_with_direction` instead of just `add_container`.
Lastly the `move_container_in_direction` function now when it realizes
the move will be across monitors simply calls the
`move_container_to_monitor` with the direction that was initially given
to it.
These changes require that all callers of `move_container_to_monitor`
add an direction option, instead of passing `None` on all of them, a new
helper function was created, named `direction_from_monitor_idx` which
calculates the direction a move will have from the currently focused
monitor and the target monitor return `None` if they are the same or
returning `Some(direction)` if not. This way now all commands that call
a move across monitor will use the logic to check from the direction if
it should add the container on front or end.
3b20e4b2fe
refactor(wm): use helper function on move to workspace
Use the same `add_container_with_direction` function on
`move_container_to_workspace` as it is being used on
`move_container_to_monitor` or `move_container_in_direction`.
This way we bring parity between all methods and make it easier to
change the way a container is added on a monitor workspace when taking
the move direction into consideration.
83f222fe84
* fix(wm): correctly define moves across monitors
Moves within the same workspace were being considered as moves across
monitors when the workspace was floating (not tiled).
This commit fixes this by changing the way we first define if a move was
across monitor or not.
We now search for the moved window on all workspaces and check if its
monitor index is different from the target monitor index (the monitor
where the move ended).
a02694348e
* fix(wm): ignore moves/resizes on floating workspaces
This commit makes sure that moves or resizes within a floating workspace
(i.e. not tiled) will be ignored, unless the move is across monitors.
We don't care about the positions or sizes of windows within a floating
workspace!
4bf24f81e0
* fix(wm): avoid workspace load on cross monitor moves
This commit replaces the `window_manager.focus_workspace` call with a
`monitor.focus_workspace` which doesn't load the workspace. There is no
need to load the workspace when moving windows across monitors since
those workspaces will already be loaded, we simply need to update them.
Loading the workspace would cause some issues as well, like when moving
a window to a floating workspace which already contained a window that
matched some `floating_windows` rules was always putting the
"floating_window" on top of the window we just moved with a bunch of
focus flickering. This is fixed with this commit.
cb53f463ae
* fix(wm): avoid workspace load on command move across monitor
If the move happens between the already focused workspaces of two
monitors we shouldn't load the workspace, since it is already loaded and
it will cause changes on focused windows, which might result on the
window we just moved not being focused.
* Added a new floating area at the center of the bar
* Optional center widgets config, fixed spacing on the center widget
* Turning transparency on by default
When moving maximized floating windows across monitors they were
magically disappearing!
The window would be on the correct place, with the correct coordinates
and size, its styles wouldn't change it would still have the `VISIBLE`
style, however the window was invisible.
If we used the system move to try to move it sometimes we would be able
to see a bar on the top of the monitor and if we moved the window with
the keyboard on the direction of another monitor then the window would
start showing up on that monitor... So it was visible on that monitor
but not on the one we just moved it into.
After some investigation I decided to atribute that behavior to magic,
since I couldn't find any other plausible explanation, if someone knows
about this please tell me, I too would like to learn the ways of this
dark mysteries from the deep of the Windows OS.
On a serious note, this commit creates a workaround for this by simply
unmaximazing the window first (it's not restore, it doesn't change the
size) then it moves the window (if animations are enabled it proceeds to
wait for the animation to finish...), then it maximizes the window
again.
Previously when moving floating windows across monitors we would keep
the size of the window as it was. For most cases this would be ok.
However for users with monitors with completely different sizes this
could result on a window that would fill across monitors when moving
from the bigger monitor to the smaller monitor.
This commit, attempts to resize the windows proportionally to the
monitors' sizes.
There is currently a slight issue with some apps (so far I've only
noticed it on 'Wezterm'...) where if the DPIs across monitors are
different they don't seem to fully get the OS DPI change completely, but
it seems that setting the `Wezterm` compatibility high DPI scaling
override to "System" on the app's executable properties, fixes the
issue.
Since this is only 1 app (so far...) and only when the scales between
monitors are different I decided to commit this anyway.
This will do more good than harm, since in the cases it was misbehaving
with 'Wezterm' the result would be a wrongly resized window that is
still completely visible on the target monitor anyway and the override
fix seems to be good so far.
This commit is comprised of the following interactively rebased commits
from PR #1002 by @thearturca.
1a184a4442
refactor(animation): move animations to its own mod
First step for more rusty version animations. The goal is to make
animations more generic so its easier to add new animations to komorebi!
d3ac6b72c2
refactor(animation): reduce mutex calls on `ANIMATION_STYLE`
8a42b738fe
refactor(animation): introduce `Lerp` trait
e449861c10
refactor(animation): generalized ANIMATION_MANAGER
Instead of a isize key for the ANIMATION_MANAGER HashMap, now we use a
String key. For window move animation, the key would be
`window_move:{hwnd}`.
This allows us to use single manager for more types of animations.
67b2a7a284
feat(animation): introduce `AnimationPrefix` enum
8290f143a6
feat(animation): introduce `RenderDispatcher` trait
2400d757fe
feat(animation): implement window transparency animation
This commit also fixes graceful shutdown of animations by disabling them
before exit and wait for all remaining animations for 20 seconds.
44189d8382
refactor(animation): move generation of `animation key` to `RenderDispatcher`
e502cb3ffb
refactor(animation): rename `animation` mod to `engine`
Linter was upset about this:
> error: module has the same name as its containing module
369107f5e0
feat(config): adds per animation configuration options
Originally static config only allowed global config for animations.
Since this refactor introduces the abilty to add more type of
animations, this change allows us to configure `enabled`, `duration` and
`style` state per animation type.
Now each of them take either the raw value or a JSON object where keys
are the animation types and values are desired config value. Also adds
support for per animation configuration for komorebic commands.
There was an issue where if you changed focus across monitors and the
target monitor had a maximized window it would focus one of the
containers beneath it instead. And if there were no containers it
wouldn't focus anything, but instead keep focus on the previous monitor.
This commit fixes that issue.
This commit follows up on a point made by @notTamion in #1128 - since we
have the monitor index, we can use it in the bar's workspace widget to
more accurately target workspaces via
SocketMessage::FocusMonitorWorkspaceNumber.
This commit adds the "CtByte" and "CtByteWithShadow" aliases for the
"Default" and "DefaultWithShadow" GroupingStyle variants respectively as
an easter egg to recognize @CtByte's work in implementing the grouping
feature.
This commit is a small fix which ensures that the latest value of
transparency_alpha will be read and applied from config rather than
self.config in the apply_config fn.
This commit ensures that when switching to a workspace which contains a
floating window or a maximized window, either the maximized window or
the first floating window index will be focused.
This is to prevent windows which have been hidden on the previous
workspace from retaining keyboard focus.
fix#1130
This commit adds various widget grouping and transparency options to
komorebi-bar, and is comprised of the individual commits listed below,
worked on in PR #1108, squashed into one.
e8f5952abb
* adding RenderConfig, and some test frames on widgets
0a5e0a4c0a
* no clone
a5a7d6906c
* comment
6a91dd46cd
* ignore unused
80f0214e47
* Group enum, Copy RenderConfig
fbe5e2c1f7
* Group -> Grouping
ce49b433f9
* GroupingConfig
f446a6a45f
* "fmt --check" fix (thanks VS)
d188222be7
* added widget grouping and group module
1008ec2031
* rounding from settings, and apply_on_side
7fff6d29a9
* dereferencing
655e8ce4c1
* AlphaColour, transparency, bar background, more grouping config options
cba0fcd882
* added RoundingConfig
ec5f7dc82d
* handling grouping edge case for komorebi focus window
12117b832b
* changed default values
645c46beb8
* background color using theme color, AlphaColour.to_color32_or, updating json format for Grouping and RoundingConfig
10d2ab21c7
* hot-reload on grouping
d88774328a
* grouping correction on init
2cd237fd0d
* added shadow to grouping, optional width on grouping stroke
4f4b617f26
* grouping on bar, converting AlphaColour from_rgba_unmultiplied, simplified grouping
3808fcec8f
* widget rounding based on grouping, atomic background color, simplified config, style on grouping
be45d14f6d
* renamed Side to Alignment, group spacing
be45d14f6d
* proper widget spacing based on alignment
b43a5bda69
* added widget_spacing to config
c18e5f4dbe
* test commit
cba2b2f7ac
* refactoring of render and grouping, widget spacing WIP
9311cb00ec
* simplify no_spacing
36c267246b
* correct spacing on komorebi and network widgets (WIP)
85a41bf5b2
* correct widget spacing on all widgets
50b49ccf69
* refactoring widget spacing
9ec67ad988
* account for ui item_spacing when setting the widget_spacing
e88a2fd9c0
* format
This commit overhauls the "Komorebi" borders implementation to use
Direct2D, which enables anti-aliasing for rounded borders.
A lot of the heavy lifting was done by @lukeyou05 in the tacky-borders
project, which this commit largely adapts to komorebi. @lukeyou05
provided an incredible amount of guidance and feedback on the
implementation of this feature on the komorebi Discord.
This commit is a squashed interactive rebase of the following commits:
238271a71e
feat(borders): initial impl of direct2d border drawing
5525a382b9
feat(borders): avoid multiple render target creation calls
431970d7b6
feat(borders): reduce redraws to improve perf
47cb19e54a
feat(borders): remove black pixels around direct2d corners
3857d1a46c
feat(borders): clean up render targets on destroy
This commit adds a new komorebi command "cycle-stack-index" which allows
the user to manipulate the index position of the focused window in the
focused stack by swapping it with either the previous or the next window
until the desired index position has been found.
After investigating further the issue where commands would randomly stop
working, we've noticed that the issue seems to be that somehow the
listening thread gets stuck reading the unix socket, as in it
continuously tries to read a socket on a connection that is not sending
anything anymore. The result would be that komorebi would no longer be
able to receive commands until it was restarted.
This fix adds a read timeout of 1s and it spawns a new thread to handle
the stream reading and process of cmds. So in case this happens again,
that specific processing thread will only be stuck for 1s but the rest
of komorebi will never get stuck and should keep working normally.
This change prevents the move animation from playing again for each
window in the stack. Tested with all hiding behaviors. Looks good so
far.
resolve#1029
This commit ensures that when attempting to reload the static
configuration file after the user has imperatively created new
workspaces, the configuration reload logic will not attempt to load a
workspace config for those imperatively created workspaces.
This commit ensures that the exact workspace indices are tracked in the
komorebi widget state.
This fixes a bug where an incorrect workspace index could be sent with
SocketMessage::FocusWorkspaceNumber if a user had hide_empty_workspaces
set to true.
fix#1102
This commit introduces a new komorebic command, close-workspace. This
command will remove the focused workspace from the window manager state
if the following conditions are met:
1. The number of workspaces on the focused monitor are >1
2. The workspace is empty
3. The workspace is unnamed
The third condition is to ensure that we are not removing workspaces
which have been declared in the static configuration file.
This commit ensures that if an IdWithIdentifer without an explicitly set
matching strategy makes it through to should_act_individual, it will be
treated the same as MatchingStrategy::Legacy instead of causing a
runtime panic.
This commit switches all relevant commands to treat the v2
applications.json asc format as the default format in all commands.
The v1 applications.yaml file will still be processed correctly if
passed.
This commit fixes the issue related to moving windows to/from a floating
workspace to a tiled workspace.
Previously the start of the move would be ignored however when moving
back from a tiled workspace since it didn't know about the existance of
that window it would also "move" that workspace focused tiled window
without physically moving it, leaving it in a weird state that seemed
like it was unmanaged.
This commit changes the way this mouse moves are handled and now also
handles moving `floating_windows` and even monocle or maximized windows.
This commit allows calls to Border::destroy to fail when called in the
context of border_manager::destroy_all_borders. This is important in the
context of the retile command, which calls this function, to not leave
the retile in an inconsistent state.
This commit ensures that when both the origin and target containers are
stacks during a stack operation, the "slurping" stack extension
behaviour introduced in cfb0c7f2ce will
not be applied.
fix#1085
Currently, komorebi checks if a move is happening by checking if the
left mouse is pressed and updates the borders when there is a move while
the left mouse button is pressed (BTW this is why when moving with the
keyboard using the system move it only updates after pressing enter).
However, for some reason AltSnap somehow steals this left button
information and komorebi thinks the button is not pressed.
This PR makes it so it checks for the state of the pending_move_op and
keeps updating the borders while this is_some().
This fixes both that issue with AltSnap and the issue with system move,
as well as any other situations that might allow moving a window with
anything else that doesn't use a left mouse button press.
This commit makes sure we refocus the window on `Show` event when it is
the only window on the workspace.
This is needed because some windows send the `FocusChange` event before
the `Show` event and on the first event we will be focusing the desktop
window to unfocus any previous window from other workspace because the
workspace will still be empty. So after adding the window, we need to
focus it again.
This commit allows `workspace-rules` and `initial_workspace_rules` to be
applied to floating windows. As a by product of this commit, now the
command to show `visible-windows` will now also show the maximized
windows, monocled windows and floating windows.
This commit adds a `matches_floating_applications` to the `RuleDebug`
which allows users to know if a window was matched as a floating window
when using the debug part of the GUI.
This commit adds a new SocketMessage::Theme which allows for themes to
be set programmatically. This change has also been plumbed through to
komorebi-bar so that the bar theme will also update after komorebi
processes the message and passes it on to subscribers.
A new theme_manager module has been introduced to add notification-based
handling of theme changes, both from the static config file being
updated and from SocketMessage::Theme being received.
This commit updates the build and release workflow to enable multi-arch
builds and releases.
A number of Rust-specific actions have been added, namely rust-cache to
handle cargo caching and actions-rust-cross to handle cross-compilation.
A release-dry-run target has been added to run on master which should
help catch any issues in release workflow changes early.
Releases drop goreleaser entirely in favour of action-gh-release which
was already in use to add msi installers to the releases previously
created by goreleaser.
This commit adds support for a v2 format of the application specific
configuration file, centralizing on JSON to maximize the knowledge
crossover for people already familiar with the types used in
komorebi.json.
The biggest difference besides the format change is that matchers must
be used explicitly for every kind of rule, rather than being able to
specify options on a default rule. This is a bit more verbose, but
ultimately allows for significantly more flexibility.
After some investigation by @alex-ds13 on Discord it looks like there
are times where attempting to gain a lock on the WindowManager inside of
read_commands_uds results in the thread becoming blocked when it's not
possible to obtain the lock.
Instead of waiting indefinitely for a lock, this change ensures that we
will wait for at most 1 second before discarding the message so that the
command listener loop can continue.
Warning logs have been added to inform when a message has been dropped
as a result of lock acquisition failure.
This commit adds a new SocketMessage variant,
RetileWithResizeDimensions, to preserve any resize dimensions applied by
the user.
This new variant is now used when clicking on a workspace using the
komorebi widget in komorebi-bar.
This commit adds a new method, subscribe_with_options to
komorebi-client.
The first option introduced is to tell komorebi to only send
notifications when the window manager state has been changed during the
processing of an event.
This new subscription option is now used with komorebi-bar to improve
rendering and update performance.
This commit changes the `move_container_to_monitor` from the WM to allow
moving floating windows as well.
It also adds a new method `move_to_area` to the `Window` that allows
moving a window from one monitor to another keeping its size.
This commit creates a new function for the workspaces to check if they
are empty or not.
This function properly accounts for maximized windows, monocle windows
and floating windows.
This should fix the cases where the WM was checking if the workspace was
empty to focus the desktop in order to loose focus from previously
focused window.
Previously it wasn't checking for floating windows so it cause continues
focus flickering when there were only floating windows on the workspace.
This commit introduces a new option `float_override`, which makes it so
every every window opened, shown or uncloaked will be set to floating,
but it won't be ignored. It will be added to the floating_windows of the
workspace, meaning that the user can later tile that window with
toggle-float command.
This allows the users to have all windows open as floating and then
manually tile the ones they want.
This interactively rebased commit contains changes from the following
individual commits:
0e8dc85fb1
feat(wm): add new float override option
30bdaf33d5
feat(cli): add command for new option `ToggleFloatOverride`
b7bedce1ca
feat(wm): add window_container_behaviour and float_override to workspaces
221e4ea545
feat(cli): add commands for workspace new window behaviour and float_override
b182cb5818
fix(wm): show floating apps in front of stacked windows as well
7c9cb11a9b
fix(wm): Remove unecessary duplicated code
This commit introduces a distinction between ignored applications
(previously identified with float_rules) and floating applications.
All instances of "float_" with the initial meaning of "ignored" have
been renamed with backwards compatibility aliases.
Floating applications will be managed under Workspace.floating_windows
if identified using a rule, and this allows them to now be moved across
workspaces.
A new border type has been added for floating applications, and the
colour can be configured via theme.floating_border.
This interactively rebased commit contains changes from the following
individual commits:
17ea1e6869
feat(wm): separate floating and ignored apps
8b344496e6
feat(wm): allow ws moves of floating apps
7d8e2ad814
refactor(wm): float_rules > ignore_rules w/ compat
d68346a640
fix(borders): no redraws on floating win title change
a93e937772
fix(borders): update on floating win drag
68e9365dda
fix(borders): send notif on ignored hwnd events
This commit ensures that whenever komorebi.json is read and deserialized
into StaticConfig via StaticConfig::read, all known paths where
$Env:KOMOREBI_CONFIG_HOME and $Env:USERPROFILE are accepted will be run
through the resolve_home_path helper fn.
This commit fixes the cases where you'd call this command on a monitor
which was not focused, for example by pressing a button on a bar like
komorebi-bar or other when you had focus on another monitor.
This change ensures that first we focus the monitor where the mouse cursor
is, this way it will act on the monitor that you've just pressed instead
of the monior that was focused before.
This commit adds a "bar_configurations" option to the static config file
which takes an array of PathBufs.
If this option is defined and the --bar flag is passed to the "komorebic
start" command, komorebic will attempt to launch multiple instances of
komorebi-bar.exe with the --config flag pointing to the PathBufs given.
This configuration option is only consumed by komorebic, not by the
window manager directly, so it could also be used by other status bar
projects to read configuration file locations from.
There is no requirement for the PathBufs to point specifically to
komorebi bar configuration files if the --bar flag is not being used
with "komorebic start".
This commit replaces almost all uses of the egui Viewport API for bar
window positioning with calls to SetWindowPos via komorebi_client's
Window struct.
This seems to play much more smoothly with multi-monitor setups where
each monitor has a different scaling factor, opening the door for
multiple instances of komorebi-bar.exe to run against multiple monitors.
As a result of this change, the "viewport" configuration option has been
renamed to "position" and doc strings have been changed to remove the
reference to the egui crate docs. Similarly, "viewport.position" and
"viewport.inner_size" have been renamed to "position.start" and
"position.end" respectively. Backwards-compatibility aliases have been
included for all renames.
This commit ensures that the komorebi-bar.exe process is DPI aware and
applies DPI compensation to viewport.position and viewport.inner size
both on launch and on configuration reload. viewport.position changes
are now hotloaded wihtout having to restart the process.
re #1024
This commit ensures that when switching to a workspace, if that
workspace is empty, the desktop window will be focused (and focus will
be removed from the last focused window on the previous workspace)
regardless of the value of follow_focus.
This commit ensures that other "slow" applications (besides firefox)
which require a compensation time to sleep before continuing with
eligibility checks can be configured by end users in komorebi.json.
As the compensation time will vary depending on the specs of the end
user's machine, the compensation time in ms has also been made
configurable.
This commit ensures that komorebi will compile when targeting 32-bit
architectures, namely `stable-i686-pc-windows-msvc`.
Thanks to @kennykerr for pointing out that Get/SetWindowLongPtrA/W calls
don't actually exist on 32-bit builds of Windows and are aliased instead
to Get/SetWindowLongA/W which take i32 args instead of isize args:
https://github.com/microsoft/windows-rs/issues/3304
This commit ensures that the full range of matching strategies for both
Simple and Composite matching rules will be respected for both initial
and persistent workspace rules.
The generate-static-config command will no longer attempt to populate
workspace rules, and will likely slowly be deprecated as the
overwhelming majority have users have already migrated to the static
configuration file format.
fix#991
This commit adds transparency_ignore_rules to the komorebi.json static
configuration format. Windows that match any rules given in this list
will not have transparency applied when they are unfocused.
For example, to ensure that a browser window is not made transparent
when the focused tab is a YouTube video:
```json
"transparency_ignore_rules": [
{
"kind": "Title",
"id": "YouTube",
"matching_strategy": "Contains"
}
]
```
This commit adds a --quickstart flag to the komorebi-bar binary to
output an example komorebi.bar.json into the user's desired
configuration directory.
This is to avoid the case where running komorebic quickstart would
result in clobbering an existing komorebi.json file.
Additionally, if a user tries to run the bar for the first time without
a configuration file, the example configuration will be written to disk
for them.
Finally support for loading a komorebi.bar.yaml file has been removed
because I have no desire to support multiple configuration formats over
the long term.
Not a huge fan of these updates in the windows-rs crate which swap the
isize values which were previously wrapped in various handles with *mut
core::ffi:c_void pointers.
In order to at least keep this codebase sane, all of the wrapper
functions exposed in WindowsApi now take isize wherever they previously
took HWND, HMONITOR, HINSTANCE etc.
Going forward any pub fn in WindowsApi should prefer isize over Windows
handles which wrap c_void pointers.
This commit builds on c3f135703e and
1080159e68 to add layout-specific edge
index awareness to all default layouts.
This is most useful for UltrawideVerticalStack and
RightMostVerticalStack, which have a lot of edge cases due to the
positioning of the 0th index changing with the number of containers on a
workspace.
This commit expands the komorebi layout subwidget to update the layout
indicator accordingly when the user switches to a floating workspace, or
when the window manager is paused.
This commit ensures that when focusing across a monitor boundary to the
left, the container at the back of the Ring<Container> in the target
workspace will be focused, and when focusing across a monitor boundary
to the right, the one at the front will be focused.
This commit introduces a new wrapper, CustomUi, which is used to
implement custom methods on top of eframe::egui::Ui.
The default ui::add_sized method always has the text in a label
centered, which is not desirable for a status bar where the layout
should be ltr.
A new function CustomUi::add_sized_left_to_right has been added to
ensure that labels can be truncated with a custom width (which requires
allocate_ui_with_layout), while also retaining the ability for the text
to be aligned to the left rather than the center of the allocated
layout.
This commit ensures that when moving across a monitor boundary to the
left, a container will be added to the back of the Ring<Container> of
the target workspace, and when moving across a monitor boundary to the
right, that it will be added to the front.
This commit ensures that the focused window komorebi subwidget is aware
of multi-window containers and displays an ordered list of windows in a
container stack which can be clicked to change focus in the stack.
When there are >1 windows in a stack, the title of the focused window
will take from komorebi.json's theme.stack_border if theme is defined
(falling back to the same default value in komorebi), or from
theme.accent in komorebi.bar.json, if defined.
This commit updates the various komorebic json schema generation
commands to generate the schemas locally, without requiring a running
instance of komorebi to communicate with over IPC.
This commit introduces a new SocketMessage, ReplaceConfiguration, which
attempts to replace a running instance of WindowManager with another
created from a (presumably) different komorebi.json file.
This will likely be useful for people who have multiple different
monitor setups that they connect and disconnect from throughout the day,
but definitely needs more testing.
An experimental sub-widget which calls this SocketMessage has been added
to komorebi-bar to aid with initial testing.
This commit adds instructions for komorebi-bar to the Getting Started
section of the documentation website, adds an example komorebi.bar.json
configuration file, integrates that file with the quickstart command,
and updates the start and stop commands to take --bar flags similar to
the --whkd flags.
In updating the documentation I also decided to rename in the internal
tag for the KomobarTheme and KomorebiTheme enums to "palette" instead of
the previous generic "type" tag which was copied from the serde docs.
This commit adds hot reloading for changes made to viewport.inner_size
in the configuration file. I still don't understand how the scaling
works with egui, but at least for the time being there are some rough
heuristics I've thrown together.
The transformation of y still seems a little off, but the transformation
of x seems pretty accurate when dividing by native_pixels_per_point.
This commit ensures that whenever komorebi.json is updated, komorebi-bar
will try to apply whichever theme is set in that file by the user (if
one is set).
Similarly, if a theme is not set in komorebi.bar.json, komorebi-bar will
load the theme set in komorebi.json (if one is set).
A new configuration "bar_accent" has been added to the KomorebiTheme
struct to make this process as uniform as possible.
This commit abstracts the theme-related code from komorebi-bar into a
separate library which is now also consumed by komorebi.
The static configuration file for komorebi has been updated to allow
users to specify themes and provide palette overrides for various border
styles and stackbar configuration options.
In the event that both a theme and border-specific and/or
stackbar-specific colours have been specified, the theme will take
priority to make it as easy as possible for users who have already spent
time tweaking their colours to try out themes and quickly revert back if
they prefer their existing colours.
This change makes it easier for users to have unified themes between
komorebi and the komorebi status bar.
This commit adds an initial version of the komorebi status bar.
At this point the bar is still considered "alpha" and the configuration
format may see some small breaking changes based on usage and feedback.
There is an accompanying video series which details the creation of this
bar on YouTube: https://www.youtube.com/watch?v=x2Z5-K05bHs
Some high level notes on the bar:
* An external application which exclusively consumes komorebi_client's
public API surface - anyone can create this without hacking directly
on komorebi's internals
* Generally a very simple bar with limited configuration options - users
who want more configurability should use alternatives such as yasb or
zebar
* Scope is deliberately limited to provide a tighter, more focused
experience: Windows-only, komorebi-only, single-monitor-only,
horizontal-only
* No support for custom widgets or templating
* Colours are controlled exclusively through themes which adhere to a
palette framework such as Base16 or Catppuccin (and possibly others in
the future)
This commit contains all of the commits listed:
e5fa03c33c
feat(bar): initial commit
b3990590f3
feat(bar): add config struct with basic opts
bc2f4a172e
feat(bar): handle komorebi restarts gracefully
ca6bf69ac7
feat(bar): add basic widget config opts
18358efed8
feat(bar): add interactive layout and media widgets
92bb9f680b
perf(bar): use explicit redraw and data refresh strategies
8e74e97706
feat(bar): add battery and network widgets
fdc7706d23
feat(bar): add custom font loader
025162769b
feat(bar): allow right side widget ordering
a1688691cf
feat(bar): add app icon next to focused window title
9f78739c3f
feat(bar): add komorebi widget (+config) and themes
a4ef85859e
feat(bar): use phosphor icons for uniformity
e99138a97e
feat(bar): add first pass at configuration loader
d6ccf4cf9a
feat(bar): add logging and config hotwatch
34d2431947
feat(bar): handle monocle containers in komorebi widget
7907dfeb79
feat(bar): add optional data refresh intervals to config
96a9cb320e
feat(bar): add flag to list system fonts
42b7a13693
feat(bar): add activity to network widget
ac38f52407
feat(bar): to_pretty_bytes on network activity
6803ffd741
feat(bar): configurable network activity fill char len
7d7a5d758d99808cd2b81da2b3ddbb11c52aa92f
ci(github): add bar to wix and goreleaser configs
da307e36fc1faf84ecca3f91811fdd15f70ef2ff
feat(bar): expand theme sources
c580ff7899889309dfa849ad4fb05b80b6af8d9b
feat(bar): add accent config for themes
bc4dabda4a941c0c9764fae2c8d11abbfdc0a9f5
feat(bar): add accents to widget emojis
a574837529dd6c5add73edf394c1c9c2e6cc6315
feat(bar): add to hard-coded float identifiers
ff41b552613f911e56b1790e68389525ee7e603c
chore(deps): bump base16-egui-themes
This commit introduces a new configuration option,
cross_boundary_behaviour, which allows the user to decide if they want
Focus and Move operations to operate across Workspace or Monitor
boundaries.
The default behaviour in komorebi has always been Monitor. Setting this
to Workspace will make komorebi act a little like PaperWM, where
"komorebic focus left" and "komorebic focus right" will switch to the
next or previous workspace respectively if the currently focused window
as at either the left or right monitor boundary.
resolve#959
This commit is a squashed combination of the following commits from #920
by @thearturca. Thanks to both @thearturca for @amnweb for their work in
fixing and thoroughly testing these changes respectively.
935079281a
fix(animation): added pending cancel count to track `is_cancelled` state
84ad947e1f
refactor(animation): remove cancel idx decreasing
804b0380f7
refactor(animation): remove `ANIMATION_TEMPORARILY_DISABLED` global vars
f25787393c
fix(animation): extend cancelling system to support multiple cancel call
dfd6e98e9c
refactor(window): reuse window rect in `animate_position` method
18522db902
fix(animations): change check for existings animation to `pending_cancel_count` field
Before it was checking `cancel_idx_counter` which is `id` counter. It
never gonna equals `0` and doesn't represent all animations that running
for that window. So it doesn't delete entry from hashmap.
That leads to bug when border and stackbar doesn't get notified after
animation ends.
This commit ensures that Shutdown signals will be sent to subscriber
sockets and that "komorebi.sock" will be cleaned up on exit.
Alongside these changes, komorebi_client::send_message no longer retries
so that integrators can receive feedback via io::Result errors when
komorebi is not running.
This commit ensures that a WindowManagerEvent::Show will not be
triggered when a WinEvent::ObjectNameChange is received for an
application in the object_name_change_on_launch whitelist.
This notably impacts Firefox when the window title changes while the
application is minimized (for example, on a page with YouTube autoplay
enabled).
fix#941
Addresses a regression introduced somewhere along the way in changing
how borders and rects sizes are calculated. Need to come back and see if
the constant calculated with the mix of BORDER_WIDTH and BORDER_OFFSET
is still relevant anymore.
fix#942
This commit adds a new command, focus-stack-window, which allows users
to focus windows in the focused container stack by their index
(zero-indexed) within the stack.
If the user tries to focus an index which does not correspond to a
window within the container stack, an error will be logged.
This commit ensures that the "Komorebi" border implementation is set as
the default as it has the maximum range of compat across different
Windows versions, whereas the "Windows" implementation requires Win 11.
Because "Windows" implementation methods will error on Windows 10,
restore_all_windows has been updated to only attempt to remove accents
if BorderImplementation::Windows is selected (this is gated behind the
WINDOWS_11 check).
re #925
This commit ensures that when a window_based_work_area_offset is set,
and the window limit is greater than 0, the offset will be applied to
monocle containers on a workspace (unless an override is specified for
that workspace).
This commit demotes the komorebi-core crate to a module (core) inside of
the komorebi lib, resulting in the komorebi-client crate lib becoming
the single public interface for programming in Rust against komorebi.
komorebic and komorebi-gui now consume komorebi-client exclusively as
the means for sending and receiving messages to and from komorebi, so
that anyone wishing to integrate with komorebi will have all of the same
functionality to them as I do.
This commit builds on these changes in win32-display-data:
32a45cebf1p
With the addition of lenient fallbacks when looking up display device
information for "RDPUDD Chained DD" virtual display adapters, komorebi
will now set Monitor.device and Monitor.device_id to "UNKNOWN" as this
virtual mirror display driver will never have a reported DeviceID.
This limitation for "RDPUDD Chained DD" devices is also noted in a
Chromium issue: https://codereview.chromium.org/2557513005/fix#883
There are quite a lot of janky animation bugs when moving window
containers across monitor and workspace boundaries.
This commit disables animation on all of the main cross-border window
container operations, meaning that animations should now only happen
within the context of a single workspace.
fix#912
This commit adds a new focus manager module to be used to trigger async
focus changes with mouse follows focus updates. Currently this should
only need to be used with animations as all other focus calls are
synchronous.
fix#910
Work on this feature was first started by @thearturca in November 2023
before komorebi v0.1.21 in #597 and has undergone numerous revisions
to reach the point of this commit.
Although this is a single squashed commit, almost all of the heavy
lifting for this feature was done by @thearturca, which is where all of
the kudos and gratitude should be directed.
This commit adds a new static configuration block for animations, where
they can be enabled, and have their style, fps and duration set.
Corresponding SocketMessages and komorebic cli commands have also been
exposed.
There are some caveats to the use of this feature, which revolve around
the quality of the Windows compositor (it is not very good):
* There will be visual artifacts with various apps when animations are
taking place - komorebi can't do anything about this as it is a
limitation of the Windows compositor
* Since komorebi's borders are implemented as independent windows are
are not a part of the windows they are drawn around, these borders
will be hidden while animations are in progress
* If you wish to use borders with this feature, you'll probably better
off using BorderImplementation::Windows, which uses the native thin
"accent" borders, which are part of the windows they are drawn around,
and can be moved with those windows during animations
As a result of these and other caveats, this feature will be marked as
"experimental" for the foreseeable future and will be off-by-default.
Below, a number of now-squashed commits that contributed to the
stabilization of this feature are referenced to help with code
archeology in the future.
fix(animation): Fixed cancelling logic
(57e9b2f4bcaedb4fdfa71adf785d661690d81dfc)
Added static animation state manager for tracking "in_progress" and
"is_cancelled" states. The idea is not to have states in Animation
struct but to keep them in HashMap<hwnd, AnimationState> behind
reference (Arc<Mutex<>>). So we each animation frame we have access to
state and can cancel animation if we have to.
Need review and testings
refactor(animation): avoid unwrap
(fa6d5bbc77c1882f85ee1ce73733ff7e53b39eaa)
fix(animation): Move cancel call to Animation struct
(306513f5dbe5f6bd6ce817f3edca0bfda13d9442)
Only focused window was cancelling its animation because we call cancel
in window::set_position and waiting for its cancelling. And because we
waiting for cancelling second window is still moving. Second window will stop
moving only after the first window. So I moved `cancel` call to
Animation struct so its happening in its own thread and doesn't block
others animation moves and cancels.
refactor(animation): renamed args parameters and variables names
(8abb4b9618bbb3823b868fc37551f0a70b98281e)
refactor(animation): inverse if-statement in `window::animate_position`
(3de2c6e932614651892da4a8c626946e427375dd)
There is was a bug when ease function generates `t` greater the
`SetWindowPos` function will be called instead of `move_window`.
`SetWindowPos` is only for last frame of animation.
fix(wm): add shadow rect to `move_window` calls
(b58620fb4de36d8e422a80541bedf9c1c1579a31)
This fixes a bug when windows get shunk during the animation
This commit ensures that one-off workspace rules added at runtime via
komorebic or generally via SocketMessages will be added to the output of
the generate-static-config command.
This commit adds three new commands, clear-workspace-rules,
clear-named-workspace-rules and clear-all-workspace-rules, to allow
users to remove workspace rules at runtime.
These commands do not distinguish between initial or persistent
workspace rules. If there is a clear use case for this distinction, this
decision can be revisited at a later date.
resolve#908
This commit adds two new fields, minimum_window_height and
minimum_window_width, to the static configuration file.
These options should be considered quite broad and heavy-handed for now
and avoided if at all possible.
These options are an escape hatch for buggy applications such as Windows
Teams which do not give application windows and child windows unique
names or classes.
Ultimately users should push for buggy applications to be fixed upstream
and respect the usual Microsoft Windows application development
guidelines.
Further support will most likely not be provided for these two
configuration options because it's not my job or my responsibility to
compensate for multi million, billion and trillion dollar companies who
can't follow basic application development guidelines.
resolve#896
This commit adds an override option
"apply_window_based_work_area_offset" to the Workspace configuration
object in the static config.
This option defaults to true to preserve existing behaviour, and can be
set to false for workspaces where the monitor-level offset changes are
undesirable.
This commit adds a soft-deprecation message for the Hide and Minimize
variants of WindowHidingBehaviour to start bringing all users towards
using the Cloak variant.
resolve#897
This commit adds a dynamic lookup method for the
window_container_behaviour configuration option. Previously if the
behaviour was set to Append, and the workspace did not have any
containers, an error would be logged.
Now, in the same situation, the behaviour will be dynamically switched
to Create when there are no containers on a workspace, and subsequent
windows will be handled with the Append behaviour if set.
This commit also makes some tweaks to ensure that when a windows in a
container stack are closed, the container itself will remain focused if
it has at least one remaining window.
resolve#889
This commit ensures that every non-focused index in a Ring<Window> will
be hidden when a new window is added and focused via
Container::add_window, which typically happens when
WindowContainerBehaviour::Append is enabled and a new window is opened.
re #889
This commit adds the ability for users to select between komorebi's
implementation of borders with variable widths and the native Windows 11
implementation of thin "accent" borders.
The new border_implementation configuration option defaults to
BorderImplementation::Komorebi in order to preserve compat with existing
user configurations.
This option will be most useful for people who prefer ultra-thin
borders, and people who want borders to be animated along with
application windows if they are using the animation feature being worked
on in PR #685.
This commit ensures that message handling threads for windows that are
created by komorebi are exited properly when the windows are destroyed.
For some reason, passing the HWND returned by CreateWindowExW to
GetMessageW continues returning TRUE even after the window has been
destroyed.
If HWND::NULL (via the Default trait) is passed to GetMessageW, which
retrieves messages for any window belonging to the current thread (our
threads here only own a single window), GetMessageW returns FALSE as
expected after the window is destroyed.
re #862
This commit is the result of a long investigation with @berknam on
Discord which uncovered that when the channels used by the *_manager
modules are full, the window manager can enter a completely locked state
which will require a hard restart of komorebi.exe.
In order to avoid entering this locked state, *_manager modules now no
longer publicly expose event_tx for sending notifications.
Instead, a new public fn send_notification is exposed which will use
try_send to attempt to send notifications in a non-blocking manner and
log warnings if the channel is full and the notification is dropped.
This commit increases various channel bounds from 5 to 20 since it was
discovered that this reduction had no impact on #862, and some
crashes/freezes have been noted due to the channel bounds of 5 being too
low.
This commit ensures that we only invalidate a border rect to send a
WM_PAINT message either when the position of the focus state of the
border has changed.
re #862
This commit pushes up the calls to BeginPaint and EndPaint in the border
callback function to ensure that the client area of the border rect is
always validated after calls to InvalidateRect from the update fn.
The callback now also logs errors whenever it is not possible to get the
border rect to operate on for any reason.
There was a call at the end of this logic to ValidateRect which has been
removed as the validation is already handled by the call to BeginPaint.
re #862
This commit handles three subtle edge cases which surfaced after adding
state snapshot comparisons to the border manager module.
1) Update borders when windows are dragged
2) Update borders on pause and unpause
3) Redraw borders on retile
These two edge cases do not change the snapshot state but still require
updates to be made to the borders.
This commit introduce state snapshot checks in the border manager, which
will ensure that we don't even attempt to acquire any mutex locks if the
state hasn't changed.
This commit ensures that in the event of a panic (we still have quite a
few that occur sporadically that are still being tracked down), the
listen_for_commands thread in process_command is restarted, similarly to
the recently added border, stackbar and transparency manager threads.
In order to do this without blocking the process startup sequence,
listen_for_commands spawns an outer thread which begins a loop in which
the actual command listener thread is started.
We call .join() on the handle of this inner thread, and log an error
whenever that inner thread terminates, as it should never terminate
unless there is a panic.
If the inner thread is terminated due to a panic, the outer loop will
start another thread to ensure that user commands continue being
processed.
One thing to note is that panics may lead to an inconsistent wm state
and undefined behaviour which will seem "new", as previously these
panics required a total restart of komorebi and any inconsistent states
would be masked.
This commit ensures that windows moved to a floating workspace on a
different monitor will have their positions updated accordingly for the
target monitor. Since floating layouts have no layout algorithm applied,
the moved window will be centered in the work_area of the target monitor
in the target workspace.
fix#865
This commit ensures that stackbar clicks will be handled properly by the
transparency manager by creating an override to process events for
windows which may not be at the top of the stack and may have previously
been made transparent before they were hidden.
fix#864
This commit makes the quickstart command aware of the
KOMOREBI_CONFIG_HOME environment variable. If this is set by the user,
references to Env:USERPROFILE will be replaced with
Env:KOMOREBI_CONFIG_HOME.
fix#861
This commit introduces a small refactor to the transparency manager
module to log instead of propagating errors which may cause infinite
thread restarts and memory ballooning in KNOWN_HWNDS if applications
such as Visual Studio do not conform to the Win32 guidelines for setting
and removing Extended Window Styles.
re #863
This commit adds a new monitor-information command to make it easier for
people to find the values they need to use the display_index_preferences
configuration option.
re #860
This commit adds the transparency manager module, which, when enabled,
will make unfocused windows transparent using a user-configurable alpha
value between 0-255.
The corresponding komorebic commands (transparency, transparency-alpha)
have been added, as well as the corresponding static configuration
values (transparency, transparency_alpha).
This feature is off-by-default and must be explicitly enabled by the user.
If the process is not shut down cleanly via the 'komorebic stop'
command, it is possible that the user will be left with transparent
windows which will not be managed by komorebi the next time it launches.
This is because the WS_EX_LAYERED style is required for transparency,
but is ignored by default in komorebi's window eligibility heuristics.
For this reason, a separate state tracker of windows that have had this
style added by the window manager is kept in the transparency manager
module.
For this edge case of shutdowns where the cleanup logic cannot be run,
the 'komorebic restore-windows' command has been updated to remove
transparency from all windows that were known to the window manager
during the last session before it was killed.
This must be run _before_ restarting komorebi, so that the previous
session's known window data is not overwritten.
In the worst case scenario that the previous session's data is
overwritten, the user will have to either kill and restart the
applications, or compile komorebi from source and explicitly set
"allow_layered" to "true" in the window_is_eligible function, before
setting the transparency alpha to 255 (fully opaque), and then resetting
to the desired value.
This is a mixture of refactoring and a fix, updating the
Direction::is_valid_direction trait impl for Default layout to return
early with false if the count is < 2.
fix#851
In the case when the `komorebi-client` is used in one project with some
dependency that is transitively used crate `parking_lot` with feature
`send_guard`, a compilation error occurs because `komorebi-client`
transitively importing `parking_lot` with feature `deadlock_detection`
and these features are mutually exclusive.
This fix suggests enabling `deadlock_detection` feature in `parking_lot`
crate only if `deadlock_detection` enabled for `komorebi` crate, by
default it is disabled so it will solve issue with `komorebi-client`
This commit ensures that HPEN, HBRUSH and HFONT objects which are used
to draw stackbar tabs are explicitly destroyed with calls to
DeleteObject after ReleaseDC has been called.
re #855
This commit ensures that HPEN and HBRUSH objects created to draw window
borders are explicitly destroyed with calls to DeleteObject after
EndPaint has been called.
re #855
This commit switches to using the bitflags from_bits_truncate fn to
handle applications like Foxit Reader which use garbage bits that aren't
part of the Window Styles or Extended Window Styles Win32 specs.
Any unknown bits that are not in the Win32 specs will be unset when this
function is run.
This commit allows for the user to expand container stacks while focused
on an an existing (len > 1) container stack by using the stack command
with a desired direction.
resolve#847
This commit addresses a regression in v0.1.26 that was introduced by the
win32-display-data crate, where virtual monitors would not be detected
in scans by the wm.
The actual fix has been made upstream in win32-display-data:
2a0f7166dafix#846
This commit adds two new commands, stack-all, which puts all windows in
the focused workspace into a single stack, and unstack-all, which
unstacks all windows in the currently focused container.
This commit finally sunsets the derive-ahk proc macro and the
ahk-library cli command.
There is now a dedicated, stripped down komorebi.ahk example on the docs
website which mirrors the contents and style of the sample whkdrc:
https://lgug2z.github.io/komorebi/common-workflows/autohotkey.html
This commit makes a small change to dynamically keep reserving space in
the VecDeque that backs Ring<Monitor> until an index preference can be
contained within the current length.
This commit also fixes some clippy lints and adds some allow
annotations.
This commit changes the handlers for the Close and Minimize
SocketMessages to operate on the output of
WindowsApi::foreground_window, without checking the window manager state
as it was doing previously.
This will allow the commands to operate on any kind of managed or
unmanaged window, and the appropriate WinEvent will be emitted by the
closed window for the window manager state to be updated when the
WinEvent goes through process_event.
fix#839
This commit ensures that EVENT_OBJECT_NAMECHANGE is handled for all
windows.
Previously this was mapped to WindowManagerEvent::Show, as this is the
event that apps like Firefox and JetBrains IDEs sent on launch instead
of EVENT_OBJECT_SHOW like normal apps.
Now that we are using EVENT_OBJECT_NAMECHANGE to update titles on
stackbar tabs, when a window which is not in the whitelist of
object_name_change_applications sends this event, it will be handled by
the new WindowManagerEvent::TitleUpdate variant.
This ensures that a stackbar_manager::Notification is sent at the end of
process_event to update stackbar tabs when application titles are
changing.
resolve#842
Until now the orphan window/container reaper has always run on every
WinEvent. Unfortunately Windows Terminal does not sent a WinEvent when
it is closed.
This is a problem for the new border_manager module which draws and
destroys borders based on notifications sent to it after WinEvents and
SocketMessages have been processed.
Since Windows Terminal is not sending a WinEvent on close, this means
that user interaction is required to remove the ghost border that gets
left behind.
This commit starts a separate thread for the reaper where it runs once
every second in a loop.
This is quite wasteful and definitely not something I wanted to
implement, but a temporary solution is needed given the popularity of
the buggy application in question.
An issue on the Windows Terminal tracker has been opened here:
https://github.com/microsoft/terminal/issues/17298
This commit ensures that whenever we receive a
stackbar_manager::Notification any stackbars not associated with the
current workspace on each monitor are destroyed.
fix#838
This commit fixes a regression introduced by hiding other containers
when monocle is enabled. When the monocle container is closed, other
containers on the workspace will now be restored.
re #834
This commit adds the komorebi-gui debug tool build with egui and eframe.
This tool was built from scratch in a YouTube mini-series which can be
found here: https://www.youtube.com/watch?v=zZKjBMt4kZ4
The most interesting part of this tool right now is the ability to view
debug information about each window as it goes through the rules engine.
While it's possible to change runtime configuration options with this
tool, it is not yet possible to write those changes out to the
configuration file.
This commit ensures that horizontal focus moves onto other monitors from
a monocle container are respected (ie. we don't try moving left/right
within the workspace on the focused monitor).
Additionally, if the user tries to alt-tab a window to the foreground on
a workspace where a monocle container exists, the window will flash
before being hidden behind the monocle container as a visual cue that
monocle mode needs to be disabled to access that window.
This is in contrast to the current behaviour where that window floats on
top of the monocle container in a somewhat broken state.
re #834
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 the promote-window command, which allows the user to
promote the window in the specified OperationDirection from the
currently focused window to the largest tile on the workspace layout.
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
The example configuration mistakenly used the key `border_padding` in
the place of `border_width`. As `border_padding` does not exist in the
spec, modifying its value has no effect.
As this file is used by `komorebic quickstart`, new users will have this
incorrect key in their default configuration. Notably, setting its value
to `0` to remove gaps has no effect. The rest of the documentation uses
the correct key, so users copying and pasting from that would not
encounter the bug.
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.
* re-add the #requires line that was removed in commit e044a5a
* remove the "generated by komorebic" comment which is incorrect. komorebic only generates an AHK v1 lib
* update common-workflows/autohotkey.md to remove line about `komorebi.generated.ahk file which no longer exists
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.
As we have been working down some bugs from earlier changes, we
introduced some additional error conditions in the logs. Now that the
new focus approach is available, switching the stackbar to that means we
can avoid needing to pass down ForceUpdate and FocusChange events for
non-windows, which removes many of these cases.
In addition we do a check in should_manage that the target object is
actually a window, ignoring the event if it is not.
We had been setting managed windows to HWND_TOPMOST which is a sticky
and viral parameter. This was also the cause of the border window ending
up behind other windows in an undesirable fashion, as even though it was
marked WS_EX_TOPMOST, we were then having to mark it HWND_NOTOPTMOST
when raising it to avoid it ending up drawing over other windows.
Since we've fixed the border window to no longer be visible when
unmanaged windows are focused, we can now set the border window to
HWND_TOP when we reposition, which will ensure it's drawing in the order
that we want.
Now we also set managed windows only to HWND_TOP, rather than
HWND_TOPMOST which stops us from incorrectly reordering internal
concerns vs. child windows and owned windows that we're not managing.
Windows are still brought to the foreground as expected/desired, but
they're no longer 'sticking' there, nor are they drawing over the border
window.
This change does have a slight transition behavior as it initially rolls
out, as prior versions of the Komorebi have been setting HWND_TOPMOST,
which as a sticky parameter won't be cleared until the application or
host system removes that flag. This means that the final z-order
behavior will come good eventually.
To immediately see the correct results, restarting affected apps or
logging out / in will do. Unfortuantely we can't just set
HWND_NOTTOPMOST, as similarly to setting HWND_TOPMOST, this can cause
issues with an applications intended owned-window Z-Ordering - mostly
affecting toolwindows and child windows, such as file dialogs, toolbars
and so on, most of which we do not manage.
Use the same method as FancyZones to enable setting the foreground
window. This makes it possible then to remove the thread attachment
behaviors that have a number of other complex side effects, and aren't
always allowed.
In addition, cleanup old focus/raise methods some, in particular the
border window is now explicitly not activated when it is raised, as it
should never be activated.
We had a mut requirement on some of the Window functions which may have
been vestigial or in preparation for more state on Window objects, but
presently unused. I removed that, as the Window struct is currently just
carrying an HWND value that's essentially always immutable - there's no
advantage to ever reusing a Window struct vs. making a new one for
another HWND.
In doing so we then no longer needed to be passing in mutable events, so
I applied a little simplification of the event receiver / dispatcher to
process_event. After that it became obvious that we could just pass the
owned event directly into process_event instead, which substantially
simplifies the ownership model and lifetime for those objects.
This is small, and shouldn't create any meaningful behavioral change.
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.
Previously we were dropping events that don't pertain to managed
windows, with one exception in should_manage that could probably do with
further cleanup (DisplayChange).
This first step fixes the latent border window problem, where we would
retain a border window when the last managed window was closed and focus
transitioned to an unmanaged window.
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See bug
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots and Videos**
Add screenshots and videos to help explain your problem.
**Operating System**
Provide the output of `systeminfo | grep "^OS Name\|^OS Version"`
For example:
```
OS Name: Microsoft Windows 11 Pro
OS Version: 10.0.22000 N/A Build 22000
```
**`komorebic check` Output**
Provide the output of `komorebic check`
For example:
```
No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\LGUG2Z
Looking for configuration files in C:\Users\LGUG2Z
No komorebi configuration found in C:\Users\LGUG2Z
If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration
```
**Additional context**
Add any other context about the problem here.
In particular, if you have any other AHK scripts or software running that handle any aspect of window management or manipulation
Please **do not** open an issue for applications with invisible windows leaving ghost tiles.
You can run `komorebic visible-windows` when the ghost tile is present on your workspace to retrieve the invisible window's exe, class name and title, and then use that information to [ignore the window](https://lgug2z.github.io/komorebi/common-workflows/ignore-windows.html) responsible for the ghost tile.
If it is not possible to uniquely identify the invisible window resulting in a ghost tile through a mixture of exe, title and class identifiers, then this is not a bug with komorebi but a bug with the application you are using, and you should open an issue with the developer(s) of that application.
- type:textarea
validations:
required:true
attributes:
label:Summary
description:>
Please provide a short summary of the bug, along with any information
you feel is relevant to replicating the bug.
You may include screenshots and videos in this section.
- type:textarea
validations:
required:true
attributes:
label:Version Information
description:>
Please provide information about the versions of Windows and komorebi
running on your machine.
Do not submit a bug if you are not using an official version of Windows
such as AtlasOS; only official versions of Windows are supported.
description:Suggest a new feature (Limited to Sponsors, Commercial License Holders, and Collaborators)
labels:[enhancement]
title:"[FEAT]: "
body:
- type:dropdown
id:Eligibility
attributes:
label:Eligibility
description:>
Feature requests are considered from individuals who are current $5+ monthly sponsors to the project, individual commercial use license holders, and approved collaborators.
Please specify the platform you use to sponsor the project.
options:
- Individual Commercial Use License
- GitHub Sponsor
- Ko-fi Sponsor
- Approved Collaborator
default:0
validations:
required:true
- type:textarea
validations:
required:true
attributes:
label:Suggestion
description:>
Please share your suggestion here. Be sure to include all necessary context.
If you sponsor on a platform where you use a different username, please specify the username here.
- type:textarea
validations:
required:true
attributes:
label:Alternatives Considered
description:>
Please share share alternatives you have considered here.
Feature requests on this repository are only open to current [GitHub sponsors](https://github.com/sponsors/LGUG2Z) on the $5/month tier and above, people with a valid [individual commercial use license](https://lgug2z.com/software/komorebi), and approved contributors.
This issue has been automatically closed until one of those pre-requisites can be validated.
No user should ever find that their configuration file has stopped working after upgrading to a new version
@@ -177,13 +247,13 @@ the IDE for completions and navigation:
- Set `Expand declarative macros`
to `Use new engine` under "Settings > Langauges & Frameworks > Rust"
- Enable the following experimental features:
-`org.rust.cargo.evaluate.build.scripts`
-`org.rust.macros.proc`
-`org.rust.cargo.evaluate.build.scripts`
-`org.rust.macros.proc`
# Logs and Debugging
Logs from `komorebi` will be appended to `%LOCALAPPDATA%/komorebi/komorebi.log`; this file is never rotated or overwritten, so it will keep
growing until it is deleted by the user.
Logs from `komorebi` will be appended to `%LOCALAPPDATA%/komorebi/komorebi.log`; this file is never rotated or
overwritten, so it will keep growing until it is deleted by the user.
Whenever running the `komorebic stop` command or sending a Ctrl-C signal to `komorebi` directly, the `komorebi` process
ensures that all hidden windows are restored before termination.
@@ -245,7 +315,7 @@ If the named pipe exists, `komorebi` will start pushing JSON data of successfull
You may then filter on the `type` key to listen to the events that you are interested in. For a full list of possible
notification types, refer to the enum variants of `WindowManagerEvent` in `komorebi` and `SocketMessage`
in `komorebi-core`.
in `komorebi::core`.
Below is an example of how you can subscribe to and filter on events using a named pipe in `nodejs`.
@@ -324,7 +394,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
```rust
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.24"}
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.38"}
use anyhow::Result;
use komorebi_client::Notification;
@@ -380,7 +450,7 @@ A TCP listener can optionally be exposed on a port of your choosing with the `--
provided to `komorebi` or `komorebic start`, no TCP listener will be created.
Once created, your client may send
any [SocketMessage](https://github.com/LGUG2Z/komorebi/blob/master/komorebi-core/src/lib.rs#L37) to `komorebi` in the
any [SocketMessage](https://github.com/LGUG2Z/komorebi/blob/master/komorebi/src/core/mod.rs#L37) to `komorebi` in the
same way that `komorebic` would.
This can be used if you would like to create your own alternative to `komorebic` which incorporates scripting and
@@ -399,12 +469,17 @@ programming languages.
# Appreciations
- First and foremost, thank you to my wife, both for naming this project and for her patience throughout its never-ending development
- First and foremost, thank you to my wife, both for naming this project and for her patience throughout its
never-ending development
- Thank you to [@sitiom](https://github.com/sitiom) for being [an exemplary open source community leader](https://jeezy.substack.com/p/the-open-source-contributions-i-appreciate)
- Thank you to [@sitiom](https://github.com/sitiom) for
being [an exemplary open source community leader](https://jeezy.substack.com/p/the-open-source-contributions-i-appreciate)
- Thank you to the developers of [nog](https://github.com/TimUntersberger/nog) who came before me and whose work taught me more than I can ever hope to repay
- Thank you to the developers of [nog](https://github.com/TimUntersberger/nog) who came before me and whose work taught
me more than I can ever hope to repay
- Thank you to the developers of [GlazeWM](https://github.com/lars-berger/GlazeWM) for pushing the boundaries of tiling window management on Windows with me and having an excellent spirit of collaboration
- Thank you to the developers of [GlazeWM](https://github.com/lars-berger/GlazeWM) for pushing the boundaries of tiling
window management on Windows with me and having an excellent spirit of collaboration
- Thank you to [@Ciantic](https://github.com/Ciantic) for helping me bring the [hidden Virtual Desktops cloaking function](https://github.com/Ciantic/AltTabAccessor/issues/1) to `komorebi`
- Thank you to [@Ciantic](https://github.com/Ciantic) for helping me bring
the [hidden Virtual Desktops cloaking function](https://github.com/Ciantic/AltTabAccessor/issues/1) to `komorebi`
Enable or disable float override, which makes it so every new window opens in floating mode, for the currently focused workspace. If there was no override value set for the workspace previously it takes the opposite of the global value
Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused workspace. If there was no behaviour set for the workspace previously it takes the opposite of the global value
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.