greetd-moongreet/CLAUDE.md
nevaforget ce9f2196ca
All checks were successful
Update PKGBUILD version / update-pkgver (push) Successful in 2s
refactor: single greeter window, drop per-output keyboard grab (v0.10.0)
The v0.8.0 → v0.8.5 multi-monitor story (login widget on primary only,
wallpaper-only on secondaries, KeyboardMode::Exclusive on the primary
surface, hotplug handler) was a pile of workarounds that kept breaking
on real hardware — after switching the greeter compositor to niri, the
pointer could not cross onto the primary output and keyboard tab did
not reach the UI. Niri in a normal user session has none of these
issues; the bug was moongreet's own output-scoped policy.

Back to basics: one layer-shell window on the built-in display,
KeyboardMode::OnDemand. Secondary outputs stay under compositor
control. No hotplug callbacks, no wallpaper-only windows, no DisplayLink
phantom workarounds.

-81 / +26 lines.
2026-04-24 11:27:48 +02:00

71 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Moongreet
## Projekt
Moongreet ist ein greetd-Greeter für Wayland, gebaut mit Rust + gtk4-rs + gtk4-layer-shell.
Teil des Moonarch-Ökosystems.
## Tech-Stack
- Rust (Edition 2024), gtk4-rs 0.11, glib 0.22
- gtk4-layer-shell 0.8 für Wayland Layer Shell (TOP Layer)
- greetd IPC über Unix Domain Socket (length-prefixed JSON)
- `cargo test` für Unit-Tests
## Projektstruktur
- `src/` — Rust-Quellcode (main.rs, greeter.rs, ipc.rs, config.rs, users.rs, sessions.rs, i18n.rs, power.rs)
- `resources/` — GResource-Assets (style.css, default-avatar.svg)
- `config/` — Beispiel-Konfigurationsdateien für `/etc/moongreet/` und `/etc/greetd/`
- `pkg/` — PKGBUILD für Arch-Linux-Paketierung (`makepkg -sf`)
## Kommandos
```bash
# Tests ausführen
cargo test
# Release-Build
cargo build --release
# Greeter im Fenster starten (ohne greetd/Layer Shell)
MOONGREET_NO_LAYER_SHELL=1 ./target/release/moongreet
# Paket bauen und installieren
cd pkg && makepkg -sf && sudo pacman -U moongreet-git-<version>-x86_64.pkg.tar.zst
```
## Architektur
- `ipc.rs` — greetd Socket-Kommunikation (4-byte LE header + JSON)
- `users.rs` — Benutzer aus /etc/passwd, Avatare (AccountsService + ~/.face), Symlink-Rejection
- `sessions.rs` — Wayland/X11 Sessions aus .desktop Files
- `power.rs` — Reboot/Shutdown via loginctl
- `i18n.rs` — Locale-Erkennung (LANG / /etc/locale.conf) und String-Tabellen (DE/EN), alle UI- und Login-Fehlermeldungen
- `fingerprint.rs` — fprintd D-Bus Probe (gio::DBusProxy) — Geräteerkennung und Enrollment-Check für UI-Feedback
- `config.rs` — TOML-Config ([appearance] background, gtk-theme, cursor-theme, cursor-size, fingerprint-enabled) + Wallpaper-Fallback + Blur-Validierung (finite, clamp 0200) + Cursor-Size-Validierung (range 1256)
- `greeter.rs` — GTK4 UI (Overlay-Layout), Login-Flow via greetd IPC (Multi-Stage-Auth für fprintd), Faillock-Warnung, Avatar-Cache, Last-User/Last-Session Persistence (0o700 Dirs, 0o600 Files).
- `main.rs` — Entry Point, GTK App, Layer Shell Setup. Ein einziges Greeter-Fenster, verankert am Built-in-Display (via `pick_primary_monitor_index`), `KeyboardMode::OnDemand` — moongreet ist ein normaler layer-shell-client, keine output-scoped policies. Sekundäre Monitore bleiben unter Compositor-Kontrolle. Systemd-journal-logger.
- `resources/style.css` — Catppuccin-inspiriertes Theme
## Design Decisions
- **TOP Layer statt OVERLAY**: Greeter läuft unter greetd, nicht über Waybar
- **GResource-Bundle**: CSS, Wallpaper und Default-Avatar sind in die Binary kompiliert
- **Async Login**: `glib::spawn_future_local` + `gio::spawn_blocking` statt raw Threads
- **Socket-Cancellation**: `Arc<Mutex<Option<UnixStream>>>` + `AtomicBool` für saubere Abbrüche
- **Avatar-Cache**: `HashMap<String, gdk::Texture>` in `Rc<RefCell<GreeterState>>`
- **GPU-Blur via GskBlurNode**: `Snapshot::push_blur()` + `GskRenderer::render_texture()` im `connect_realize` Callback — kein CPU-Blur, kein Disk-Cache, kein `image`-Crate. Blurred Texture wird per `Rc<RefCell<Option<gdk::Texture>>>` über alle Monitore gecacht (1x GPU-Renderpass statt N).
- **Fingerprint via greetd Multi-Stage PAM**: fprintd D-Bus nur als Probe (Gerät/Enrollment), eigentliche Verifizierung läuft über PAM im greetd-Auth-Loop. `auth_message_type: "secret"` → Passwort, alles andere → `None` (PAM entscheidet). 60s Socket-Timeout bei fprintd. Device-Proxy in `GreeterState` gecacht, Generation-Counter gegen Race Conditions bei schnellem User-Switch.
- **Symmetrie mit moonlock/moonset**: Gleiche Patterns (i18n, config, users, power, GResource, GPU-Blur)
- **Session-Validierung**: Relative Pfade erlaubt (greetd löst PATH auf), nur `..`/Null-Bytes werden abgelehnt
- **GTK-Theme-Validierung**: Nur alphanumerisch + `_-+.` erlaubt, verhindert Path-Traversal über Config
- **Cursor-Theme via GtkSettings**: GTK4 unter greetd liest `XCURSOR_THEME` env nicht zuverlässig — Cursor wird via `gtk::Settings::set_gtk_cursor_theme_name()` gesetzt, analog zu `gtk-theme`. Gleiche Validierung (`is_valid_gtk_theme`) gegen Path-Traversal.
- **Journal-Logging**: `systemd-journal-logger` statt File-Logging — `journalctl -t moongreet`, Debug-Level per `MOONGREET_DEBUG` Env-Var
- **File Permissions**: Cache-Verzeichnisse 0o700 via `DirBuilder::mode()`, Cache-Dateien 0o600
- **Testbare Persistence**: `save_*_to`/`load_*_from` Varianten mit konfigurierbarem Pfad für Unit-Tests
- **Shared Wallpaper Texture**: `gdk::Texture` wird einmal in `load_background_texture()` dekodiert und per Ref-Count an alle Fenster geteilt — vermeidet redundante JPEG-Dekodierung pro Monitor
- **Wallpaper-Validierung**: GResource-Zweig via `resources_lookup_data()` + `from_bytes()` (kein Abort bei fehlendem Pfad), Dateigröße-Limit 50 MB, non-UTF-8-Pfade → `None`
- **Error-Detail-Filterung**: GDK/greetd-Fehlerdetails nur auf `debug!`-Level, `warn!` ohne interne Details — verhindert Systeminfo-Leak ins Journal
- **Single Greeter Window, keine Output-Policies**: Ein einziges layer-shell-fenster auf dem Built-in-Display, `KeyboardMode::OnDemand`. Sekundäre Outputs bleiben unter Compositor-Kontrolle. Grund: Die output-scoped policies aus v0.8.0v0.8.5 (Exclusive-Keyboard auf Primary, Wallpaper-Only auf Secondaries, Hotplug-Callbacks) haben den Greeter bei realen Multi-Monitor-Setups wiederholt kaputt gemacht (Pointer kommt nicht zum Primary, Keyboard tabt nicht zur UI). Im User-Session-Niri gibt es diese Probleme nicht — moongreet verhält sich jetzt wie jeder normale layer-shell-client.