While the screen is locked or the machine is asleep, KWin sends its clients no frame callbacks, so nothing komorebi asked for in that time is done: a window that something else moved stays where it was moved, and the monitors can come back in another order or at another size. Nothing told komorebi it had happened, and it kept the layout it had until the next event. kwin::power now watches for the two ends of it: logind's PrepareForSleep on the system bus, which only logind may send, and the lock screen's ActiveChanged on the session bus. When the machine wakes (2.5 seconds after it, while the outputs are found one after another) or the screen is unlocked (0.6 seconds after it, once the lock screen has gone), the monitor reconciliator gets a Wake and calls wake_up: it reconciles the monitors as for an unplug, reads their sizes, follows the windows to the monitors they are on and tiles every monitor, unless the window manager is paused. Going to sleep and locking do nothing, and a machine with no system bus or a session with no lock screen runs without them. The lock screen is a window of KWin's that the bridge already does not report as an application window, so it has no tile. The bridge also compares KWin's active window with the one it last announced once a second, because the window that is active again after an unlock is not always announced. vm-lock-sleep locks and unlocks a real Plasma session and checks that the windows come back to their tiles; a real suspend cannot be tested in the QEMU guest, only the signal wiring, which tests/power.rs covers on private buses. vm-lock-sleep waits for the panel's room before it opens the windows, so that they are tiled once, and compares the window that was moved with the tile the daemon has for it when it looks, give or take a cell of the terminal's font, and not with the frames read earlier: the room can come while the screen is locked, and the tiles read before are then not the ones. The wait is not a check, because a session on a machine as slow as TCG may never take the room.
4.5 KiB
Subscribing to notifications
A program such as a status bar, a widget or a script can follow what komorebi does by subscribing to its notifications. After each event the window manager handles (a window was shown, closed, focused, minimized, restored or moved to another output), each message it takes on its socket and each change of the monitors, the daemon sends every subscriber a notification: the event, the message or the change, and the state of the window manager after it.
Subscribing
A subscriber listens on a Unix socket of its own in the daemon's data directory,
$XDG_RUNTIME_DIR/komorebi (on NixOS and most systemd distributions,
/run/user/<uid>/komorebi), and tells the daemon the name of the socket with
komorebic subscribe-socket. The socket has to exist before
it subscribes: the daemon sends the notification of the subscription at once, and removes a
subscriber it cannot connect to.
With socat, a shell can subscribe and print every notification:
socat -u UNIX-LISTEN:"$XDG_RUNTIME_DIR/komorebi/bar.sock",fork STDOUT &
komorebic subscribe-socket bar.sock
komorebic unsubscribe-socket bar.sock stops the
notifications.
Notifications
The daemon sends each notification on a new connection to the subscriber's socket: it connects, writes one JSON object, and closes the connection. There is no newline after the object. The first notification a subscriber receives is the one of its subscription.
A notification has two fields:
event: the event, the message or the change of the monitors. An event is a window event, with the signal it came from and the window, such as{"type":"Show","content":[{"type":"KWin","content":"WindowAdded"},{"id":...}]}. A message is written the way a client writes it on the daemon's socket, such as{"type":"Retile"}. A change of the monitors is the name of the change with its content:{"Resize":0}for a monitor that changed size, with the id of the monitor, or 0 when KWin does not say which, and{"DisplayConnectionChange":0}for a monitor that was unplugged or plugged in, and"Wake"for the machine waking up or the screen being unlocked. Changing monitors and Sleeping and locking say when each is sent.state: the state of the window manager after it, with the same fields as whatkomorebic stateprints, on one line.
An event about a window that komorebi does not manage, and a message that fails, are not sent.
Only when something changed
A subscriber can ask to be sent a notification only when the event or the message changed
the state, with the filter_state_changes option. It is still sent the notification of a
window that is shown, of every change of the monitors, of every new subscription, so it
receives the state as soon as it subscribes, of a theme, which changes the colors of the
borders and nothing in the state, and of every reload of komorebi.json.
komorebic subscribe-socket has no option for it; a program writes the message
on the daemon's socket itself:
printf '%s' '{"type":"AddSubscriberSocketWithOptions","content":["bar.sock",{"filter_state_changes":true}]}' |
socat - UNIX-CONNECT:"$XDG_RUNTIME_DIR/komorebi/komorebi.sock"
When a subscriber goes away
A subscriber that the daemon cannot connect to, because its program has exited or its socket was removed, is removed at the next notification, and its socket file with it. The daemon does not try it again: a program that wants notifications again subscribes again. The daemon keeps its subscribers only while it runs, so after a restart every program has to subscribe again.
When the daemon stops, it connects to each subscriber and closes the connection without writing anything.
A subscriber should accept and read every connection as it comes. The daemon writes each notification while the window manager is locked, and waits when the socket's buffer is full, so a subscriber that stops reading can hold up the window manager. While it is held up, the window events KWin reports wait for it, and once 20 are waiting the daemon drops the ones that come after them.
In Rust
The komorebi-client crate has subscribe and subscribe_with_options, which listen on
the socket, subscribe, and return the listener: each connection on it is one
Notification. cargo doc --package komorebi-client --open shows their documentation,
with an example.