Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2017,6 +2017,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
private var browserAddressBarFocusedPanelId: UUID?
private var browserOmnibarRepeatStartWorkItem: DispatchWorkItem?
private var browserOmnibarRepeatTickWorkItem: DispatchWorkItem?
private var screenChangeSnapshotWorkItem: DispatchWorkItem?
private var browserOmnibarRepeatKeyCode: UInt16?
private var browserOmnibarRepeatDelta: Int = 0
private var browserAddressBarFocusObserver: NSObjectProtocol?
Expand Down Expand Up @@ -2324,6 +2325,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
}
}
NSWindow.allowsAutomaticWindowTabbing = false
// Disable macOS system window restoration to prevent duplicate windows
// when external displays are disconnected/reconnected (#1802).
// The app uses its own SessionPersistenceStore for window state.
// Uses register(defaults:) so we set the app default without overwriting
// a user-level preference if one exists.
UserDefaults.standard.register(defaults: ["NSQuitAlwaysKeepsWindows": false])
disableNativeTabbingShortcut()
ensureApplicationIcon()
if !isRunningUnderXCTest {
Expand Down Expand Up @@ -2638,6 +2645,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent

func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
isTerminatingApp = true
screenChangeSnapshotWorkItem?.cancel()
_ = saveSessionSnapshot(includeScrollback: true, removeWhenEmpty: false)
return .terminateNow
}
Expand Down Expand Up @@ -3304,6 +3312,32 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
}
}
lifecycleSnapshotObservers.append(didWakeObserver)

// When an external display is disconnected/reconnected, macOS can trigger
// window restoration that creates duplicate windows (#1802). Save a snapshot
// so the session state stays consistent after the display topology change.
// Debounced because this notification can fire many times in rapid succession
// during a single display reconfiguration event.
let screenChangeObserver = NotificationCenter.default.addObserver(
forName: NSApplication.didChangeScreenParametersNotification,
object: nil,
queue: .main
) { [weak self] _ in
self?.scheduleScreenChangeSnapshot()
}
lifecycleSnapshotObservers.append(screenChangeObserver)
}

private func scheduleScreenChangeSnapshot() {
screenChangeSnapshotWorkItem?.cancel()
let work = DispatchWorkItem { [weak self] in
Task { @MainActor [weak self] in
guard let self, !self.isTerminatingApp else { return }
_ = self.saveSessionSnapshot(includeScrollback: false)
}
Comment thread
elvistranhere marked this conversation as resolved.
Comment thread
elvistranhere marked this conversation as resolved.
}
screenChangeSnapshotWorkItem = work
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: work)
}

private func socketListenerConfigurationIfEnabled() -> (mode: SocketControlMode, path: String)? {
Expand Down Expand Up @@ -3735,6 +3769,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
sidebarSelectionState: SidebarSelectionState
) {
tabManager.window = window
// Prevent macOS from restoring this window on display reconfiguration (#1802).
Comment thread
elvistranhere marked this conversation as resolved.
window.isRestorable = false

let key = ObjectIdentifier(window)
#if DEBUG
Expand Down
2 changes: 2 additions & 0 deletions Sources/Panels/BrowserPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9353,6 +9353,7 @@ final class BrowserDataImportCoordinator {
defaultValue: "Import Browser Data"
)
panel.isReleasedWhenClosed = false
panel.isRestorable = false
panel.delegate = self
panel.standardWindowButton(.miniaturizeButton)?.isHidden = true
panel.standardWindowButton(.zoomButton)?.isHidden = true
Expand Down Expand Up @@ -10095,6 +10096,7 @@ final class BrowserDataImportCoordinator {
)
window.title = title
window.isReleasedWhenClosed = false
window.isRestorable = false
window.standardWindowButton(.closeButton)?.isHidden = true
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true
Expand Down
1 change: 1 addition & 0 deletions Sources/Panels/BrowserPopupWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ final class BrowserPopupWindowController: NSObject, NSWindowDelegate {
panel.level = NSWindow.Level.normal
panel.hidesOnDeactivate = false
panel.isReleasedWhenClosed = false
panel.isRestorable = false
panel.minSize = NSSize(width: minWidth, height: minHeight)
panel.title = String(localized: "browser.popup.loadingTitle", defaultValue: "Loading\u{2026}")
self.panel = panel
Expand Down
7 changes: 7 additions & 0 deletions Sources/cmuxApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ private final class SettingsAboutTitlebarDebugWindowController: NSWindowControll
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.settingsAboutTitlebarDebug")
window.center()
window.contentView = NSHostingView(rootView: SettingsAboutTitlebarDebugView())
Expand Down Expand Up @@ -1805,6 +1806,7 @@ private final class DebugWindowControlsWindowController: NSWindowController, NSW
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.debugWindowControls")
window.center()
window.contentView = NSHostingView(rootView: DebugWindowControlsView())
Expand Down Expand Up @@ -2109,6 +2111,7 @@ private final class BrowserImportHintDebugWindowController: NSWindowController,
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.browserImportHintDebug")
window.center()
window.contentView = NSHostingView(rootView: BrowserImportHintDebugView())
Expand Down Expand Up @@ -2146,6 +2149,7 @@ private final class BrowserProfilePopoverDebugWindowController: NSWindowControll
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.browserProfilePopoverDebug")
window.center()
window.contentView = NSHostingView(rootView: BrowserProfilePopoverDebugView())
Expand Down Expand Up @@ -2756,6 +2760,7 @@ private final class SidebarDebugWindowController: NSWindowController, NSWindowDe
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.sidebarDebug")
window.center()
window.contentView = NSHostingView(rootView: SidebarDebugView())
Expand Down Expand Up @@ -3157,6 +3162,7 @@ private final class MenuBarExtraDebugWindowController: NSWindowController, NSWin
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.menubarDebug")
window.center()
window.contentView = NSHostingView(rootView: MenuBarExtraDebugView())
Expand Down Expand Up @@ -3327,6 +3333,7 @@ private final class BackgroundDebugWindowController: NSWindowController, NSWindo
window.titlebarAppearsTransparent = false
window.isMovableByWindowBackground = true
window.isReleasedWhenClosed = false
window.isRestorable = false
window.identifier = NSUserInterfaceItemIdentifier("cmux.backgroundDebug")
window.center()
window.contentView = NSHostingView(rootView: BackgroundDebugView())
Expand Down
Loading