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:
parent
86afe00dba
commit
a89556aef7
3 changed files with 76 additions and 2 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
68
packaging/souveraine-button
Executable 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"
|
||||
Loading…
Reference in a new issue