Repository navigation
Make Settings a top-level peer window, not a floating child (#5081) - #5083
Conversation
Settings is attached to the main window via addChildWindow, which pins it above the parent forever — clicking the main window can never raise it above Settings. These tests assert the peer-window invariant (never a child window, stays .normal level, survives the main window closing) and fail against the current child-window implementation. The fix lands in the next commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Settings window was attached to the main window via addChildWindow(ordered: .above), and ConfigSettingsView set window.level = .floating. Both pin the window above the main window forever: a child window can never recede when the user clicks its parent, so clicking the main cmux window could not raise it above Settings. This is the bug reported in #5081. Fix the class of bugs, not just Settings: - SettingsWindowPresenter no longer creates a parent-child relationship. To preserve PR #3612's intent (a global hotkey / app activation surfaces the main window behind Settings), performFocus now orders the preferred main window front *once* and then fronts Settings as an independent peer. Normal click-to-raise ordering is left fully intact afterwards. The entire child-attachment + parent-close-detach observer apparatus is deleted (~80 lines): "Settings survives the main window closing" is now automatic because there is no child relationship to tear down. - ConfigSettingsView stops forcing .floating; it is a peer editor window. - Add NSWindow.adoptCmuxPeerWindowLevel() as the single, documented seam that states the .normal peer-window invariant. Both Settings and the Config editor adopt it, so the only remaining way to float a window is a deliberate, commented level = .floating at the call site (DEBUG HUD/lab panels keep that). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR moves Settings and related editor windows from floating/child behavior to independent top-level peers by adding an NSWindow helper to set ChangesSettings window as independent peer
Sequence Diagram(s): sequenceDiagram
participant User
participant SettingsWindowPresenter
participant PreferredMainWindow
participant SettingsWindow
participant App
User->>SettingsWindowPresenter: performFocus()
SettingsWindowPresenter->>SettingsWindow: adoptCmuxPeerWindowLevel()
SettingsWindowPresenter->>PreferredMainWindow: deminiaturize() / orderFront(nil)
SettingsWindowPresenter->>App: activate(ignoringOtherApps: true)
SettingsWindowPresenter->>SettingsWindow: orderFront(nil)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 17 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (17 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR fixes the "Settings window floats above the main window forever" bug by removing the AppKit parent-child relationship (
Confidence Score: 5/5Safe to merge — window ordering and level changes are localized to Settings and the Config editor, with targeted structural tests and no auth or data paths involved. The change deletes the parent-child wiring that caused the bug and replaces it with a simple, well-documented peer-window pattern. The new adoptCmuxPeerWindowLevel() helper is a one-liner with no side effects beyond setting level = .normal. Actor isolation is correct throughout, no timing primitives are introduced, and the tests directly assert the structural invariants that prevented the bug from being caught earlier. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant SettingsWindowPresenter
participant MainWindow as Main Window (peer)
participant SettingsWindow as Settings Window (peer)
Note over SettingsWindowPresenter: configure(window:) called by SwiftUI Window scene
SettingsWindowPresenter->>SettingsWindow: "adoptCmuxPeerWindowLevel() level = .normal"
SettingsWindowPresenter->>SettingsWindow: clampToVisibleAreaIfNeeded()
SettingsWindowPresenter-->>SettingsWindowPresenter: "Task { focus(window) }"
Note over SettingsWindowPresenter: performFocus() no addChildWindow
SettingsWindowPresenter->>SettingsWindow: adoptCmuxPeerWindowLevel() defensive reset
SettingsWindowPresenter->>MainWindow: orderFront(nil) surfaces main first as peer
SettingsWindowPresenter->>SettingsWindowPresenter: NSRunningApplication.activate()
SettingsWindowPresenter->>SettingsWindow: makeKeyAndOrderFront(nil) Settings lands above main
SettingsWindowPresenter->>SettingsWindow: orderFrontRegardless()
User->>MainWindow: click main window
Note over MainWindow,SettingsWindow: Standard click-to-raise main comes forward Settings recedes no permanent float
Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile |
…dow.swift
Old-style plist values containing '+' must be quoted; the unquoted
path = App/NSWindow+CmuxPeerWindow.swift made xcodebuild fail to read the
project ("missing semicolon in dictionary on line 963"), failing every
build-dependent check. Matches the quoting of existing AppDelegate+*.swift refs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…indow-level # Conflicts: # cmux.xcodeproj/project.pbxproj
Fixes #5081.
Problem
The Settings window stays painted on top of the main cmux window. Clicking the main window cannot raise it above Settings — Settings only recedes if you close it.
Two independent instances of the same class of bug:
parentWindow.addChildWindow(window, ordered: .above)inSettingsWindowPresenter. An AppKit child window is pinned above its parent forever and can never recede when the user clicks the parent — exactly the reported symptom. This was introduced in Keep Settings layered above the main window #3612 to surface the main window behind Settings on a global hotkey, butaddChildWindowover-delivered into a permanent float.window.level = .floatingon the user-facing Config editor — another peer window that should not float.Fix (class of bugs, not just Settings)
SettingsWindowPresenterno longer creates a parent-child relationship.performFocusorders the preferred main window front once and then fronts Settings as an independent peer — same initial "Settings in front of its app" layering Keep Settings layered above the main window #3612 wanted, but normal click-to-raise ordering stays intact afterwards. The whole child-attachment + parent-close-detach observer apparatus is deleted (~80 lines); "Settings survives the main window closing" is now automatic because there is no child relationship to tear down.ConfigSettingsViewadopts the peer level instead of.floating.NSWindow.adoptCmuxPeerWindowLevel()is the single, documented seam that states the.normalpeer-window invariant. Both Settings and the Config editor use it, so the only remaining way to float a window is a deliberate, commentedlevel = .floatingat the call site (the#if DEBUGHUD/lab panels keep that, intentionally). A new top-level peer window can no longer accidentally inherit floating behavior.Acceptance criteria
Tests
Two-commit red/green:
SettingsWindowPresentertests to assert the peer invariant (never a child window, stays.normal, survives the main window closing). These fail against the child-window implementation.adoptCmuxPeerWindowLevel()bringing a.floatingwindow back to.normal. AppKit z-order itself isn't unit-testable, but the structural invariants that caused the bug are.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.Note
Low Risk
macOS window ordering and presentation only; no auth, data, or network changes. Behavioral risk is limited to how auxiliary windows layer with the main window.
Overview
Fixes #5081 by treating Settings and the Config editor as normal top-level windows instead of windows that stay pinned above the main cmux window.
Settings no longer uses
addChildWindowon the main window (that relationship kept Settings above the parent permanently). Focus now does a one-timeorderFronton the preferred main window, then brings Settings forward as a peer at.normal, so click-to-raise works again. The parent/child attach, detach, and close observers are removed.Config editor drops
window.level = .floatingin favor of the same peer behavior.New
NSWindow.adoptCmuxPeerWindowLevel()centralizes the.normalinvariant for top-level auxiliary windows. Tests assert Settings is never a child window and stays at normal level.Reviewed by Cursor Bugbot for commit f6ed774. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Make Settings a top‑level peer window instead of a floating child, so it no longer stays pinned above the main window. The Config editor adopts the same behavior; fixes #5081.
NSWindow.adoptCmuxPeerWindowLevel()and used it in Settings and the Config editor to enforce.normal.App/NSWindow+CmuxPeerWindow.swiftincmux.xcodeprojto fix an xcodebuild parse error.mainand resolvedproject.pbxprojconflict; no behavior changes.Written for commit f6ed774. Summary will update on new commits.
Summary by CodeRabbit