Skip to content

Fix focus jumping when same-app floating windows closes#1914

Closed
jperras wants to merge 1 commit intonikitabobko:mainfrom
jperras:fix-focus-jump-same-app-dialog-window-close
Closed

Fix focus jumping when same-app floating windows closes#1914
jperras wants to merge 1 commit intonikitabobko:mainfrom
jperras:fix-focus-jump-same-app-dialog-window-close

Conversation

@jperras
Copy link
Copy Markdown

@jperras jperras commented Jan 23, 2026

Summary

Skip focus recalculation when a floating window (dialog) is destroyed if it belongs to the same app as the currently focused window.

This fixes Emacs child frames (posframes, completion popups, etc.) causing focus to jump to another application when they close.

References

Fixes #776
Fixes #1220

PR checklist

  • Explain your changes in the relevant commit messages rather than in the PR description. The PR description must not contain more information than the commit messages (except for images and other media).
  • Each commit must explain what/why/how and motivation in its description. https://cbea.ms/git-commit/
  • Don't forget to link the appropriate issues/discussions in commit messages (if applicable).
  • Each commit must be an atomic change (a PR may contain several commits). Don't introduce new functional changes together with refactorings in the same commit.
  • ./run-tests.sh exits with non-zero exit code.
  • Avoid merge commits, always rebase and force push.

Failure to follow the checklist with no apparent reasons will result in silent PR rejection.

Skip focus recalculation when a floating window (dialog) is destroyed if
it belongs to the same app as the currently focused window.

This fixes Emacs child frames (posframes, completion popups) causing
focus to jump to another application when they close.

Fixes nikitabobko#776
Fixes nikitabobko#1220
Davincible added a commit to Davincible/AeroSpace that referenced this pull request Feb 11, 2026
@zarthross
Copy link
Copy Markdown

This is effecting me to. I would love to see this PR merged!

@jamescrake-merani
Copy link
Copy Markdown

I just tested this PR on my machine, and it fixes the issue for me with Emacs. As others have said, it would be great to see this merged! :)

@zarthross
Copy link
Copy Markdown

@nikitabobko Can this PR get some attention please 🥺

@nikitabobko
Copy link
Copy Markdown
Owner

nikitabobko commented Mar 31, 2026

I don't like the proposed logic as it sounds wrong to me. I don't like the existing logic in general, but I don't know how to do it better.

This PR just increases the technical debt and the complexity of the code that I didn't like already.

I'd like to notice that this "preserve the focused workspace" logic doesn't activate if the window is detected as a popup. So the alternative fix could be to improve AeroSpace popup heuristics to detect these Emacs windows as popups (according to your descriptions, they do sound like popups, not real windows)

Pointers:

  1. You can use aerospace debug-winddows to capture Emacs windows properties
  2. You can try to improve the popup detection logic in Sources/AppBundle/model/AxUiElementWindowType.swift + cover the logic with tests by placing Emacs windows dumps in axDumps directory

Closing the PR for now

Comment on lines +101 to +104
if focus.windowOrNil?.app.pid == app.pid && parent is Workspace {
// The destroyed window was a floating window (dialog) from the same app.
// Don't recalculate focus - let the app handle it internally.
break
Copy link
Copy Markdown
Owner

@nikitabobko nikitabobko Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the guard logic was added to avoid setFocus(to: deadWindowFocus) or deadWindowFocus.windowOrNil?.nativeFocus() or both?

Copy link
Copy Markdown
Author

@jperras jperras Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emacs (at least the flavour I have) doesn't end up calling nativeFocus() in the branching logic after this because, well, all the windows/frames that emacs creates belong to emacs.

The setFocus(to: deadWindowFocus), from what I remember, is what messes things up, though it might be a red herring. When I was bisecting, it was a bit tough to pinpoint things exactly because of gc changes in 405dec8, where you moved to a polling-based implementation.

@jperras
Copy link
Copy Markdown
Author

jperras commented Mar 31, 2026

@nikitabobko yeah, that's fair - this isn't the cleanest fix. Emacs child frames should probably just be treated as popups, even though they're a bit weird (because emacs).

FWIW I've been running this fix for a while now without any complications, but I'm not the most adventurous when it comes to macOS app usage, so it's definitely possible this diff would cause additional problems for other apps that might do some more esoteric/weird stuff with child windows.

I'll see if I can improve the popup detection heuristics instead.

@jamescrake-merani
Copy link
Copy Markdown

If I'm not mistaken, I think some applications create new windows for popups like completion similar to what we see with Emacs. I remember someone having an issue with MATLAB (which I think uses Swing but not 100% certain of this) on a tiling manager because it would try to tile the completion popups... I don't know if that error is the same with Aerospace (I try to avoid MATLAB like the plague :P ), but it could be.

@jperras
Copy link
Copy Markdown
Author

jperras commented Mar 31, 2026

For anyone following along on this PR that uses emacs, try out #2036 - I believe it's a more sane fix.

@jperras jperras deleted the fix-focus-jump-same-app-dialog-window-close branch March 31, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants