Popup-Blur-Guard ohne Timer: Sperre fällt mit dem ersten Focused(true)

Bisher löste ein Thread die Sperre nach 350 ms (geraten gegen das
spuriose Focused(false), das KDE direkt nach show/set_focus feuert).
Jetzt steht die Sperre ab dem Anzeigen und fällt deterministisch mit
dem ersten echten Fokus-Event des Popups.
This commit is contained in:
marcus hinz
2026-07-17 00:17:17 +02:00
parent 3fe911040d
commit be1e4aad3f
+15 -17
View File
@@ -9,8 +9,9 @@ use crate::domain::watcher::spawn_session_watcher;
use crate::platform::Anchor;
use crate::{commands, terminal};
/// Sperrt das Auto-Hide des Popups bei Fokusverlust für einen Moment nach dem
/// Anzeigen (KDE-Erststart-Race). Als Tauri-State geführt.
/// Sperrt das Auto-Hide des Popups bei Fokusverlust nach dem Anzeigen, bis das
/// Popup einmal Focused(true) gemeldet hat (KDE feuert nach show/set_focus ein
/// spurioses Focused(false)). Als Tauri-State geführt.
#[cfg(target_os = "linux")]
pub(crate) struct PopupBlurGuard(pub(crate) std::sync::Arc<std::sync::atomic::AtomicBool>);
@@ -65,6 +66,7 @@ pub(crate) fn show_popup(app: &tauri::AppHandle, anchor: Anchor) {
Anchor::Cursor => {
#[cfg(target_os = "linux")]
{
// Gelöst wird die Sperre vom ersten Focused(true) im Event-Handler.
if let Some(g) = win.try_state::<PopupBlurGuard>() {
g.0.store(true, std::sync::atomic::Ordering::SeqCst);
}
@@ -74,15 +76,6 @@ pub(crate) fn show_popup(app: &tauri::AppHandle, anchor: Anchor) {
let _ = w.center();
}
}
// Guard nach kurzer Zeit lösen — danach schließt Fokusverlust wieder
// normal.
let g2 = win.clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_millis(350));
if let Some(g) = g2.try_state::<PopupBlurGuard>() {
g.0.store(false, std::sync::atomic::Ordering::SeqCst);
}
});
}
}
// GNOME-Extension/KWin: der Compositor positioniert selbst.
@@ -197,21 +190,26 @@ pub(crate) fn main_builder() -> tauri::Builder<tauri::Wry> {
window.hide().unwrap();
}
// Popup schließt bei Fokusverlust.
if let tauri::WindowEvent::Focused(false) = event {
if let tauri::WindowEvent::Focused(focused) = event {
if window.label() == "popup" {
// KDE feuert direkt nach show/set_focus ein Focused(false) — ohne
// diese kurze Sperre verschwände das Popup sofort wieder (erst der
// zweite Klick hielte). GNOME/macOS setzen die Sperre nie.
// KDE feuert direkt nach show/set_focus ein spurioses Focused(false),
// vor dem echten Fokus. Die Sperre steht ab dem Anzeigen und fällt mit
// dem ersten Focused(true) — das spuriose Blur läuft ins Leere.
// GNOME/macOS setzen die Sperre nie.
#[cfg(target_os = "linux")]
{
use tauri::Manager;
if let Some(g) = window.try_state::<PopupBlurGuard>() {
if g.0.load(std::sync::atomic::Ordering::SeqCst) {
if *focused {
g.0.store(false, std::sync::atomic::Ordering::SeqCst);
} else if g.0.load(std::sync::atomic::Ordering::SeqCst) {
return;
}
}
}
let _ = window.hide();
if !focused {
let _ = window.hide();
}
}
}
})