Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions openless-all/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
33 changes: 33 additions & 0 deletions openless-all/app/scripts/macos-capsule-spaces-contract.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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')
).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"\)\]/,
);

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}`);
}
}
7 changes: 6 additions & 1 deletion openless-all/app/src-tauri/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4500,7 +4500,12 @@ fn show_capsule_window_no_activate<R: tauri::Runtime>(

// 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];
}
Expand Down
Loading