Watch
1
0
Fork
You've already forked souveraine
0

packaging: ship souveraine-button, the reporter that replaces the policy script

Reports down/up edges to sessiond and decides nothing. Wire it in
hyprland.lua as a bind/bindr pair — reporting only the press leaves the
machine believing the button is held forever.
This commit is contained in:
Fimeg 2026-07-31 21:48:08 -04:00
commit a89556aef7
3 changed files with 76 additions and 2 deletions

View file

@ -344,6 +344,7 @@ jobs:
cp packaging/souveraine-sensord.service "$PKG_WORK/"
fi
cp packaging/souveraine-verify-trail "$PKG_WORK/"
cp packaging/souveraine-button "$PKG_WORK/"
cp packaging/arch/PKGBUILD.prebuilt "$PKG_WORK/PKGBUILD"
(
cd "$PKG_WORK"

View file

@ -15,9 +15,9 @@ options=('!strip')
source=('souveraine-binary' 'souveraine.service'
'souveraine-secrets-binary' 'souveraine-secrets.service'
'souveraine-machined-binary' 'souveraine-machined.service'
'souveraine-verify-trail'
'souveraine-verify-trail' 'souveraine-button'
'LICENSE')
sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
sha256sums=('SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP')
# sessiond ships on aarch64 only (the phone is its target; the laptop hit
# lock-screen errors with it). CI drops the two files into the build dir for
# that arch and omits them otherwise, so package() picks them up conditionally
@ -50,6 +50,11 @@ package() {
install -Dm644 "$srcdir/souveraine-sensord.service" \
"$pkgdir/usr/lib/systemd/user/souveraine-sensord.service"
fi
# Hardware button reporter. Every arch: it decides nothing and depends on
# nothing, and a laptop with a power button is the same shape. Replaces
# blueline-power-button, which was owned by no package and carried its own
# copy of the lock-then-blank ordering.
install -Dm755 "$srcdir/souveraine-button" "$pkgdir/usr/bin/souveraine-button"
# Secrets rail (user service, owns org.freedesktop.secrets) and machined
# (system service, machine identity). Both were hand-copied to the phone
# and owned by no package — same gap as sessiond.

68
packaging/souveraine-button Executable file
View file

@ -0,0 +1,68 @@
#!/bin/sh
# Report a hardware button edge to the session authority. That is all it does.
#
# It replaces `blueline-power-button`, which was policy in shell script: it read
# its own copy of the panel state, asked the SHELL to lock over `qs ipc`, polled
# `session state` twenty times at 100 ms grepping JSON for `"locked": true`, and
# then called `blueline-screen-toggle off` itself. Three separate problems:
#
# 1. It blanked the panel without going through sessiond's `request_blank()`,
# so LOCK-DPMS-LESSONS §1 ("every path to a dark panel routes through it —
# an invariant, not a coincidence") had a hole in it, and the hole was the
# most-used control on the device.
# 2. It carried its own copy of the lock-then-blank ordering, which is the
# exact duplication DEVICE-STATE-MACHINE §1 is about: seven blind actors,
# three of which can turn the screen off.
# 3. It could only ever see one edge, so it could never tell a tap from a
# hold. Gesture recognition needs time, and a process that exits cannot
# hold any.
#
# Now the machine owns all three. This reports `down` and `up`; sessiond
# accumulates them into tap / double / triple / hold and decides what, if
# anything, that means.
#
# Wire it up in hyprland.lua as a PAIR — press and release:
#
# hl.bind( "XF86PowerOff", hl.dsp.exec_cmd("souveraine-button power down"), { locked = true })
# hl.bindr("XF86PowerOff", hl.dsp.exec_cmd("souveraine-button power up"), { locked = true })
#
# Only reporting `down` gives you a machine that thinks the button is held
# forever: the hold threshold passes, `Hold` fires, and no `Tap` ever resolves.
set -eu
button=${1:-power}
edge=${2:-down}
case "$edge" in
down | up) ;;
*)
echo "usage: souveraine-button <power|volume_up|volume_down> <down|up>" >&2
exit 2
;;
esac
runtime=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}
sock="$runtime/souveraine/sessiond.sock"
line="{\"op\":\"button\",\"button\":\"$button\",\"edge\":\"$edge\"}"
# Fire and forget, with a hard timeout. A button press must never block on the
# authority being slow — the user is holding the button and the phone must not
# feel stuck. Losing an edge degrades to a missed gesture, which is recoverable;
# hanging here is not.
#
# No nc/socat on this device (checked), so this is Python's stdlib or nothing.
exec timeout 1 python3 -c '
import socket, sys
sock, line = sys.argv[1], sys.argv[2]
try:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.settimeout(0.8)
s.connect(sock)
s.sendall((line + "\n").encode())
except Exception:
# sessiond down. Say so in the journal and drop it: a button reporter that
# falls back to acting on its own is the thing this file exists to delete.
print("sessiond unreachable; button edge dropped: " + line, file=sys.stderr)
sys.exit(1)
' "$sock" "$line"