Skip to content

Avoid activating OpenLess when showing dictation capsule#456

Open
H-Chris233 wants to merge 1 commit into
Open-Less:betafrom
H-Chris233:issue-452-aerospace-capsule-no-activate
Open

Avoid activating OpenLess when showing dictation capsule#456
H-Chris233 wants to merge 1 commit into
Open-Less:betafrom
H-Chris233:issue-452-aerospace-capsule-no-activate

Conversation

@H-Chris233
Copy link
Copy Markdown
Collaborator

@H-Chris233 H-Chris233 commented May 16, 2026

User description

Summary

  • Route the dictation capsule show path through platform no-activate behavior.
  • Add a macOS NSWindow orderFrontRegardless path so showing the recording capsule does not normally activate OpenLess or pull AeroSpace back to the OpenLess workspace.
  • Keep the existing window.show() fallback when no-activate cannot access the native window, so recording feedback is not lost.

Fallback behavior

  • macOS no-activate is the intended path for issue [windows] aerospace 工作区不合理跳转 #452.
  • If ns_window() is unavailable/null, the code intentionally falls back to window.show().
  • That fallback may still trigger the old AeroSpace workspace switch, but it is retained as a product decision so users still see that dictation has started instead of getting no capsule feedback.

Needs macOS real-device validation

This PR was implemented and tested from a non-macOS environment. Before treating issue #452 as fully accepted, please verify on a real macOS machine with AeroSpace:

  1. Put the OpenLess main window on workspace A.
  2. Put a working text app on workspace B.
  3. Trigger dictation from workspace B.
  4. Confirm the workspace does not switch back to OpenLess during normal capsule display.
  5. Confirm the capsule is visible, the working app remains frontmost, and dictated text inserts into the working app.
  6. Also verify tray / explicit “show main window” behavior still focuses OpenLess as expected.

Test plan

  • npm run build
  • cargo test --manifest-path openless-all/app/src-tauri/Cargo.toml --lib -- --test-threads=1
  • git diff --check
  • Real macOS + AeroSpace workspace validation

Refs #452


PR Type

Bug fix


Description

  • Route capsule display through no-activate

  • Preserve fallback when native handle unavailable

  • Add macOS AeroSpace-safe window showing

  • Cover platform strategy with tests


Diagram Walkthrough

flowchart LR
  A["emit_capsule"] -- "show capsule" --> B["show_capsule_window_for_recording"]
  B -- "macOS/Windows" --> C["no-activate show"]
  C -- "macOS" --> D["orderFrontRegardless"]
  C -- "Windows" --> E["SWP_NOACTIVATE show"]
  B -- "fallback" --> F["window.show()"]
  B -- "logs once" --> G["warning"]
Loading

File Walkthrough

Relevant files
Bug fix
coordinator.rs
Use no-activate capsule showing by platform                           

openless-all/app/src-tauri/src/coordinator.rs

  • Introduce CapsuleShowStrategy to choose no-activate or fallback
    behavior per platform.
  • Add show_capsule_window_for_recording() to centralize capsule display
    and fallback logging.
  • Implement macOS ns_window() handling with orderFrontRegardless to
    avoid AeroSpace workspace switches.
  • Add a test asserting the platform strategy matches the activation
    contract.
+84/-9   

Route the capsule show path through platform no-activate behavior so macOS can use orderFrontRegardless during dictation while preserving the existing fallback path when native handles are unavailable.

Constraint: issue Open-Less#452 requires AeroSpace users not to be pulled back to the OpenLess workspace during dictation startup.

Rejected: removing macOS fallback entirely | product decision is to preserve visible recording feedback if no-activate cannot access ns_window.

Confidence: medium

Scope-risk: narrow

Directive: macOS fallback to window.show is intentional but may still switch workspace; validate on real macOS with AeroSpace before claiming full issue acceptance.

Tested: npm run build; cargo test --manifest-path openless-all/app/src-tauri/Cargo.toml --lib -- --test-threads=1; git diff --check

Not-tested: macOS real-device AeroSpace workspace behavior
@github-actions
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

452 - Partially compliant

Compliant requirements:

  • Routes capsule display through a no-activate path on macOS and Windows

Non-compliant requirements:

  • If the native macOS window handle is unavailable, the code still falls back to window.show(), which can re-activate OpenLess and trigger the workspace switch the ticket is trying to avoid

Requires further human verification:

  • Real macOS + AeroSpace validation to confirm the capsule stays visible without switching workspaces in the target setup
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Fallback Regression

If ns_window() is unavailable on macOS, this path falls back to window.show(). That can still activate OpenLess and pull AeroSpace back to the OpenLess workspace, so the workspace-jump bug remains for startup or initialization cases where the native handle is not ready.

if capsule_show_strategy_for_platform() == CapsuleShowStrategy::NoActivate {
    needs_fallback = !show_capsule_window_no_activate(app, window);
    if needs_fallback && !CAPSULE_NO_ACTIVATE_FALLBACK_WARNED.swap(true, Ordering::SeqCst) {
        // 产品取舍:no-activate 是 macOS/AeroSpace 的主路径;但如果 ns_window
        // 暂不可用,仍优先保住录音反馈,不让用户以为听写没启动。fallback 可能
        // 重新触发 workspace 跳转,只在 no-activate 失败时作为降级路径。
        log::warn!("[capsule] no-activate show failed; falling back to window.show()");
    }
}

if needs_fallback {
    if let Err(e) = window.show() {
        log::warn!("[capsule] show fallback failed: {e}");
    }

@H-Chris233
Copy link
Copy Markdown
Collaborator Author

@appergb 请在真机上进行测试

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants