Skip to content

fix(windows): pin a screenshot window's size when it is built, not from inside its layout pass - #3092

Merged
datlechin merged 2 commits into
mainfrom
fix/window-chrome-background-creation
Sep 23, 2026
Merged

datlechin merged 2 commits into
mainfrom
fix/window-chrome-background-creation

Conversation

@datlechin

Copy link
Copy Markdown
Member

What was wrong

A connection window opened while TablePro was in the background, with its size pinned through TABLEPRO_SCREENSHOT_FRAME, came up broken and stayed broken after the app was activated:

  • the sidebar's Tables | Favorites chooser and the filter field sat under the titlebar, behind the traffic lights and the sidebar toggle
  • the toolbar's trailing items, the inspector toggle among them, were in the overflow menu

Found while capturing the screenshots for #3060: 3 of 3 background-created windows broken, 0 of 2 active ones.

Root cause

ScreenshotEnvironment.pinWindowSize resized the window from MainContentView.configureWindow, which runs from WindowAccessorView.viewDidMoveToWindow. SwiftUI calls that while it renders inside NSHostingView.layout(), inside the window's own layout pass. The call stack from a standalone probe: -[NSWindow layoutIfNeeded] → -[NSView _layoutSubtreeWithOldSize:] (several levels) → NSHostingView.layout → addSubview → viewDidMoveToWindow → setFrame. That pass has already captured the old size, so after setFrame it resizes the content view by the difference a second time.

Measured from the app's accessibility tree, background URL open, window pinned from 1200x800 to 1512x861:

window split view (content view) inspector toggle
main (f626e9a) 1512x861 1824x922 at y -61 in the overflow menu
this branch 1512x861 1512x861 at y 0 at x 1468

1824 = 1512 + 312 and 922 = 861 + 61: the delta twice. The split view starting 61pt above the window is what put the sidebar's top row under the titlebar, and its inspector divider at x 1824, past the 1512pt window, is what pushed the toolbar section that tracks it into the overflow menu.

A standalone AppKit probe (unified toolbar, NSSplitViewController, NSHostingController detail, the same resize from viewDidMoveToWindow) gives the same 1824x922 whether the window is visible or not and whether the app is active or not, and 1512x861 when the same resize runs from a plain main-queue block. So the defect is where the resize is issued. Activation only changed whether TablePro's SwiftUI update landed inside the window's layout pass.

Which paths hit it

Only runs that set TABLEPRO_SCREENSHOT_FRAME, which ScreenshotEnvironment reads only under the UI test storage sandbox: screenshot captures, and the three UI suites that pin a frame (InspectorToolbarPlacementUITests, ConnectionWindowChromeUITests, ResultStatusBarUITests). A shipping build never pins, and its first frame comes from setFrameUsingName in TabWindowController.init, before the window is shown or laid out.

Measured to be sure: the same background URL open with a saved 1512x861 frame and no pin lays out correctly (split view 1512x861, chooser at y 56, inspector toggle in the toolbar). Reopening the last session at launch, a URL or file from another app, and MCP or AppleScript opens all build the window through that same initializer.

The pin has been in configureWindow since #2180. #3041 made it more visible by moving the chooser into the sidebar, above the filter field that was already there.

Fix

The pinned size is decided where every other first frame is decided. TabWindowController.init applies the pin, else the autosaved frame, else the default size, before the window is shown, and before the controller becomes the window's delegate so a starting frame is not saved as one the user chose. ScreenshotEnvironment only computes the centred frame and no longer touches a window, and configureWindow no longer resizes anything.

Side effect: the pin used to run again each time a connection's content mounted, re-centring a window a second connection was adopted into. It now runs once per window.

Tests

  • EditorWindowInitialFrameTests (new):
    • a connection window built through TabWindowController.init starts at its pinned size before it is shown. Moving the pin anywhere after construction fails this.
    • that window's split view spans exactly the pinned frame once laid out
    • a resize from a WindowAccessor callback inside the layout pass leaves the content view the delta too large. This pins the AppKit behaviour the placement rule rests on.
  • ScreenshotEnvironmentTests: the pinned frame is centred on the visible frame.

verify.sh test EditorWindowInitialFrameTests ScreenshotEnvironmentTests EditorWindowChromeTests ConnectionWindowInitialFocusTests: 29 executed, 29 passed. Build passes on the rebased commit.

No new UI test. The failure needs SwiftUI to mount the content inside the window's layout pass, which in the app happened for a window built in the background, and XCUITest activates the app it launches. The unit test reproduces the mechanism deterministically instead.

Before / After

Both from sandboxed Debug builds opened with open -g and a postgresql:// URL while another app stayed frontmost, window pinned to 1512x861, the connect confirmed through accessibility without activating TablePro. Before is main at f626e9a, after is this branch.

Before: chooser under the traffic lights, filter field at the top edge, inspector toggle in the overflow menu, the empty state off-centre.

Before

After: chooser and filter field below the titlebar, full toolbar with the inspector toggle.

After

No CHANGELOG entry: the defect never reached a shipping build.

@datlechin
datlechin merged commit fe6ebab into main Sep 23, 2026
8 of 9 checks passed
@datlechin
datlechin deleted the fix/window-chrome-background-creation branch September 23, 2026 19:25
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.

1 participant