cmux NEXT: multi-view window, a row dropped on a pane edge shows its workspace beside the shown one (Debug toggle)
Summary
With the Debug toggle sidebar.multiView on, one window can show several workspaces side by side. This is item D, the window half; #23437 added the toggle and the sidebar half.
- Placing one beside. Hold a sidebar row, then drag it onto a pane edge of the shown workspace. That workspace now shows on that side of the shown one, whole. Its tabs stay where they are. A top or bottom edge stacks the two. The workspace you were in keeps the focus.
- Focus. A press in a workspace beside focuses it, and focuses the pane you pressed. Clicking its sidebar row does the same.
- Back to one. Either of these returns the window to one workspace:
- clicking a row that is not on screen;
- turning the toggle off.
- Closing one. Closing a shown workspace, or moving it out of the window, takes only that one off screen. The others stay on screen in their places.
SidebarModel.onScreenis exactly the set of workspaces on screen. It changes in the same turn as each show.- Persistence. The window record keeps the set in an optional
multi_viewkey, so it comes back on relaunch. With the toggle off the key is never written.
With the toggle off, nothing changes. An edge drop still merges the workspace's tabs, and no layout, focus or record path behaves differently.
How it works:
- Rendering. The workspaces beside the focused one are its parked contents. Their views stay visible in the content area, and
MainPaneCardView.arrangeContentlays them out. - Focus model. They send the window no focus topology, so the titlebar, actions and focus still follow the one focused workspace.
- Attention rings. They keep drawing while the workspace is on screen, and stop once it leaves.
- Code. The set is
WorkspaceViewSet, a split tree with workspaces as leaves. The window code is in the newWindowController+MultiView.swiftandWindowController+Parking.swift.WindowController.swiftshrank from 521 to 500 lines.
Changelog
none
Testing
A new suite, SidebarMultiViewWindowTests, drives the real sidebar list's mouse handlers, the window drag session and NSApp.sendEvent on a real window. It covers:
- an edge drop placing the workspace beside the shown one (left, and bottom stacked);
- a hover that shows nothing until the release;
onScreenequal to the shown set after every step of a sequence: drop, press, row clicks, a second drop, and a workspace closing;- a press on a pane beside focusing that workspace and that pane;
- attention rings in a workspace beside;
- turning the toggle off at runtime;
- the set coming back from the window's record;
- with the toggle off, an edge drop still resolving to the merge.
The suite needs a display, like the other drag and motion suites (.enabled(if: !NSScreen.screens.isEmpty)). A host with no display clamps the window to 520x320, where the drop zones resolve differently.
Red, on the test commits before each fix:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --ref <sha> --key mvw-before-... --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarMultiViewWindowTests --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app
- Step 3d3c5bc9a4b8e4fc07beca50 and step 8f4720e07e13897a42adac31 (the latter rebased, b05d9a1c8a19), both on aws-m4pro-9: the four behavior tests fail and the toggle-off test passes.
- Step 4f574b07494d15d401c38a61 (27e17cc98c25): the press and runtime toggle-off tests were added and fail.
- Step e15adad512651298af0ced10 (6f5c5a1e9128, aws-m4pro-9): only the attention-ring test fails (
k1.layoutModel.attentionis empty).
Green at head d52bac982c28, step 928d8ddb4ee7f512075b891f on aws-m4pro-9: all 7 suites pass. Those are SidebarMultiViewWindowTests plus the neighbor suites SidebarMultiViewPressTests, SidebarSameTurnTests, WindowCloseNeighborTests, WorkspaceSwitchRedrawHoldTests, UnreadRingClickReadTests and DragGlassTests.
cmux-ci compile-check --app --ref d52bac982c28 passed (job 0346a8384aad84da3ebd0189).
Observed / Not run
Observed:
- The fleet runs listed above.
prepush-gate.pyreports no new violations.check-no-godfiles.shshows no new lines from this branch. One existing warning grew:TabDragSessionspans 1014 lines, up from 1013 on base, still in the warning tier.
Not run:
- A dogfood pass in a tagged build. The feature is behind an off-by-default Debug toggle.
- The suite on display-less hosts, where it is skipped (see Testing).
Known limits of this prototype:
- A restored set drops a Cloud workspace whose machine is still connecting.
- A drop onto the area of a workspace beside is not targeted.
- The floating-pane shade covers the workspaces beside.
- A scroll, or hover with focus-follows-mouse, in a workspace beside also focuses it.
- Opening a top page resizes the focused workspace to full width while the page paints.
- A window restored with the toggle off that never shows a workspace writes
multi_viewback unchanged.
No localized strings were added; the only new text is the Debug tunable's help.
No capture: the change is behind the off-by-default Debug toggle sidebar.multiView.
🤖 Generated with Claude Code
Agent session: cosmic-gray
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
With the sidebar.multiView Debug toggle on, dragging a sidebar row onto a pane edge of the shown workspace now places that workspace beside it, whole, instead of merging its tabs. The focused workspace keeps the focus model, titlebar, and actions; the workspaces beside it are parked contents whose views stay on screen.
- A press in a workspace beside focuses it and the pane pressed; clicking an off-screen row or turning the toggle off returns the window to one workspace; closing a shown workspace leaves the others on screen.
SidebarModel.onScreenis exactly the workspaces on screen, updated in the same turn as each show; attention rings keep drawing while a workspace is beside.- The window record saves the set in an optional
multi_viewkey, restored on relaunch; with the toggle off the key is never written. - With the toggle off, edge drops still merge and no layout, focus, or record behavior changes.
Testing
SidebarMultiViewWindowTests drives the real sidebar list, the window drag session, and NSApp.sendEvent on a real window, covering edge drops, focus, on-screen sets, attention rings, a runtime toggle-off, record restoration, and the toggle-off merge. It is skipped on display-less hosts, like the other drag and motion suites.