Fix fullscreen new windows opening in current Space (#2345)

* Fix fullscreen new windows opening in current Space

* works

* Stabilize fullscreen tiling regression test
This commit is contained in:
Austin Wang 2026-03-30 01:43:41 -07:00 committed by GitHub
parent 79bcf1d370
commit 63dd7281f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 81 additions and 2 deletions

View file

@ -2147,6 +2147,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
let isFirstResponder: Bool
}
var debugCloseMainWindowConfirmationHandler: ((NSWindow) -> Bool)?
var debugCreateMainWindowSourceIsNativeFullScreenOverride: Bool?
// Keep debug-only windows alive when tests intentionally inject key mismatches.
private var debugDetachedContextWindows: [NSWindow] = []
@ -5975,9 +5976,21 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
// Use the current key window's size for new windows so Cmd+Shift+N
// creates a window matching the previous one's dimensions.
let styleMask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView]
let existingFrame = preferredMainWindowContextForWorkspaceCreation(
let sourceContext = preferredMainWindowContextForWorkspaceCreation(
debugSource: "createMainWindow.initialGeometry"
).flatMap { resolvedWindow(for: $0)?.frame }
)
let sourceWindow = sourceContext.flatMap { resolvedWindow(for: $0) }
let existingFrame = sourceWindow?.frame
let sourceWindowIsNativeFullScreen: Bool = {
#if DEBUG
if let debugCreateMainWindowSourceIsNativeFullScreenOverride {
return debugCreateMainWindowSourceIsNativeFullScreenOverride
}
#endif
return sourceWindow?.styleMask.contains(.fullScreen) == true
}()
let shouldTemporarilyDisallowFullScreenTiling =
sessionWindowSnapshot == nil && sourceWindowIsNativeFullScreen
let initialRect: NSRect
if sessionWindowSnapshot == nil, let existingFrame {
// Convert frame rect to content rect so the new window matches the
@ -5993,6 +6006,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
backing: .buffered,
defer: false
)
// When creating a new window from an existing native fullscreen window,
// temporarily opt out of fullscreen tiling so AppKit doesn't place the
// new window into the active fullscreen Space.
if shouldTemporarilyDisallowFullScreenTiling {
window.collectionBehavior.insert(.fullScreenDisallowsTiling)
}
window.title = ""
window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true
@ -6045,6 +6064,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
setActiveMainWindow(window)
NSApp.activate(ignoringOtherApps: true)
}
if shouldTemporarilyDisallowFullScreenTiling {
DispatchQueue.main.async { [weak window] in
window?.collectionBehavior.remove(.fullScreenDisallowsTiling)
}
}
if let restoredFrame {
window.setFrame(restoredFrame, display: true)
#if DEBUG

View file

@ -33,6 +33,7 @@ final class AppDelegateShortcutRoutingTests: XCTestCase {
override func tearDown() {
AppDelegate.shared?.shortcutLayoutCharacterProvider = KeyboardLayout.character(forKeyCode:modifierFlags:)
AppDelegate.shared?.debugCloseMainWindowConfirmationHandler = nil
AppDelegate.shared?.debugCreateMainWindowSourceIsNativeFullScreenOverride = nil
AppDelegate.shared?.dismissNotificationsPopoverIfShown()
RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.05))
for action in KeyboardShortcutSettings.Action.allCases {
@ -98,6 +99,60 @@ final class AppDelegateShortcutRoutingTests: XCTestCase {
XCTAssertEqual(secondManager.tabs.count, secondCount + 1, "Cmd+N should add workspace to the event's window")
}
func testCreateMainWindowDoesNotDisallowFullScreenTilingByDefault() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")
return
}
let windowId = appDelegate.createMainWindow()
defer {
closeWindow(withId: windowId)
}
guard let window = window(withId: windowId) else {
XCTFail("Expected test window")
return
}
XCTAssertFalse(
window.collectionBehavior.contains(.fullScreenDisallowsTiling),
"Main windows should still support standard macOS Split View when not created from a fullscreen source"
)
}
func testCreateMainWindowTemporarilyDisallowsFullScreenTilingFromFullscreenSource() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")
return
}
appDelegate.debugCreateMainWindowSourceIsNativeFullScreenOverride = true
let newWindowId = appDelegate.createMainWindow()
defer {
closeWindow(withId: newWindowId)
}
guard let newWindow = window(withId: newWindowId) else {
XCTFail("Expected new window")
return
}
XCTAssertTrue(
newWindow.collectionBehavior.contains(.fullScreenDisallowsTiling),
"New windows should temporarily opt out of fullscreen tiling while opening from a fullscreen source"
)
appDelegate.debugCreateMainWindowSourceIsNativeFullScreenOverride = nil
RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.05))
XCTAssertFalse(
newWindow.collectionBehavior.contains(.fullScreenDisallowsTiling),
"The fullscreen tiling opt-out should be cleared after initial presentation so Split View keeps working"
)
}
func testAddWorkspaceInPreferredMainWindowIgnoresStaleTabManagerPointer() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")