Files
komorebi/docs/dev/DESIGN.md
T
LGUG2Z c0345eb0e9 feat(wm): windows, containers, workspaces and monitors
The window manager tiles a tree of four levels: monitors, each with a ring of
workspaces, each with a ring of containers, each with a ring of windows. It is
the model komorebi has on Windows and macOS, and the first thing the daemon
keeps that the backend does not give it.

A window is a Copy handle that carries the compositor's id and asks the backend
for everything else, so moving one is a call on the handle and needs no context
passed to it. A workspace tiles itself: the layout gives each container a tile
of the work area its monitor hands it, less the offset and the padding, and
every window of the container is asked to move there. A locked container keeps
its index because the workspace inserts, removes and swaps its containers
through LockableSequence.

This is tiling only. Stacks, monocle, maximize, the floating layer, resize
adjustments, placement rules and the link between workspaces and KWin's desktops
come with the commits that use them. impl_ring_elements!, which gives every
holder of a ring the same accessors, lands here with its first users.
2026-10-27 14:07:28 -07:00

3.0 KiB

Design

This document explains why komorebi for KDE is built the way it is, one decision at a time. It is opinionated: these are the reasons behind the code, and reasonable people may disagree with them. Where a reason was not written down, the entry says that it needs one.

It grows with the code: a decision is added in the commit that makes it.

What is komorebi for KDE the port of?

komorebi has a Windows implementation, the original, and a macOS one. The Windows one is the reference. I used it as the reference for what to adapt, and I prefer what KDE and Wayland do natively over a workaround that the other two platforms need. The events the window manager reacts to follow the Windows ones (a window is shown, destroyed, focused, minimized, moved, resized), and a window is a small Copy handle, as there. The model the window manager tiles is the one both platforms have: monitors, each with workspaces, each with containers, each with windows.

Why is everything the window manager needs behind one trait?

So that the window manager can be tested without a compositor. A test that needs a real KWin has to boot a virtual machine, which takes a minute or more and needs QEMU with a hypervisor (vm-tests.md); a test against an in-memory desktop takes milliseconds and runs anywhere. The logic (which window goes where, what happens when one closes, how a stack cycles) is tested with the second kind, and the VM tests are kept for what only KWin can tell.

The cost is that a second implementation has to be kept honest. A fake that does what it is told is not KWin: a real client may refuse a size, a compositor may report an event the fake never raises, and a fake that is too permissive hides a bug that a compositor would show. The fake is therefore written to be strict where KWin is (a command about a window that no longer exists is an error) and to clamp where a real client does (a window with a minimum size keeps to it).

Why is the backend a process-wide singleton?

So that a window can be a small Copy value that carries only its id. A window that had to hold a reference to its backend would not be Copy, and every function that moves, focuses or hides one would take a context argument as well. That is a lot of plumbing for a thing that never changes while the daemon runs.

The cost is a global. A test that wants a private desktop overrides it for its own thread with with_backend, which restores the previous one afterwards, also on a panic.

Why does a backend answer from a table instead of asking the compositor?

A query that waits for the compositor can wait for a long time, and the window manager asks a lot of questions: every move of a container is followed by a look at where each window ended up. A backend keeps a table that the compositor's events update, so a query is a lookup. The trade-off is that the table can be a moment behind the compositor, which is why a command returns when it has been accepted and not when the client has acted, and why the frame a window really has is read back afterwards.