This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1{ 2 config, 3 pkgs, 4 ... 5}: 6let 7 # Run the patched launcher from the on-disk strom checkout at 8 # /home/strom/strom (it carries STROM_NO_GAMESCOPE support until that lands 9 # upstream). With the kiosk itself being a gamescope session (below), games 10 # are launched as <slug>.no-gamescope so they render directly in the session 11 # compositor instead of nesting a per-game gamescope. 12 strom-session = pkgs.writeShellScript "strom-session" '' 13 set -u 14 # xpadneo owns the Xbox pad's hidraw node, so force SDL (pygame launcher and 15 # the games) to read the pad through evdev instead of its HIDAPI backend - 16 # same fix as 2configs/steam.nix, without it SDL finds no controller. 17 export SDL_JOYSTICK_HIDAPI_XBOX=0 18 # SDL's udev-monitor hotplug does not deliver in this kiosk session, so a pad 19 # powered on after the launcher starts is never seen. Force SDL to poll 20 # /dev/input instead, which reliably picks up pads as they connect/disconnect. 21 export SDL_JOYSTICK_DISABLE_UDEV=1 22 # Under cage the launcher window never reports input focus, and SDL suppresses 23 # joystick (not keyboard) events while unfocused - so keyboard works but the 24 # pad does not. Allow joystick events regardless of focus. 25 export SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS=1 26 # The kiosk compositor is already gamescope on DRM (see services.greetd 27 # below), so tell the launcher to run games directly in it rather than 28 # nesting a per-game gamescope (which double-nests and, on this GPU, storms 29 # the Vulkan swapchain and crashes games like Baba Is You). 30 export STROM_NO_GAMESCOPE=1 31 # strom-run (the per-game supervisor) needs a delegated cgroup v2 so it can 32 # mkdir a child cgroup and cgroup.kill the game tree atomically. The greetd 33 # PAM session drops us into a root-owned logind session scope 34 # (user-1011.slice/session-cN.scope) that is NOT delegated, so strom-run dies 35 # with "could not create cgroup (Permission denied)" and the game never 36 # launches. Re-parent into a delegated transient scope under the user manager 37 # (user@UID.service, which logind DOES delegate). Wait for the user bus first: 38 # on boot the PAM session opens slightly before the user manager's bus socket. 39 rd="''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" 40 for _ in $(seq 1 50); do 41 [ -S "$rd/bus" ] && break 42 sleep 0.2 43 done 44 # Relaunch whenever the couch launcher exits (gamepad B / Esc) so the kiosk 45 # never drops to a blank screen. The loop runs inside the delegated scope so 46 # every game inherits a writable cgroup; the gamescope compositor stays up 47 # (it is the session's other child) across relaunches. 48 # 49 # setpriv --ambient-caps=-all: the login session may carry an ambient 50 # capability (e.g. cap_wake_alarm) that every child inherits. bwrap refuses 51 # to start when it sees capabilities in its permitted set without being 52 # setuid ("Unexpected capabilities but not setuid, old file caps config?"), 53 # which instant-crashes every sandboxed game. Drop the ambient set for the 54 # whole launcher tree so bwrap (and thus each game) starts clean. 55 exec ${pkgs.systemd}/bin/systemd-run --user --scope -p Delegate=yes \ 56 --quiet --collect -- \ 57 ${pkgs.util-linux}/bin/setpriv --ambient-caps=-all \ 58 ${pkgs.bash}/bin/bash -c 'while true; do 59 ${config.nix.package}/bin/nix run /home/strom/strom#scripts.launcher 60 sleep 2 61 done' 62 ''; 63 64 # Bluetooth pairing helper for Xbox Wireless Controllers. Run `strom-pair` 65 # once per controller (as root / on the console, e.g. 66 # `ssh root@coaxmetal.r strom-pair`): put the pad in pairing mode (hold the 67 # Xbox button to power on, then hold the small round sync button on the top 68 # edge until the light flashes rapidly) and the script blocks until it pairs 69 # that one pad, then exits. A pad currently paired to another device is 70 # re-paired here (its stale bond is cleared); a pad already connected and 71 # working is left alone. Run once per controller. Bonded+trusted pads 72 # reconnect on their own on every later boot. Pass a MAC to pair just one. 73 strom-pair = pkgs.writeShellApplication { 74 name = "strom-pair"; 75 runtimeInputs = [ pkgs.bluez ]; 76 text = '' 77 # Find one Xbox pad that is here right now (advertising in pairing mode) 78 # and not already connected; echo its MAC (empty if none). We key off what 79 # actually shows up in THIS scan, not the bonded-device list: a pad that 80 # was since re-paired to another host still lingers as "bonded" here but 81 # only appears in a scan when it is genuinely present and pairable. 82 find_target() { 83 local sl m 84 local -a bonded present 85 sl=$(mktemp) 86 bluetoothctl --timeout 12 scan on > "$sl" 2>&1 || true 87 mapfile -t bonded < <(bluetoothctl devices 2>/dev/null | grep -i xbox | awk '{print $2}') 88 # MACs of xbox pads that showed up in this scan (present + advertising). 89 mapfile -t present < <( 90 { 91 # freshly discovered pads announce their name 92 grep -i xbox "$sl" | grep -oiE '([0-9a-f]{2}:){5}[0-9a-f]{2}' 93 # known/bonded pads emit nameless RSSI lines; match their MAC in-scan 94 for m in "''${bonded[@]:-}"; do 95 [ -n "$m" ] && grep -qiF "$m" "$sl" && printf '%s\n' "$m" 96 done 97 } | sort -uf 98 ) 99 rm -f "$sl" 100 for m in "''${present[@]:-}"; do 101 [ -n "$m" ] || continue 102 bluetoothctl info "$m" 2>/dev/null | grep -q "Connected: yes" && continue 103 printf '%s\n' "$m" 104 return 0 105 done 106 return 0 107 } 108 109 # Pair one pad. Xbox controllers use JustWorks pairing, which needs a 110 # NoInputNoOutput agent held in the SAME bluetoothctl session as `pair` 111 # (plus disable_ertm, set system-wide below). Remove any existing bond 112 # first: a pad re-paired to another host still shows bonded here but never 113 # reconnects, and bluez refuses a fresh pair while that stale bond exists. 114 # `connect` succeeds even when pairing fails, so success is judged by 115 # "Bonded: yes", not by connect. 116 pair_one() { 117 local mac="$1" 118 bluetoothctl remove "$mac" >/dev/null 2>&1 || true 119 { 120 echo "power on" 121 echo "agent NoInputNoOutput" 122 echo "default-agent" 123 echo "scan on" 124 sleep 14 125 echo "pair $mac" 126 sleep 12 127 echo "trust $mac" 128 echo "connect $mac" 129 sleep 4 130 echo "quit" 131 } | bluetoothctl >/dev/null 2>&1 || true 132 # Bonding can finalize a moment after the session exits; poll a few 133 # seconds before deciding it failed. 134 for _ in 1 2 3 4 5; do 135 bluetoothctl info "$mac" 2>/dev/null | grep -q "Bonded: yes" && return 0 136 sleep 1 137 done 138 return 1 139 } 140 141 bluetoothctl power on >/dev/null 2>&1 || true 142 143 # Single-pad mode: (re)pair exactly the given MAC and exit. 144 if [ -n "''${1:-}" ]; then 145 if pair_one "$1"; then 146 echo ">> paired, trusted, connected: $1" 147 exit 0 148 fi 149 echo "!! could not pair $1." >&2 150 exit 1 151 fi 152 153 # Default: wait for a pad that is present and in pairing mode, (re)pair it, 154 # then exit. Run once per controller. A pad that was paired to another 155 # device in the meantime is re-paired here (its stale bond is cleared) 156 # rather than skipped; a pad already connected and working is left alone. 157 echo ">> put a controller in pairing mode: hold the Xbox button to power" 158 echo " on, then hold the small round sync button on the top edge until" 159 echo " the light flashes rapidly. Waiting... (Ctrl-C to abort)" 160 while true; do 161 echo ">> scanning..." 162 mac=$(find_target) 163 if [ -n "$mac" ]; then 164 printf '>> pairing %s ... ' "$mac" 165 if pair_one "$mac"; then 166 echo "OK" 167 echo ">> paired, trusted, connected: $mac" 168 exit 0 169 fi 170 echo "failed, retrying (keep it in pairing mode)" 171 fi 172 sleep 1 173 done 174 ''; 175 }; 176in 177{ 178 # Dedicated, unprivileged kiosk user. Gamepad input comes through evdev 179 # (input group), audio through the system-wide pipewire socket (pipewire 180 # group), and the games need video/audio like any local player. 181 users.users.strom = { 182 isNormalUser = true; 183 extraGroups = [ 184 "video" 185 "audio" 186 "input" 187 "pipewire" 188 ]; 189 }; 190 191 # Kiosk autostart: a gamescope session on DRM (via greetd autologin), 192 # replacing cage. gamescope presents straight to the display, so there is no 193 # nested Wayland swapchain for RADV to storm on this Vega iGPU. greetd gives 194 # the strom user a real seat/VT (DRM master) and a delegated user manager, 195 # which the launcher's systemd-run --user --scope relies on for game cgroups. 196 services.greetd = { 197 enable = true; 198 settings = 199 let 200 session = { 201 command = "${pkgs.gamescope}/bin/gamescope -- ${strom-session}"; 202 user = "strom"; 203 }; 204 in 205 { 206 # initial_session autologins on boot with no prompt; default_session 207 # re-runs it (also autologin) if the gamescope session ever exits. 208 initial_session = session; 209 default_session = session; 210 }; 211 }; 212 213 # The panel comes up at ~1% backlight, unreadable for a couch setup. Ship 214 # brightnessctl + its udev rules (chgrp backlight to the video group, g+w) so 215 # any video-group user (strom, lass) can adjust it without root, e.g. 216 # `brightnessctl set 100%` / `brightnessctl set 50%`. 217 environment.systemPackages = [ 218 pkgs.brightnessctl 219 strom-pair 220 ]; 221 services.udev.packages = [ pkgs.brightnessctl ]; 222 223 # Force the backlight to maximum on every boot. Ordered after 224 # systemd-backlight, which would otherwise restore the last (dim) saved level. 225 systemd.services.max-brightness = { 226 wantedBy = [ "multi-user.target" ]; 227 after = [ "systemd-backlight@backlight:amdgpu_bl1.service" ]; 228 serviceConfig = { 229 Type = "oneshot"; 230 ExecStart = "${pkgs.brightnessctl}/bin/brightnessctl set 100%"; 231 }; 232 }; 233 234 # Xbox Wireless Controllers (Bluetooth). xpadneo for correct rumble/axis 235 # mapping; the two bluez tweaks + disable_ertm are what make Xbox pads 236 # actually bond (without disable_ertm they fail with AuthenticationFailed). 237 # Bluetooth itself (adapter + powerOnBoot) already comes from 238 # 2configs/pipewire.nix. Pair each pad once with `strom-pair` (see above). 239 hardware.xpadneo.enable = true; 240 # Xbox One/Series controllers pair over Bluetooth only with L2CAP ERTM off. 241 boot.extraModprobeConfig = "options bluetooth disable_ertm=1"; 242 hardware.bluetooth.settings.General = { 243 # JustWorksRepairing lets bluez accept fresh pairings without a manual 244 # remove; Privacy = device pins a static host address so the controller's 245 # bond key survives RPA rotation. 246 JustWorksRepairing = "always"; 247 Privacy = "device"; 248 # Keep page scan always on so a bonded pad reconnects promptly when powered 249 # back on (otherwise bonded pads bond but never re-link). Fine on a 250 # mains-powered kiosk. 251 FastConnectable = true; 252 }; 253}