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.