Skip to content

fix: prevent floating windows from getting stuck in corner after work…#1985

Closed
buacanning wants to merge 1 commit intonikitabobko:mainfrom
buacanning:fix/floating-window-stuck-in-corner
Closed

fix: prevent floating windows from getting stuck in corner after work…#1985
buacanning wants to merge 1 commit intonikitabobko:mainfrom
buacanning:fix/floating-window-stuck-in-corner

Conversation

@buacanning
Copy link
Copy Markdown

…space switch

When AeroSpace hides windows from inactive workspaces, it moves them to a screen corner and saves their previous position so they can be restored later (unhideFromCorner). A race condition with AX notifications could cause the following broken cycle:

  1. hideInCorner() saves the normal position, moves window to corner
  2. unhideFromCorner() restores it, clears prevUnhiddenProportionalPosition
  3. A spurious AX event triggers unhideFromCorner() again — no-op since prevUnhiddenProportionalPosition is already nil, window stays in place
  4. Next workspace switch calls hideInCorner() again — isHiddenInCorner is false (nil check) — so it saves the current position, which is already the corner position
  5. unhideFromCorner() then restores the window to the corner → stuck forever

Fix: in hideInCorner(), only record the window's position when its top-left corner is actually inside the monitor's visible rect. If it's already outside (stuck in a corner from a previous broken cycle), skip saving to avoid permanently anchoring it to the corner.

Fixes: #1875

…space switch

When AeroSpace hides windows from inactive workspaces, it moves them to a
screen corner and saves their previous position so they can be restored later
(unhideFromCorner). A race condition with AX notifications could cause the
following broken cycle:

1. hideInCorner() saves the normal position, moves window to corner
2. unhideFromCorner() restores it, clears prevUnhiddenProportionalPosition
3. A spurious AX event triggers unhideFromCorner() again — no-op since
   prevUnhiddenProportionalPosition is already nil, window stays in place
4. Next workspace switch calls hideInCorner() again — isHiddenInCorner is
   false (nil check) — so it saves the *current* position, which is already
   the corner position
5. unhideFromCorner() then restores the window to the corner → stuck forever

Fix: in hideInCorner(), only record the window's position when its top-left
corner is actually inside the monitor's visible rect. If it's already outside
(stuck in a corner from a previous broken cycle), skip saving to avoid
permanently anchoring it to the corner.

Fixes: nikitabobko#1875
nikitabobko added a commit that referenced this pull request Mar 5, 2026
#1987

AeroSpace has idempotent architecture: hideInCorner can be called multiple times. isHiddenInCorner serves as guard
against writing invalid values to prevUnhiddenProportionalPositionInsideWorkspaceRect. We should make sure that there
are no suspension points between the guard check and the prevUnhiddenProportionalPositionInsideWorkspaceRect assignment.

Kudos to the community for finding this bug and the root cause. Specifically to:
- https://github.com/fbuetler (#1875 (comment))
- https://github.com/tweezerticle (#1875 (comment))
- https://github.com/buacanning (#1985)
@nikitabobko
Copy link
Copy Markdown
Owner

Thanks! The patch indeed fixes the issue, but I prefer to write it in a slightly different way

The PR is superseded by 90a7c67

@nikitabobko nikitabobko closed this Mar 5, 2026
nikitabobko added a commit that referenced this pull request Mar 8, 2026
#1987

AeroSpace has idempotent architecture: hideInCorner can be called multiple times. isHiddenInCorner serves as guard
against writing invalid values to prevUnhiddenProportionalPositionInsideWorkspaceRect. We should make sure that there
are no suspension points between the guard check and the prevUnhiddenProportionalPositionInsideWorkspaceRect assignment.

Kudos to the community for finding this bug and the root cause. Specifically to:
- https://github.com/fbuetler (#1875 (comment))
- https://github.com/tweezerticle (#1875 (comment))
- https://github.com/buacanning (#1985)

(cherry picked from commit 90a7c67)
ZimengXiong pushed a commit to ZimengXiong/winmux that referenced this pull request Apr 6, 2026
nikitabobko/AeroSpace#1987

AeroSpace has idempotent architecture: hideInCorner can be called multiple times. isHiddenInCorner serves as guard
against writing invalid values to prevUnhiddenProportionalPositionInsideWorkspaceRect. We should make sure that there
are no suspension points between the guard check and the prevUnhiddenProportionalPositionInsideWorkspaceRect assignment.

Kudos to the community for finding this bug and the root cause. Specifically to:
- https://github.com/fbuetler (nikitabobko/AeroSpace#1875 (comment))
- https://github.com/tweezerticle (nikitabobko/AeroSpace#1875 (comment))
- https://github.com/buacanning (nikitabobko/AeroSpace#1985)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants