From 410b1816ada7b6d6cbcd34c03767689e0164d304 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 9 Sep 2022 07:39:38 +0530 Subject: [PATCH] More work on cocoa clipboard backend --- glfw/cocoa_window.m | 77 +++++++++++++++++++++++++++++++++++++++++++-- glfw/x11_window.c | 4 +-- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 5f386fe09..c43226bd5 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -2538,18 +2538,91 @@ list_clipboard_mimetypes(GLFWclipboardwritedatafun write_data, void *object) { #undef w } +static void +get_text_plain(GLFWclipboardwritedatafun write_data, void *object) { + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES}; + NSArray* objs = [pasteboard readObjectsForClasses:@[[NSURL class], [NSString class]] options:options]; + bool found = false; + if (objs) { + const NSUInteger count = [objs count]; + if (count) { + NSMutableString *path_list = [NSMutableString stringWithCapacity:4096]; // auto-released + NSMutableString *text_list = [NSMutableString stringWithCapacity:4096]; // auto-released + for (NSUInteger i = 0; i < count; i++) { + id obj = objs[i]; + if ([obj isKindOfClass:[NSURL class]]) { + NSURL *url = (NSURL*)obj; + if (url.fileURL && url.fileSystemRepresentation) { + if ([path_list length] > 0) [path_list appendString:@("\n")]; + [path_list appendString:@(url.fileSystemRepresentation)]; + } + } else if ([obj isKindOfClass:[NSString class]]) { + if ([text_list length] > 0) [text_list appendString:@("\n")]; + [text_list appendString:obj]; + } + } + const char *text = NULL; + if (path_list.length > 0) text = [path_list UTF8String]; + else if (text_list.length > 0) text = [text_list UTF8String]; + if (text) { + found = true; + write_data(object, text, strlen(text)); + } + } + } + if (!found) _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to retrieve text/plain from pasteboard"); +} + void _glfwPlatformGetClipboard(GLFWClipboardType clipboard_type, const char* mime_type, GLFWclipboardwritedatafun write_data, void *object) { if (clipboard_type != GLFW_CLIPBOARD) return; - (void)mime_type; (void) write_data; (void) object; if (mime_type == NULL) { list_clipboard_mimetypes(write_data, object); return; } + if (strcmp(mime_type, "text/plain") == 0) { + get_text_plain(write_data, object); + return; + } } -void _glfwPlatformSetClipboard(GLFWClipboardType t) { +static NSMutableData* +get_clipboard_data(const _GLFWClipboardData *cd, const char *mime) { + NSMutableData *ans = [NSMutableData dataWithCapacity:8192]; + if (ans == nil) return nil; + GLFWDataChunk chunk = cd->get_data(mime, NULL, cd->ctype); + void *iter = chunk.iter; + if (!iter) return ans; + while (true) { + chunk = cd->get_data(mime, iter, cd->ctype); + if (!chunk.sz) break; + [ans appendBytes:chunk.data length:chunk.sz]; + if (chunk.free) chunk.free((void*)chunk.free_data); + } + cd->get_data(NULL, iter, cd->ctype); + return ans; +} + + +void +_glfwPlatformSetClipboard(GLFWClipboardType t) { if (t != GLFW_CLIPBOARD) return; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + if (@available(macOS 11.0, *)) { + } else { + for (size_t i = 0; i < _glfw.clipboard.num_mime_types; i++) { + const char *mime = _glfw.clipboard.mime_types[i]; + if (strcmp(mime, "text/plain") == 0) { + NSMutableData *data = get_clipboard_data(&_glfw.clipboard, mime); // auto-released + if (data != nil) { + [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; + [pasteboard setData:data forType:NSPasteboardTypeString]; + } + } + } + return; + } } // }}} diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 4e9989e5e..b59455775 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -822,7 +822,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { char *data = NULL; size_t sz = get_clipboard_data(cd, aa->array[j].mime, &data); - if (data && sz) XChangeProperty(_glfw.x11.display, + if (data) XChangeProperty(_glfw.x11.display, request->requestor, targets[i + 1], targets[i], @@ -876,7 +876,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) // The requested target is one we support char *data = NULL; size_t sz = get_clipboard_data(cd, aa->array[i].mime, &data); - if (data && sz) XChangeProperty(_glfw.x11.display, + if (data) XChangeProperty(_glfw.x11.display, request->requestor, request->property, request->target,