From 40b8c0ce13164a353b3d4c372cacc94df9d81993 Mon Sep 17 00:00:00 2001 From: H-Chris233 Date: Fri, 29 May 2026 10:59:58 +0800 Subject: [PATCH 1/2] fix(macos): show capsule across Spaces --- .github/workflows/ci.yml | 3 ++ openless-all/app/package.json | 1 + .../macos-capsule-spaces-contract.test.mjs | 31 +++++++++++++++++++ openless-all/app/src-tauri/src/coordinator.rs | 7 ++++- 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 788d6f91..bf38b54f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,6 +85,9 @@ jobs: } } + - name: Check macOS capsule Spaces contract + run: npm run check:macos-capsule-spaces + - name: Build frontend (tsc + vite) run: npm run build diff --git a/openless-all/app/package.json b/openless-all/app/package.json index 5ec2d5eb..d03c66b2 100644 --- a/openless-all/app/package.json +++ b/openless-all/app/package.json @@ -8,6 +8,7 @@ "build": "tsc && vite build", "preview": "vite preview", "tauri": "tauri", + "check:macos-capsule-spaces": "node scripts/macos-capsule-spaces-contract.test.mjs", "check:hotkey-injection": "node scripts/check-hotkey-injection.mjs" }, "dependencies": { diff --git a/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs b/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs new file mode 100644 index 00000000..540ccc0f --- /dev/null +++ b/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs @@ -0,0 +1,31 @@ +import { readFile } from 'node:fs/promises'; + +function assertMatch(source, pattern, name) { + if (!pattern.test(source)) { + throw new Error(`${name}: pattern ${pattern} not found`); + } +} + +const coordinatorRs = await readFile(new URL('../src-tauri/src/coordinator.rs', import.meta.url), 'utf-8'); +const functionMatch = coordinatorRs.match( + /#\[cfg\(target_os = "macos"\)\]\s*fn show_capsule_window_no_activate[\s\S]*?\n}\n\n#\[cfg\(target_os = "linux"\)\]/, +); + +if (!functionMatch) { + throw new Error('macOS capsule no-activate function not found'); +} + +const macosNoActivateFunction = functionMatch[0]; +const executableMacosNoActivateFunction = macosNoActivateFunction.replace(/\/\/.*$/gm, ''); + +assertMatch( + macosNoActivateFunction, + /set_visible_on_all_workspaces\(true\)[\s\S]*?orderFrontRegardless/, + 'macOS capsule should join all Spaces before showing without activation', +); + +for (const forbidden of ['window.show()', 'set_focus', 'NSApp.activate', 'makeKeyAndOrderFront']) { + if (executableMacosNoActivateFunction.includes(forbidden)) { + throw new Error(`macOS capsule no-activate path must not call ${forbidden}`); + } +} diff --git a/openless-all/app/src-tauri/src/coordinator.rs b/openless-all/app/src-tauri/src/coordinator.rs index 21fab30b..2bafe7e7 100644 --- a/openless-all/app/src-tauri/src/coordinator.rs +++ b/openless-all/app/src-tauri/src/coordinator.rs @@ -4500,7 +4500,12 @@ fn show_capsule_window_no_activate( // emit_capsule 已经把窗口操作 marshal 到 Tauri 主线程;这里不能再调用 // window.show()/set_focus()/NSApp.activate,否则 AeroSpace 会把 workspace 切回 - // OpenLess 主窗口所在空间。orderFrontRegardless 只让胶囊可见,不成为 key window。 + // OpenLess 主窗口所在空间。先让胶囊加入所有 Spaces,再用 + // orderFrontRegardless 做无激活展示。 + if let Err(e) = window.set_visible_on_all_workspaces(true) { + log::warn!("[capsule] set visible on all macOS Spaces failed: {e}"); + } + unsafe { let _: () = msg_send![ns_window, orderFrontRegardless]; } From 57f186f054e0fe42d89ad22f73e48807dbc287ac Mon Sep 17 00:00:00 2001 From: H-Chris233 Date: Fri, 29 May 2026 11:07:07 +0800 Subject: [PATCH 2/2] test: make capsule Spaces contract cross-platform --- .../app/scripts/macos-capsule-spaces-contract.test.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs b/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs index 540ccc0f..0d48305a 100644 --- a/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs +++ b/openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs @@ -6,7 +6,9 @@ function assertMatch(source, pattern, name) { } } -const coordinatorRs = await readFile(new URL('../src-tauri/src/coordinator.rs', import.meta.url), 'utf-8'); +const coordinatorRs = ( + await readFile(new URL('../src-tauri/src/coordinator.rs', import.meta.url), 'utf-8') +).replace(/\r\n/g, '\n'); const functionMatch = coordinatorRs.match( /#\[cfg\(target_os = "macos"\)\]\s*fn show_capsule_window_no_activate[\s\S]*?\n}\n\n#\[cfg\(target_os = "linux"\)\]/, );