Chapter 2.3  ·  Gate 02.3 ·  The App Environment

Window Restoration

The platform restores last session’s windows at a moment when the app hasn’t yet decided whether it’s allowed to show any. This subchapter covers the restoration coordinator that holds every restored window until the startup gates resolve, then shows or replays it.

Why restoration needs a coordinator

The platform triggers window restoration between will-finish-launching and did-finish-launching — before phase 2 of Startup has had a chance to decide whether a gate needs to show. A restored window can’t simply appear the moment the platform hands it back, or it would appear behind (or before) an onboarding screen that hasn’t been decided yet. A restoration coordinator resolves this: it holds each restored window until the startup-gate decision is final, then either shows it immediately or replays it once the gate clears.

static func restoreWindow(
    withIdentifier identifier: NSUserInterfaceItemIdentifier,
    state: NSCoder,
    completionHandler: @escaping (NSWindow?, Error?) -> Void
) {
    guard let window = window(for: identifier, state: state) else {
        completionHandler(nil, nil)
        return
    }

    if AppStatus.shared.startupMode == .normal {
        completionHandler(window, nil)   // no gate pending — show it now
    } else {
        // hold until the gate resolves, then replay
        shared.store(RestoredWindow(window: window, completionHandler: completionHandler))
    }
}

The deferred windows surface again in phase 4: launch shows whatever the coordinator held back, and only opens a default window if nothing was restored at all.

What a window restores

Restoration hands back windows, not app state — what a window shows is re-derived, not deserialized. Persist identifiers in the window’s NSCoder state (a selected notebook’s ID, not the notebook), and re-resolve them against whatever the Model layer has actually loaded once launch completes. Chapter 9 covers this identifier-not-object rule in full, because it’s the same rule navigation state lives by everywhere, not just at restoration time.