The two render.rs differed in two places. The Windows bar documented transparency_alpha with '(default: 200)' in its text; the macOS bar documented it without and put the default into the schema (schemars extend default 200), so the macOS nix options file gets default = 200. The macOS spelling is taken for both, because a change to the macOS schema.bar.json would also change the generated nix/komorebi-bar-options.nix, which cannot be regenerated here. Windows: the description loses the '(default: 200)' text and the property gains "default": 200 (reviewed diff of schema.bar.json below, pin updated in tests/schema_oracle.rs); the one comment on RenderConfig that only Windows had ('/// Render configuration') is added to the macOS copy. The two render.rs are then byte-identical.
The schema diff is the two lines of the property: description 'Alpha value for the color transparency [[0-255]] (default: 200)' -> 'Alpha value for the color transparency [[0-255]]', and one added "default": 200. macOS schema.bar.json is untouched (its harness regeneration is byte-identical).
Verified: Windows cargo clippy --workspace --locked --all-targets -D warnings clean; macOS fake-CC cargo check --locked --workspace --all-targets finished, 0 errors; native cargo test -p komorebi-bar-core: 3 unit + 2 oracle passed, 0 failed; harness regeneration: macOS byte-identical (3,774 lines), Windows byte-identical to the updated schema.bar.json (9,091 lines, diff exactly the two lines above). Not verified: rendering.
Step 2 put SocketMessage in komorebi-protocol, so the Windows bar schema (reached through MouseConfig.message) changed. The file was regenerated with the harness that reproduced the old file byte for byte except for the State closure (S/bar2/regen.sh: real config.rs, render.rs, selected_frame.rs, ui.rs and widgets over the real komorebi-protocol, komorebi-layouts and komorebi-themes with the Windows cfgs on).
Diff, 10,552 -> 9,090 lines, all from step 2 (D15, D16, D27):
- State is now the opaque StateBlob (object, no properties) and the 31 defs only reachable through it are gone: Column, ColumnSplit, ColumnSplitWithCapacity, ColumnWidth, Container, CustomLayout, FloatingLayerBehaviour, GridLayoutOptions, IdWithIdentifier, InitialWindowPlacementRules, Layout, LayoutOptions, MatchingRule, Monitor, PlacementMatchingRules, PlacementTarget, Ring, Ring2-4, ScrollingCentering, ScrollingLayoutOptions, ThemeOptions, ThemeVariant, Wallpaper, Window, WindowContainerBehaviour, WindowPlacement, Workspace, WorkspaceConfig, WorkspaceLayer.
- SocketMessage gains ReloadHotkeys and HotkeysState (the unified enum) and a description; DebugWindow is int64 (was int).
- Descriptions added to State, StateQuery, SubscribeOptions; WindowKind description reworded.
Nothing in the bar's own types changed. The macOS file regenerates byte-identical (3,774 lines) and is not touched.
Verified: S/bar2/regen.sh (macOS cmp identical; Windows differs only by the items above, checked with jq after deleting the 31 defs from the old file). Not verified: against a real Windows komorebi-bar --schema run (cannot run here).
schema.bar.json embeds the socket messages, so it gets Pan, with the PanDirection that it
takes, and PanGesture, with what the fingers of a gesture do. The other two schemas are
the same as they were.
Workspaces are going to slide in and out of the monitor when they are
switched, and that is its own kind of animation (workspace) next to moving
and transparency: it is turned on, and given a duration and an easing, the
same way (animation.enabled, duration and style take a workspace entry, as do
komorebic animation, animation-duration and animation-style with
--animation-type workspace), with the duration and the easing of the other
animations when it has none of its own.
Animations being enabled for everything enables it too, and it can be turned
off in particular (animation.enabled with workspace set to false), so that
enabled: true keeps meaning everything. It needs ghost movement, as the
windows slide as ghosts. Nothing uses it yet.
schema.json gets the center_focused_column layout option as a boolean or one
of Never, Always and OnOverflow, and schema.bar.json, which embeds the socket
messages, gets the new scrolling commands.
PlacementTarget deserialized through String, so the integer the docs
promise ("initial_window_placement_rules": 2) made the daemon exit at
start with an untagged enum error while "2" worked. Accept integers as
well as strings.
The derived schema described an externally tagged object that neither
form matches, so describe the type by hand and regenerate both schemas.
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 new configuration to the Network widget from komorebi-bar, which
allows you to toggle between viewing your Default Interface's friendly
name, IPv4 or IPv6.
Motivation: I find it very useful to check your local IP at a glance,
and missed the feature heavily from other wms in Linux.
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.
This allows clients to send a state and get it applied to the wm.
By using the already there apply_state function we have all the
safety we need to apply the sent state.
This is also intentionally not open for the komorebic binary because I
think the average user doesnt need such a command and this is much safer
also to not give them the ability.
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 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).
Getting tired of making little changes in both this and the komorebi for
Mac repo - I think eventually either komorebi-themes will live in its
own repo or komorebi for Mac will be integrated here.
But for now, at least everything is defined in komorebi-themes and I
don't have to redefine any theme-related stuff in komorebi for Mac.
This commit ensures that the various default values that the different
Option<T> config properties can be unwrapped to are encoded by schemars
so that they can be picked up by docgen.
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 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
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 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 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.
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 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.
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 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 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 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
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