diff --git a/app/internal/window/os_darwin.go b/app/internal/window/os_darwin.go index 5b8467d6..7ccb7b1d 100644 --- a/app/internal/window/os_darwin.go +++ b/app/internal/window/os_darwin.go @@ -3,9 +3,17 @@ package window /* +#include + __attribute__ ((visibility ("hidden"))) void gio_wakeupMainThread(void); +__attribute__ ((visibility ("hidden"))) NSUInteger gio_nsstringLength(CFTypeRef str); +__attribute__ ((visibility ("hidden"))) void gio_nsstringGetCharacters(CFTypeRef str, unichar *chars, NSUInteger loc, NSUInteger length); */ import "C" +import ( + "unicode/utf16" + "unsafe" +) var mainFuncs = make(chan func(), 1) @@ -28,3 +36,14 @@ func gio_dispatchMainFuncs() { } } } + +// nsstringToString converts a NSString to a Go string, and +// releases the original string. +func nsstringToString(str C.CFTypeRef) string { + defer C.CFRelease(str) + n := C.gio_nsstringLength(str) + chars := make([]uint16, n) + C.gio_nsstringGetCharacters(str, (*C.unichar)(unsafe.Pointer(&chars[0])), 0, n) + utf8 := utf16.Decode(chars) + return string(utf8) +} diff --git a/app/internal/window/os_darwin.m b/app/internal/window/os_darwin.m index 37544dfd..dc4f00b7 100644 --- a/app/internal/window/os_darwin.m +++ b/app/internal/window/os_darwin.m @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Unlicense OR MIT @import Dispatch; +@import Foundation; #include "_cgo_export.h" @@ -9,3 +10,13 @@ void gio_wakeupMainThread(void) { gio_dispatchMainFuncs(); }); } + +NSUInteger gio_nsstringLength(CFTypeRef cstr) { + NSString *str = (__bridge NSString *)cstr; + return [str length]; +} + +void gio_nsstringGetCharacters(CFTypeRef cstr, unichar *chars, NSUInteger loc, NSUInteger length) { + NSString *str = (__bridge NSString *)cstr; + [str getCharacters:chars range:NSMakeRange(loc, length)]; +} diff --git a/app/internal/window/os_macos.go b/app/internal/window/os_macos.go index b6f2804b..3e0fa5d6 100644 --- a/app/internal/window/os_macos.go +++ b/app/internal/window/os_macos.go @@ -11,6 +11,7 @@ import ( "sync" "time" "unicode" + "unicode/utf16" "unsafe" "gioui.org/f32" @@ -24,7 +25,6 @@ import ( /* #cgo CFLAGS: -DGL_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c - #include #define GIO_MOUSE_MOVE 1 @@ -37,6 +37,8 @@ __attribute__ ((visibility ("hidden"))) CGFloat gio_viewHeight(CFTypeRef viewRef __attribute__ ((visibility ("hidden"))) void gio_setAnimating(CFTypeRef viewRef, BOOL anim); __attribute__ ((visibility ("hidden"))) void gio_updateDisplayLink(CFTypeRef viewRef, CGDirectDisplayID dispID); __attribute__ ((visibility ("hidden"))) CGFloat gio_getViewBackingScale(CFTypeRef viewRef); +__attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void); +__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length); */ import "C" @@ -89,6 +91,24 @@ func (w *window) contextView() C.CFTypeRef { return w.view } +func (w *window) ReadClipboard() { + runOnMain(func() { + content := nsstringToString(C.gio_readClipboard()) + w.w.Event(system.ClipboardEvent{Text: content}) + }) +} + +func (w *window) WriteClipboard(s string) { + u16 := utf16.Encode([]rune(s)) + runOnMain(func() { + var chars *C.unichar + if len(u16) > 0 { + chars = (*C.unichar)(unsafe.Pointer(&u16[0])) + } + C.gio_writeClipboard(chars, C.NSUInteger(len(u16))) + }) +} + func (w *window) ShowTextInput(show bool) {} func (w *window) SetAnimating(anim bool) { diff --git a/app/internal/window/os_macos.m b/app/internal/window/os_macos.m index b6804a67..19705f8e 100644 --- a/app/internal/window/os_macos.m +++ b/app/internal/window/os_macos.m @@ -46,6 +46,26 @@ } @end +void gio_writeClipboard(unichar *chars, NSUInteger length) { + @autoreleasepool { + NSString *s = [NSString string]; + if (length > 0) { + s = [NSString stringWithCharacters:chars length:length]; + } + NSPasteboard *p = NSPasteboard.generalPasteboard; + [p declareTypes:@[NSPasteboardTypeString] owner:nil]; + [p setString:s forType:NSPasteboardTypeString]; + } +} + +CFTypeRef gio_readClipboard(void) { + @autoreleasepool { + NSPasteboard *p = NSPasteboard.generalPasteboard; + NSString *content = [p stringForType:NSPasteboardTypeString]; + return (__bridge_retained CFTypeRef)content; + } +} + CGFloat gio_viewHeight(CFTypeRef viewRef) { NSView *view = (__bridge NSView *)viewRef; return [view bounds].size.height;