@@ -62,13 +62,29 @@ extension AppDelegate {
6262 openWelcomeWindow ( )
6363 }
6464
65+ @objc func newWindowForTab( _ sender: Any ? ) {
66+ guard let keyWindow = NSApp . keyWindow,
67+ let connectionId = MainActor . assumeIsolated ( {
68+ WindowLifecycleMonitor . shared. connectionId ( fromWindow: keyWindow)
69+ } )
70+ else { return }
71+
72+ let payload = EditorTabPayload (
73+ connectionId: connectionId,
74+ intent: . newEmptyTab
75+ )
76+ MainActor . assumeIsolated {
77+ WindowOpener . shared. openNativeTab ( payload)
78+ }
79+ }
80+
6581 @objc func connectFromDock( _ sender: NSMenuItem ) {
6682 guard let connectionId = sender. representedObject as? UUID else { return }
6783 let connections = ConnectionStorage . shared. loadConnections ( )
6884 guard let connection = connections. first ( where: { $0. id == connectionId } ) else { return }
6985
70- WindowOpener . shared . pendingConnectionId = connection. id
71- NotificationCenter . default . post ( name : . openMainWindow , object : connection . id )
86+ let payload = EditorTabPayload ( connectionId : connection. id, intent : . restoreOrDefault )
87+ WindowOpener . shared . openNativeTab ( payload )
7288
7389 Task { @MainActor in
7490 do {
@@ -248,65 +264,50 @@ extension AppDelegate {
248264 if isMainWindow ( window) && !configuredWindows. contains ( windowId) {
249265 window. tabbingMode = . preferred
250266 window. isRestorable = false
251- let pendingId = MainActor . assumeIsolated { WindowOpener . shared. consumePendingConnectionId ( ) }
252-
253- // If no code opened this window (pendingId is nil), this is a
254- // SwiftUI WindowGroup state restoration — not a window we created.
255- // Hide it (orderOut, not close) to break the close→restore loop.
256- // Exception: if the window is already part of a tab group, it was
257- // attached by our addTabbedWindow call — not a restoration orphan.
258- // Ordering it out would crash NSWindowStackController.
259- if pendingId == nil && !isAutoReconnecting {
260- configuredWindows. insert ( windowId)
267+ configuredWindows. insert ( windowId)
268+
269+ let pendingConnectionId = MainActor . assumeIsolated {
270+ WindowOpener . shared. consumeOldestPendingConnectionId ( )
271+ }
272+
273+ if pendingConnectionId == nil && !isAutoReconnecting {
261274 if let tabbedWindows = window. tabbedWindows, tabbedWindows. count > 1 {
262- // Already in a tab group — leave it alone
263275 return
264276 }
265277 window. orderOut ( nil )
266278 return
267279 }
268280
269- let existingIdentifier = NSApp . windows
270- . first { $0 !== window && isMainWindow ( $0) && $0. isVisible } ?
271- . tabbingIdentifier
272- let groupAll = MainActor . assumeIsolated { AppSettingsManager . shared. tabs. groupAllConnectionTabs }
273- let resolvedIdentifier = TabbingIdentifierResolver . resolve (
274- pendingConnectionId: pendingId,
275- existingIdentifier: existingIdentifier,
276- groupAllConnections: groupAll
277- )
278- window. tabbingIdentifier = resolvedIdentifier
279- configuredWindows. insert ( windowId)
281+ if let connectionId = pendingConnectionId {
282+ let groupAll = MainActor . assumeIsolated { AppSettingsManager . shared. tabs. groupAllConnectionTabs }
283+ let resolvedIdentifier = WindowOpener . tabbingIdentifier ( for: connectionId)
284+ window. tabbingIdentifier = resolvedIdentifier
280285
281- if !NSWindow. allowsAutomaticWindowTabbing {
282- NSWindow . allowsAutomaticWindowTabbing = true
283- }
284-
285- // Explicitly attach to existing tab group — automatic tabbing
286- // doesn't work when tabbingIdentifier is set after window creation.
287- let matchingWindow : NSWindow ?
288- if groupAll {
289- // When grouping all connections, attach to any visible main window
290- // and normalize all existing windows' tabbingIdentifiers so future
291- // windows also match (not just the first one found).
292- let existingMainWindows = NSApp . windows. filter {
293- $0 !== window && isMainWindow ( $0) && $0. isVisible
286+ if !NSWindow. allowsAutomaticWindowTabbing {
287+ NSWindow . allowsAutomaticWindowTabbing = true
294288 }
295- for existing in existingMainWindows {
296- existing. tabbingIdentifier = resolvedIdentifier
289+
290+ let matchingWindow : NSWindow ?
291+ if groupAll {
292+ let existingMainWindows = NSApp . windows. filter {
293+ $0 !== window && isMainWindow ( $0) && $0. isVisible
294+ }
295+ for existing in existingMainWindows {
296+ existing. tabbingIdentifier = resolvedIdentifier
297+ }
298+ matchingWindow = existingMainWindows. first
299+ } else {
300+ matchingWindow = NSApp . windows. first {
301+ $0 !== window && isMainWindow ( $0) && $0. isVisible
302+ && $0. tabbingIdentifier == resolvedIdentifier
303+ }
297304 }
298- matchingWindow = existingMainWindows. first
299- } else {
300- matchingWindow = NSApp . windows. first {
301- $0 !== window && isMainWindow ( $0) && $0. isVisible
302- && $0. tabbingIdentifier == resolvedIdentifier
305+ if let existingWindow = matchingWindow {
306+ let targetWindow = existingWindow. tabbedWindows? . last ?? existingWindow
307+ targetWindow. addTabbedWindow ( window, ordered: . above)
308+ window. makeKeyAndOrderFront ( nil )
303309 }
304310 }
305- if let existingWindow = matchingWindow {
306- let targetWindow = existingWindow. tabbedWindows? . last ?? existingWindow
307- targetWindow. addTabbedWindow ( window, ordered: . above)
308- window. makeKeyAndOrderFront ( nil )
309- }
310311 }
311312 }
312313
@@ -354,8 +355,8 @@ extension AppDelegate {
354355
355356 Task { @MainActor [ weak self] in
356357 guard let self else { return }
357- WindowOpener . shared . pendingConnectionId = connection. id
358- NotificationCenter . default . post ( name : . openMainWindow , object : connection . id )
358+ let payload = EditorTabPayload ( connectionId : connection. id, intent : . restoreOrDefault )
359+ WindowOpener . shared . openNativeTab ( payload )
359360
360361 defer { self . isAutoReconnecting = false }
361362 do {
0 commit comments