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?, forSendType sendType: NSPasteboard.PasteboardType?,
returnType: NSPasteboard.PasteboardType? returnType: NSPasteboard.PasteboardType?
) -> Any? { ) -> Any? {
// Types that we accept sent to us // This function confused me a bit so I'm going to add my own commentary on
let accepted: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")] // 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.
// We can always receive the accepted types // Types we can receive
if (returnType == nil || accepted.contains(returnType!)) { let receivable: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")]
return self
// 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
// 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)
}
} }
// 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!))
) {
return self return self
} }