Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

feat: drop cage/Wayland, run ac-native DRM-direct on NixOS

Remove the cage Wayland compositor and run ac-native directly on
DRM/evdev — matching the bare-metal build's architecture:

- Drop USE_WAYLAND=1, wayland deps from Nix package
- Rewrite kiosk.nix: exec ac-native on tty1, no cage wrapper
- Remove seatd (root has DRM master), cage from system packages
- Remove Wayland env vars (WLR_*, XCURSOR_*, XDG_RUNTIME_DIR)

This eliminates the entire Wayland input stack
(evdev -> libinput -> cage -> wl_pointer) that caused trackpad
drift, cursor conflicts, and input latency. ac-native now owns
DRM and evdev directly, same as the bare-metal build.

Net: -59 lines of config, zero abstraction layers between
ac-native and the hardware.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+20 -79
-1
fedac/nixos/configuration.nix
··· 54 54 # System packages — only what ac-native needs at runtime 55 55 environment.systemPackages = with pkgs; [ 56 56 ac-native 57 - cage 58 57 wpa_supplicant 59 58 iw 60 59 dhcpcd
+19 -66
fedac/nixos/modules/kiosk.nix
··· 22 22 } > "$out" 2>/dev/null || true 23 23 sync || true 24 24 ''; 25 - ac-native-client = pkgs.writeShellScript "ac-native-cage-client" '' 25 + ac-native-start = pkgs.writeShellScript "ac-native-start" '' 26 26 set -u 27 27 28 - rm -f /tmp/ac-native-cage.log 29 - ${write-breadcrumb} ac-native-starting "binary=${ac-native}/bin/ac-native" "piece=${ac-native}/share/ac-native/piece.mjs" 30 - printf '[ac-native-cage-client] starting %s %s\n' \ 31 - "${ac-native}/bin/ac-native" \ 32 - "${ac-native}/share/ac-native/piece.mjs" >&2 28 + ${write-breadcrumb} ac-native-starting \ 29 + "binary=${ac-native}/bin/ac-native" \ 30 + "piece=${ac-native}/share/ac-native/piece.mjs" \ 31 + "mode=drm-direct" 33 32 34 - status=0 35 - "${ac-native}/bin/ac-native" \ 36 - "${ac-native}/share/ac-native/piece.mjs" \ 37 - >/tmp/ac-native-cage.log 2>&1 || status=$? 33 + # Switch to tty1 and run ac-native in DRM-direct mode. 34 + # No cage, no Wayland — ac-native owns DRM master and reads evdev directly. 35 + chvt 1 38 36 39 - printf '[ac-native-cage-client] ac-native exited status=%s\n' "$status" >&2 40 - if [ -s /tmp/ac-native-cage.log ]; then 41 - ${pkgs.gnused}/bin/sed 's/^/[ac-native-cage-log] /' \ 42 - /tmp/ac-native-cage.log >&2 || true 43 - else 44 - printf '[ac-native-cage-client] no /tmp/ac-native-cage.log output\n' >&2 45 - fi 46 - 47 - exit "$status" 48 - ''; 49 - ac-native-kiosk = pkgs.writeShellScript "ac-native-kiosk" '' 50 - set -u 51 - 52 - rm -f /tmp/cage-stderr.log 53 - ${write-breadcrumb} kiosk-launching "tty=/dev/tty1" "display=cage" 54 - printf '[ac-native-kiosk] launching cage on tty1\n' >&2 55 - 56 - status=0 57 - ${pkgs.cage}/bin/cage -s -- ${ac-native-client} \ 58 - 2>/tmp/cage-stderr.log || status=$? 59 - 60 - printf '[ac-native-kiosk] cage exited status=%s\n' "$status" >&2 61 - if [ -s /tmp/cage-stderr.log ]; then 62 - ${pkgs.gnused}/bin/sed 's/^/[cage-stderr] /' /tmp/cage-stderr.log >&2 || true 63 - else 64 - printf '[ac-native-kiosk] no /tmp/cage-stderr.log output\n' >&2 65 - fi 66 - 67 - exit "$status" 37 + exec "${ac-native}/bin/ac-native" \ 38 + "${ac-native}/share/ac-native/piece.mjs" 68 39 ''; 69 40 ac-native-stop = pkgs.writeShellScript "ac-native-stop" '' 70 41 set -u ··· 81 52 -u mount-usb-config.service \ 82 53 -u ac-native-kiosk.service \ 83 54 >"$journal" 2>&1 || true 84 - 85 - if [ -f /tmp/ac-native-cage.log ]; then 86 - cp /tmp/ac-native-cage.log "/mnt/logs/ac-native-cage-''${stamp}.log" || true 87 - fi 88 - if [ -f /tmp/cage-stderr.log ]; then 89 - cp /tmp/cage-stderr.log "/mnt/logs/cage-stderr-''${stamp}.log" || true 90 - fi 91 55 sync || true 92 56 fi 93 57 ··· 99 63 ''; 100 64 in 101 65 { 102 - # seatd for unprivileged GPU/input access 103 - services.seatd.enable = true; 104 - 105 - # Kiosk service: cage compositor running ac-native 66 + # DRM-direct kiosk: ac-native owns the display and input hardware. 67 + # No cage compositor, no seatd, no Wayland — matching the bare-metal build. 106 68 systemd.services.ac-native-kiosk = { 107 - description = "AC Native OS kiosk"; 69 + description = "AC Native OS kiosk (DRM direct)"; 108 70 conflicts = [ "getty@tty1.service" ]; 109 - after = [ "getty@tty1.service" "mount-usb-config.service" "seatd.service" ]; 110 - wants = [ "mount-usb-config.service" "seatd.service" ]; 71 + after = [ "getty@tty1.service" "mount-usb-config.service" ]; 72 + wants = [ "mount-usb-config.service" ]; 111 73 wantedBy = [ "multi-user.target" ]; 112 74 113 75 path = with pkgs; [ 114 76 coreutils gnugrep gnused gawk findutils 115 - which psmisc # killall (psmisc), which 77 + which psmisc 116 78 systemd util-linux 117 79 wpa_supplicant iw dhcpcd curl 118 80 dosfstools efibootmgr parted ··· 120 82 ]; 121 83 122 84 environment = { 123 - XDG_RUNTIME_DIR = "/run/user/0"; 124 85 HOME = "/tmp/ac-home"; 125 86 SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; 126 87 ALSA_PLUGIN_DIR = "${pkgs.alsa-plugins}/lib/alsa-lib"; 127 88 ALSA_CONFIG_PATH = "${pkgs.alsa-lib}/share/alsa/alsa.conf"; 128 - # Hide the Wayland compositor cursor — ac-native renders its own. 129 - WLR_NO_HARDWARE_CURSORS = "1"; 130 - XCURSOR_SIZE = "1"; 131 89 }; 132 90 133 91 serviceConfig = { 134 - # Run as root — ac-native needs full hardware access (WiFi, ALSA, 135 - # DRM) matching the old bare-metal build where it ran as PID 1. 136 - # Security hardening can be layered on once all features work. 92 + # Run as root for DRM master + evdev + WiFi + ALSA access. 137 93 Type = "simple"; 138 94 Restart = "on-failure"; 139 95 RestartSec = 2; ··· 145 101 StandardOutput = "journal"; 146 102 StandardError = "journal"; 147 103 148 - # cage -s for single-app mode, wrapped so child logs land in journal. 149 - ExecStart = "${ac-native-kiosk}"; 104 + ExecStart = "${ac-native-start}"; 150 105 151 - # Exit code handling: 152 - # 0 = shutdown, 2 = reboot (matching current ac-native convention) 106 + # Exit code: 0 = shutdown, 2 = reboot 153 107 SuccessExitStatus = "0 2"; 154 108 ExecStopPost = "+${ac-native-stop}"; 155 109 }; 156 110 }; 157 111 158 - # Ensure XDG_RUNTIME_DIR exists for the ac user 159 112 systemd.tmpfiles.rules = [ 160 113 "d /mnt 0755 root root -" 161 114 "d /run/user/0 0700 root root -"
+1 -12
fedac/nixos/packages/ac-native/default.nix
··· 1 1 { lib, stdenv, fetchurl, pkg-config 2 2 , libdrm, alsa-lib, flite, openssl, curl 3 - , wayland, wayland-protocols, wayland-scanner 4 3 , ffmpeg, esbuild 5 4 , nativeSrc 6 5 , kidlispSrc ? null ··· 21 20 22 21 nativeBuildInputs = [ 23 22 pkg-config 24 - wayland-scanner 25 23 esbuild 26 24 ]; 27 25 ··· 31 29 flite 32 30 openssl 33 31 curl 34 - wayland 35 - wayland-protocols 36 32 ffmpeg 37 33 ]; 38 34 ··· 45 41 $sourceRoot/build/quickjs/ 46 42 ''; 47 43 48 - # Fix hardcoded wayland protocol path 49 - postPatch = '' 50 - substituteInPlace Makefile \ 51 - --replace '/usr/share/wayland-protocols' \ 52 - '${wayland-protocols}/share/wayland-protocols' 53 - ''; 54 - 44 + # DRM-direct mode — no Wayland compositor, no cage overhead. 55 45 makeFlags = [ 56 - "USE_WAYLAND=1" 57 46 "CC=cc" 58 47 ]; 59 48