Skip to content

Fix native macOS tabs being treated as separate windows#2027

Closed
EdenRochmanSharabi wants to merge 2 commits intonikitabobko:mainfrom
EdenRochmanSharabi:fix/native-tab-detection
Closed

Fix native macOS tabs being treated as separate windows#2027
EdenRochmanSharabi wants to merge 2 commits intonikitabobko:mainfrom
EdenRochmanSharabi:fix/native-tab-detection

Conversation

@EdenRochmanSharabi
Copy link
Copy Markdown

Summary

Fixes #68. macOS accessibility API reports native tabs as separate AXWindow elements, causing AeroSpace to tile each tab as its own window (e.g., Terminal with 3 tabs creates 3 tiled windows, 2 of which are empty).

This PR detects inactive native tabs using CGWindowListCopyWindowInfo (public API, no private APIs): if a window detected by the AX API is not on-screen but another window from the same app is on-screen, it's an inactive background tab and should not be tiled.

Changes

  • windowLevelCache.swift: Extended the CG window info cache to track bounds and owner PID alongside window level. Added isLikelyNativeTab(windowId:appPid:) function.
  • MacWindow.swift: Check isLikelyNativeTab before binding new windows — detected tabs go to the popup container instead of tiling.
  • normalizeLayoutReason.swift: Added demoteNativeTabsToPopup() to move tiled windows that become inactive tabs (e.g., after the user opens a new tab) to the popup container. Modified validateStillPopups() to skip promoting windows that are still native tabs.

How it works

  1. New window detected: If CGWindowListCopyWindowInfo(.optionOnScreenOnly) doesn't include the window but does include another window from the same PID → it's a background tab → popup container.
  2. Tab switch: When the user switches tabs, the previously active tab disappears from the on-screen list → demoteNativeTabsToPopup() moves it to popup. The newly active tab either gets detected as new or gets promoted from popup via validateStillPopups().
  3. Tab closed: When the active tab is closed, the next tab becomes on-screen → promoted from popup to tiling automatically.

Tested with

  • Terminal.app (multiple tabs, rapid tab creation, tab switching, tab closing)
  • Finder (native tabs)
  • Safari (native tabs)
  • Mixed: multiple apps with tabs simultaneously
  • Two separate windows of the same app (correctly tiled, not confused with tabs)
  • Moving windows between workspaces (not confused with tabs)

Test plan

  • Open Terminal with 3+ tabs → only 1 should be tiled
  • Switch between tabs → tiled window updates to active tab
  • Close active tab → next tab promotes to tiling
  • Open 2 separate Terminal windows → both tile normally
  • Open Finder/Safari with tabs → same behavior
  • Move window to another workspace → not confused with tabs

Eden Rochman added 2 commits March 26, 2026 18:43
macOS accessibility API reports native tabs as separate AXWindow elements,
causing AeroSpace to tile each tab as its own window. This uses
CGWindowListCopyWindowInfo (public API) to detect inactive tabs: if a
window is not on-screen but another window from the same app is, it's
likely a background native tab.

Changes:
- windowLevelCache.swift: extended CG window info cache with bounds and
  PID tracking; added isLikelyNativeTab() detection function
- MacWindow.swift: check for native tabs before tiling new windows
- normalizeLayoutReason.swift: demote tiled windows that become inactive
  tabs to popup container; prevent tab windows from being promoted back

Works with Terminal.app, Finder, Safari, and any app using native macOS
tabs. No private APIs used.
- Add appWindowCount safety check: only consider windows as tabs if
  the app has 2+ windows known to AeroSpace, preventing false positives
  when CGWindowList is slow to update
- Simplify normalization: split into validatePopups() and
  demoteInactiveTabs() for clearer logic
- Refresh CG cache once per pass for consistency
- Add refreshNativeTabDetection() and windowCountForApp() helpers
@nikitabobko
Copy link
Copy Markdown
Owner

The PR is a workaround and not a complete fix. Also please make sure to read all the discussions around this issue

A complete fix is much more complicated and I don't expect 3rd party contributors to fix this issue

@EdenRochmanSharabi
Copy link
Copy Markdown
Author

I am well aware that it is a workaround and not perfect. It introduced a smaller bug: when you navigate between tabs in the same app while you have three apps open vertically, sometimes the order of the apps swaps. However, I think that bug is less frustrating than the current one. I understand it is a workaround, but I thought it was a good temporary solution.

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.

Native macOS Big Sur tabs are considered windows

2 participants