From 57c1baf43ae5b576644879212ec6e9cc46284ff3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 5 Aug 2026 14:22:45 -0700 Subject: [PATCH] macos: defer overlapping clipboard completion Fixes #/13074 Overlapping clipboard confirmations now defer denial until the next main queue turn rather than completing inside the confirmation callback. This prevents the native request state from being invalidated while its callback is still active, avoiding the OSC 52 crash reported in #13074. The deferred closure retains the originating surface view and completes the ignored request with empty data, preserving the existing deny behavior. --- .../Features/Terminal/BaseTerminalController.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index 5b8d130d9..88e68af20 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -1156,10 +1156,14 @@ class BaseTerminalController: NSWindowController, guard let state = notification.userInfo?[Ghostty.Notification.ConfirmClipboardStateKey] as? UnsafeMutableRawPointer? else { return } guard let request = notification.userInfo?[Ghostty.Notification.ConfirmClipboardRequestKey] as? Ghostty.ClipboardRequest else { return } - // If we already have a clipboard confirmation view up, we ignore this request. - // This shouldn't be possible... + // If we already have a clipboard confirmation view up, ignore this + // request. Complete it on the next run loop iteration so that we don't + // invalidate the state pointer from inside its confirmation callback. guard self.clipboardConfirmation == nil else { - Ghostty.App.completeClipboardRequest(surface, data: "", state: state, confirmed: true) + DispatchQueue.main.async { + guard let surface = target.surface else { return } + Ghostty.App.completeClipboardRequest(surface, data: "", state: state, confirmed: true) + } return }