Skip to main content

max / alloy

Pick smithay-client-toolkit for the lockscreen Wayland binding Resolves open question #1 in crates/alloy_lockscreen/README.md. SCTK is the only option with a purpose-built session_lock module that encodes ext-session-lock-v1's lifecycle (must wait for locked, must unlock before drop) as types, plus an upstream working examples/ session_lock.rs to start from. Multi-maintainer Smithay org backing beats wayrs's single-maintainer bus factor. The ~20-crate dep premium over wayrs doesn't pay off for a compile-once lockscreen binary. Architectural consequence: alloy_lockscreen does not use eframe. eframe drives Wayland through winit, which opens its own wl_display connection — that connection can't share state with the client that owns the session lock. Instead, alloy_lockscreen owns the Wayland connection via SCTK and drives egui through egui_glow on raw GL contexts (one per output). alloy_ui consumption is unchanged. Three open questions remain: PAM crate, single- vs per-output process model, and lockscreen-process crash recovery semantics.
Co-Authored-By
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-26 19:38 UTC
Signed with PGP, not checked
Commit: 4dcac456e6c851b4f774e7d43c2d6167578aea35
Parent: 142b631
1 file changed, +15 insertions, -1 deletion
@@ -45,9 +45,23 @@
45 45 - The focus ring is `border-strong`, never accent. Failed-auth state may *temporarily* color the status text in `accent-error`, per the accent-on-text rule in [TOKENS.md](../../docs/TOKENS.md#accent-on-surface-text-rule). The password field's border does **not** flip to accent.
46 46 - The lockscreen runs at `surface` tier. The password field sits on `surface-raised`. No popovers, no overlays — there is nowhere for an overlay to go on a lockscreen.
47 47
48 + ## Architecture
49 +
50 + The lockscreen does **not** use `eframe`. eframe drives Wayland through winit, which opens its own `wl_display` connection — that connection can't share state with whatever owns the session lock, and the session lock has to be owned by the same client that owns the surfaces it draws into. So alloy_lockscreen owns its Wayland connection directly via `smithay-client-toolkit` and drives egui via `egui_glow` on raw GL contexts (one per output).
51 +
52 + Practically: a small render loop pulls Wayland events from SCTK's `calloop` source, feeds keyboard/pointer events into an `egui::Context`, runs the egui pass, and submits the painted output through `egui_glow` to the GL context bound to each `ExtSessionLockSurfaceV1`. The alloy_ui crate is consumed exactly as in the showcase example — `apply_alloy_visuals` + primitives — only the host loop differs.
53 +
54 + ## Stack picks
55 +
56 + | Layer | Pick | Why |
57 + |---|---|---|
58 + | Wayland client | **`smithay-client-toolkit`** | First-class `session_lock` module encodes ext-session-lock-v1's lifecycle (must wait for `locked`, must `unlock` before drop) as types. Upstream `examples/session_lock.rs` is a working starting point. Multi-maintainer Smithay org vs wayrs's single maintainer. Dep-tree premium (~20 crates over wayrs) doesn't matter for a compile-once binary. |
59 + | egui rendering | **`egui` + `egui_glow`** (not `eframe`) | We need to own the Wayland connection, which means we can't use winit (which eframe wraps). egui_glow lets us submit egui paint to GL contexts we manage. |
60 + | GL context | **`glutin`** (or `glow` directly if SCTK exposes EGL helpers) | Decision deferred until first protocol code lands; pick after seeing what SCTK gives us for EGL surface creation. |
61 +
48 62 ## Open questions blocking implementation
49 63
50 - 1. **Wayland protocol crate.** `wayrs-client` (lighter, async-ergonomic, smaller dep tree, newer), `smithay-client-toolkit` (canonical, larger, more battle-tested), or raw `wayland-client` (control, more code). Decision criterion: what gives us a clean ext-session-lock-v1 binding with the smallest stable dep surface. To be resolved before any Wayland code lands.
64 + 1. ~~**Wayland protocol crate.**~~ Resolved: smithay-client-toolkit. See above.
51 65 2. **PAM crate.** `pam` (canonical bindings, may be stale), `pam-client` (newer, more ergonomic), or vendoring a thin FFI ourselves. PAM is a small enough API surface that vendoring is reasonable if no current crate is well-maintained.
52 66 3. **Process model.** Single-process binding all outputs, or one process per output. Single-process is simpler and matches how swaylock works; one-process-per-output gets us isolation if PAM blocks. Default: single-process.
53 67 4. **Recovery path.** If the lockscreen process crashes while holding the session lock, the compositor stays locked and the user is stranded. ext-session-lock-v1 has explicit semantics for this; document the chosen recovery path (compositor-side fallback, watchdog, intentional crash-to-greeter) before shipping.