Skip to content

Keep Cmd-Shift-N windows on source display - #3214

Merged
lawrencecchen merged 4 commits into
mainfrom
task-command-shift-new-window-same-display
Apr 28, 2026
Merged

lawrencecchen merged 4 commits into
mainfrom
task-command-shift-new-window-same-display

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Apr 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Route Cmd-Shift-N new window creation through the shortcut event window.
  • Place new windows relative to the source cmux window and clamp them to that display.
  • Keep command palette New Window scoped to the current cmux window.

Testing

  • ./scripts/reload.sh --tag cmdwin passed.
  • Unit test added in the required first commit; local test run skipped per repo policy.

Issues

  • Task: Cmd-Shift-N should create a new window on the same display, not a new workspace.

Summary by cubic

Cmd+Shift+N now opens a new window on the same display as the window that triggered it, placed next to it and matching its size, instead of creating a workspace elsewhere. The command palette “New Window” and shortcut now explicitly target the current cmux window. Addresses Linear task: Cmd-Shift-N should create a new window on the same display, not a new workspace.

  • Bug Fixes
    • Route new window creation via the shortcut’s event window or an explicit preferred window, with fallbacks to the active main terminal window.
    • Place the new window beside the source and clamp it within the source display’s visible area; preserve the source window’s dimensions.
    • Add a regression test ensuring Cmd+Shift+N creates a single new main window from the event window (not a workspace), sized like the source and kept on the same display.

Written for commit 40f4b4b. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Source-aware new window placement: new windows now open relative to the triggering window (menu, shortcut, or context), cascading and clamped to the visible screen with sensible offsets and minimum sizing instead of generic centering.
  • Tests

    • Added regression test ensuring Cmd+Shift+N creates a single new window anchored to the event window, preserving workspace/tab counts and proper on-screen positioning.

@vercel

vercel Bot commented Apr 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 28, 2026 8:06am
cmux-staging Building Building Preview, Comment Apr 28, 2026 8:06am

@coderabbitai

coderabbitai Bot commented Apr 28, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Threads a preferred source NSWindow through main-window creation: menu/shortcut/event context resolves a source window, which is passed into createMainWindow and used to position new windows with cascade and screen-visible-frame clamping.

Changes

Cohort / File(s) Summary
Window Creation Logic
Sources/AppDelegate.swift
createMainWindow(...) now accepts sourceWindow preferredSourceWindow: NSWindow?; openNewMainWindow(_:) derives a preferred source via event/sender/key/main/registered context and calls createMainWindow(sourceWindow:). Positioning uses positionNewMainWindow when no restored frame. Added openNewMainWindow(preferredWindow:) overload.
Window Command Integration
Sources/ContentView.swift
Palette "palette.newWindow" handler now obtains AppDelegate.shared and passes a non-nil preferredWindow (from appDelegate.mainWindow(for: windowId)) into openNewMainWindow instead of nil.
Shortcut Routing Tests
cmuxTests/AppDelegateShortcutRoutingTests.swift
Added regression test testCmdShiftNCreatesWindowFromEventWindowWithoutAddingWorkspace() that synthesizes Cmd+Shift+N tied to an event window and asserts a single new main window is created, existing workspace/tab counts remain unchanged, and the new window’s frame is sourced/contained within the event window’s display bounds.

Sequence Diagram

sequenceDiagram
    participant User as User (shortcut/menu)
    participant App as AppDelegate
    participant EventCtx as Event / Sender Resolution
    participant Creator as createMainWindow
    participant Position as positionNewMainWindow

    User->>App: trigger new-window action (with event/sender)
    App->>EventCtx: preferredSourceWindowForNewMainWindow(sender)
    EventCtx-->>App: resolved preferredSourceWindow
    App->>Creator: createMainWindow(..., sourceWindow: preferredSourceWindow)
    Creator->>Creator: resolvedMainWindowSource(preferredSourceWindow)
    Creator->>Position: positionNewMainWindow(resolved source)
    Position-->>Creator: positioned frame (clamped, cascaded)
    Creator-->>App: new main window UUID / instance
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

Poem

🐰 I nudged a window, soft and sly,

from elder pane the new one flies.
With cascade steps and bounds in view,
each shortcut knows just what to do.
Hooray — a hop, a window new! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: Cmd-Shift-N windows now remain on the source display rather than appearing elsewhere.
Description check ✅ Passed The description covers Summary, Testing, and addresses the core issue. Demo Video and Review Trigger sections are missing, but core requirements are substantially met.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-command-shift-new-window-same-display

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Routes Cmd-Shift-N through the shortcut event's source window so new windows open on the same display as the triggering cmux window, using a 24-pt cascade offset clamped to the source screen's visible frame. The command-palette path is updated to scope the preferred window to the current windowId, and a behavioral regression test is added in the required first commit.

Confidence Score: 4/5

Safe to merge; only P2 style findings, logic and test structure are correct

All findings are P2. The two-commit test structure is followed per policy, the resolution chain handles nil and non-terminal windows gracefully, and clamping prevents off-screen placement. Minor concerns about minWidth/minHeight floor and double singleton dereference do not affect correctness.

Sources/AppDelegate.swift — clampFrame minWidth/minHeight floor in positionNewMainWindow

Important Files Changed

