macOS: avoid holding SurfaceView when sending notifications (#13810)

We shouldn't hold a closing surface view when sending notifications and
waiting to dismiss that notification. This happens rarely, but it's the
right thing to do.

### AI Disclosure
Found by Claude when judging other branches, I applied the changes
myself.

> Forgot that after force pushing, you can't reopen #13787 🫪, linking it
here for the review history.
This commit is contained in:
Mitchell Hashimoto
2026-08-14 06:55:40 -07:00
committed by GitHub

View File

@@ -1787,20 +1787,31 @@ extension Ghostty {
// Note the callback may be executed on a background thread as documented
// so we need @MainActor since we're reading/writing view state.
Task { @MainActor in
// We use [weak self] here because we don't want to extend the surface's
// lifetime when a notification is triggered right before the surface closes.
Task { @MainActor [weak self] in
do {
try await UNUserNotificationCenter.current().add(request)
guard let focused = self?.focused else {
// We remove the notification if the surface is deallocated.
UNUserNotificationCenter.current()
.removeDeliveredNotifications(withIdentifiers: [uuid])
return
}
// We need to keep track of this notification so we can remove it
// under certain circumstances
notificationIdentifiers.insert(uuid)
self?.notificationIdentifiers.insert(uuid)
// If we're focused then we schedule to remove the notification
// after a few seconds. If we gain focus we automatically remove it
// in focusDidChange.
if self.focused {
try await Task.sleep(for: .seconds(3))
notificationIdentifiers.remove(uuid)
if focused {
// If the suspension is failed, we remove the notification anyway.
try? await Task.sleep(for: .seconds(3))
self?.notificationIdentifiers.remove(uuid)
// We remove the notification if the surface is deallocated while we wait.
UNUserNotificationCenter.current()
.removeDeliveredNotifications(withIdentifiers: [uuid])
}