#!/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 " >&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"