macos: correct SurfaceView supported send/receive types for services

Fixes #8785

This is the callback AppKit sends when it wants to know if our
application can handle sending and receiving certain types of data.

The prior implementaiton was incorrect and would erroneously claim
support over combinations that we couldn't handle (at least, at the
SurfaceView layer). 

This corrects the implementation. The services we expect still show up
and the error in 8785 goes away.
This commit is contained in:
Mitchell Hashimoto
2025-09-19 11:44:37 -07:00
parent 1b6cda2b10
commit d27bc69f2e

View File

@@ -1815,18 +1815,39 @@ extension Ghostty.SurfaceView: NSServicesMenuRequestor {
forSendType sendType: NSPasteboard.PasteboardType?,
returnType: NSPasteboard.PasteboardType?
) -> Any? {
// Types that we accept sent to us
let accepted: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")]
// This function confused me a bit so I'm going to add my own commentary on
// how this works. macOS sends this callback with the given send/return types and
// we must return the responder capable of handling the COMBINATION of those send
// and return types (or super up if we can't handle it).
//
// The "COMBINATION" bit is key: we might get sent a string (we can handle that)
// but get requested an image (we can't handle that at the time of writing this),
// so we must bubble up.
// Types we can receive
let receivable: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")]
// Types that we can send. Currently the same as receivable but I'm separating
// this out so we can modify this in the future.
let sendable: [NSPasteboard.PasteboardType] = receivable
// The sendable types that require a selection (currently all)
let sendableRequiresSelection = sendable
// We can always receive the accepted types
if (returnType == nil || accepted.contains(returnType!)) {
return self
}
// If we have a selection we can send the accepted types too
if ((self.surface != nil && ghostty_surface_has_selection(self.surface)) &&
(sendType == nil || accepted.contains(sendType!))
) {
// If we expect no data to be sent/received we can obviously handle it (that's
// the nil check), otherwise it must conform to the types we support on both sides.
if (returnType == nil || receivable.contains(returnType!)) &&
(sendType == nil || sendable.contains(sendType!)) {
// If we're expected to send back a type that requires selection, then
// verify that we have a selection. We do this within this block because
// validateRequestor is called a LOT and we want to prevent unnecessary
// performance hits because `ghostty_surface_has_selection` isn't free.
if let sendType, sendableRequiresSelection.contains(sendType) {
if surface == nil || !ghostty_surface_has_selection(surface) {
return super.validRequestor(forSendType: sendType, returnType: returnType)
}
}
return self
}