Files
komorebi/docs/dev
LGUG2Z b49c4fab0a feat(kwin): the daemon registers with KGlobalAccel
A static shortcut can only be one combo, pressed, the same in every application.
Modes, chord chains, release bindings and per-application bindings need komorebi
to hold the keys and decide what each press does: the engine of
komorebi-hotkeys, a state machine with no I/O. This commit runs it against
KWin's global shortcut daemon, which KWin 6.8 runs inside itself on the session
bus.

kwin::hotkeys owns the component komorebi in kglobalaccel, with one action per
combo, named after the combo (Alt+H). An activation of the engine is
setShortcutKeys(id, [[combo]], 6), with a doRegister the first time; a
deactivation is setInactive, after which the key reaches the focused window
again. The calls of one event are sent without waiting for each other's answers,
which Phase 0 measured at 60 calls in 2.4 ms. globalShortcutPressed and
globalShortcutReleased of /component/komorebi feed the engine;
globalShortcutRepeated is ignored, so a held key runs its binding once. A
komorebic command runs the komorebic next to the daemon with its words when they
need no shell, anything else runs through sh -c. The calls are computed by
Registry, which is pure and tested; the D-Bus part is proved by the VM test.

The engine hears the presses at the path /component/komorebi and does not ask
kglobalaccel for the object with getComponent. kglobalaccel makes the object
when the component gets its first action, so a start with no key to grab (every
binding is for an application other than the one with the focus) has none to ask
for: getComponent fails with NoSuchComponent, and an engine that asked would
never start. A signal is matched by the path it comes from, so the presses are
heard as soon as there is an object. PLATFORM.md says so.

kglobalaccel keeps the actions and the grabs of a client that was killed, so a
start is an idempotent reconcile: the actions of the component that the keymap
names are taken over and released unless the default mode wants them, the others
are unregistered. A stop releases and unregisters everything, from
KWinBackend::shutdown, which SIGINT, SIGTERM and the Stop message all go
through.

The daemon takes --keybindings FILE, --keybindings-format skhd|whkd|sxhkd (by
default from the file's name) and --keybindings-mode (the mode komorebic hotkeys
compile wrote the static shortcuts in, so that the daemon leaves those to KDE);
without --keybindings it reads the first of skhdrc, whkdrc and sxhkdrc in the
config directory (HOME_DIR, KOMOREBI_CONFIG_HOME). It logs one line about the
file and the diagnostics at debug level. An engine that cannot start is logged
and the window manager runs without keys; the fake backend runs none.

The VM test vm-keys-engine starts the daemon in a Plasma session with an skhdrc
in the config directory, presses its keys (a command, one through a shell,
komorebic retile reaching the daemon), kills the daemon and sees its keys stay
registered, starts it with another file and sees the old keys unregistered and
the new ones work, and stops it with komorebic stop, after which no key is
registered and none runs. The library gains spawn_komorebi,
kill_spawned_komorebi and shortcut_actions, and Checks.finish names the checks
that failed, since nix build shows only the last lines of a failed run. The
suite's node turns the module's unit off: the test runs daemons of its own.
2026-10-28 07:21:14 -07:00
..