Files
blocker/desktop/daemon
SellPL 69602636b1 feat(linux): wire the KWin path end to end, and verify it live
The daemon now owns `vu.valiq.blocker`, loads the KWin script, and enters the
event loop on the primary backend. Verified against the running session:

```
$ blocker-daemon
blocker-daemon 0.1.0 (M0/M1)
database: /tmp/bsmoke/blocker/blocker.db
backend: kwin — native Wayland windows are visible
owning the D-Bus name; entering the event loop
enforcement: Freeze; entering the event loop
```

The process then parked until killed — which is the point. There is no tick; the
loop blocks on a focus event and on the engine's `next_wakeup`.

**Ordering is load-bearing and worth stating.** `callDBus` has nothing to resolve
until the daemon holds the bus name, so the name must be acquired *before* the
script is loaded. Loading first means a handler calling a name nobody owns, and
every focus event silently dropped.

**A real defect found by running it rather than reading it.** After the daemon
was killed, `isScriptLoaded` still returned `true` — the script was left in KWin.
`Drop` does not run on SIGTERM, so the cleanup path never executes. It is
fail-open and harmless (the script's `callDBus` fails inside the compositor,
which is exactly the section 1.5.4 behaviour), and `KwinBackend::connect`
unloads any stale script before loading a fresh one, so a restart recovers. But
"harmless" is not "correct", and the honest fix — a systemd `ExecStopPost` or a
signal handler that unloads — is not in this PR.

Also fixes the duplicated loop body: both backends now share one `run_loop`, so
the X11 and KWin paths cannot drift into enforcing differently.

Verified: clippy `-D warnings` clean, `fmt --check` clean, all tests passing,
stripped daemon within the 5 MB budget.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 22:41:31 +03:00
..