greetd-moongreet/CLAUDE.md
nevaforget 29ce185886
All checks were successful
Update PKGBUILD version / update-pkgver (push) Successful in 2s
feat: apply cursor theme via GtkSettings instead of XCURSOR_THEME env (v0.9.0)
GTK4 under greetd does not honour XCURSOR_THEME reliably — the env-prefix
hack in /etc/greetd/config.toml only reached the wlroots pointer in cage,
while GTK widgets kept using the default fallback cursor. Mirror the
existing gtk-theme handling: new cursor-theme + cursor-size fields in the
[appearance] section, applied via gtk::Settings::set_gtk_cursor_theme_*.
Keeps the fix scoped to the greeter, no system-wide GTK config changes.
2026-04-24 08:56:41 +02:00

5.4 KiB
Raw Blame History

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

# 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). Zweite Funktion create_wallpaper_window() für Sekundär-Monitore (Background only, keine Widgets)
  • main.rs — Entry Point, GTK App, Layer Shell Setup, Multi-Monitor mit Hotplug via items-changed auf Monitor-ListModel. Built-in display (via pick_primary_monitor_index) zeigt das Login-Widget mit KeyboardMode::Exclusive, alle anderen Monitore (inkl. Hotplug) zeigen nur Wallpaper mit KeyboardMode::None. 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 UI, Wallpaper auf Sekundären: Login-Widget nur auf dem Built-in-Panel, andere Monitore bekommen create_wallpaper_window() mit KeyboardMode::None. Grund: Niri (und andere Compositor) scopen Layer-Shell Keyboard-Routing per Output — ein einziges Exclusive-Surface auf dem "falschen" Output verhindert nicht, dass Keys woanders versanden. Compositor-agnostisch, kein Niri-IPC.