diff --git a/src/video/cocoa/SDL_cocoaclipboard.h b/src/video/cocoa/SDL_cocoaclipboard.h index 72756a4db..bad760cf8 100644 --- a/src/video/cocoa/SDL_cocoaclipboard.h +++ b/src/video/cocoa/SDL_cocoaclipboard.h @@ -30,5 +30,10 @@ extern int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text); extern char *Cocoa_GetClipboardText(SDL_VideoDevice *_this); extern SDL_bool Cocoa_HasClipboardText(SDL_VideoDevice *_this); extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data); +extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, size_t *len, const char *mime_type); +extern SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type); +extern int Cocoa_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count, + const char **mime_types, void *userdata); + #endif /* SDL_cocoaclipboard_h_ */ diff --git a/src/video/cocoa/SDL_cocoaclipboard.m b/src/video/cocoa/SDL_cocoaclipboard.m index ad424707c..c54a76c18 100644 --- a/src/video/cocoa/SDL_cocoaclipboard.m +++ b/src/video/cocoa/SDL_cocoaclipboard.m @@ -25,6 +25,50 @@ #include "SDL_cocoavideo.h" #include "../../events/SDL_clipboardevents_c.h" +@interface Cocoa_PasteboardDataProvider : NSObject +{ + SDL_ClipboardDataCallback m_callback; + void *m_userdata; +} +@end + +@implementation Cocoa_PasteboardDataProvider + +- (nullable instancetype)initWith:(SDL_ClipboardDataCallback)callback + userData:(void *)userdata +{ + self = [super init]; + if (!self) { + return self; + } + m_callback = callback; + m_userdata = userdata; + return self; +} + +- (void)pasteboard:(NSPasteboard *)pasteboard + item:(NSPasteboardItem *)item +provideDataForType:(NSPasteboardType)type +{ + @autoreleasepool { + size_t size = 0; + CFStringRef mimeType; + void *callbackData; + NSData *data; + mimeType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)type, kUTTagClassMIMEType); + callbackData = m_callback(&size, [(__bridge NSString *)mimeType UTF8String], m_userdata); + CFRelease(mimeType); + if (callbackData == NULL || size == 0) { + return; + } + data = [NSData dataWithBytes: callbackData length: size]; + [item setData: data forType: type]; + } +} + +@end + + int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text) { @autoreleasepool { @@ -103,4 +147,81 @@ void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data) } } +void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, size_t *len, const char *mime_type) +{ + @autoreleasepool { + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSData *itemData; + void *data; + *len = 0; + for (NSPasteboardItem *item in [pasteboard pasteboardItems]) { + CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8); + CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); + CFRelease(mimeType); + itemData = [item dataForType: (__bridge NSString *)utiType]; + CFRelease(utiType); + if (itemData != nil) { + *len = (size_t)[itemData length]; + data = malloc(*len); + [itemData getBytes: data length: *len]; + return data; + } + } + return nil; + } +} + +SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) +{ + + SDL_bool result = SDL_FALSE; + @autoreleasepool { + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8); + CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); + CFRelease(mimeType); + if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) { + result = SDL_TRUE; + } + CFRelease(utiType); + } + return result; + +} + +int Cocoa_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count, + const char **mime_types, void *userdata) +{ + @autoreleasepool { + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSPasteboardItem *newItem = [NSPasteboardItem new]; + NSMutableArray *utiTypes = [NSMutableArray new]; + Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: callback userData: userdata]; + BOOL itemResult = FALSE; + BOOL writeResult = FALSE; + SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata; + + for (int i = 0; i < mime_count; i++) { + CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_types[i], kCFStringEncodingUTF8); + CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); + CFRelease(mimeType); + + [utiTypes addObject: (__bridge NSString *)utiType]; + CFRelease(utiType); + } + itemResult = [newItem setDataProvider: provider forTypes: utiTypes]; + if (itemResult == FALSE) { + return SDL_SetError("Unable to set clipboard item data"); + } + + [pasteboard clearContents]; + writeResult = [pasteboard writeObjects: @[newItem]]; + if (writeResult == FALSE) { + return SDL_SetError("Unable to set clipboard data"); + } + data.clipboard_count = [pasteboard changeCount]; + } + return 0; +} + #endif /* SDL_VIDEO_DRIVER_COCOA */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index d8e939f93..cc4d38489 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -175,6 +175,10 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void) device->GetClipboardText = Cocoa_GetClipboardText; device->HasClipboardText = Cocoa_HasClipboardText; + device->GetClipboardData = Cocoa_GetClipboardData; + device->HasClipboardData = Cocoa_HasClipboardData; + device->SetClipboardData = Cocoa_SetClipboardData; + device->free = Cocoa_DeleteDevice; device->quirk_flags = VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT;