Repository navigation
cmux NEXT captures: a window snapshot shows an open popover with its glass, and waits behind a busy main actor - #24240
Conversation
…toggle reaches the Home (red) debug.window_snapshot is now built by DebugWindowSnapshot.controlMethod (no behavior change) so a test can register it. Both tests fail on this commit: the snapshot times out at the control-plane deadline while the main actor is busy, and with no key window a child window in front takes the Chief Settings toggle instead of its window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oggle reaches the Home debug.window_snapshot keeps its own 30 s deadline instead of the 2 s control-plane one. On a capture mini that also runs builds and tests (cua-5 at load 30 to 44 on 14 cores) the wait for the main actor passed 2 s, the snapshot timed out, and pr-capture refused the capture for want of a still. The capture itself takes about 50 ms. With no key window, home.toggleChiefSettings resolves the frontmost visible window to the window it belongs to. Outside an active app AppKit lists Chromium page child window first, so a toggle from the CLI with cmux in the background (every capture slot) reached no Home and the popover never opened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A window snapshot composited the window, then its overlay panels alone, then the menus over it. A glass popover composited alone blurs nothing and came out grey. The window, its child windows and the app's windows over it now go to the window server as one composite, so the glass blurs the window under it as on screen. Where a Chromium page image is painted over that, the overlays come back on top through a coverage mask. Only this app's windows are composited, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green |
|
Owned by deputy-2 on cosmic-gray · session |
|
Found 9 test failures on Blacksmith runners: Failures
|
|
Bead |
|
Orphaned: no activity for 13 h, and no lane holds a lease on it. Adopted by the orphan sweep: merged |
|
|
Resolved NSWindow+Snapshot.swift: base split capture into main-actor plans (WindowCapturePlan, FloatingWindowsCapturePlan) and nonisolated window-server calls, dropping windowServerImage(ofNumbers:croppedTo:) and isBlank. Kept base's plan/off-main API; ported the PR's floatingWindowNumbers, compositedSnapshotWithOverlays, overlays(cutFrom:includeChild:) and masked onto it (floating numbers now read through a nonisolated floatingWindowNumbers(in:) shared with capture(_:), crops via windowServerImage(ofNumbers:rect:), blank check via isFullyTransparent), and kept the PR's frontToBack(_:onScreen:) split under base's nonisolated frontToBack(_:). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1603a-6462-72f0-a4b0-6937eb58e4c3&host=cosmic-gray
|
|
…overlays before the page awaits Where the overlays alone are translucent (a shadow, a fade, an edge), the cut now takes their own pixels instead of the composite times their alpha, which painted over a page image faded them twice. The overlays are cut right after the composite, before the page images' awaits, so a popover that opens meanwhile is not cut from a composite it is not in. The deadline test waits for the request to start before it blocks the main actor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1603a-6462-72f0-a4b0-6937eb58e4c3&host=cosmic-gray
|
|
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
The ask (from the capture lane, reported by chief-ui and projects-50): "(a) the capture tool's window snapshot leaves out child panels and popovers (NSPanel/child windows), so no popover PR can attach a capture" and "(b) the fleet window snapshot timed out and was refused." Done when "a capture of an open popover shows the popover."
Three causes, three fixes, all in the DEBUG capture path (
debug.window_snapshot, which pr-capture'sdriver.pyuses for every still):CMUX_NEXT_NO_ACTIVATE=1), so there is no key window.home.toggleChiefSettingsthen picked the front visible window, and AppKit lists a child window before its parent when the app is not active. The front window was Chromium's page window (aCefNSWindowchild of the main window), no Home answered, and nothing opened.HomeChiefSettingsPopover.toggleTargetnow walks a child window up to its parent, as it already did for a key child panel.NSWindow.compositedSnapshotWithOverlays()), so the glass blurs the window under it, as on screen. Where a Chromium page image is then painted over the composite, the overlays are cut from that same composite by their own coverage (overlays(cutFrom:includeChild:)) and painted back on top, so a popover over a web page stays on top too. As before, only this app's windows are composited, never another app's.debug.window_snapshotran under the 2 s control-plane deadline, and that deadline counts the wait for the main actor. The capture itself takes about 50 ms, but on cua-5 (load 30 to 44 on 14 cores, shared with builds and test suites) and during app launch, the wait passed 2 s. The driver then had no still, and pr-capture refused the capture. The deadline exists to catch a handler that hangs, but a snapshot queued behind main-actor work isn't hung, and the driver needs the still either way. So the method keeps its own 30 s deadline (DebugWindowSnapshot.controlMethod), which matches the driver's 30 s socket timeout. The route moves out ofAppControlintoDebugWindowSnapshotso a test can drive it through a realControlRouter.cmux window|pane|tab screenshot(AppWindowImage,WindowImageLayer) is left as on base. Two open PRs (#23972, #23983) rework that path, and this one doesn't touch it.Testing
Red first (471c8b8), then the fix:
DebugWindowSnapshotDeadlineTests.aSnapshotWaitsBehindABusyMainActor: a router with a 50 ms request deadline, the main actor busy for 400 ms. On base the call fails with a timeout. On the head it answers (no such windowfor a made-up window number).HomeChiefSettingsToggleTests.withoutAKeyWindowAChildInFrontStandsForItsWindow: with no key window and a visible child listed first, the toggle reaches the parent. On base it returned the child.WindowSnapshotOverlaysTests.theWindowAndItsOverlaysAreOneCompositeTopmostFirst: the composite's window order (on-screen order first, then unlisted windows, each once).WindowSnapshotOverlaysTests.aPopoverCutFromTheCompositeShowsOverAPageImage: pixel check. Where the popover covers the window, the cut shows the popover over a page image; elsewhere the page shows.cmux-ci compile-check --apppassed at the head d04352f (job 29e40325ba693a068a630a72).Observed / Not run
home.showthenhome.toggleChiefSettingsfrom the CLI, with the app in the background. The window list showed theNativePopupPanelchild, anddebug.window_snapshotreturned in 18 to 51 ms withchild_windows: 5. The still shows the Chief Settings popover open with its glass over Home, in light and dark. Before the toggle fix, the same steps opened nothing. Before the composite change, the popover came out as an opaque grey card.Changelog
none
Proof
Capture
steps-108f6bc705atd04352ff7e7f(fleet build, capture mini, text checked for private data)Steps:
cmux action run home.show, thencmux action run home.toggleChiefSettings, with the app in the background as every capture slot runs it. Capture job (fleet build)bdb92487ed96664bf8987012.Checklist
Agent session: cosmic-gray
🤖 Generated with Claude Code