Skip to content

fix(typing): stop raising every window of the target app when restoring focus after dictation - #810

Merged
altic-dev merged 1 commit into
altic-dev:mainfrom
YuriNachos:YuriNachos/w6-FluidVoice
Aug 10, 2026
Merged

fix(typing): stop raising every window of the target app when restoring focus after dictation#810
altic-dev merged 1 commit into
altic-dev:mainfrom
YuriNachos:YuriNachos/w6-FluidVoice

Conversation

@YuriNachos

@YuriNachos YuriNachos commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Description

After dictation, FluidVoice restores focus to the target app through TypingService.activateApp(pid:), which called NSRunningApplication.activate(options: [.activateAllWindows, .activateIgnoringOtherApps]).

.activateAllWindows raises every window of the target process, not just the one the user was typing into. On a multi-window app (WebStorm, VS Code, multiple Finder windows) that reshuffles the whole window layout after each dictation — the behaviour reported in #748.

This PR removes .activateAllWindows and keeps .activateIgnoringOtherApps, so the target app still becomes frontmost and its key window comes forward, while sibling windows stay where the user left them.

The options are now built from one named constant, TypingService.focusRestoreActivationOptions, so the four focus-restore call sites (all of which already funnel through activateApp(pid:)) share a single definition and the contract is unit-testable.

Diff: Sources/Fluid/Services/TypingService.swift (+8/-1) and one test.

Type of Change

  • 🐞 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 🧹 Chore
  • 📝 Documentation update

Related Issue or Discussion

Closes #748.

Testing

  • Tested on Apple Silicon Mac
  • Tested on Intel Mac
  • Tested on macOS version: 26.0 (Darwin 25.6.0), Xcode latest-stable
  • Ran linter locally: swiftlint --strict --config .swiftlint.yml Sources0 violations, 0 serious in 139 files
  • Ran tests locally: xcodebuild test -project Fluid.xcodeproj -scheme Fluid -destination 'platform=macOS,arch=arm64' CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO -skip-testing:FluidDictationIntegrationTests/DictationE2ETests/testDictationEndToEnd_whisperTiny_transcribesFixture

New regression test — TypingServiceTransientPasteboardTests.testFocusRestoreDoesNotRaiseAllWindowsOfTargetApp: asserts focusRestoreActivationOptions contains .activateIgnoringOtherApps and does not contain .activateAllWindows. It is red on main (the option set still carries .activateAllWindows) and green here. TypingServiceTransientPasteboardTests passes in full.

Two unrelated tests are red on my machine only, both for the environment reasons documented in this repo's own prerequisites, and both are red on a clean main here too:

  • HotkeyShortcutTests.testKeyboardPayloadIgnoresStrayMouseButtonField — asserts the ASCII glyph at a keyCode; my host has a non-U.S. input source active.
  • DictationE2ETests.testAppPromptBinding_defaultFallbackIgnoresGlobalSelection — reads real com.FluidApp.app defaults, which are customised on this machine.

Neither touches TypingService. CI runs on a clean U.S.-layout runner, so both should be green there.

Manual check for the actual behaviour (it cannot be captured in a screenshot): open two windows of a multi-window app, focus one, dictate into it. On main both windows are raised; with this change only the focused window comes forward.

Screenshots / Video

  • No UI/visual changes; screenshots/video are not applicable.

To be explicit rather than just tick a box: this PR changes no FluidVoice UI surface — no view, layout, styling, settings, overlay or menu-bar change. What it changes is which windows of the target third-party app macOS raises when focus is restored; that is window-activation behaviour in another process, which a static screenshot cannot show. The manual repro steps above are the way to observe it.

Notes

  • Behaviour is unchanged for single-window targets: .activateIgnoringOtherApps alone already brings the app frontmost with its key window.
  • focusRestoreActivationOptions is internal static so the test target can reach it via @testable import; no new public surface.

Authored by @YuriNachos. Implementation written by a cccc (Claude Code) worker under orchestrator acceptance; an independent adversarial review (logic + behaviour-equivalence + test-integrity) returned APPROVE with no blocking findings.

@github-actions github-actions Bot added needs PR template Pull request is missing required template content. needs screenshots Pull request needs screenshot or video evidence. labels Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

The PR Policy check is blocking this PR because required template information is missing.

Please update the PR description with:

  • Description
  • Type of Change
  • Related Issue or Discussion
  • Testing
  • Screenshots / Video

Screenshots or video are required for UI, UX, settings, onboarding, overlay, menu bar, or visual behavior changes. If this PR has no visual changes, check the no-visual-change box in the template.

If this remains incomplete for 48 hours after opening, the PR may be closed.

@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR narrows post-dictation activation to avoid raising every window belonging to the target application.

  • Centralizes focus-restoration activation options in TypingService.
  • Retains .activateIgnoringOtherApps while removing .activateAllWindows.
  • Adds a regression test for the activation-option contract.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (3): Last reviewed commit: "fix(typing): stop raising every window o..." | Re-trigger Greptile

@YuriNachos
YuriNachos force-pushed the YuriNachos/w6-FluidVoice branch from ffd6547 to 752c3df Compare August 8, 2026 11:18
@github-actions github-actions Bot removed needs PR template Pull request is missing required template content. needs screenshots Pull request needs screenshot or video evidence. labels Aug 8, 2026
@YuriNachos

Copy link
Copy Markdown
Contributor Author

Force-pushed a housekeeping fix: the branch accidentally carried an internal report file from my own tooling directory that has nothing to do with this change. It is gone now — the diff is only the source and test files listed above.

No production or test code changed in this push; the branch is otherwise identical to what was reviewed.

@altic-dev

Copy link
Copy Markdown
Owner

@YuriNachos Love all your PRs!!! The gold standard contributions I was hoping to get!!!!

…ng focus after dictation

Drop .activateAllWindows from the focus-restore activation options in
TypingService.activateApp(pid:); keep .activateIgnoringOtherApps so the target
app is still brought forward without raising every window of a multi-window app
(WebStorm, multi-window Xcode, browsers) on each dictation. Issue altic-dev#748.

The inline options literal is extracted into a named internal testable seam
(focusRestoreActivationOptions) and a regression test is added to the existing
TypingServiceTransientPasteboardTests asserting the option set contains
.activateIgnoringOtherApps and not .activateAllWindows.

Co-Authored-By: Claude <noreply@anthropic.com>
@altic-dev
altic-dev force-pushed the YuriNachos/w6-FluidVoice branch from 752c3df to 81ac1c3 Compare August 10, 2026 20:11
@altic-dev
altic-dev merged commit 53d8d84 into altic-dev:main Aug 10, 2026
8 of 9 checks passed
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.

[BUG] Restoring focus after dictation raises all windows of the target app (.activateAllWindows)

2 participants