All checks were successful
Update PKGBUILD version / update-pkgver (push) Successful in 3s
The v0.8.4 keyboard fix only half-worked: keys were still dropped until the pointer moved to the built-in panel. Niri scopes layer-shell keyboard routing per active output, so a single Exclusive surface is not enough when another output is active. Revert 2026-04-08 partially: only the built-in panel shows the login widget, other monitors get a wallpaper-only window with KeyboardMode::None. Hotplugged monitors also get wallpaper-only. Compositor-agnostic — no Niri IPC.
13 KiB
13 KiB
Decisions
2026-04-23 – Wallpaper-only windows on secondary monitors (v0.8.5)
- Who: ClaudeCode, Dom
- Why: The v0.8.4 fix (keyboard grab on the built-in panel) only half-worked. The greeter still rejected keystrokes until the user moved the mouse to eDP-1 — Niri scopes layer-shell keyboard routing by active output, so even though the primary window was the sole
KeyboardMode::Exclusivesurface, keys went nowhere when another output was active. Hardcoding a compositor focus call (e.g.niri msg action focus-monitor) would tie moongreet to a specific compositor. - Tradeoffs: Reverts part of 2026-04-08: only the built-in panel shows the full greeter UI, other monitors go back to wallpaper-only. Users with multiple monitors lose the symmetric "login widget on every screen" look, but gain a reliable keyboard path regardless of which output the compositor considers active at startup. Compositor-agnostic — no Niri-specific IPC.
- How: New
create_wallpaper_window()ingreeter.rsbuilds a minimalApplicationWindowwith the shared backgroundPicture(sameblur_cacheas the primary) and no login widgets.main.rsusescreate_greeter_window()for the index returned bypick_primary_monitor_index()andcreate_wallpaper_window()for the rest. Hotplugged monitors also get wallpaper-only windows. Both variants useLayer::Top; only the primary setsKeyboardMode::Exclusive.
2026-04-23 – Keyboard focus on built-in display, not first enumerated monitor (v0.8.4)
- Who: ClaudeCode, Dom
- Why: With a DisplayLink dock attached, the greeter showed its UI on all monitors but the password entry accepted no input.
display.monitors()enumerated evdi phantom connectors (DVI-I-*) before the laptop panel (eDP-1); the v0.8.0 logic gaveKeyboardMode::Exclusiveto index 0, so the keyboard grab landed on an invisible surface. Symptom showed up on 2026-04-23 after kernel 6.19.11 → 6.19.12 + moongreet 0.8.0 → 0.8.2 changed evdi enumeration timing — previous Thursdays with the same dock worked. - Tradeoffs: Prefers built-in displays by connector-name pattern (
eDP*/LVDS*/DSI*) rather than a generic "primary monitor" concept — Wayland has no portable primary signal, and gdk4'sprimary_monitor()was removed. Pattern-matching covers every current Linux laptop, at the cost of a tiny list to maintain if a new form factor ships a new connector type. Fallback is still index 0, so behavior on desktops without a built-in panel is unchanged. - How: New pure function
pick_primary_monitor_index()inmain.rsscans connector names and returns the built-in index (or 0). Used during initial enumeration to decide which window getsKeyboardMode::Exclusive. Hotplug branch unchanged — new monitors still get keyboard=false so focus never migrates off the panel. Unit-tested against evdi/eDP/LVDS/DSI/HDMI/DP mixes.
2026-04-21 – Ship polkit rule in moongreet instead of moonarch (v0.8.3)
- Who: ClaudeCode, Dom
- Why: Reboot/shutdown from the greeter silently failed on a fresh install. The polkit rule that grants the
greeteruserorg.freedesktop.login1.{reboot,power-off}lived in the moonarch repo but was never installed by any PKGBUILD. The laptop worked only because the rule had been hand-deployed once. - Tradeoffs: Rule ownership moves from moonarch (system defaults) to moongreet (greeter-specific auth). Cleaner boundary — moonarch no longer needs to know about the greeter's auth requirements — but it means moongreet is now responsible for a system polkit rule that ties it to a fixed username (
greeter). - How: Source file moved to
moongreet/config/polkit/50-moongreet-power.rules, installed to/etc/polkit-1/rules.d/bymoongreet-git/PKGBUILD. Old file removed from the moonarch repo.
2026-04-09 – Monitor hotplug via ListModel items-changed
- Who: ClaudeCode, Dom
- Why: Greeter windows were only created at startup. If a monitor was hotplugged (e.g. HDMI reconnect), it would show no greeter UI. Aligned with moonlock's hotplug fix (same day).
- Tradeoffs: Hotplugged monitors get greeter windows without keyboard input (keyboard stays on the primary monitor). Acceptable — user can still interact on the primary screen.
- How: Connect to
display.monitors().connect_items_changed()and create new greeter windows for added monitors. Shared state (config, texture, blur_cache) moved to Rc for the closure.
2026-04-08 – Show greeter UI on all monitors instead of just one
- Who: ClaudeCode, Dom
- Why: moonlock showed its UI on all monitors via ext-session-lock-v1, but moongreet only showed the login UI on one monitor (compositor-picked) with wallpaper-only windows on the rest. Inconsistent UX across the ecosystem.
- Tradeoffs: Each monitor gets its own full greeter widget tree (slightly more memory), but the UI is lightweight. Screen mirroring (e.g., wl-mirror/screencopy) was considered and rejected — it requires an external process, compositor screencopy support, adds latency, and fights Wayland's per-output model. One-window-per-monitor is the established Wayland pattern (swaylock, hyprlock, moonlock all do this).
- How: Create one
create_greeter_window()per monitor withset_monitor(), only the first getsKeyboardMode::Exclusive. Removedcreate_wallpaper_window()(no longer needed). No layer shell fallback keeps single-window mode for development.
2026-04-06 – Restore explicit gtk-theme in moongreet config
- Who: ClaudeCode, Dom
- Why: GTK4 under greetd does not reliably read
/etc/xdg/gtk-4.0/settings.ini— likely requires a settings daemon that doesn't run in the greeter session. moongreet fell back to Adwaita/Colloid-default (blue accent) instead of Colloid-Grey-Dark-Catppuccin. - Tradeoffs: Reverts
094878f("Remove gtk-theme from app config, use system-wide GTK settings instead"). Duplicates the theme name between settings.ini and moongreet.toml, but the explicit set viaset_gtk_theme_name()is the only reliable path in a greetd context. - How: Added
gtk-theme = "Colloid-Grey-Dark-Catppuccin"to example config and deployed/etc/moongreet/moongreet.toml.
2026-04-02 – Replace hardcoded CSS colors with GTK theme variables
- Who: ClaudeCode, Dom
- Why: moongreet used hardcoded colors (#1a1a2e, white, #ff6b6b) while moonset already used @theme_bg_color, @theme_fg_color, @error_color etc. Inconsistent across the ecosystem and broke theme flexibility.
- Tradeoffs: Depends on the active GTK theme defining standard color variables. Catppuccin Colloid provides all needed vars (@theme_bg_color, @theme_fg_color, @error_color, @success_color, @theme_selected_bg_color). Fallback behavior if a theme lacks vars is GTK's default colors — acceptable.
- How: Replaced all hardcoded hex/named colors with GTK theme variables. Coordinated change across moongreet, moonlock, and moonset (all three now use identical pattern).
2026-03-31 – Fourth audit: power timeout, timing mitigation, release profile, GREETD_SOCK caching
- Who: ClaudeCode, Dom
- Why: Fourth triple audit found moongreet power.rs had no timeout on loginctl (greeter could freeze), username enumeration via timing differential, GREETD_SOCK re-read on every login, missing release profile, and missing GResource compression.
- Tradeoffs: 500ms minimum login response time adds slight delay on fast auth but prevents timing-based username enumeration. Power timeout (30s + SIGKILL) matches moonset pattern — aggressive but prevents greeter freeze.
- How: (1) power.rs adapted from moonset with 30s timeout + SIGKILL (nix dependency added). (2) 500ms min response floor in attempt_login via Instant + glib::timeout_future. (3) GREETD_SOCK cached in GreeterState at startup. (4)
[profile.release]with LTO, codegen-units=1, strip. (5)compressed="true"on GResource entries. (6) SYNC comments on duplicated blur/background functions.
2026-03-30 – Full audit fix: security, quality, performance (v0.6.2)
- Who: ClaudeCode, Dom
- Why: Three parallel audits (security, code quality, performance) identified 10 actionable findings across the codebase — from world-readable cache dirs to a GPU blur geometry bug to a race condition in fingerprint probing.
- Tradeoffs:
too_many_argumentsClippy warnings suppressed with#[allow]rather than introducing aUiWidgetsstruct — GTK'sclone!macro with#[weak]refs requires individual widget parameters, a struct would fight the idiom. Async avatar loading skipped becausePixbufis!Send; cache already prevents repeat loads. TOCTOU socket pre-check removed entirely —connect()in login_worker already handles errors, themetadata()check gave false security guarantees. - How: Cache dirs use
DirBuilder::mode(0o700)instead ofcreate_dir_all. Blur config clamped to0.0..=200.0withis_finite()guard. Blur texture cached inRc<RefCell<Option<gdk::Texture>>>across monitors. FingerprintProbe device proxy cached inGreeterStatewith generation counter to prevent stale async writes. GPU blur geometry fixed (-padorigin shift instead of texture stretching).is_valid_gtk_themeextracted as testable function. 9 new tests.
2026-03-29 – Fingerprint authentication via greetd multi-stage PAM
- Who: ClaudeCode, Dom
- Why: moonlock supports fprintd but moongreet rejected multi-stage auth. Users with enrolled fingerprints couldn't use them at the login screen.
- Tradeoffs: Direct fprintd D-Bus verification (like moonlock) can't start a greetd session — greetd controls session creation via PAM. Using greetd multi-stage means PAM decides the auth order (fingerprint first, then password fallback), not truly parallel. Acceptable — matches standard pam_fprintd behavior.
- How: Replace single-pass auth with a loop over auth_message rounds. Secret prompts get the password, non-secret prompts (fprintd) get None and block until PAM resolves. fprintd D-Bus probe (gio::DBusProxy) only for UI — detecting device availability and enrolled fingers. 60s socket timeout when fingerprint available. Config option
fingerprint-enabled(default true).
2026-03-28 – Remove embedded wallpaper from binary
- Who: ClaudeCode, Dom
- Why: Wallpaper is installed by moonarch to /usr/share/moonarch/wallpaper.jpg. Embedding a 374K JPEG in the binary is redundant. GTK background color (Catppuccin Mocha base) is a clean fallback.
- Tradeoffs: Without moonarch installed AND without config, greeter shows plain dark background instead of wallpaper. Acceptable — that's the expected minimal state.
- How: Remove wallpaper.jpg from GResources, return None from resolve_background_path when no file found, skip wallpaper window creation and background picture when no path available.
2026-03-28 – GPU blur via GskBlurNode replaces CPU blur
- Who: ClaudeCode, Dom
- Why: CPU-side Gaussian blur (
imagecrate) blocked the GTK main thread for 500ms–2s on 4K wallpapers at cold cache. Disk cache and async orchestration added significant complexity. - Tradeoffs: GPU blur quality is slightly different (box-blur approximation vs true Gaussian), acceptable for wallpaper backgrounds. Removes
imagecrate dependency entirely (~15 transitive crates eliminated). No disk cache needed. - How:
Snapshot::push_blur()+GskRenderer::render_texture()onconnect_realize. Blur happens once on the GPU when the widget gets its renderer, producing a concretegdk::Texture. Zero startup latency. Symmetric with moonlock and moonset.
2026-03-28 – Optional background blur via image crate (superseded)
- Who: ClaudeCode, Dom
- Why: Blurred wallpaper as greeter background is a common UX pattern for login screens
- Tradeoffs: Adds
imagecrate dependency (~15 transitive crates); CPU-side Gaussian blur at load time adds startup latency proportional to image size and sigma. Acceptable because blur runs once and the texture is shared across monitors. - How:
load_background_texture(bg_path, blur_radius)loads texture, optionally appliesimageops::blur(), returns blurredgdk::Texture. Config optionbackground-blur: Option<f32>in[appearance]TOML section.
2026-03-28 – Audit fixes for shared wallpaper texture (v0.4.1)
- Who: ClaudeCode, Dominik
- Why: Quality, performance, and security audits flagged issues in
load_background_texture(), debug logging, and greetd error handling - Tradeoffs: GResource path now requires UTF-8 (returns
Nonefor non-UTF-8 instead of aborting); 50 MB wallpaper limit is generous but prevents OOM; debug logging off by default trades observability for security - How: GResource branch via
resources_lookup_data()+from_bytes()(no abort), file size limit, error details only at debug level,MOONGREET_DEBUGenv var for log level, greetd retry path truncation matchingshow_greetd_error()