Filename Overview
Sources/AppDelegate.swift Adds source-window resolution chain, cascade positioning, and screen-clamping for Cmd-Shift-N; logic is sound with one minor concern around clampFrame's minWidth/minHeight of 1
Sources/ContentView.swift Scopes palette.newWindow to the current cmux window via windowId; double AppDelegate.shared? access is safe but redundant
cmuxTests/AppDelegateShortcutRoutingTests.swift Behavioral regression test added in the correct first commit per two-commit policy; uses timing-based RunLoop spin which could be flaky under CI load

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Cmd-Shift-N shortcut event] --> B[mainWindowForShortcutEvent]
    B --> C{resolvedShortcutEventWindow\nisMainTerminalWindow?}
    C -- yes --> D[sourceWindow = event window]
    C -- no --> E{NSApp.keyWindow\nisMainTerminalWindow?}
    E -- yes --> D
    E -- no --> F{NSApp.mainWindow\nisMainTerminalWindow?}
    F -- yes --> D
    F -- no --> G[sourceWindow = nil]
    D --> H[createMainWindow sourceWindow: window]
    G --> H
    H --> I[resolvedMainWindowSource]
    I --> J{preferredSourceWindow is terminal window?}
    J -- yes --> K[use as source]
    J -- no --> L{contextForMainWindow or contextForMainTerminalWindow?}
    L -- found --> M[resolvedWindow for context]
    L -- not found --> N[fall back to preferredMainWindowContextForWorkspaceCreation]
    K --> O[positionNewMainWindow]
    M --> O
    N --> P{sourceWindow nil?}
    P -- yes --> Q[window.center + cascadeTopLeft]
    P -- no --> O
    O --> R[cascade 24pt from source origin clampFrame to source screen visibleFrame]
    R --> S[window displayed on source display]
    PA[palette.newWindow] --> PB[mainWindow for windowId] --> H
Loading

Reviews (1): Last reviewed commit: "Place Cmd-Shift-N windows on source disp..." | Re-trigger Greptile

Comment thread Sources/AppDelegate.swift Outdated
Comment on lines +6232 to +6234
Self.clampFrame(frame, within: visibleFrame, minWidth: 1, minHeight: 1),
display: false
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Near-invisible window when cascade lands far off-screen

clampFrame is called with minWidth: 1, minHeight: 1. If the source window is so large that it nearly fills the display and the 24-pt cascade pushes the new window outside the visible frame, the clamp will shrink it down to as small as 1×1 pt — effectively invisible and non-resizable in practice. Other call sites in the file typically pass something closer to the minimum usable size. Consider using a sensible minimum (e.g., the default 460×360 fallback rect) so the window remains functional after clamping.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by using the app's default minimum window size when clamping the cascaded frame, so the new window remains usable on constrained displays.

— Claude Code

Comment thread Sources/ContentView.swift
Comment on lines 7685 to 7689
registry.register(commandId: "palette.newWindow") {
AppDelegate.shared?.openNewMainWindow(nil)
AppDelegate.shared?.openNewMainWindow(
preferredWindow: AppDelegate.shared?.mainWindow(for: windowId)
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Double optional-chain on AppDelegate.shared

AppDelegate.shared is dereferenced twice: once for the call site and again inside the argument expression. Because AppDelegate.shared is a singleton the double dereference is safe, but it reads as if the inner call could diverge. Capturing the delegate once is cleaner:

registry.register(commandId: "palette.newWindow") {
    guard let delegate = AppDelegate.shared else { return }
    delegate.openNewMainWindow(preferredWindow: delegate.mainWindow(for: windowId))
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by capturing AppDelegate.shared once in the palette command and using that delegate for both the lookup and the new-window call.

— Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/AppDelegate.swift (1)

6205-6241: Use shared minimum-size policy instead of hardcoded values.

Line 6226 introduces a second source of truth (460x360). Prefer SessionPersistencePolicy.minimumWindowWidth/Height here to keep clamping behavior consistent across restore/create paths.

♻️ Suggested change
-        let minimumWindowSize = NSSize(width: 460, height: 360)
+        let minimumWindowSize = NSSize(
+            width: CGFloat(SessionPersistencePolicy.minimumWindowWidth),
+            height: CGFloat(SessionPersistencePolicy.minimumWindowHeight)
+        )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/AppDelegate.swift` around lines 6205 - 6241, The clamp in
positionNewMainWindow currently uses a hardcoded minimumWindowSize (460x360);
replace that with the shared policy values by using
SessionPersistencePolicy.minimumWindowWidth and
SessionPersistencePolicy.minimumWindowHeight when calling Self.clampFrame so the
same minimum-size policy is used across restore/create paths; update/remove the
local minimumWindowSize variable and ensure the clampFrame call passes those two
policy values instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/AppDelegate.swift`:
- Around line 6205-6241: The clamp in positionNewMainWindow currently uses a
hardcoded minimumWindowSize (460x360); replace that with the shared policy
values by using SessionPersistencePolicy.minimumWindowWidth and
SessionPersistencePolicy.minimumWindowHeight when calling Self.clampFrame so the
same minimum-size policy is used across restore/create paths; update/remove the
local minimumWindowSize variable and ensure the clampFrame call passes those two
policy values instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71aa3a54-82be-48a2-acec-a033941a398c

📥 Commits

Reviewing files that changed from the base of the PR and between e910c34 and 40f4b4b.

📒 Files selected for processing (2)
  • Sources/AppDelegate.swift
  • Sources/ContentView.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/ContentView.swift

@lawrencecchen
lawrencecchen merged commit 2132562 into main Apr 28, 2026
24 checks passed
@lawrencecchen
lawrencecchen deleted the task-command-shift-new-window-same-display branch April 28, 2026 08:15
ShubhamPatilsd pushed a commit to emergent-inc/mosaic that referenced this pull request Jul 9, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 40f4b4b6 Deployed Apr 28, 2026 by vercel[bot]
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