33// TablePro
44//
55// Bridges SwiftUI's openWindow environment action to imperative code.
6- // Stored by ContentView on appear so MainContentCommandActions can open native tabs .
6+ // Stored on appear by ContentView, WelcomeViewModel, or ConnectionFormView .
77//
88
99import os
@@ -15,40 +15,42 @@ internal final class WindowOpener {
1515
1616 internal static let shared = WindowOpener ( )
1717
18- /// Set by ContentView when it appears. Safe to store — OpenWindowAction is app-scoped, not view-scoped.
18+ /// Set on appear by ContentView, WelcomeViewModel, or ConnectionFormView.
19+ /// Safe to store — OpenWindowAction is app-scoped, not view-scoped.
1920 internal var openWindow : OpenWindowAction ?
2021
21- /// Payloads for windows that have been requested but not yet acknowledged
22- /// by MainContentView.configureWindow. Keyed by payload.id .
23- /// Stores connectionId so windowDidBecomeKey can compute tabbingIdentifier
24- /// synchronously (before SwiftUI renders) to avoid flicker .
25- internal private( set) var pendingPayloads : [ UUID : UUID ] = [ : ] // [payloadId: connectionId ]
22+ /// Ordered queue of pending payloads — windows requested via openNativeTab
23+ /// but not yet acknowledged by MainContentView.configureWindow .
24+ /// Ordered so consumeOldestPendingConnectionId returns the correct entry
25+ /// when multiple windows open in quick succession (e.g., tab restore) .
26+ internal private( set) var pendingPayloads : [ ( id : UUID , connectionId : UUID ) ] = [ ]
2627
2728 /// Whether any payloads are pending — used for orphan detection in windowDidBecomeKey.
2829 internal var hasPendingPayloads : Bool { !pendingPayloads. isEmpty }
2930
3031 /// Opens a new native window tab with the given payload.
32+ /// Falls back to .openMainWindow notification if openWindow is not yet available
33+ /// (cold launch from Dock menu before any SwiftUI view has appeared).
3134 internal func openNativeTab( _ payload: EditorTabPayload ) {
32- pendingPayloads [ payload. id] = payload. connectionId
33- guard let openWindow else {
34- Self . logger. warning ( " openNativeTab called before openWindow was set — payload dropped " )
35- pendingPayloads. removeValue ( forKey: payload. id)
36- return
35+ pendingPayloads. append ( ( id: payload. id, connectionId: payload. connectionId) )
36+ if let openWindow {
37+ openWindow ( id: " main " , value: payload)
38+ } else {
39+ Self . logger. info ( " openWindow not set — falling back to .openMainWindow notification " )
40+ NotificationCenter . default. post ( name: . openMainWindow, object: payload)
3741 }
38- openWindow ( id: " main " , value: payload)
3942 }
4043
4144 /// Called by MainContentView.configureWindow after the window is fully set up.
4245 internal func acknowledgePayload( _ id: UUID ) {
43- pendingPayloads. removeValue ( forKey : id )
46+ pendingPayloads. removeAll { $0 . id == id }
4447 }
4548
4649 /// Consumes and returns the connectionId for the oldest pending payload.
47- /// Removes the entry so subsequent calls don't return stale data.
48- internal func consumeAnyPendingConnectionId( ) -> UUID ? {
49- guard let first = pendingPayloads. first else { return nil }
50- pendingPayloads. removeValue ( forKey: first. key)
51- return first. value
50+ /// Removes the entry so subsequent calls return the next payload in order.
51+ internal func consumeOldestPendingConnectionId( ) -> UUID ? {
52+ guard !pendingPayloads. isEmpty else { return nil }
53+ return pendingPayloads. removeFirst ( ) . connectionId
5254 }
5355
5456 /// Returns the tabbingIdentifier for a connection.
0 commit comments