fixes crashes and filedrop fatal issue

This commit is contained in:
Austin Wang 2026-02-18 20:46:31 -08:00 committed by GitHub
parent 915e34bd38
commit 2d64ecfc44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 36 additions and 12 deletions

View file

@ -196,19 +196,31 @@ final class FileDropOverlayView: NSView {
// MARK: Mouse forwarding safety net for the rare case where stale drag pasteboard
// data causes hitTest to return self when no drag is actually active.
// The isForwarding guard prevents infinite recursion: sendEvent mouseDown
// forwardEvent sendEvent, which can stack overflow when gesture recognizer
// routing re-delivers the event despite isHidden.
private var isForwarding = false
// We hit-test contentView directly and dispatch to the target rather than using
// window.sendEvent(), which caches the mouse target and causes infinite recursion.
private func forwardEvent(_ event: NSEvent) {
guard !isForwarding else { return }
isForwarding = true
guard let window, let contentView = window.contentView,
let themeFrame = contentView.superview else { return }
isHidden = true
window?.sendEvent(event)
let point = themeFrame.convert(event.locationInWindow, from: nil)
let target = contentView.hitTest(point)
isHidden = false
isForwarding = false
guard let target else { return }
switch event.type {
case .leftMouseDown: target.mouseDown(with: event)
case .leftMouseUp: target.mouseUp(with: event)
case .leftMouseDragged: target.mouseDragged(with: event)
case .rightMouseDown: target.rightMouseDown(with: event)
case .rightMouseUp: target.rightMouseUp(with: event)
case .rightMouseDragged: target.rightMouseDragged(with: event)
case .otherMouseDown: target.otherMouseDown(with: event)
case .otherMouseUp: target.otherMouseUp(with: event)
case .otherMouseDragged: target.otherMouseDragged(with: event)
case .scrollWheel: target.scrollWheel(with: event)
default: break
}
}
override func mouseDown(with event: NSEvent) { forwardEvent(event) }

View file

@ -2132,9 +2132,21 @@ private struct OmnibarTextFieldRepresentable: NSViewRepresentable {
firstResponder === nsView ||
((firstResponder as? NSTextView)?.delegate as? NSTextField) === nsView
if isFocused, !isFirstResponder {
window.makeFirstResponder(nsView)
// Defer to avoid triggering input method XPC during layout pass,
// which can crash via re-entrant view hierarchy modification.
DispatchQueue.main.async { [weak nsView] in
guard let nsView, let window = nsView.window else { return }
window.makeFirstResponder(nsView)
}
} else if !isFocused, isFirstResponder {
window.makeFirstResponder(nil)
DispatchQueue.main.async { [weak nsView] in
guard let nsView, let window = nsView.window else { return }
let fr = window.firstResponder
let stillFirst = fr === nsView ||
((fr as? NSTextView)?.delegate as? NSTextField) === nsView
guard stillFirst else { return }
window.makeFirstResponder(nil)
}
}
}

@ -1 +1 @@
Subproject commit a06b95531ead59479d4655b314f2b86cb4cc4c84
Subproject commit 1da02f8acbe6ba7ee90b720d8328941b62f73f8b