fix: wallpaper-only windows on secondary monitors (v0.8.5)
All checks were successful
Update PKGBUILD version / update-pkgver (push) Successful in 3s
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.
This commit is contained in:
parent
97165d94f8
commit
91b4289748
@ -44,8 +44,8 @@ cd pkg && makepkg -sf && sudo pacman -U moongreet-git-<version>-x86_64.pkg.tar.z
|
|||||||
- `i18n.rs` — Locale-Erkennung (LANG / /etc/locale.conf) und String-Tabellen (DE/EN), alle UI- und Login-Fehlermeldungen
|
- `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
|
- `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)
|
- `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)
|
- `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 (one greeter window per monitor; keyboard goes to the built-in display via `pick_primary_monitor_index`, falls back to first), systemd-journal-logger
|
- `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
|
- `resources/style.css` — Catppuccin-inspiriertes Theme
|
||||||
|
|
||||||
## Design Decisions
|
## Design Decisions
|
||||||
@ -66,3 +66,4 @@ cd pkg && makepkg -sf && sudo pacman -U moongreet-git-<version>-x86_64.pkg.tar.z
|
|||||||
- **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
|
- **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`
|
- **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
|
- **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.
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -575,7 +575,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moongreet"
|
name = "moongreet"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "moongreet"
|
name = "moongreet"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A greetd greeter for Wayland with GTK4 and Layer Shell"
|
description = "A greetd greeter for Wayland with GTK4 and Layer Shell"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
# Decisions
|
# 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::Exclusive` surface, 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()` in `greeter.rs` builds a minimal `ApplicationWindow` with the shared background `Picture` (same `blur_cache` as the primary) and no login widgets. `main.rs` uses `create_greeter_window()` for the index returned by `pick_primary_monitor_index()` and `create_wallpaper_window()` for the rest. Hotplugged monitors also get wallpaper-only windows. Both variants use `Layer::Top`; only the primary sets `KeyboardMode::Exclusive`.
|
||||||
|
|
||||||
## 2026-04-23 – Keyboard focus on built-in display, not first enumerated monitor (v0.8.4)
|
## 2026-04-23 – Keyboard focus on built-in display, not first enumerated monitor (v0.8.4)
|
||||||
|
|
||||||
- **Who**: ClaudeCode, Dom
|
- **Who**: ClaudeCode, Dom
|
||||||
|
|||||||
@ -12,7 +12,7 @@ Part of the Moonarch ecosystem.
|
|||||||
- **Last user/session** — Remembered in `/var/cache/moongreet/`
|
- **Last user/session** — Remembered in `/var/cache/moongreet/`
|
||||||
- **Power actions** — Reboot / Shutdown via `loginctl`
|
- **Power actions** — Reboot / Shutdown via `loginctl`
|
||||||
- **Layer Shell** — Fullscreen via gtk4-layer-shell (TOP layer)
|
- **Layer Shell** — Fullscreen via gtk4-layer-shell (TOP layer)
|
||||||
- **Multi-monitor + hotplug** — Full greeter UI on all monitors (keyboard input on first), hotplugged monitors get windows automatically
|
- **Multi-monitor + hotplug** — Login UI on the built-in display, wallpaper-only on other monitors; hotplugged monitors get wallpaper windows automatically
|
||||||
- **GPU blur** — Background blur via GskBlurNode (shared cache across monitors)
|
- **GPU blur** — Background blur via GskBlurNode (shared cache across monitors)
|
||||||
- **i18n** — German and English (auto-detected from system locale)
|
- **i18n** — German and English (auto-detected from system locale)
|
||||||
- **Faillock warning** — Warns after 2 failed attempts, locked message after 3
|
- **Faillock warning** — Warns after 2 failed attempts, locked message after 3
|
||||||
|
|||||||
@ -219,6 +219,31 @@ fn create_background_picture(
|
|||||||
background
|
background
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a wallpaper-only window for secondary monitors.
|
||||||
|
///
|
||||||
|
/// Shows the same background (and shared blurred texture via `blur_cache`) as
|
||||||
|
/// the primary greeter window, but carries no login widgets. Paired with
|
||||||
|
/// `KeyboardMode::None` at the layer-shell level so the compositor never
|
||||||
|
/// routes input here — preventing focus from landing on a secondary output.
|
||||||
|
pub fn create_wallpaper_window(
|
||||||
|
texture: Option<&gdk::Texture>,
|
||||||
|
config: &Config,
|
||||||
|
blur_cache: &Rc<RefCell<Option<gdk::Texture>>>,
|
||||||
|
app: >k::Application,
|
||||||
|
) -> gtk::ApplicationWindow {
|
||||||
|
let window = gtk::ApplicationWindow::builder()
|
||||||
|
.application(app)
|
||||||
|
.build();
|
||||||
|
window.add_css_class("greeter");
|
||||||
|
window.set_default_size(1920, 1080);
|
||||||
|
|
||||||
|
if let Some(texture) = texture {
|
||||||
|
window.set_child(Some(&create_background_picture(texture, config.background_blur, blur_cache)));
|
||||||
|
}
|
||||||
|
|
||||||
|
window
|
||||||
|
}
|
||||||
|
|
||||||
/// Shared mutable state for the greeter UI.
|
/// Shared mutable state for the greeter UI.
|
||||||
struct GreeterState {
|
struct GreeterState {
|
||||||
selected_user: Option<User>,
|
selected_user: Option<User>,
|
||||||
|
|||||||
17
src/main.rs
17
src/main.rs
@ -113,15 +113,20 @@ fn activate(app: >k::Application) {
|
|||||||
.item(i)
|
.item(i)
|
||||||
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
||||||
{
|
{
|
||||||
let window = greeter::create_greeter_window(bg_texture.as_ref(), &config, &blur_cache, app);
|
let is_primary = i as usize == primary_idx;
|
||||||
setup_layer_shell(&window, i as usize == primary_idx, gtk4_layer_shell::Layer::Top);
|
let window = if is_primary {
|
||||||
|
greeter::create_greeter_window(bg_texture.as_ref(), &config, &blur_cache, app)
|
||||||
|
} else {
|
||||||
|
greeter::create_wallpaper_window(bg_texture.as_ref(), &config, &blur_cache, app)
|
||||||
|
};
|
||||||
|
setup_layer_shell(&window, is_primary, gtk4_layer_shell::Layer::Top);
|
||||||
window.set_monitor(Some(&monitor));
|
window.set_monitor(Some(&monitor));
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle monitor hotplug — create greeter windows for newly added monitors
|
// Handle monitor hotplug — hotplugged monitors get wallpaper-only
|
||||||
// (without keyboard, since the primary monitor already has it)
|
// windows so keyboard focus never migrates off the primary.
|
||||||
let bg_texture = Rc::new(bg_texture);
|
let bg_texture = Rc::new(bg_texture);
|
||||||
let config = Rc::new(config);
|
let config = Rc::new(config);
|
||||||
monitors.connect_items_changed(clone!(
|
monitors.connect_items_changed(clone!(
|
||||||
@ -135,8 +140,8 @@ fn activate(app: >k::Application) {
|
|||||||
.item(i)
|
.item(i)
|
||||||
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
||||||
{
|
{
|
||||||
log::debug!("Monitor hotplug: creating greeter window");
|
log::debug!("Monitor hotplug: creating wallpaper window");
|
||||||
let window = greeter::create_greeter_window(
|
let window = greeter::create_wallpaper_window(
|
||||||
bg_texture.as_ref().as_ref(), &config, &blur_cache, &app,
|
bg_texture.as_ref().as_ref(), &config, &blur_cache, &app,
|
||||||
);
|
);
|
||||||
setup_layer_shell(&window, false, gtk4_layer_shell::Layer::Top);
|
setup_layer_shell(&window, false, gtk4_layer_shell::Layer::Top);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user