mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
app: [macOS,iOS] don't use [NSString UTF8String]
UTF8String is lossy in the presence of nul (\x00) runes. While here, don't CFRelease the input to nsstringToString; leave it up to the caller. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+21
-3
@@ -28,6 +28,16 @@ static void nsstringGetCharacters(CFTypeRef cstr, unichar *chars, NSUInteger loc
|
|||||||
NSString *str = (__bridge NSString *)cstr;
|
NSString *str = (__bridge NSString *)cstr;
|
||||||
[str getCharacters:chars range:NSMakeRange(loc, length)];
|
[str getCharacters:chars range:NSMakeRange(loc, length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CFTypeRef newNSString(unichar *chars, NSUInteger length) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSString *s = [NSString string];
|
||||||
|
if (length > 0) {
|
||||||
|
s = [NSString stringWithCharacters:chars length:length];
|
||||||
|
}
|
||||||
|
return CFBridgingRetain(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
@@ -89,13 +99,11 @@ func gio_dispatchMainFuncs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nsstringToString converts a NSString to a Go string, and
|
// nsstringToString converts a NSString to a Go string.
|
||||||
// releases the original string.
|
|
||||||
func nsstringToString(str C.CFTypeRef) string {
|
func nsstringToString(str C.CFTypeRef) string {
|
||||||
if str == 0 {
|
if str == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
defer C.CFRelease(str)
|
|
||||||
n := C.nsstringLength(str)
|
n := C.nsstringLength(str)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -106,6 +114,16 @@ func nsstringToString(str C.CFTypeRef) string {
|
|||||||
return string(utf8)
|
return string(utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stringToNSString converts a Go string to a retained NSString.
|
||||||
|
func stringToNSString(str string) C.CFTypeRef {
|
||||||
|
u16 := utf16.Encode([]rune(str))
|
||||||
|
var chars *C.unichar
|
||||||
|
if len(u16) > 0 {
|
||||||
|
chars = (*C.unichar)(unsafe.Pointer(&u16[0]))
|
||||||
|
}
|
||||||
|
return C.newNSString(chars, C.NSUInteger(len(u16)))
|
||||||
|
}
|
||||||
|
|
||||||
func NewDisplayLink(callback func()) (*displayLink, error) {
|
func NewDisplayLink(callback func()) (*displayLink, error) {
|
||||||
d := &displayLink{
|
d := &displayLink{
|
||||||
callback: callback,
|
callback: callback,
|
||||||
|
|||||||
+5
-3
@@ -226,9 +226,9 @@ func onDeleteBackward(view C.CFTypeRef) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export onText
|
//export onText
|
||||||
func onText(view C.CFTypeRef, str *C.char) {
|
func onText(view, str C.CFTypeRef) {
|
||||||
w := views[view]
|
w := views[view]
|
||||||
w.w.EditorInsert(C.GoString(str))
|
w.w.EditorInsert(nsstringToString(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export onTouch
|
//export onTouch
|
||||||
@@ -259,7 +259,9 @@ func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) ReadClipboard() {
|
func (w *window) ReadClipboard() {
|
||||||
content := nsstringToString(C.readClipboard())
|
cstr := C.readClipboard()
|
||||||
|
defer C.CFRelease(cstr)
|
||||||
|
content := nsstringToString(cstr)
|
||||||
w.w.Event(clipboard.Event{Text: content})
|
w.w.Event(clipboard.Event{Text: content})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -179,7 +179,7 @@ NSArray<UIKeyCommand *> *_keyCommands;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertText:(NSString *)text {
|
- (void)insertText:(NSString *)text {
|
||||||
onText((__bridge CFTypeRef)self, (char *)text.UTF8String);
|
onText((__bridge CFTypeRef)self, (__bridge CFTypeRef)text);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)canBecomeFirstResponder {
|
- (BOOL)canBecomeFirstResponder {
|
||||||
|
|||||||
+19
-25
@@ -11,8 +11,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf16"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/io/clipboard"
|
"gioui.org/io/clipboard"
|
||||||
@@ -36,14 +34,11 @@ import (
|
|||||||
|
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_main(void);
|
__attribute__ ((visibility ("hidden"))) void gio_main(void);
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createView(void);
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createView(void);
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
||||||
|
|
||||||
static void writeClipboard(unichar *chars, NSUInteger length) {
|
static void writeClipboard(CFTypeRef str) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSString *s = [NSString string];
|
NSString *s = (__bridge NSString *)str;
|
||||||
if (length > 0) {
|
|
||||||
s = [NSString stringWithCharacters:chars length:length];
|
|
||||||
}
|
|
||||||
NSPasteboard *p = NSPasteboard.generalPasteboard;
|
NSPasteboard *p = NSPasteboard.generalPasteboard;
|
||||||
[p declareTypes:@[NSPasteboardTypeString] owner:nil];
|
[p declareTypes:@[NSPasteboardTypeString] owner:nil];
|
||||||
[p setString:s forType:NSPasteboardTypeString];
|
[p setString:s forType:NSPasteboardTypeString];
|
||||||
@@ -144,9 +139,9 @@ static NSRect getScreenFrame(CFTypeRef windowRef) {
|
|||||||
return [[window screen] frame];
|
return [[window screen] frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setTitle(CFTypeRef windowRef, const char *title) {
|
static void setTitle(CFTypeRef windowRef, CFTypeRef titleRef) {
|
||||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
NSWindow *window = (__bridge NSWindow *)windowRef;
|
||||||
window.title = [NSString stringWithUTF8String: title];
|
window.title = (__bridge NSString *)titleRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CFTypeRef layerForView(CFTypeRef viewRef) {
|
static CFTypeRef layerForView(CFTypeRef viewRef) {
|
||||||
@@ -229,17 +224,16 @@ func (w *window) contextView() C.CFTypeRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) ReadClipboard() {
|
func (w *window) ReadClipboard() {
|
||||||
content := nsstringToString(C.readClipboard())
|
cstr := C.readClipboard()
|
||||||
|
defer C.CFRelease(cstr)
|
||||||
|
content := nsstringToString(cstr)
|
||||||
w.w.Event(clipboard.Event{Text: content})
|
w.w.Event(clipboard.Event{Text: content})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) WriteClipboard(s string) {
|
func (w *window) WriteClipboard(s string) {
|
||||||
u16 := utf16.Encode([]rune(s))
|
cstr := stringToNSString(s)
|
||||||
var chars *C.unichar
|
defer C.CFRelease(cstr)
|
||||||
if len(u16) > 0 {
|
C.writeClipboard(cstr)
|
||||||
chars = (*C.unichar)(unsafe.Pointer(&u16[0]))
|
|
||||||
}
|
|
||||||
C.writeClipboard(chars, C.NSUInteger(len(u16)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) updateWindowMode() {
|
func (w *window) updateWindowMode() {
|
||||||
@@ -338,8 +332,8 @@ func (w *window) Configure(options []Option) {
|
|||||||
func (w *window) setTitle(prev, cnf Config) {
|
func (w *window) setTitle(prev, cnf Config) {
|
||||||
if prev.Title != cnf.Title {
|
if prev.Title != cnf.Title {
|
||||||
w.config.Title = cnf.Title
|
w.config.Title = cnf.Title
|
||||||
title := C.CString(cnf.Title)
|
title := stringToNSString(cnf.Title)
|
||||||
defer C.free(unsafe.Pointer(title))
|
defer C.CFRelease(title)
|
||||||
C.setTitle(w.window, title)
|
C.setTitle(w.window, title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,8 +385,8 @@ func (w *window) setStage(stage system.Stage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export gio_onKeys
|
//export gio_onKeys
|
||||||
func gio_onKeys(view C.CFTypeRef, cstr *C.char, ti C.double, mods C.NSUInteger, keyDown C.bool) {
|
func gio_onKeys(view, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) {
|
||||||
str := C.GoString(cstr)
|
str := nsstringToString(cstr)
|
||||||
kmods := convertMods(mods)
|
kmods := convertMods(mods)
|
||||||
ks := key.Release
|
ks := key.Release
|
||||||
if keyDown {
|
if keyDown {
|
||||||
@@ -411,8 +405,8 @@ func gio_onKeys(view C.CFTypeRef, cstr *C.char, ti C.double, mods C.NSUInteger,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export gio_onText
|
//export gio_onText
|
||||||
func gio_onText(view C.CFTypeRef, cstr *C.char) {
|
func gio_onText(view, cstr C.CFTypeRef) {
|
||||||
str := C.GoString(cstr)
|
str := nsstringToString(cstr)
|
||||||
w := mustView(view)
|
w := mustView(view)
|
||||||
w.w.EditorInsert(str)
|
w.w.EditorInsert(str)
|
||||||
}
|
}
|
||||||
@@ -579,7 +573,7 @@ func newWindow(win *callbacks, options []Option) error {
|
|||||||
}
|
}
|
||||||
errch <- nil
|
errch <- nil
|
||||||
w.w = win
|
w.w = win
|
||||||
w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0)
|
w.window = C.gio_createWindow(w.view, 0, 0, 0, 0, 0, 0)
|
||||||
win.SetDriver(w)
|
win.SetDriver(w)
|
||||||
w.Configure(options)
|
w.Configure(options)
|
||||||
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
|
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
|
||||||
|
|||||||
+4
-8
@@ -117,16 +117,15 @@ static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFlo
|
|||||||
}
|
}
|
||||||
- (void)keyDown:(NSEvent *)event {
|
- (void)keyDown:(NSEvent *)event {
|
||||||
NSString *keys = [event charactersIgnoringModifiers];
|
NSString *keys = [event charactersIgnoringModifiers];
|
||||||
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], true);
|
gio_onKeys((__bridge CFTypeRef)self, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], true);
|
||||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||||
}
|
}
|
||||||
- (void)keyUp:(NSEvent *)event {
|
- (void)keyUp:(NSEvent *)event {
|
||||||
NSString *keys = [event charactersIgnoringModifiers];
|
NSString *keys = [event charactersIgnoringModifiers];
|
||||||
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], false);
|
gio_onKeys((__bridge CFTypeRef)self, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], false);
|
||||||
}
|
}
|
||||||
- (void)insertText:(id)string {
|
- (void)insertText:(id)string {
|
||||||
const char *utf8 = [string UTF8String];
|
gio_onText((__bridge CFTypeRef)self, (__bridge CFTypeRef)string);
|
||||||
gio_onText((__bridge CFTypeRef)self, (char *)utf8);
|
|
||||||
}
|
}
|
||||||
- (void)doCommandBySelector:(SEL)sel {
|
- (void)doCommandBySelector:(SEL)sel {
|
||||||
// Don't pass commands up the responder chain.
|
// Don't pass commands up the responder chain.
|
||||||
@@ -210,7 +209,7 @@ void gio_setCursor(NSUInteger curID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight) {
|
CFTypeRef gio_createWindow(CFTypeRef viewRef, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSRect rect = NSMakeRect(0, 0, width, height);
|
NSRect rect = NSMakeRect(0, 0, width, height);
|
||||||
NSUInteger styleMask = NSTitledWindowMask |
|
NSUInteger styleMask = NSTitledWindowMask |
|
||||||
@@ -229,9 +228,6 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width,
|
|||||||
window.contentMaxSize = NSMakeSize(maxWidth, maxHeight);
|
window.contentMaxSize = NSMakeSize(maxWidth, maxHeight);
|
||||||
}
|
}
|
||||||
[window setAcceptsMouseMovedEvents:YES];
|
[window setAcceptsMouseMovedEvents:YES];
|
||||||
if (title != nil) {
|
|
||||||
window.title = [NSString stringWithUTF8String: title];
|
|
||||||
}
|
|
||||||
NSView *view = (__bridge NSView *)viewRef;
|
NSView *view = (__bridge NSView *)viewRef;
|
||||||
[window setContentView:view];
|
[window setContentView:view];
|
||||||
[window makeFirstResponder:view];
|
[window makeFirstResponder:view];
|
||||||
|
|||||||
Reference in New Issue
Block a user