-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Avoid beachball during update relaunch #4988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
43e0923
ff8b446
0433c3c
3e71a96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1001,6 +1001,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| var shouldDeferInitialMainWindowBootstrapForExternalConfirmation = false | ||
| private var didBootstrapInitialMainWindow = false | ||
| private var isTerminatingApp = false | ||
| private var isUpdateRelaunchInProgress = false | ||
| private var didPersistUpdateRelaunchSnapshot = false | ||
| private var closedWindowHistorySuppressedWindowIds: Set<UUID> = [] | ||
| #if DEBUG | ||
| var closeMainWindowContainingTabIdObserverForTesting: ((UUID, Bool) -> Void)? | ||
|
|
@@ -1763,7 +1765,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| StartupBreadcrumbLog.append("appDelegate.willTerminate.begin") | ||
| isTerminatingApp = true | ||
| closeAllWebInspectorsBeforeAppTeardown() | ||
| _ = saveSessionSnapshotIncludingProcessDetectedIndexes(includeScrollback: true, removeWhenEmpty: false) | ||
| saveSessionSnapshotForAppTermination() | ||
| stopSessionAutosaveTimer() | ||
| CloudVMActionLauncher.shared.terminateAll() | ||
| CmuxSSHURLProcessLauncher.shared.terminateAll() | ||
|
|
@@ -1792,7 +1794,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
|
|
||
| func persistSessionForUpdateRelaunch() { | ||
| isTerminatingApp = true | ||
| _ = saveSessionSnapshotIncludingProcessDetectedIndexes(includeScrollback: true, removeWhenEmpty: false) | ||
| isUpdateRelaunchInProgress = true | ||
| stopSessionAutosaveTimer() | ||
| didPersistUpdateRelaunchSnapshot = saveSessionSnapshot( | ||
| includeScrollback: false, | ||
| removeWhenEmpty: false, | ||
| forceSynchronousWrite: true | ||
| ) | ||
| } | ||
|
|
||
| func configure(tabManager: TabManager, notificationStore: TerminalNotificationStore, sidebarState: SidebarState) { | ||
|
|
@@ -3687,7 +3695,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| includeScrollback: Bool, | ||
| removeWhenEmpty: Bool = false, | ||
| restorableAgentIndex: RestorableAgentSessionIndex? = nil, | ||
| surfaceResumeBindingIndex: SurfaceResumeBindingIndex? = nil | ||
| surfaceResumeBindingIndex: SurfaceResumeBindingIndex? = nil, | ||
| forceSynchronousWrite: Bool = false | ||
| ) -> Bool { | ||
| if Self.shouldSkipSessionSaveDuringRestore( | ||
| isApplyingSessionRestore: isApplyingSessionRestore, | ||
|
|
@@ -3700,7 +3709,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| } | ||
| let writeSynchronously = Self.shouldWriteSessionSnapshotSynchronously( | ||
| isTerminatingApp: isTerminatingApp, | ||
| includeScrollback: includeScrollback | ||
| includeScrollback: includeScrollback, | ||
| forceSynchronousWrite: forceSynchronousWrite | ||
| ) | ||
| if writeSynchronously { | ||
| TextBoxInputTextView.flushPendingSessionDraftAttachmentCopies() | ||
|
|
@@ -3958,14 +3968,41 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| @discardableResult | ||
| private func saveSessionSnapshotIncludingProcessDetectedIndexes( | ||
| includeScrollback: Bool, | ||
| removeWhenEmpty: Bool = false | ||
| removeWhenEmpty: Bool = false, | ||
| forceSynchronousWrite: Bool = false | ||
| ) -> Bool { | ||
| let resumeIndexes = ProcessDetectedResumeIndexes.loadSynchronously() | ||
| return saveSessionSnapshot( | ||
| includeScrollback: includeScrollback, | ||
| removeWhenEmpty: removeWhenEmpty, | ||
| restorableAgentIndex: resumeIndexes.restorableAgentIndex, | ||
| surfaceResumeBindingIndex: resumeIndexes.surfaceResumeBindingIndex | ||
| surfaceResumeBindingIndex: resumeIndexes.surfaceResumeBindingIndex, | ||
| forceSynchronousWrite: forceSynchronousWrite | ||
| ) | ||
| } | ||
|
|
||
| private func saveSessionSnapshotForAppTermination() { | ||
| guard Self.shouldSaveSessionSnapshotOnApplicationTerminate( | ||
| didPersistUpdateRelaunchSnapshot: didPersistUpdateRelaunchSnapshot | ||
| ) else { | ||
| StartupBreadcrumbLog.append("appDelegate.willTerminate.snapshotSkipped.updateRelaunch") | ||
| return | ||
| } | ||
|
|
||
| if Self.shouldUseFastSessionSnapshotForUpdateRelaunch( | ||
| isUpdateRelaunchInProgress: isUpdateRelaunchInProgress | ||
| ) { | ||
| _ = saveSessionSnapshot( | ||
| includeScrollback: false, | ||
| removeWhenEmpty: false, | ||
| forceSynchronousWrite: true | ||
| ) | ||
| return | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Rule Used: Flag Swift fixes that patch symptoms while leaving... (source) |
||
|
|
||
| _ = saveSessionSnapshotIncludingProcessDetectedIndexes( | ||
| includeScrollback: true, | ||
| removeWhenEmpty: false | ||
| ) | ||
| } | ||
|
|
||
|
|
@@ -4004,9 +4041,23 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
|
|
||
| nonisolated static func shouldWriteSessionSnapshotSynchronously( | ||
| isTerminatingApp: Bool, | ||
| includeScrollback: Bool | ||
| includeScrollback: Bool, | ||
| forceSynchronousWrite: Bool = false | ||
| ) -> Bool { | ||
| if forceSynchronousWrite { return true } | ||
| return isTerminatingApp && includeScrollback | ||
| } | ||
|
|
||
| nonisolated static func shouldSaveSessionSnapshotOnApplicationTerminate( | ||
| didPersistUpdateRelaunchSnapshot: Bool | ||
| ) -> Bool { | ||
| !didPersistUpdateRelaunchSnapshot | ||
| } | ||
|
|
||
| nonisolated static func shouldUseFastSessionSnapshotForUpdateRelaunch( | ||
| isUpdateRelaunchInProgress: Bool | ||
| ) -> Bool { | ||
| isTerminatingApp && includeScrollback | ||
| isUpdateRelaunchInProgress | ||
| } | ||
|
|
||
| nonisolated static func shouldSkipSessionAutosaveForUnchangedFingerprint( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,14 +108,22 @@ extension UpdateDriver: SPUUpdaterDelegate { | |
| } | ||
|
|
||
| func updaterWillRelaunchApplication(_ updater: SPUUpdater) { | ||
| Task { @MainActor in | ||
| AppDelegate.shared?.persistSessionForUpdateRelaunch() | ||
| TerminalController.shared.stop() | ||
| NSApp.invalidateRestorableState() | ||
| for window in NSApp.windows { | ||
| window.invalidateRestorableState() | ||
| let prepareForRelaunch = { | ||
| MainActor.assumeIsolated { | ||
| AppDelegate.shared?.persistSessionForUpdateRelaunch() | ||
| TerminalController.shared.stop() | ||
| NSApp.invalidateRestorableState() | ||
| for window in NSApp.windows { | ||
| window.invalidateRestorableState() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if Thread.isMainThread { | ||
| prepareForRelaunch() | ||
| } else { | ||
| DispatchQueue.main.sync(execute: prepareForRelaunch) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
A conforming alternative is to check Sparkle's documented thread-delivery guarantee for Rule Used: Flag new blocking or timing-based synchronization ... (source) |
||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 50373
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 8910
🏁 Script executed:
Repository: owner/repo
Length of output: 2026
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 12336
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 25784
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 11536
🏁 Script executed:
Repository: manaflow-ai/cmux
Length of output: 15512
Fix update-relaunch session snapshot:
includeScrollback: truepersists scrollback in a main-thread synchronous savepersistSessionForUpdateRelaunch()setsisTerminatingApp = trueand callssaveSessionSnapshotIncludingProcessDetectedIndexes(includeScrollback: true, ..., forceSynchronousWrite: true).updaterWillRelaunchApplication(_:)invokes this on the main thread (directly if already on main, otherwise viaDispatchQueue.main.sync). WithforceSynchronousWrite: true,saveSessionSnapshot(...)performs an immediate write (persistSessionSnapshot(..., synchronously: true)runswriteBlock()inline).Because
includeScrollbackistrue, snapshot building captures scrollback (bounded) viaTerminalController.shared.readTerminalTextForSnapshot(..., includeScrollback: true, lineLimit: SessionPersistencePolicy.maxScrollbackLinesPerTerminal)whenshouldPersistScrollback && shouldReplaySessionScrollback && hibernationState == nil. This means the relaunch snapshot is not “no scrollback” (even though it’s truncated to policy limits).If the update-relaunch path is intended to be “minimal, no scrollback”, switch
includeScrollbacktofalse(or ensure the policy conditions match that goal).🐢 Proposed change if scrollback should be excluded on the relaunch path
📝 Committable suggestion
🤖 Prompt for AI Agents