fix(launch): open files passed at cold launch instead of the welcome screen (#1443)#1449
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e45320e26e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await LaunchIntentRouter.shared.route(intent) | ||
| } | ||
| if !intents.isEmpty { | ||
| WindowOpener.shared.orderOutWelcome() |
There was a problem hiding this comment.
Keep welcome visible when routing fails
When a collected launch intent is recognized but cannot actually be opened (for example a stale tablepro deep link whose connection is missing, or an inspector document that NSDocumentController rejects), LaunchIntentRouter.route handles the error internally and returns Void, so this branch cannot tell success from failure. Because finalizeWindowsIfNoVisibleMain is skipped whenever intents is non-empty, hiding the welcome window here can leave a cold-launched app with no visible window and may also remove the window that the error sheet was attached to; only dismiss the welcome window after routing has produced a visible target window or after route success is observable.
Useful? React with 👍 / 👎.
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
Fixes #1443.
Problem
When TablePro is closed and the user double-clicks a
.csvfile in Finder (with TablePro as the default app for CSV), TablePro launches and shows its welcome screen. The CSV that triggered the launch is never opened.Root cause
On cold launch, macOS calls
application(_:open:)betweenapplicationWillFinishLaunchingandapplicationDidFinishLaunching.URLClassifier.classifyFilequeriesPluginManager.allInspectorFileExtensions, butPluginManager.shared.loadPlugins()ran insideapplicationDidFinishLaunching(42ms too late, verified by the existing OSLog instrumentation). At the moment the open event arrived,lazyInspectorFileExtensionswas empty, the classifier returnednil, the URL was silently dropped with anUnrecognized URLwarning, anddeliver([])early-returned. The 150ms intent-collection timer inAppLaunchCoordinatorthen fired with no intents,finalizeWindowsIfNoVisibleMainshowed the welcome window, and the CSV never opened.Captured cold-launch log:
Same class of issue would have applied to any inspector file type the plugin system registers (TSV, future inspectors), not just CSV.
Fix
AppDelegate—PluginManager.shared.loadPlugins()moves fromapplicationDidFinishLaunchingtoapplicationWillFinishLaunching, right after the existingInspectorDocumentController().InspectorDocumentController.typeForContents(of:)already readsallInspectorFileExtensions, so putting plugin load next to it matches the existing precedent for "must be ready before any file-open event." The synchronous lazy-manifest registration insideloadPluginspopulateslazyInspectorFileExtensionsbefore returning; the async eager-loadingTaskcontinues in the background, unchanged.AppLaunchCoordinator—WindowOpener.shared.orderOutWelcome()is now called after intents are routed in both code paths:deliver's warm-launch branch andtransitionToRouting's cold-launch branch. The pre-existingorderOutloop indeliver's accepting-phase branch only ran duringapplication(_:open:), when SwiftUI had not yet auto-shown the welcomeWindowscene, soNSApp.windowswas empty and the loop was a no-op. The post-routing dismissal is deterministic and runs after SwiftUI has had a chance to show the welcome window.Verification
Cold-launch reproduction with logging on the patched build:
application(_:open:)receives the URL, classifier returns.openInspectorFile, the intent is captured inpendingIntents,transitionToRoutingroutes it throughNSDocumentController.openDocument, the CSV inspector window opens, and the welcome window is dismissed.One caveat: the welcome window may briefly flash (≤150ms, the intent-collection window) before being dismissed, because SwiftUI auto-shows the first
Windowscene duringdidFinishLaunchingand macOS 14 has no API to suppress that (defaultLaunchBehavior(.suppressed)is macOS 15+). Eliminating the flash entirely would require replacing the SwiftUI welcomeWindowscene with an AppKitNSWindowControllermanaged byWindowOpener. Out of scope for this fix.Tests
Not added. The bug is a singleton-lifecycle ordering race across
AppDelegate,AppLaunchCoordinator,WindowOpener,LaunchIntentRouter, andPluginManager. A meaningful regression test would need invasive dependency injection across all of them. The existing OSLog instrumentation (AppDelegate.application(_:open:),AppLaunchCoordinator.handleOpenURLs,LaunchIntentRouter.openInspectorDocument) makes the cold-launch reproduction the practical verification path.