Keep dragged tabs and sidebar rows on glass in translucent windows
Summary
In a translucent window (any appearance.backgroundOpacity below 1, frosted or Liquid Glass), dragging a tab or a sidebar workspace turned it from glass into a flat block of the theme color the moment it lifted:
- a tab lifted in its strip painted
windowBackgroundat full alpha (TabCell), - the tab's drag image was rendered on a solid
windowBackgroundcard, and the ghost's glass stayed at alpha 0 until the preview card unfolded (TabStripView.snapshot,TabDragGhostPanel), - a lifted sidebar row (and the image it hands to the window drag) sat on a solid
elevatedBackgroundcard (DragLiftView).
DragGlass (CmuxNextDesign) now decides all three from the window's backdrop. Over glass, the lifted tab's fill is a thicker piece of the window tint (the tint plus 60% of the rest, so tabs sliding under it stay quiet while the art reads through), the sidebar lift card is a glass panel, and the ghost's tab image has no card of its own and stands on the ghost's glass from the first frame. Opaque windows and Reduce Transparency keep the solid cards they had.
Torn-off windows themselves were checked, not changed: every main window, including one opened for a torn-off tab or workspace, goes through WindowController.init โ NSWindow.install(kind: .main, content:scope:), whose root paints the same WindowBackdrop from a room scope that inherits the app scope's art, opacity and blur. A new boundary test pins that.
Workspace naming (the workspace-N titles) is not touched; another PR owns it.
Testing
Added DragGlassTests (CmuxNextAppTests):
liftAndCardFillsAreGlassOnlyInATranslucentWindowaLiftedSidebarRowIsGlassInATranslucentWindow/aLiftedSidebarRowStaysSolidInAnOpaqueWindowaLiftedTabLetsTheWindowsGlassReadThroughtheDragGhostStandsOnGlassFromItsFirstFrameaNewSecondaryWindowHasTheMainWindowsBackdrop(boundary: a second main window with its own room scope showing a new workspace scope gets the first window's opacity, background, material and tint)
SubtleElevationTests' two ghost cases now pin onGlass: false, the opaque path whose tab shadow they measure.
Observed / Not run
Not run locally (no Swift builds on this laptop). The fleet build and the cmux-next swift test dispatch for this head are recorded below once they finish. Not yet checked live in a tagged build with a background image.
Changelog
Fixed: Dragging a tab or a sidebar workspace in a translucent window keeps it glass instead of turning it into a solid theme-colored block
Proof
Native drag preview change; per the capture rule, the tests above prove the fills, and a live capture is pending a tagged build.
Localization: no user-facing strings changed.
๐ค Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Keeps dragged tabs and sidebar rows in translucent windows glass over the window's art and tint instead of turning into flat theme-colored blocks when lifted.
- A new
WindowBackdropextension decides all drag previews from the window's backdrop: a lifted tab's fill is a thicker piece of the window tint, the sidebar lift card is a glass panel, and the drag ghost's tab image has no card of its own and stands on glass from the first frame. - Opaque windows and Reduce Transparency keep the solid cards they had.
- The ghost's glass follows the source scope the image was drawn in, not the app's: a workspace that pins its own background over an opaque app keeps its glass preview.
- Torn-off windows are unchanged: they install the same backdrop through the existing main-window path, now pinned by a boundary test.
- Adds
DragGlassTests(the lift fills, sidebar and ghost cards, the source-scope ghost glass, and the torn-off window backdrop);SubtleElevationTests' ghost cases now pin the opaqueonGlass: falsepath.