Adds a new initial_window_placement_rules workspace configuration option
that allows users to control where new tiled windows are inserted in the
container list. Supports placement by named strategy (Primary,
Secondary, BeforeFocused, AfterFocused, Last), fixed container index, or
per-application matching rules with OR/AND logic.
Adds a top-level layout_defaults setting that defines default
layout_options and layout_options_rules per layout. Workspaces without
their own layout_options or layout_options_rules automatically inherit
the global defaults. If a workspace defines either setting, all global
defaults for that layout are fully replaced.
Adds layout_options_rules to workspace configuration, allowing
layout_options to dynamically change based on container count. Uses the
same threshold semantics as layout_rules: when container count >=
threshold, the highest matching rule fully replaces the base
layout_options.
A new System Tray widget has been added to komorebi-bar, bringing native
Windows system tray functionality directly into the bar.
Special thanks to the Zebar project and its contributors for developing
the systray-util crate library that makes Windows system tray
integration possible.
The widget intercepts system tray icon data by creating a hidden "spy"
window that mimics the Windows taskbar. When applications use the
Shell_NotifyIcon API to manage their tray icons, the widget receives the
same broadcast messages, allowing it to monitor all system tray activity
while forwarding messages to the real taskbar to avoid disruption.
Users can configure which icons to hide using flexible rules. A plain
string matches by exe name (case-insensitive). A structured object can
match on exe, tooltip, and/or GUID fields using AND logic. Each field
supports matching strategies from komorebi's window rules (Equals,
StartsWith, EndsWith, Contains, Regex, and their negated variants),
allowing precise filtering even when multiple icons share the same exe
and GUID. An info button opens a floating panel listing all icons with
their properties and copy buttons, making it easy to identify which
values to use in filter rules.
The widget fully supports mouse interactions including left-click,
right-click, middle-click, and double-click actions on tray icons.
Double-click support uses the LeftDoubleClick action from systray-util
0.2.0, which sends WM_LBUTTONDBLCLK and NIN_SELECT messages. It handles
right-aligned placement correctly by adjusting the rendering order and
toggle button arrow directions to maintain consistent visual appearance
regardless of which panel the widget is placed in.
Some system tray icons register a click callback but never actually
respond to click messages, effectively becoming "zombie" icons from an
interaction standpoint. The widget includes fallback commands for known
problematic icons that override the native click action with a direct
shell command (e.g. opening Windows Security or volume settings).
The implementation uses a background thread with its own tokio runtime
to handle the async systray events, communicating with the UI thread
through crossbeam channels. Icon images are cached efficiently using
hash-based keys that update when icons change. Rapid icon updates are
deduplicated to prevent UI freezing, and image conversion (RgbaImage to
ColorImage) is performed on the background thread to keep the UI
responsive.
The widget automatically detects and removes stale icons whose owning
process has exited, using the Win32 IsWindow API on a configurable
interval. A manual refresh button is also available for immediate
cleanup.
A shortcuts button can be configured to toggle komorebi-shortcuts by
killing the process if running or starting it otherwise. The refresh,
info, and shortcuts buttons can each be placed in the main visible area
or in the overflow section.
The grid layout calculates row heights using integer division, which
truncates the result when the area height is not evenly divisible by the
number of rows in a column. Since every row received this truncated
height, columns with an odd row count (e.g. 3 rows in 800px: 266*3=798)
would fall short of the full area height, leaving a visible gap at the
bottom compared to columns with an even row count (e.g. 2 rows:
400*2=800).
The last row in each column now absorbs the remainder pixels from the
integer division. The vertical flip position calculation was also
updated so that the last row, which becomes the topmost window when
flipped, starts at the area top edge instead of being offset by the
truncation error.
The same integer division truncation also affected column widths in the
grid layout when the area width is not evenly divisible by the number of
columns. The last column now absorbs the width remainder using the same
pattern, and this correction is applied before the flipped column
positions are calculated so that horizontal flips also tile correctly.
The two shared helper functions columns_with_ratios and rows_with_ratios
had the same issue, which propagated to every layout that delegates to
them: Columns, Rows, VerticalStack stack rows, RightMainVerticalStack
stack rows, HorizontalStack stack columns, and UltrawideVerticalStack
tertiary rows. Both functions now correct the last element after the
sizing loop so that the total tiled dimension matches the area exactly.
The Scrolling layout computes a uniform column width by dividing the
area width by the visible column count, which can also leave a remainder
gap on the right edge. The last visible column in the current viewport
now absorbs this remainder. Since the layout is recalculated on every
scroll event, the correction stays accurate regardless of which column
is rightmost.
The recursive_fibonacci function used formulas for main_x and main_y
that mixed unresized area dimensions with resized dimensions when
calculating flipped positions.
This caused a gap between containers proportional to resize_delta * (2 *
ratio - 1), meaning any column_ratios or row_ratios value other than the
default 0.5 would produce visible gaps or overlaps between containers
when the layout was both flipped and resized.
The fix replaces the flipped position formulas with ones that derive
main_x and main_y directly from the alt area width and height
expressions used by the recursive child call, ensuring the main
container is always positioned immediately adjacent to the alt area
regardless of ratio or resize delta.
The horizontal flip for grid layouts swapped column left positions
directly from the unflipped layout. With non-default column ratios this
caused narrow columns to receive wide column positions, producing
overlapping containers.
Precompute flipped column left positions by laying out the original
column widths in reverse order from the area left edge, ensuring
containers tile without overlap regardless of column ratio.
Separated all unit test for arrangements into a new file.
Added 4 BSP-specific regression tests (horizontal flip, vertical flip,
both axes, sweep across multiple ratios/deltas).
Added 7 adjacency tests covering ALL other layouts (Columns, Rows,
VerticalStack, RightMainVerticalStack, HorizontalStack,
UltrawideVerticalStack, Scrolling) confirming they don't have the gap
issue.
Added 2 Grid tests that verify containers don't overlap and tile the
full area when column ratios are non-default. The first test checks a
horizontal flip specifically, confirming 2 columns form with no gaps
edge-to-edge. The second test runs all three flip axes and asserts no
overlaps and full area coverage for each.
The implementation adds a new layout-ratio CLI command to komorebi that
allows users to dynamically set column and row ratios for layouts at
runtime via komorebic layout-ratio --columns 0.3 0.4 --rows 0.5.
A public validate_ratios function was added to komorebi-layouts that
clamps ratio values between 0.1 and 0.9, truncates when the cumulative
sum would reach or exceed 1.0, and limits to a maximum of 5 ratios. This
function is shared between config file deserialization and the new CLI
command, ensuring consistent validation behavior.
The SocketMessage enum in komorebi/src/core/mod.rs has a new
LayoutRatios variant. The handler in process_command.rs uses the shared
validate_ratios function to process the ratios before applying them to
the focused workspace's layout options.
When the CLI command is called without any arguments, it prints a
helpful message instead of returning an error.
The Media widget has been enhanced with a new MediaDisplayFormat
configuration option that controls how the widget is displayed. It
supports seven formats: Icon, Text, IconAndText (the default),
ControlsOnly, IconAndControls, TextAndControls, and Full.
The widget now detects whether the Previous and Next buttons are
actually available for the current media session using the Windows Media
Control API. When a button is not available, it appears dimmed at 50
percent opacity and clicking it has no effect.
Tooltips were added to improve usability. Hovering over the media info
label shows the full artist and title text, which is helpful when the
text is truncated. The Play/Pause button also shows the media info on
hover.
The rendering logic was refactored to properly handle right-aligned
widgets.
When the Media widget is placed in right_widgets, the UI renders items
from right to left, so the code now renders elements in reverse order to
ensure the visual appearance remains consistent regardless of which
panel the widget is placed in.
Added customizable split ratios for layouts via layout_options
configuration. Users can now specify column_ratios and row_ratios arrays
to control window sizing in various layouts.
Ratios are validated at config load time: values are clamped between 0.1
and 0.9 to prevent zero-sized windows, and arrays are automatically
truncated when their cumulative sum would reach or exceed 1.0. This
ensures there's always remaining space for additional windows.
Ratio support varies by layout:
- Columns and Rows layouts use the full arrays for each column/row width
or height
- VerticalStack, RightMainVerticalStack, and HorizontalStack use the
first ratio for the primary split and the remaining ratios for stack
windows
- BSP uses the first value from each array for horizontal and vertical
splits respectively
- Grid only supports column_ratios since row counts vary dynamically.
- UltrawideVerticalStack uses the first two column ratios for center and
left columns.
All ratio-related values are now defined as constants in
default_layout.rs: MAX_RATIOS (5), MIN_RATIO (0.1), MAX_RATIO (0.9),
DEFAULT_RATIO (0.5), and DEFAULT_SECONDARY_RATIO (0.25 for
UltrawideVerticalStack).
This commit changes the way how the default interface and network
activity is loaded by spawning a new thread on each request. This way
the main thread is not blocked by this process.
There has been instances where getting the default interface blocked the
egui ui thread, resulting in a frozen bar.
fix#1423#1499
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 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
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 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 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 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 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).
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
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 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 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.
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 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
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.