checkpoint: Linux display compatibility + icon alpha fixes (2026-09-09)

This commit is contained in:
Avi 2026-09-09 20:19:10 -05:00
commit 1d5940fb82

View file

@ -0,0 +1,103 @@
# Checkpoint — Linux display compatibility + icon alpha fixes (2026-09-09)
## Where things are
- Project: `/home/avi/Projects/Keynctr`
- Branch: `master` @ **`d580139`** ("fix(icons): true alpha channel, no white matte or
white tile") on top of **`0814a53`** ("fix(linux): work on X11, Wayland, and Hyprland").
- Working tree: **clean for tracked files.** Untracked leftovers are the pre-existing
hygiene entries (`.directory`, `.impeccable/`, `.opencode/`, `COSMIC_THEME.md`,
`src/publish.rs.bak`, `src/signer/nip46_external.rs`) plus `deferred/SignerConnectionPanel.tsx.wip`
(a broken WIP component, moved out of the build — see below). Original white-background
icons are preserved under `deferred/original-icons/` (tracked).
## What was completed (this session)
### 1. Linux display-server compatibility — `0814a53`
The app did not start on a friend's Wayland machine. Root causes found and fixed:
- **No explicit platform choice.** Hyprland (and any Wayland session with XWayland)
exports both `$DISPLAY` and `$WAYLAND_DISPLAY`, so Electron must be told which
backend to use before Chromium initializes. `frontend/electron/main.ts` now sets
`ozone-platform` (wayland/x11) from `XDG_SESSION_TYPE`/`WAYLAND_DISPLAY` at module
load, with `KEYNCTR_FORCE_X11=1` / `KEYNCTR_FORCE_WAYLAND=1` overrides.
- **GPU process crashes (SIGSEGV in `eglCreateWindowSurface`, Mesa `libGLESv2`).**
Reproduced on this box (Intel Iris Xe, Hyprland, mesa 26.2.1): with hardware GL the
GPU helper died repeatedly and the window never appeared. Fix: **software rendering
by default on Linux** (`app.disableHardwareAcceleration()`); hardware GL is opt-in
via `KEYNCTR_ENABLE_GPU=1`.
- **Startup watchdog + bounded relaunch ladder.** A marker file
(`<tmp>/keynctr-startup.json`, stamped clean on deliberate quit) records each launch;
if the previous process died before its window proved itself (painted and survived
8 s), the next launch advances one rung: detected platform → other platform → GPU
opt-in → other+GPU, then stops with an error dialog listing the escape hatches.
AppImage-safe relaunch via `$APPIMAGE`. No infinite cascades.
- **Sandbox pre-flight.** Packaged builds check for a non-setuid `chrome-sandbox`
combined with blocked unprivileged user namespaces (Ubuntu 24.04 AppArmor knob,
`unprivileged_userns_clone`) and fall back to `--no-sandbox` instead of dying
silently. Root also gets `--no-sandbox` as Chromium requires.
- Window now uses `show: false` + `ready-to-show` (always shown, even with the
watchdog disabled).
### 2. Icon white-fringe fix — `d580139`
The source icons were grayscale (mode **L**, no alpha at all): a black bird on a flat
white field, which rendered as a white box/halo on every non-white surface (window
icon, taskbar, sidebar, launchers).
- `frontend/public/icon.png` and `frontend/src/assets/logo.png` regenerated as
**RGBA**: alpha = ink coverage of the original artwork; RGB forced to 0 everywhere,
so no white matte can bleed through semi-transparent edge pixels (verified: 0 pixels
with RGB > 200 at alpha < 20). Artwork bbox/shape unchanged (IoU 1.0 vs originals).
- `frontend/src/styles.css`: `.sidebar-logo` dropped its `background: #fff` white tile,
`border-radius`, and `object-fit: cover`; the artwork now composites directly with
`contain`. Dark-theme `invert(1)` kept (ink artwork must flip on dark sidebars).
- Originals preserved: `deferred/original-icons/icon-public-512-white.png`,
`deferred/original-icons/logo-sidebar-338-white.png`.
### 3. Build hygiene (uncommitted by design? no — landed with the fixes)
- `frontend/src/components/signer/SignerConnectionPanel.tsx` was an untracked,
non-compiling WIP (broken `useCallback` closures, APIs that don't exist on
`SignerManager`, dependency on uninstalled `react-router-dom`) that blocked
`npm run typecheck`. Moved intact to `deferred/SignerConnectionPanel.tsx.wip`
(untracked) — nothing deleted; it needs a rewrite against the real hooks before
returning.
## Verification (all run this session)
- Rust: `cargo fmt --check` clean, `cargo clippy --all-targets` clean, `cargo test`
green, `cargo build --release` succeeded.
- Frontend: `npm run electron:build`, `npm run typecheck`, `npm run lint` clean;
`npm test` **116/116 passed**; `npx prettier --check electron/main.ts` and
`src/styles.css` clean; `npm run build` succeeded. (5 pre-existing Prettier warnings
in untouched files — `ExportSecretKeyModal.tsx`, `SignerModeScreen.tsx`,
`AppProvider.tsx`, `ExportSecretKey.test.tsx`, `fakeBackend.ts` — predate this
session and were left alone.)
- **On-device (Hyprland/Wayland, this machine):** app launched under a clean systemd
user scope: Keynctr window mapped (`class: keynectr`), watchdog marker cleared
(= config proven), **no new Electron core dumps** after 19:40 while multiple
software-render launches ran. `grim` screenshot + visual inspection confirmed the
sidebar bird sits directly on the sidebar with **no white tile, border, or halo**.
- Icon proof: checkerboard composite of the new `public/icon.png` shows clean
anti-aliased edges into transparency, no white fringe.
## How to run / reproduce
- GUI: `cd frontend && npm start` (or the packaged AppImage/deb once rebuilt via
`npm run dist`).
- Escape hatches: `KEYNCTR_FORCE_X11=1`, `KEYNCTR_FORCE_WAYLAND=1`,
`KEYNCTR_ENABLE_GPU=1`, `KEYNCTR_DISABLE_GPU=1`, `KEYNCTR_NO_RELAUNCH=1`.
- CLI: `cargo run --release -- serve` (JSON-lines IPC) as before.
## Outstanding / next steps
- **Repackage for the friend:** `npm run dist` (AppImage + deb) with the new icon and
display fixes; the old `frontend/release/` artifacts predate both commits.
- `deferred/SignerConnectionPanel.tsx.wip`: rewrite against the real `useSignerManager`
API (+ either add `react-router-dom` or drop the import) before reinstating.
- Consider a taskbar-visible test on a pure-X11 session and on GNOME Wayland for the
friend matrix (only Hyprland/Wayland was verifiable here).
- Step 3 sub-step 2 (IPC reroute) is untouched and remains the next signer milestone.
- The user's crash-reporter still holds old core dumps from pre-fix launches
(`coredumpctl rm` clears them).