From f7e258d4027ec3678a8d32c7499bdf168de6e492 Mon Sep 17 00:00:00 2001 From: nevaforget Date: Wed, 8 Apr 2026 08:48:04 +0200 Subject: [PATCH] feat: show greeter UI on all monitors, not just one (v0.8.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wayland surfaces belong to exactly one output — mirroring is not an option. Create one full greeter window per monitor via set_monitor(), with only the first receiving KeyboardMode::Exclusive. Removes the old wallpaper-only secondary windows. Matches moonlock's per-monitor pattern. --- CLAUDE.md | 2 +- Cargo.toml | 2 +- DECISIONS.md | 7 +++++++ README.md | 2 +- src/greeter.rs | 18 ------------------ src/main.rs | 25 +++++++++++-------------- 6 files changed, 21 insertions(+), 35 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ba81f18..8ddcf52 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,7 +47,7 @@ cd pkg && makepkg -sf && sudo pacman -U moongreet-git--x86_64.pkg.tar.z - `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, fingerprint-enabled) + Wallpaper-Fallback + Blur-Validierung (finite, clamp 0–200) - `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, Multi-Monitor, systemd-journal-logger +- `main.rs` — Entry Point, GTK App, Layer Shell Setup, Multi-Monitor (one greeter window per monitor, first gets keyboard), systemd-journal-logger - `resources/style.css` — Catppuccin-inspiriertes Theme ## Design Decisions diff --git a/Cargo.toml b/Cargo.toml index 6b921b7..50758a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moongreet" -version = "0.7.4" +version = "0.8.0" edition = "2024" description = "A greetd greeter for Wayland with GTK4 and Layer Shell" license = "MIT" diff --git a/DECISIONS.md b/DECISIONS.md index 21298bc..cc05e4b 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1,5 +1,12 @@ # Decisions +## 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 with `set_monitor()`, only the first gets `KeyboardMode::Exclusive`. Removed `create_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 diff --git a/README.md b/README.md index ba6f9b4..4fb9e09 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Part of the Moonarch ecosystem. - **Last user/session** — Remembered in `/var/cache/moongreet/` - **Power actions** — Reboot / Shutdown via `loginctl` - **Layer Shell** — Fullscreen via gtk4-layer-shell (TOP layer) -- **Multi-monitor** — Greeter on primary, wallpaper on all monitors +- **Multi-monitor** — Full greeter UI on all monitors (keyboard input on first) - **GPU blur** — Background blur via GskBlurNode (shared cache across monitors) - **i18n** — German and English (auto-detected from system locale) - **Faillock warning** — Warns after 2 failed attempts, locked message after 3 diff --git a/src/greeter.rs b/src/greeter.rs index ecedc80..fa73b37 100644 --- a/src/greeter.rs +++ b/src/greeter.rs @@ -188,24 +188,6 @@ fn render_blurred_texture( Some(renderer.render_texture(&node, Some(&viewport))) } -/// Create a wallpaper-only window for secondary monitors. -pub fn create_wallpaper_window( - texture: &gdk::Texture, - blur_radius: Option, - blur_cache: &Rc>>, - app: >k::Application, -) -> gtk::ApplicationWindow { - let window = gtk::ApplicationWindow::builder() - .application(app) - .build(); - window.add_css_class("wallpaper"); - - let background = create_background_picture(texture, blur_radius, blur_cache); - window.set_child(Some(&background)); - - window -} - /// Create a Picture widget for the wallpaper background, optionally with GPU blur. /// Uses `blur_cache` to compute the blurred texture only once across all monitors. fn create_background_picture( diff --git a/src/main.rs b/src/main.rs index ba1d6cd..72276a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,30 +63,27 @@ fn activate(app: >k::Application) { let use_layer_shell = std::env::var("MOONGREET_NO_LAYER_SHELL").is_err(); log::debug!("Layer shell: {use_layer_shell}"); - // Main greeter window (login UI) — compositor picks focused monitor - let greeter_window = greeter::create_greeter_window(bg_texture.as_ref(), &config, &blur_cache, app); if use_layer_shell { - setup_layer_shell(&greeter_window, true, gtk4_layer_shell::Layer::Top); - } - greeter_window.present(); - - // Wallpaper-only windows on all monitors (only with layer shell) - if use_layer_shell - && let Some(ref texture) = bg_texture - { + // One greeter window per monitor — only the first gets keyboard input let monitors = display.monitors(); log::debug!("Monitor count: {}", monitors.n_items()); + let mut first = true; for i in 0..monitors.n_items() { if let Some(monitor) = monitors .item(i) .and_then(|obj| obj.downcast::().ok()) { - let wallpaper = greeter::create_wallpaper_window(texture, config.background_blur, &blur_cache, app); - setup_layer_shell(&wallpaper, false, gtk4_layer_shell::Layer::Bottom); - wallpaper.set_monitor(Some(&monitor)); - wallpaper.present(); + let window = greeter::create_greeter_window(bg_texture.as_ref(), &config, &blur_cache, app); + setup_layer_shell(&window, first, gtk4_layer_shell::Layer::Top); + window.set_monitor(Some(&monitor)); + window.present(); + first = false; } } + } else { + // No layer shell — single window for development + let greeter_window = greeter::create_greeter_window(bg_texture.as_ref(), &config, &blur_cache, app); + greeter_window.present(); } }