From 11965a338bf633f12ae063a57fb1676695d7d6ad Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 21 Apr 2026 09:36:49 +0100 Subject: [PATCH] fix(preview): set GTK WindowTypeHint::Utility for non-KDE compositor coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KWin reads _NET_WM_STATE_SKIP_TASKBAR for its Alt+Tab list, which OW-2 already wired via skip_taskbar(true) on the builder. On Hyprland, Sway, and GNOME Mutter that's not always enough — some switchers still enumerate the overlay. Classifying the window as gdk::WindowTypeHint::Utility signals to the compositor that this is an assistive auxiliary surface, so switchers and auto-tilers leave it alone. No behavioural change on KWin. GTK3 only honours the type hint before the window maps, so the preview builder now starts .visible(false); we grab the gtk_window() via Tauri's escape hatch, set the hint, then show(). The existing hide/show on re-open still works — hint is a property of the gtk::ApplicationWindow and survives the cycle. Added gtk = "0.18" and gdk = "0.18" as Linux-only deps. Both are already pulled in transitively via webkit2gtk 2.0, so this is just surfacing them by name — no new compile cost. Co-Authored-By: Claude Opus 4.7 (1M context) --- src-tauri/Cargo.toml | 5 +++++ src-tauri/src/commands/windows.rs | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 41e3a1b..ed4be82 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -46,3 +46,8 @@ uuid = { version = "1", features = ["v4"] } [target.'cfg(target_os = "linux")'.dependencies] webkit2gtk = "2.0" +# Needed for setting the preview overlay's WindowTypeHint to Utility via +# the Tauri gtk_window() escape hatch. Versions track what webkit2gtk 2.0 +# transitively depends on (GTK 3). +gtk = "0.18" +gdk = "0.18" diff --git a/src-tauri/src/commands/windows.rs b/src-tauri/src/commands/windows.rs index 5c2cc36..4f4abca 100644 --- a/src-tauri/src/commands/windows.rs +++ b/src-tauri/src/commands/windows.rs @@ -66,6 +66,9 @@ pub async fn open_preview_window(app: tauri::AppHandle) -> Result<(), String> { // visible_on_all_workspaces sets _NET_WM_STATE_STICKY via GTK on X11 // / XWayland so the overlay is pinned. Matches the ergonomic OpenWhispr // PR #183 shipped for KDE Plasma Wayland. + // + // Built hidden so we can set the Linux WindowTypeHint before the + // window maps — GTK3 only honours the hint pre-realize. let mut builder = WebviewWindowBuilder::new( &app, "transcription-preview", @@ -79,6 +82,7 @@ pub async fn open_preview_window(app: tauri::AppHandle) -> Result<(), String> { .skip_taskbar(true) .visible_on_all_workspaces(true) .focused(false) + .visible(false) .decorations(use_native_decorations) .resizable(true); @@ -88,7 +92,24 @@ pub async fn open_preview_window(app: tauri::AppHandle) -> Result<(), String> { } } - builder.build().map_err(|e| e.to_string())?; + let window = builder.build().map_err(|e| e.to_string())?; + + // Defence-in-depth for non-KDE compositors (Hyprland, Sway, GNOME + // Mutter) where SKIP_TASKBAR alone may not hide a window from the + // alt-tab switcher. Classifying as Utility signals to the compositor + // that this is an assistive auxiliary window — switchers and tilers + // treat it accordingly. Noop on KWin (already handled by skip_taskbar) + // but harmless. Must happen before show() per GTK3 docs. + #[cfg(target_os = "linux")] + { + use gdk::WindowTypeHint; + use gtk::prelude::GtkWindowExt; + if let Ok(gtk_window) = window.gtk_window() { + gtk_window.set_type_hint(WindowTypeHint::Utility); + } + } + + window.show().map_err(|e| e.to_string())?; Ok(()) }