komorebi-for-kde/docs/ -> docs/linux/ komorebi-for-mac/docs/ -> docs/macos/ The Windows docs stay where they are (docs/). Renames only, so links and include paths that named the old directories are broken at this revision; they are fixed in the revision that fixes the paths of the whole layout move.
60 KiB
komorebi for KDE Plasma compared with komorebi for Windows and for macOS
STALE (snapshot of 2026-10-27, kfw
173aa802, kfm 125a9a5): this comparison predates the consolidation. The three programs now sharecrates/(protocol, config, collections, transport, backend, core, settings, komorebic-core) and onekomorebi,komorebic,komorebi-clientandkomorebi-barpackage, so counts of duplicated commands, messages and keys below are out of date, andscripts/compare-gen.pyno longer runs against the current tree (it fails withcannot find '^enum SubCommand', because the command definitions moved tocrates/komorebic-core). For what is shared and what differs on purpose now, read the repository-level docs/dev/ARCHITECTURE-UNIFIED.md and docs/dev/core-model.md. The platform-difference tables (KWin versus Win32 versus AppKit mechanisms) remain a fair description of the platform layers.
This document compares komorebi for KDE Plasma on KWin and Wayland (kfde) with komorebi for Windows (kfw), the original, and komorebi for macOS (kfm). It is written for a reader who knows komorebi on one of those two systems and wants to know what is the same on KDE, what is different, what KDE does by itself that komorebi does on the other systems, and what is not supported.
It states facts that can be checked against the code, and does not assign value judgments. "kfw draws the borders itself and kfde asks the compositor to" is a fact. "The compositor's borders are better" is not, and is not said here. The reasons behind kfde's choices are in DESIGN.md, where they are opinions and say so.
It is written for kfde, so it leans toward kfde, and it was written from the sources of the three programs, not from running them side by side. Where something could not be verified, it says so. A correction is welcome.
How to read this document
Every table in a marked block is generated by scripts/compare-gen.py from the source trees
of the three programs, so a count or a name in it is what the code had when the block was last
generated. The text around the tables is written by hand and states what the tables say.
python3 -I scripts/compare-gen.py --update docs/dev/COMPARE.md # rewrite the blocks
python3 -I scripts/compare-gen.py --check docs/dev/COMPARE.md # exit 1 when one is stale
The script reads this checkout and checkouts of kfw and
kfm (~/komorebi and ~/komorebi-for-mac by
default; --kfw and --kfm name others). Continuous integration has neither checkout, so it
does not run the script: a change to a command, a message, a key of komorebi.json, an event or
a method of Backend is followed by --check on a machine that has them, and by --update and
a read of the text around the block when it reports a stale one. The script also checks the
hand-written notes it holds (why a Windows command has no counterpart, which KWin call stands in
for a Win32 one) against the sources, and the sentences of this document that depend on a
generated fact, and stops on a note or a sentence that is no longer true. The revisions it read
are:
| Name | What | Read from | Revision |
|---|---|---|---|
| kfw | komorebi for Windows, the upstream | ~/komorebi |
173aa802, 2026-10-27 |
| kfm | komorebi for macOS | ~/komorebi-for-mac |
125a9a5, 2026-10-27 |
| kfde | this project | this repository | the commit that has this document |
kfm changes often, so the numbers for kfm in particular are those of that revision.
Terms used below:
- KWin's script (the bridge) is a small JavaScript program that komorebi loads into KWin. It is the only code of kfde that runs inside the compositor, and it contains no window manager logic.
- A workspace is komorebi's name for one of the desktops of a monitor, in all three programs.
- A parking desktop is a KWin virtual desktop that nobody looks at, which kfde moves windows to in order to hide them.
- The strip is the scrolling layout of kfm, in the crate
komorebi-scrolling. Since upstream'snextbranch it is also what theScrollinglayout ofkomorebi-layoutsis laid out with, in kfde too (scrolling-next.md).
What is the same
One tiling model, and the same layouts
The model is the same in all three programs: a list of monitors, each with workspaces, each with
containers, each with windows. kfde adds no layer to it. The layouts come from the crate
komorebi-layouts, which kfw owns and kfm and kfde use as a git dependency:
DefaultLayout |
kfw | kfm | kfde |
|---|---|---|---|
BSP |
yes | yes | yes |
Columns |
yes | yes | yes |
Rows |
yes | yes | yes |
VerticalStack |
yes | yes | yes |
HorizontalStack |
yes | yes | yes |
UltrawideVerticalStack |
yes | yes | yes |
Grid |
yes | yes | yes |
RightMainVerticalStack |
yes | yes | yes |
Scrolling |
yes | yes | yes |
The crate each tree builds: kfw: komorebi-layouts in the tree; kfm: komorebi-layouts at git rev f08aa55; kfde: komorebi-layouts at git rev f08aa55.
Compared file by file with the crate of kfw, kfm: 0 of 13 source files differ from the ones of kfw; kfde: 0 of 13 source files differ from the ones of kfw.
The layouts of komorebi-layouts are calculated by the same code in the three programs, so the same
windows in the same order get the same rectangles, apart from what the window manager takes off for
the work area, the padding and the borders. The exception is the Scrolling layout, which is laid
out with the strip of komorebi-scrolling in kfm and in kfde, and not in kfw before its next
branch (see the section on configuration). What differs between the programs is
what the system does with the rectangles: the next sections.
One configuration file, largely portable
A komorebi.json written for kfw or kfm loads in kfde. The keys that kfde does not read are
accepted and ignored, not rejected. The tables of the sections on configuration say which keys
those are, and why.
Commands
komorebic has the same shape in the three programs: a command writes a message on the socket of the
daemon, and the message is a variant of the SocketMessage of komorebi-client. A command's name is
the variant of SubCommand in kebab case, which is what the pages of docs/cli are named after.
| kfw | kfm | kfde | |
|---|---|---|---|
Commands komorebic has |
192 | 158 | 158 |
| In all three | 148 | 148 | 148 |
| Also in kfw, not in kfm | 7 | - | 7 |
| Also in kfm, not in kfw | - | 1 | 1 |
| Only in kfde | - | - | 2 |
| In kfw or kfm, not in kfde | 37 | 9 | - |
| Same command under another name | - | - | 0 |
No command of kfw or kfm is kept in kfde under another name, not even as an alias.
kfde has the commands kfw and kfm share
These commands exist in all three programs, with the same name. The ones that the tiling and the workspaces are driven with do the same on KDE; where they do it differently (a workspace is a KWin desktop) the section on workspaces says how.
adjust-container-padding, adjust-workspace-padding, animation, animation-duration, animation-fps, animation-style, application-specific-configuration-schema, border, border-colour, border-offset, border-width, cancel-preselect, change-layout, clear-all-workspace-rules, clear-named-workspace-layout-rules, clear-named-workspace-rules, clear-session-float-rules, clear-workspace-layout-rules, clear-workspace-rules, close, close-workspace, configuration, container-padding, cross-monitor-move-behaviour, cycle-empty-workspace, cycle-focus, cycle-layout, cycle-monitor, cycle-move, cycle-move-to-monitor, cycle-move-to-workspace, cycle-move-workspace-to-monitor, cycle-send-to-monitor, cycle-send-to-workspace, cycle-stack, cycle-stack-index, cycle-workspace, data-directory, disable-autostart, display-index-preference, docgen, eager-focus, enable-autostart, enforce-workspace-rules, ensure-named-workspaces, ensure-workspaces, flip-layout, focus, focus-last-workspace, focus-monitor, focus-monitor-at-cursor, focus-monitor-workspace, focus-named-workspace, focus-stack-window, focus-workspace, focus-workspaces, focused-workspace-container-padding, focused-workspace-padding, generate-static-config, global-state, global-work-area-offset, ignore-rule, initial-named-workspace-rule, initial-workspace-rule, layout-ratios, load-resize, log, manage, manage-rule, minimize, monitor-information, monitor-work-area-offset, monocle-focus-behaviour, mouse-follows-focus, move, move-to-last-workspace, move-to-monitor, move-to-monitor-workspace, move-to-named-workspace, move-to-workspace, move-workspace-to-monitor, named-workspace-container-padding, named-workspace-layout, named-workspace-layout-rule, named-workspace-padding, named-workspace-rule, named-workspace-tiling, new-workspace, notification-schema, preselect-direction, promote, promote-focus, promote-swap, promote-window, query, quick-load-resize, quick-save-resize, quickstart, replace-configuration, resize-axis, resize-delta, resize-edge, retile, save-resize, scrolling-layout-columns, send-to-last-workspace, send-to-monitor, send-to-monitor-workspace, send-to-named-workspace, send-to-workspace, session-float-rule, session-float-rules, socket-schema, stack, stack-all, start, state, static-config-schema, stop, subscribe-socket, swap-workspaces-with-monitor, toggle-cross-monitor-move-behaviour, toggle-float, toggle-float-override, toggle-lock, toggle-monocle, toggle-monocle-focus-behaviour, toggle-mouse-follows-focus, toggle-pause, toggle-tiling, toggle-window-based-work-area-offset, toggle-window-container-behaviour, toggle-workspace-float-override, toggle-workspace-layer, toggle-workspace-window-container-behaviour, unmanage, unmanaged-window-operation-behaviour, unstack, unstack-all, unsubscribe-socket, visible-windows, workspace-layout, workspace-layout-rule, workspace-name, workspace-padding, workspace-rule, workspace-tiling, workspace-work-area-offset
kfde has the commands kfw has and kfm lacks, for the features it took from kfw
kfm has no counterpart for these. kfde has them because it has the feature:
| Command | What the help of kfw says |
|---|---|
check |
Check komorebi configuration and related files for common errors |
focus-follows-mouse |
Enable or disable focus follows mouse for the operating system |
toggle-focus-follows-mouse |
Toggle focus follows mouse for the operating system |
toggle-maximize |
Toggle native maximization for the focused window |
toggle-transparency |
Toggle transparency for unfocused windows |
transparency |
Enable or disable transparency for unfocused windows |
transparency-alpha |
Set the alpha value for unfocused window transparency |
focus-follows-mouse and toggle-focus-follows-mouse are hidden from --help in kfw and kfde
alike.
kfde has the command kfm has and kfw lacks
| Command | What it does |
|---|---|
completions |
Generate komorebic CLI completions for the target shell |
kfde has commands that neither has
These commands are about KDE: a key binding file is turned into KDE's global shortcuts, and the keys the daemon registers itself are looked at and let go.
| Command | What it does |
|---|---|
export-kde-shortcuts |
Turn an skhdrc into KDE global shortcuts (they work over RDP, unlike evdev hotkey daemons) |
hotkeys |
Key bindings: KDE global shortcuts from a key binding file, and the keys of the daemon |
The user guide on key bindings describes them. hotkeys has
subcommands: komorebic hotkeys compile does what export-kde-shortcuts does for all three
formats, and state, reload and release act on the keys the daemon has registered.
kfde does not start helper programs
komorebic start of kfw can start whkd, AutoHotkey, the bar and masir along with the daemon. In
kfde the daemon reads the key binding files itself and there is no bar, so start has one flag the
others share and none of the flags that launch another program:
| Command | Flag | kfw | kfm | kfde |
|---|---|---|---|---|
start |
--ahk |
yes | - | - |
start |
--await-configuration |
yes | - | - |
start |
--bar |
yes | yes | - |
start |
--clean-state |
yes | - | - |
start |
--config |
yes | yes | yes |
start |
--ffm |
yes | - | - |
start |
--masir |
yes | - | - |
start |
--tcp-port |
yes | - | - |
start |
--whkd |
yes | - | - |
stop |
--ahk |
yes | - | - |
stop |
--bar |
yes | yes | - |
stop |
--ignore-restore |
yes | yes | yes |
stop |
--masir |
yes | - | - |
stop |
--whkd |
yes | - | - |
check |
--configuration-only |
- | no command | yes |
check |
--komorebi-config |
yes | no command | yes |
kfde has no counterpart for these commands
Every command that kfw or kfm has and kfde lacks is here, with the reason. A group that is a "Win32 quirk" is a workaround for how Windows treats windows, which a Wayland compositor does not need.
| Group | Command | In | Why kfde has no counterpart |
|---|---|---|---|
| AutoHotkey and PowerShell | ahk-app-specific-configuration |
kfw | Writes application rules for komorebi.ahk. |
| AutoHotkey and PowerShell | complete-configuration |
kfw | Part of the legacy komorebi.ahk and komorebi.ps1 configurations. |
| AutoHotkey and PowerShell | pwsh-app-specific-configuration |
kfw | Writes application rules for a PowerShell script. |
| AutoHotkey and PowerShell | reload-configuration |
kfw | Part of the legacy komorebi.ahk and komorebi.ps1 configurations. |
| AutoHotkey and PowerShell | watch-configuration |
kfw | Part of the legacy komorebi.ahk and komorebi.ps1 configurations. komorebi.json is watched always. |
| Win32 quirks | alt-focus-hack |
kfw | Works around the rules Windows has for taking the foreground. |
| Win32 quirks | force-focus |
kfw | Works around the rules Windows has for taking the foreground. |
| Win32 quirks | identify-layered-application |
kfw | A Win32 window style. There is no counterpart in a Wayland compositor. |
| Win32 quirks | identify-object-name-change-application |
kfw | A Win32 event some applications send on launch. |
| Win32 quirks | identify-tray-application |
kfw | A Win32 notion: an application that closes to the system tray. |
| Windows tooling | bar-configuration |
kfw | komorebi-bar is not ported: the Plasma panel is used, and the work area accounts for it. |
| Windows tooling | gui |
kfw | Launches komorebi-gui, which is not ported. |
| Windows tooling | kill |
kfw | Stops the helper programs komorebic start launches on Windows (whkd, AutoHotkey, the bar, masir). It launches none on KDE. |
| Windows tooling | toggle-shortcuts |
kfw | Toggles komorebi-shortcuts, which is not ported. |
| Windows tooling | whkdrc |
kfw | Shows the path of the whkd file. The daemon reads key binding files itself. |
| borders | border-implementation |
kfw | How a Win32 border window is drawn. The compositor draws the border. |
| borders | border-style |
kfw | How a Win32 border window is drawn. The compositor draws the border. |
| borders | identify-border-overflow-application |
kfw | A border window that overflows is a Win32 problem. The compositor draws the border. |
| borders | invisible-borders |
kfw | The size of the invisible frame Windows adds around a window. |
| custom layouts | load-custom-layout |
kfw | Not supported yet. |
| custom layouts | named-workspace-custom-layout-rule |
kfw | Not supported yet. |
| custom layouts | named-workspace-custom-layout |
kfw | Not supported yet. |
| custom layouts | workspace-custom-layout-rule |
kfw | Not supported yet. |
| custom layouts | workspace-custom-layout |
kfw | Not supported yet. |
| hiding | restore-windows |
kfw | Debugging command for windows komorebi hid itself. On KDE stop and the next start send parked windows home. |
| hiding | window-hiding-behaviour |
kfw | One native mechanism hides windows, so there is nothing to choose. |
| kfm scrolling strip | center-focus |
kfm | Belongs to the scrolling strip of kfm (komorebi-scrolling). The Scrolling layout of kfde is the one of komorebi-layouts. |
| kfm scrolling strip | consume |
kfm | Belongs to the scrolling strip of kfm (komorebi-scrolling). |
| kfm scrolling strip | expel |
kfm | Belongs to the scrolling strip of kfm (komorebi-scrolling). |
| kfm scrolling strip | scrolling-layout-full-width |
kfm | Belongs to the scrolling strip of kfm (komorebi-scrolling). |
| kfm scrolling strip | toggle-column-stack |
kfm | Belongs to the scrolling strip of kfm (komorebi-scrolling). |
| license | license |
kfw and kfm | No license check was ported. |
| license | splash |
kfw and kfm | No splash screen was ported. |
| macOS | permissions |
kfm | Shows the System Settings dialogs macOS asks for. KDE asks for none. |
| monitors | monitor-index-preference |
kfw | Identifies a monitor by its size. kfde has display-index-preference, which names the display, as kfm does. |
| named pipes | subscribe-pipe |
kfw | A named pipe is a Windows facility. Subscribers use a Unix domain socket. |
| named pipes | unsubscribe-pipe |
kfw | A named pipe is a Windows facility. Subscribers use a Unix domain socket. |
| stackbar | stackbar-mode |
kfw | komorebi draws the tab bar of a stack on Windows. KDE has no counterpart; a stack is cycled with cycle-stack and focus-stack-window. |
| title bars | remove-title-bar |
kfw | A window without a title bar has no shadow in KWin, and so no border. |
| title bars | toggle-title-bars |
kfw | A window without a title bar has no shadow in KWin, and so no border. |
| upstream applications file | convert-app-specific-configuration |
kfw | Maintains the YAML file of the Windows applications list. |
| upstream applications file | fetch-app-specific-configuration |
kfw and kfm | Not supported yet: there is no applications file for KDE upstream, so there is nothing to fetch. |
| upstream applications file | format-app-specific-configuration |
kfw | Maintains the YAML file of the Windows applications list. |
The groups "hiding", "borders" and "title bars" are Windows workarounds that KDE does natively,
which is the reason the project recorded when it decided not to port them
(DESIGN.md). The other reasons say what the code
of kfw and kfm shows each command is for. For "upstream applications file": at time of writing
(2026-10-28) no applications file for KDE exists upstream, so fetch-app-specific-configuration
has nothing to fetch. The configuration key that points at a file of application rules works (see
the section on keys), and the user supplies the file.
The socket protocol
The messages that komorebi-client sends are the variants of SocketMessage. The counts follow
the ones of the commands, since nearly every command is one message.
| kfw | kfm | kfde | |
|---|---|---|---|
SocketMessage variants |
187 | 153 | 156 |
| In all three | 148 | 148 | 148 |
| In kfde and kfw, not kfm | 6 | - | 6 |
| In kfde and kfm, not kfw | - | 0 | 0 |
| Only in kfde | - | - | 2 |
| In kfw or kfm, not in kfde | 33 | 5 | - |
Of the messages kfde has, these are not in both of the other programs:
- Only in kfde:
HotkeysState,ReloadHotkeys. - In kfde and kfw, not in kfm:
FocusFollowsMouse,ToggleFocusFollowsMouse,ToggleMaximize,ToggleTransparency,Transparency,TransparencyAlpha. - In kfde and kfm, not in kfw: none.
The two messages that only kfde has are the ones behind komorebic hotkeys state and
komorebic hotkeys reload. The names of the variants are the same in the programs that share them.
Whether every variant has the same payload in the three programs was not compared. Subscribers use
a Unix domain socket, as in kfm and, next to named pipes, in kfw.
Configuration
kfde reads the keys of komorebi.json that both others read
The counts, by struct of static_config.rs. "Not read by kfde" is the number of keys that kfw or
kfm has and kfde does not:
| Struct | kfw | kfm | kfde | All three | kfw and kfde | kfm and kfde | kfde only | Not read by kfde |
|---|---|---|---|---|---|---|---|---|
StaticConfig (top level) |
53 | 34 | 37 | 30 | 4 | 3 | 0 | 20 |
WorkspaceConfig (workspace) |
22 | 19 | 20 | 19 | 1 | 0 | 0 | 2 |
MonitorConfig (monitor) |
8 | 9 | 9 | 8 | 0 | 1 | 0 | 0 |
| Total | 83 | 62 | 66 | 57 | 5 | 4 | 0 | 22 |
The keys that kfw, kfm and kfde all read, which mean the same, apart from what the next sections say:
- top level (
StaticConfig):animation,app_specific_configuration_path,border,border_colours,border_offset,border_width,cross_boundary_behaviour,cross_monitor_move_behaviour,default_container_padding,default_workspace_padding,display_index_preferences,float_override,float_override_placement,float_rule_placement,floating_applications,floating_layer_behaviour,floating_layer_placement,floating_window_aspect_ratio,global_work_area_offset,ignore_rules,layout_defaults,manage_rules,monitors,monocle_focus_behaviour,mouse_follows_focus,resize_delta,theme,toggle_float_placement,unmanaged_window_operation_behaviour,window_container_behaviour. - workspace (
WorkspaceConfig):apply_window_based_work_area_offset,container_padding,float_override,floating_layer_behaviour,initial_workspace_rules,layout,layout_flip,layout_options,layout_options_rules,layout_rules,name,tile,wallpaper,window_container_behaviour,window_container_behaviour_rules,work_area_offset,work_area_offset_rules,workspace_padding,workspace_rules. - monitor (
MonitorConfig):container_padding,floating_layer_behaviour,wallpaper,window_based_work_area_offset,window_based_work_area_offset_limit,work_area_offset,workspace_padding,workspaces.
kfde reads keys from kfw and keys from kfm
kfde reads the keys kfw has for the features it took from kfw, and the ones kfm has that kfw does not:
| Key | Level | Also in | What it is |
|---|---|---|---|
focus_follows_mouse |
top level | kfw | Focus the window under the pointer. |
transparency |
top level | kfw | Add transparency to unfocused windows (default: false) |
transparency_alpha |
top level | kfw | Alpha value for unfocused window transparency 0-255 (default: 200) |
transparency_ignore_rules |
top level | kfw | Individual window transparency ignore rules |
border_radius |
top level | kfm | Radius of window borders |
tabbed_applications |
top level | kfm | Accepted so that a configuration written for another platform loads, and ignored: a KWin window has no native tabs |
titleless_applications |
top level | kfm | Accepted so that a configuration written for another platform loads, and ignored: a KWin window is always a window |
initial_window_placement_rules |
workspace | kfw | Initial window placement rules that determine where new tiled windows are placed in the container list. |
window_hiding_position |
monitor | kfm | Accepted so that a configuration written for another platform loads, and ignored: there is no hiding position on KDE Plasma |
No key of komorebi.json is read only on KDE
none
That is by decision: a file should load on every platform that has the feature (why). The keys that mean something else on KDE, or do less, are these:
| Key | Level | What is different on KDE |
|---|---|---|
border_width |
top level | At most 20 px: the effect draws the ring in the window's shadow, and a window without a shadow has none. While borders are drawn, the layout leaves border_width plus border_offset on each side of a window, also past 20. |
border_colours |
top level | Six colors, one for each kind of window, when komorebi's build of the border effect is installed. With the stock effect only single and unfocused take effect, and komorebi says so once in its log. |
animation |
top level | style is the Qt easing curve of that name (EaseInOutSine is InOutSine) and a custom cubic Bezier curve is an ease out, when komorebi's build of the Geometry Change effect is installed; the stock effect always eases out exponentially. fps is read and ignored: the compositor animates at the refresh rate of the screen. |
focus_follows_mouse |
top level | Both implementations kfw names (Windows and Komorebi) ask KWin for the same thing: its focus policy, put back as the user had it when it is turned off or komorebi exits. |
transparency |
top level | KWin's window opacity, set for the unfocused windows of each monitor's shown workspace by kfw's rules (the focused window and a monocled one stay opaque). |
theme |
top level | A theme by name or a palette of your own gives the six border colors, and the palette of a wallpaper takes over from it when its workspace is shown. |
wallpaper |
workspace | Set through the Plasma shell, which keeps one wallpaper for each screen and not for each desktop, so komorebi changes it as the workspace in front changes. The picture fills the screen. |
workspaces |
monitor | Workspace i is KWin's desktop i on every monitor, so every monitor has as many desktops as the largest workspace count, and where the names differ the desktop takes the first monitor's. |
app_specific_configuration_path |
top level | Read as in kfm and kfw. There is no applications file for KDE upstream, so komorebi has none to download. |
Some keys are read and do nothing on KDE
They are read so that a file written for another platform loads, and komorebic check lists them
once as accepted and ignored:
| Key | Level | Also in | Effect on KDE |
|---|---|---|---|
tabbed_applications |
top level | kfm | Read, so that a file written for kfm loads, and does nothing on KDE. |
titleless_applications |
top level | kfm | Read, so that a file written for kfm loads, and does nothing on KDE. |
window_hiding_position |
monitor | kfm | Read, so that a file written for kfm loads, and does nothing on KDE. |
animation.fps |
nested | kfw, kfm | Read, and ignored: the compositor animates at the refresh rate of the screen. |
Some keys are not read at all
These are keys of kfw or kfm that kfde does not have. They are not an error: serde skips a key it
does not know, so the file loads, and komorebic check tells them apart from a typo.
| Key | Level | In | Why kfde does not read it |
|---|---|---|---|
bar_configurations |
top level | kfw | komorebi-bar is not ported. |
border_implementation |
top level | kfw | How a Win32 border window is drawn. The compositor draws the border. |
border_overflow_applications |
top level | kfw | How a Win32 border window is drawn. The compositor draws the border. |
border_style |
top level | kfw | How a Win32 border window is drawn. The compositor draws the border. |
border_z_order |
top level | kfw | How a Win32 border window is drawn. The compositor draws the border. |
invisible_borders |
top level | kfw | The size of the invisible frame Windows adds around a window. |
layered_applications |
top level | kfw | A Win32 window style. There is no counterpart in a Wayland compositor. |
minimum_window_height |
top level | kfw | Marked DISCOURAGED in komorebi for Windows. Commented out in kfde. |
minimum_window_width |
top level | kfw | Marked DISCOURAGED in komorebi for Windows. Commented out in kfde. |
monitor_index_preferences |
top level | kfw | Identifies a monitor by its size. kfde reads display_index_preferences, which names the display, as kfm does. |
object_name_change_applications |
top level | kfw | A Win32 event some applications send on launch. |
object_name_change_title_ignore_list |
top level | kfw | A Win32 event some applications send on launch. |
remove_titlebar_applications |
top level | kfw | A window without a title bar has no shadow in KWin, and so no border. |
scrolling |
top level | kfm | The ScrollingConfig of the strip in kfm (komorebi-scrolling). kfde has the Scrolling layout of komorebi-layouts, tuned with layout_options. |
slow_application_compensation_time |
top level | kfw | A Win32 workaround for applications that are slow to move. |
slow_application_identifiers |
top level | kfw | A Win32 workaround for applications that are slow to move. |
stackbar |
top level | kfw | KDE has no counterpart of the tab bar komorebi draws on Windows. |
tray_and_multi_window_applications |
top level | kfw | A Win32 notion: an application that closes to the system tray. |
window_handling_behaviour |
top level | kfw | A Win32 quirk of how windows are moved. |
window_hiding_behaviour |
top level | kfw | One native mechanism hides windows, so there is nothing to choose. |
custom_layout |
workspace | kfw | Custom layouts are not supported yet. |
custom_layout_rules |
workspace | kfw | Custom layouts are not supported yet. |
The nested structs have the same keys, except for these:
| Struct | kfw | kfm | kfde | In kfw, not kfde | In kfm, not kfde |
|---|---|---|---|---|---|
BorderColours |
6 | 6 | 6 | - | - |
ThemeOptions |
11 | 8 | 8 | stackbar_background, stackbar_focused_text, stackbar_unfocused_text |
- |
Wallpaper |
3 | 3 | 3 | - | - |
AnimationsConfig |
5 | 4 | 4 | ghost_movement |
- |
There is one more difference that is not a key. kfm has a scrolling key. kfde has the Scrolling
layout of komorebi-layouts, which is laid out with the same strip as kfm's, with columns that hold
several windows and the commands consume, expel, toggle-column-stack,
scrolling-layout-full-width, center-focus, expand and pan, and is tuned with
layout_options and the command scrolling-layout-columns, which kfw and kfm have too. A
scrolling key in a file written for kfm is skipped by kfde. The generated tables above were made
before kfde took these commands: scripts/compare-gen.py --update makes them again.
Events, and what drives them
The window manager reacts to events about windows. In kfw the operating system raises them, through
SetWinEventHook, and in kfm through the accessibility API and the notification center. In kfde
the script in KWin connects to the signals of KWin's workspace and of each window and sends every
one to the daemon as a JSON string over D-Bus. The daemon turns a signal into a
WindowManagerEvent, the way kfw and kfm turn what they get.
| Tree | What the OS layer reports | Kinds |
|---|---|---|
| kfw | WinEvent, the events of SetWinEventHook |
84 |
| kfm | AccessibilityNotification and AppKitWorkspaceNotification |
41 and 21 |
| kfde | KWinNotification, the signals of the KWin script |
16 |
The events follow kfw's model: each is about a window, and a window is a small Copy handle. kfm's
events carry a process id and a window id instead. The table puts the events of kfde next to the
ones of the other two that play the same part:
| kfde event | Source on KDE | kfw | kfm |
|---|---|---|---|
Show |
workspace.windowAdded |
Show, Uncloak |
Show |
Destroy |
workspace.windowRemoved |
Destroy |
Destroy |
FocusChange |
workspace.windowActivated |
FocusChange, Raise |
FocusChange |
Minimize |
window.minimizedChanged, to true |
Minimize |
Minimize |
Restore |
window.minimizedChanged, to false |
- | Restore |
TitleUpdate |
window.captionChanged |
TitleUpdate |
- |
Manage |
komorebi itself (manage, a rule) |
Manage |
Manage |
Unmanage |
komorebi itself (unmanage, a rule) |
Unmanage |
Unmanage |
MoveStart |
window.interactiveMoveResizeStarted, for a move |
MoveResizeStart |
MoveStart |
MoveEnd |
window.interactiveMoveResizeFinished, after a move |
MoveResizeEnd |
MoveEnd |
ResizeStart |
window.interactiveMoveResizeStarted, for a resize |
MoveResizeStart |
ResizeStart |
ResizeEnd |
window.interactiveMoveResizeFinished, after a resize |
MoveResizeEnd |
ResizeEnd |
ResizeStep |
window.interactiveMoveResizeStepped |
- | - |
WorkspaceChange |
workspace.currentDesktopChanged |
- | SpaceChange |
WorkspaceMove |
window.desktopsChanged |
- | - |
OutputChange |
window.outputChanged |
- | - |
MaximizeChange |
window.maximizedChanged |
- | - |
FullscreenChange |
window.fullScreenChanged |
- | - |
| Event with no counterpart in kfde | In | Why |
|---|---|---|
Hide |
kfw | Win32 hides and cloaks windows; kfde has no counterpart because KWin shows and hides windows by desktop, and says so with WorkspaceChange. |
Cloak |
kfw | Win32 hides and cloaks windows; kfde has no counterpart because KWin shows and hides windows by desktop, and says so with WorkspaceChange. |
MouseCapture |
kfw | Windows tells komorebi that a mouse button went down on a window. KWin reports the start of a move or resize instead. |
ScreenLock |
kfm | KDE locks and unlocks the screen with org.freedesktop.ScreenSaver; komorebi hears it in kwin/power.rs and reconciles, with no event of this kind. |
ScreenUnlock |
kfm | KDE locks and unlocks the screen with org.freedesktop.ScreenSaver; komorebi hears it in kwin/power.rs and reconciles, with no event of this kind. |
Three things about this are worth knowing:
- A signal reaches the daemon in 0 to 1 ms, from
Date.now()in the script to the receipt in the daemon (the spikes, 2026-10-26, KWin 6.8.1 in a virtual machine on HVF). - KWin emits
windowActivatedbeforewindowAddedfor a new window, so the script announces the window from the activation, and no event mentions a window before the event that adds it. - The script contains no logic. Why and why the commands come back to the script as the answer to a held call are in DESIGN.md.
What the operating system layer is
kfw calls Win32 from WindowsApi, kfm calls the accessibility API and Core Graphics from
MacosApi and its modules. kfde puts the whole of what the window manager needs behind one trait,
Backend, which a test replaces with FakeBackend (a desktop in memory). The sizes are not a
measure of the effort: the Win32 and macOS calls are scattered over more modules than the ones the
counts name.
| Tree | The operating system layer | Size |
|---|---|---|
| kfw | WindowsApi in windows_api.rs |
92 public functions |
| kfm | MacosApi in macos_api.rs, and the accessibility, core_graphics and skylight modules |
14 public functions in MacosApi |
| kfde | Backend, with FakeBackend for tests and KWinBackend for KWin |
31 methods (27 are required, 4 are provided), and a script of 684 lines that runs inside KWin |
What each method of Backend is on KDE, and the function of kfw and kfm that does the same job,
where there is one:
Backend method |
On KDE | kfw function | kfm function |
|---|---|---|---|
windows |
workspace.windowList() once, then the events of the bridge |
enum_windows |
window_elements |
window |
the table the bridge keeps, fed by events | window_rect, exe_path |
window_by_title |
foreground_window |
workspace.activeWindow |
foreground_window |
foreground_window |
monitors |
workspace.screens and clientArea(KWin.PlacementArea, ...), which leaves out the panel |
load_monitor_information |
load_monitor_information |
cursor_pos |
workspace.cursorPos |
cursor_pos |
cursor_pos |
drag_origin |
the frame the bridge saw at interactiveMoveResizeStarted |
none | none |
drag_end |
the frame the bridge saw at the last interactiveMoveResizeStepped |
none | none |
set_rect |
frameGeometry, and a second request for the position once the size settles |
position_window |
set_position |
focus |
workspace.activeWindow = w |
raise_and_focus_window |
focus |
raise |
workspace.raiseWindow(w) |
raise_window |
raise |
hide |
moves the window to the parking desktop (desktops) |
hide_window |
hide |
restore |
moves the window back from the parking desktop (desktops) |
restore_window |
restore |
minimize |
minimized = true |
minimize_window |
minimize |
unminimize |
minimized = false |
restore_window |
unminimize |
close |
closeWindow() |
close_window |
close |
center_cursor_in |
the "Move Mouse to Focus" action (MoveMouseToFocus) |
center_cursor_in_rect |
center_cursor_in_rect |
ensure_workspaces |
createDesktop on org.kde.KWin.VirtualDesktopManager |
none | none |
switch_workspace |
setCurrentDesktopForScreen |
none | none |
set_window_workspace |
desktops of the window |
none | none |
window_workspace |
desktops of the window |
none | none |
current_workspaces |
currentDesktopForScreen |
none | none |
apply_look |
writes the effects' groups of kwinrc, loadEffect and reconfigureEffect |
none | none |
set_border_colours |
org.komorebi.BorderColours1, which only komorebi's build of the border effect has |
none | none |
set_opacity |
opacity |
set_transparent |
none |
set_focus_follows_mouse |
the FocusPolicy of kwinrc, then reconfigure |
enable_focus_follows_mouse |
none |
set_wallpaper |
org.kde.PlasmaShell setWallpaper |
set_wallpaper |
set_wallpaper |
maximize |
setMaximize |
maximize_window |
none |
A method with "none" in both columns is something kfw and kfm do not need an operating system call for, because the window manager keeps its own workspaces there, or something they do not have. Why everything is behind one trait is in DESIGN.md.
What KDE does by itself
The table lists what kfw and kfm do themselves and what KDE does, for the features where the compositor, the shell or the desktop has a mechanism of its own. The sections below say what is different for each.
| What | kfw | kfm | On KDE |
|---|---|---|---|
| Workspaces | komorebi's own workspaces; the windows of the other workspaces are hidden | komorebi's own workspaces; the windows of the other workspaces are hidden | KWin's virtual desktops, one set per output (Plasma 6.8): workspace i is desktop i on every monitor |
| Hiding windows (a stack, a monocle) | window_hiding_behaviour: cloak, hide or minimize |
moves the window to a corner of the screen | a virtual desktop nobody looks at (komorebi-park) |
| Borders | a topmost tool window per border, drawn by komorebi with Direct2D | an NSWindow per border, drawn by komorebi |
the KDE Rounded Corners effect, with komorebi's patch for one color per kind of window |
| Animation | komorebi moves the window step by step | komorebi moves the window step by step | the Geometry Change effect, with komorebi's patch for the easing curve |
| Transparency of unfocused windows | SetLayeredWindowAttributes, called by komorebi |
no key or command | KWin's window opacity, through the same patched effect as the borders |
| Focus follows mouse | the Windows setting, or komorebi's own implementation (focus_follows_mouse) |
no key or command | KWin's focus policy; the user's policy is put back when it is turned off or komorebi exits |
| Maximize | toggle-maximize: the Win32 maximize |
no key or command | toggle-maximize: KWin's maximize, which respects the panel. A window the user maximizes is taken out of the layout until restored |
| Fullscreen windows | no handling of its own in the sources | no handling of its own, except that the reaper keeps a window that fails to move | left alone, and put back in its tile when it leaves fullscreen |
| Wallpapers | the desktop wallpaper of each monitor | the desktop picture of each display | the Plasma shell, asked over D-Bus, one wallpaper per screen |
| Hotkeys | a separate program: whkd (or AutoHotkey) |
a separate program: skhd |
KDE global shortcuts: .desktop files for plain bindings, and the daemon through KGlobalAccel for modes, chords and scopes |
| Monitors added, removed or changed | a reconciliator thread, fed by WM_DISPLAYCHANGE in a hidden window |
a reconciliator thread, fed by the display reconfiguration callback | the same thread, fed by the script (when KWin's list of outputs changes) and by kwin/power.rs; reconcile.rs follows the windows the compositor moved |
| Sleep, wake and lock | power setting and session notifications (register_power_setting_notification, wts_register_session_notification) |
ScreenLock and ScreenUnlock events |
PrepareForSleep of logind and ActiveChanged of the KDE screen saver, on D-Bus |
| Reloading the configuration | watch-configuration is about komorebi.ahk and komorebi.ps1; komorebi.json is watched |
komorebi.json is watched |
komorebi.json is watched |
Workspaces are KWin's virtual desktops
kfw and kfm have a workspace layer of their own: komorebi keeps a list of workspaces for each
monitor, and when one is left it hides the windows of that workspace, because Windows and macOS
have no virtual desktop API to ask. On KDE, KWin 6.8 can give each output its own current desktop,
so komorebi's workspace i is KWin's desktop i on every monitor, and each monitor shows one at a
time. A switch is one request per monitor, and KWin shows, hides and focuses. komorebi
follows a switch made by something else (the pager, a shortcut, an application raising a window)
and answers it with no command. Why
is in DESIGN.md.
This has consequences that are measured, or read from KWin's sources:
- A switch made by an application raising a window produces one focus event and one switch (spike 10, 2026-10-27). Answering a switch with commands makes KWin and komorebi fight: a design in which komorebi did the hiding flipped between two workspaces about 280 times a second, because KWin delivered focus events it had generated before it applied the commands, and komorebi read them as new intent. komorebi therefore issues no commands in reply to a switch.
- The workspaces are visible in the pager and in the overview: they are the user's desktops, and a stop leaves them in place (it removes the parking desktop).
- Desktops are global: every monitor has as many as the largest workspace count, and the name of a desktop is shared by the monitors (the first monitor's, where they differ).
- A window that komorebi does not manage (a dialog, an ignored application) belongs to the desktop it opened on, and goes out of view with it. kfw and kfm hide what a workspace holds (its containers, its floating windows and its monocle) when they leave it, so a window they do not manage stays visible across workspaces.
- The floor is KWin 6.8, because per-output desktops arrived there. Older KWin versions were not tested. At time of writing (2026-10-28) the versions run are 6.8.1 (the spikes) and 6.8.2 (the VM suites), in Plasma 6.8.1 and 6.8.2.
- komorebi turns
PerOutputVirtualDesktopson inkwinrcwhen it starts and puts it back when it exits. It edits the file itself:kwriteconfig6was not on the path of the user service in the first live run.
Hiding windows: cloaking, a corner, or a parking desktop
komorebi hides windows for a stack (the other windows of a container) and for a monocle (the other
containers). kfw offers three ways, chosen with window_hiding_behaviour: cloak (an undocumented
Win32 call), minimize, and the end-of-life SW_HIDE. kfm moves the window to a bottom corner of
its display, which window_hiding_position of a monitor chooses. kfde moves the window to a
parking desktop and moves it back, and there is nothing to choose. The scrolling layout needs none
of this: KWin keeps a window at a position outside the screen when it is moved there.
Three ways were measured on six tiled windows (spike 3, 2026-10-26, KWin 6.8.1):
| Way | Spurious focus events | Geometry restored |
|---|---|---|
| minimize | 2 (KWin picks a new active window as each window minimizes) | 6 of 6 |
| parking desktop | 0 | 6 of 6 |
| a position outside the screen | 0, but the windows stay mapped on the current desktop (task switcher, overview) | 6 of 6 |
KWin saves a virtual desktop in kwinrc the moment it is made, so a run that dies leaves the
parking desktop for the next session. komorebi removes it on exit, and the next start finds a stale
one, sends its windows home and removes it. A parked window still appears in the task manager unless
that is set to show the current desktop only (by construction, not measured).
Why a parking desktop
is in DESIGN.md.
Borders: komorebi draws them, or the compositor does
kfw draws a topmost tool window for each border, with Direct2D, and kfm an NSWindow for each. kfde draws nothing: the
KDE Rounded Corners effect draws the outer outline of every window, and komorebi writes its settings
to kwinrc and tells it to read them again. KWin keeps the copy of kwinrc it read at start, so
komorebi asks for a reconfiguration every time, also straight after it loads the effect.
The limits, as of 2026-10-27:
- The ring is drawn in the window's shadow, so a window without a shadow has none, and its thickness
is at most 20 px. That is why kfde has no counterpart of
remove_titlebar_applications: removing the title bar removes the shadow. - The stock effect has a color for the active window and one for the others. komorebi's build of it
takes a color for each window over D-Bus (
org.komorebi.BorderColours1), which gives the six kinds of kfw's rules:single,stack,monocle,floating,unfocusedandunfocused_locked. Without that build, every kind falls back tosingleandunfocused, and komorebi says so once in its log. - KDE Rounded Corners 0.10.0 draws the ring about 24 px too low on KWin 6.8 (measured on screenshots of KWin 6.8.1). kfde builds 0.11.0, which nixpkgs has too at time of writing (2026-10-28).
- KWin finds effects when it starts, so an effect installed later is not loaded until the next login.
Why the compositor draws the borders, why the effects are patched and why the border is the outer outline are in DESIGN.md.
Animation: komorebi moves the window step by step, or the compositor animates
kfw and kfm animate by moving the window a little at a time, at animation.fps. kfde sends the final
rectangle and the Geometry Change effect animates the move, so fps has nothing to map to: the
compositor animates at the refresh rate of the screen. The styles are Qt's easing curves of the same
name, which komorebi's build of the effect reads from a Curve setting. The stock effect eases out
exponentially, whatever the style says. Cross-fading is off.
KWin refuses effects that animate under software rendering, which includes every virtual machine the
tests run in, unless KWIN_EFFECTS_FORCE_ANIMATIONS=1 is in KWin's environment. A screenshot cannot
show a short animation, because spectacle takes seconds and the curve is front-loaded: the look test
uses a 30 s animation to see the effect at work.
Transparency, themes and wallpapers
Transparency is KWin's window opacity, set from the same rules as kfw. A window drawn through the border effect comes from a texture with its opacity in it, which the effect redrew only when the contents changed. komorebi's build redraws it when the opacity changes.
A wallpaper is set through the Plasma shell, over D-Bus (org.kde.PlasmaShell), for one screen. The
shell keeps one wallpaper for each screen, not for each virtual desktop, so komorebi sets it when a
workspace comes into view, as kfw and kfm do. If the shell is not running, komorebi tries again for
about half a minute and then says once that it leaves wallpapers alone. A palette made from a
wallpaper is cached in $XDG_CACHE_HOME/komorebi, by the name of the picture and a hash of its
path, size and time of change; a large picture takes seconds (not measured further).
Focus follows mouse
kfw has two implementations to choose from, Windows and Komorebi, and calls the first legacy. kfm
has none. kfde asks KWin to use its focus policy, "focus follows mouse", with the same result for
both names, and puts the user's policy back when the setting is turned off or komorebi exits. KWin
waits for the pointer to settle before it moves the focus: DelayFocusInterval, 300 ms by default
in KWin 6.8.1. kfde sets it to 0 while the setting is on, and puts the user's value back with the
policy; why 0 is not recorded
(DESIGN.md).
Maximize and fullscreen
toggle-maximize is kfw's command, and does KWin's maximize on KDE: the window leaves the layout
and goes back to its tile when toggled again, and the panel is respected. A window that the user
maximizes (the title bar, a double click, a shortcut) is the same from then on: the commands that act
on the layout do nothing until it is restored. Why
is in DESIGN.md. A fullscreen window covers its monitor, komorebi never moves it, and it is put back
in its tile when it leaves fullscreen. kfw has no code for fullscreen, and kfm has one
mention of it in its reaper.
Dragging
All three programs let the user move a tile by dragging it and resize it by dragging an edge. KWin
reports where the pointer has the edge at every step of a resize
(interactiveMoveResizeStepped), so in kfde the neighbors follow the edge while it is dragged, and
not only when it is let go. The way a drag is measured, from the frame the window had when the drag
began, and granted as far as the layout can take it, is written down in
drag-resize.md, for the three programs. The frame KWin reports at the end of a
resize lags the pointer by a moment (PLATFORM.md). kfm
reads the frame of a window with an accessibility call when it needs it (MacosApi::window_rect);
whether that frame lags was not measured.
Key bindings
kfw and kfm leave the keys to a separate program: kfw uses whkd, or AutoHotkey, kfm uses skhd, and
the program runs komorebic. On Plasma under Wayland no program sees the keys of another, so kfde
cannot do that: the keys are KDE's global shortcuts, in one of two ways, and komorebi reads the same
three formats a hotkey daemon would (skhdrc, whkdrc, sxhkdrc).
| kfw | kfm | kfde | |
|---|---|---|---|
| Who sees the keys | whkd, or AutoHotkey | skhd | KWin, through KDE's global shortcuts |
| The file the user writes | whkdrc |
skhdrc |
skhdrc, whkdrc or sxhkdrc, each read by a parser written for komorebi |
The measurements that decide when each is used, at time of writing (2026-10-27), on aarch64 under HVF with four cores, KWin 6.8.1:
| What | Result |
|---|---|
A static shortcut, key to the start of its Exec |
165 to 436 ms, median 233 ms, 8 runs of 8 |
| The daemon, key to the signal it gets | median 2.5 ms (min 2.2, max 3.9), 20 of 20 delivered |
60 calls to setInactive and setShortcutKeys, pipelined |
answered in 2.4 ms in total |
A native multi-key shortcut (Meta+A, B) |
did not fire: the second key reached the focused client |
| A client killed after registering a key | the grab stays, and the key is swallowed, until unRegister |
The last two are why the daemon emulates chord chains, and why the module's unit releases the keys
when the daemon stops. A static shortcut works with the daemon stopped and shows in System Settings,
but costs about 0.2 seconds on each press; the daemon's keys are only as reliable as the daemon. The
default mode is the daemon for every binding (keybindings.mode = "engine"), which these
measurements favor (why, which
also says that the default is still open for a decision), and auto and static use shortcut
files for the bindings that can be one.
What is not emulated, and approximated, is listed in
the user guide: side-specific modifiers,
mouse buttons, skhd's fn, and the sxhkd chain that a wrong key does not end. The reasons are in
DESIGN.md: why some bindings are shortcut files
and why the engine grabs keys instead of using KDE's key sequences.
Keystrokes over RDP: KDE's shortcuts sit inside KWin's input pipeline and see them, and swhkd
reads the kernel's input devices and would not (read from the sources of KRDP and swhkd, not run).
Keys sent over RDP to a session were not verified end to end: the scripted client fails NTLM
against KRDP, and a real client was not tried.
Multiple monitors, sleep and lock
All three programs have a monitor reconciliator: a thread that takes notifications one at a time to
move the windows of a monitor that went away and to bring them back. In kfw a hidden window
(WM_DISPLAYCHANGE) feeds it, and in kfm a display reconfiguration callback. In kfde the script feeds
it, with the whole list of outputs whenever KWin's changes, and so does the code that hears of a wake
or an unlock. The daemon takes the windows of an unplugged monitor over (each container, a stack whole, to the workspace of the same number), keeps what is left
of the monitor for when it comes back, and follows a window that something else moved to another
output. A moment after each notification (1.5 s) it looks at every window again, because KWin has
moved some. A monitor that changes size or scale is tiled again: every coordinate komorebi uses is
KWin's logical one. Why
is in DESIGN.md.
For the screen lock, kfm has ScreenLock and ScreenUnlock events, and kfw registers for power and
session notifications. kfde listens on D-Bus: logind's PrepareForSleep for a wake, and KDE's screen
saver ActiveChanged for a lock. With the screen off or locked KWin sends clients no frame callbacks,
so what komorebi asked for in that time is not done: komorebi waits 600 ms after an unlock and 2.5 s
after a wake and looks at every window again. The lock screen is a window of KWin's that is in no
task list and on every desktop; komorebi does not manage it.
At time of writing (2026-10-27) a real suspend and resume was not tested: the QEMU guests have no way to wake from one. The signals are tested on private buses, and the lock screen against a real KWin in a Plasma session. PLATFORM.md says so too.
Checking the configuration
kfw and kfde have komorebic check, and kfm has none. kfw's reads the files in the configuration
home (komorebi.json, komorebi.ahk and whkdrc among them) and shows what is wrong with them.
kfde's reads komorebi.json the way the daemon will, tells a key of another platform from a typo
(with the nearest key that is a setting), looks at the key binding file and at whether it has been
made into KDE shortcuts, and then looks at the desktop: a Plasma session on Wayland, KWin 6 on the session bus, komorebi's
script in KWin, which build of each effect is installed, the Plasma shell when there are wallpapers,
and what starts komorebi at login. It exits with status 1 when something stops komorebi from working
(a file that is not JSON, no KWin), and 0 with warnings when it only will not do what was meant.
--komorebi-config FILE checks another file and --configuration-only leaves the desktop out; the
first flag is kfw's too.
kfw's check also asks GitHub for the latest release. kfde's does not look for a newer release, and
it does not know the AutoHotkey and PowerShell files of Windows.
What kfw and kfm have that kfde does not
From the tables above, and from what has no row in them:
- The bar.
komorebi-baris not ported: the Plasma panel is used, and the work area accounts for it (a panel moved is a change of the work area, and the tiles are made again). - The stackbar and its settings. A stack is cycled with
cycle-stackandfocus-stack-window. - Custom layouts, which kfw has and kfm does not. Not supported yet.
- The Win32 workarounds of the "Win32 quirks" group, the AutoHotkey and PowerShell configurations, the named-pipe subscribers, and whkd as a separate program.
- The license check and the splash screen of the macOS and Windows builds.
- The tab and title bar commands (
remove-title-bar,toggle-title-bars).
What kfde has that kfw and kfm do not
- Native workspaces: they show in KWin's pager and overview, and KWin focuses the window of the desktop it switches to.
- Borders, animation, transparency and focus follows mouse as a compositor does them, and
checkfor a desktop. - Key bindings that work from a physical keyboard, the QEMU console and RDP, with modes, chords and
scopes realized by the daemon, and the
skhdrc,whkdrcandsxhkdrcformats. - A NixOS module (
services.komorebi) with a user unit, the effects, and the key bindings as options, and a version check of KWin. kfm has a module for nix-darwin, in its own form. - A test suite that runs the window manager against a real KWin in virtual machines, and a
Backendthat tests replace with a desktop in memory. vm-tests.md describes it.
Costs, measured
At time of writing (2026-10-27), on an Apple silicon Mac, in virtual machines under HVF, KWin 6.8.1
(Plasma 6.8.1, nixpkgs d3b13ad of 2026-10-24). No number here compares kfde with kfw or kfm:
nothing of the same kind was measured on them.
| What | Result | Source |
|---|---|---|
A retile of 10 foot windows on a 3840x2160 output, from the answer to Poll to the last frame KWin reported (5.5 windows moved on average) |
p50 17.3 ms, p95 27.7 ms, max 31.4 ms | vm-latency, PLATFORM.md |
| The same channel alone, 20 windows in each batch | p50 16 ms, p95 19 ms, max 20 ms | the spikes |
| A client's answer to a frame | exact for Qt, GTK 4 down to its minimum, XWayland; foot rounds to its cells; GTK 4 Calculator and Firefox keep a minimum size |
vm-client-geometry, PLATFORM.md |
| A window resized off the screen | KWin keeps 100 px of it on an output | PLATFORM.md |
| KWin restarting under a running daemon | the script is loaded again about 1 s after KWin is back | the spikes |
What was not measured is listed in PLATFORM.md: a real suspend and resume, KWin before 6.8, activities, outputs beyond a second one, applications in a sandbox, keys from an RDP client and graphics other than software rendering, among others.