From 334042ad9c87cd65e49a8d18e303f7b8d1691c9f Mon Sep 17 00:00:00 2001 From: yuanchenglu Date: Mon, 13 Jul 2026 00:22:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(linux):=20prevent=20startup=20panic=20f?= =?UTF-8?q?rom=20unrealized=20capsule=20GDK=20window=20|=20fix(linux):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=83=B6=E5=9B=8A=E7=AA=97=E5=8F=A3=E5=9B=A0?= =?UTF-8?q?=20GDK=20=E6=9C=AA=E5=AE=9E=E4=BE=8B=E5=8C=96=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E5=90=AF=E5=8A=A8=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Linux X11, when the capsule window is created with `visible: false` + `transparent: true` in tauri.conf.json, its underlying GDK window is never realized. The subsequent call to `capsule.set_ignore_cursor_events(true)` triggers a panic inside tao's Linux event loop (event_loop.rs:457) because `window.window().unwrap()` returns `None` for an unrealized GDK window. The fix follows the same approach as voicebox PR#837 (PhamBit): force GDK window realization before calling set_ignore_cursor_events, by first moving the window off-screen and calling show(). The window is then repositioned correctly by the existing position_capsule_bottom_center() call and hidden as normal. Refs: - https://github.com/jamiepine/voicebox/pull/837 - https://github.com/tauri-apps/tao/issues/635 在 Linux X11 上,tauri.conf.json 中定义的 capsule 窗口设置了 visible: false + transparent: true,导致其底层 GDK 窗口从未被实例化。 随后调用 capsule.set_ignore_cursor_events(true) 时,tao 的 Linux 事件循环 (event_loop.rs:457) 因 window.window().unwrap() 返回 None 而 panic 崩溃。 修复方法参考 voicebox PR#837:在设置鼠标穿透前先将窗口移出屏幕并 调用 show() 强制 GDK 实例化,后续由原有的 position_capsule_bottom_center() 重新定位并隐藏。 --- openless-all/app/src-tauri/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openless-all/app/src-tauri/src/lib.rs b/openless-all/app/src-tauri/src/lib.rs index 252e2aeb..79d5671c 100644 --- a/openless-all/app/src-tauri/src/lib.rs +++ b/openless-all/app/src-tauri/src/lib.rs @@ -520,6 +520,18 @@ fn run_desktop() { } // 纯光效舞台没有任何可点元素(✕/✓ 按钮已移除),而窗口放大到 460×180 // 盖住屏幕底部中央 —— 必须鼠标穿透,否则会挡住底下应用的点击。 + // + // Linux (X11) 兼容:tao 在调用 set_ignore_cursor_events 时要求 GDK + // 窗口已实例化(window.window() 返回 Some),但 Capsule 在 + // tauri.conf.json 中定义 visible=false → GDK 窗口从未 real ize → + // tao event_loop.rs:457 unwrap() 崩溃。 + // 解决办法:先移到屏幕外,show() 强制 GDK 实例化,然后再设穿透。 + // 参考 voicebox PR#837: https://github.com/jamiepine/voicebox/pull/837 + #[cfg(target_os = "linux")] + { + let _ = capsule.set_position(tauri::LogicalPosition::new(-10000.0, -10000.0)); + let _ = capsule.show(); + } if let Err(e) = capsule.set_ignore_cursor_events(true) { log::warn!("[capsule] set_ignore_cursor_events failed: {e}"); } From 641da39ceb80794d97fc4b2fb0670e0037e2adeb Mon Sep 17 00:00:00 2001 From: Chris233 Date: Mon, 13 Jul 2026 14:31:03 +0800 Subject: [PATCH 2/2] fix(linux): realize hidden capsule without showing it --- openless-all/app/src-tauri/Cargo.lock | 1 + openless-all/app/src-tauri/Cargo.toml | 1 + openless-all/app/src-tauri/src/lib.rs | 36 +++++++++++++++++---------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/openless-all/app/src-tauri/Cargo.lock b/openless-all/app/src-tauri/Cargo.lock index e621b2ec..7b070452 100644 --- a/openless-all/app/src-tauri/Cargo.lock +++ b/openless-all/app/src-tauri/Cargo.lock @@ -3909,6 +3909,7 @@ dependencies = [ "futures-util", "getrandom 0.3.4", "global-hotkey", + "gtk", "hmac", "hyper", "hyper-util", diff --git a/openless-all/app/src-tauri/Cargo.toml b/openless-all/app/src-tauri/Cargo.toml index ae493403..65f84f07 100644 --- a/openless-all/app/src-tauri/Cargo.toml +++ b/openless-all/app/src-tauri/Cargo.toml @@ -90,6 +90,7 @@ features = ["windows-native"] [target.'cfg(target_os = "linux")'.dependencies] dbus = "0.9" +gtk = "0.18" [target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))'.dependencies.keyring] version = "3.6.3" default-features = false diff --git a/openless-all/app/src-tauri/src/lib.rs b/openless-all/app/src-tauri/src/lib.rs index 79d5671c..e47f8cea 100644 --- a/openless-all/app/src-tauri/src/lib.rs +++ b/openless-all/app/src-tauri/src/lib.rs @@ -95,6 +95,9 @@ use std::sync::mpsc; use std::sync::Arc; use std::time::Duration; +#[cfg(target_os = "linux")] +use gtk::prelude::WidgetExt; + const LOG_ROTATE_LIMIT_BYTES: u64 = 10 * 1024 * 1024; #[cfg(target_os = "macos")] const OPENLESS_BUNDLE_ID: &str = "com.openless.app"; @@ -520,20 +523,27 @@ fn run_desktop() { } // 纯光效舞台没有任何可点元素(✕/✓ 按钮已移除),而窗口放大到 460×180 // 盖住屏幕底部中央 —— 必须鼠标穿透,否则会挡住底下应用的点击。 - // - // Linux (X11) 兼容:tao 在调用 set_ignore_cursor_events 时要求 GDK - // 窗口已实例化(window.window() 返回 Some),但 Capsule 在 - // tauri.conf.json 中定义 visible=false → GDK 窗口从未 real ize → - // tao event_loop.rs:457 unwrap() 崩溃。 - // 解决办法:先移到屏幕外,show() 强制 GDK 实例化,然后再设穿透。 - // 参考 voicebox PR#837: https://github.com/jamiepine/voicebox/pull/837 + // Linux 下 tao 的鼠标穿透实现会直接解包底层 GDK 窗口;visible=false 时 + // 窗口尚未 realize。这里只创建窗口系统资源而不 map,避免 X11 崩溃, + // 也不会像 show() 那样在不支持窗口定位的 Wayland 上造成启动闪窗。 #[cfg(target_os = "linux")] - { - let _ = capsule.set_position(tauri::LogicalPosition::new(-10000.0, -10000.0)); - let _ = capsule.show(); - } - if let Err(e) = capsule.set_ignore_cursor_events(true) { - log::warn!("[capsule] set_ignore_cursor_events failed: {e}"); + let cursor_passthrough_ready = match capsule.gtk_window() { + Ok(gtk_window) => { + gtk_window.realize(); + true + } + Err(e) => { + log::warn!("[capsule] gtk_window failed; skipping cursor passthrough: {e}"); + false + } + }; + #[cfg(not(target_os = "linux"))] + let cursor_passthrough_ready = true; + + if cursor_passthrough_ready { + if let Err(e) = capsule.set_ignore_cursor_events(true) { + log::warn!("[capsule] set_ignore_cursor_events failed: {e}"); + } } if let Err(e) = position_capsule_bottom_center(&capsule, false) { log::warn!("[capsule] position failed: {e}");