app: [iOS] use cgo.Handle for referring to Go windows from native code

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2023-12-11 14:40:53 -06:00
parent a880d6403d
commit 9bca5bfdcf
2 changed files with 59 additions and 49 deletions
+33 -28
View File
@@ -12,6 +12,8 @@ package app
#include <UIKit/UIKit.h> #include <UIKit/UIKit.h>
#include <stdint.h> #include <stdint.h>
__attribute__ ((visibility ("hidden"))) void gio_viewSetHandle(CFTypeRef viewRef, uintptr_t handle);
struct drawParams { struct drawParams {
CGFloat dpi, sdpi; CGFloat dpi, sdpi;
CGFloat width, height; CGFloat width, height;
@@ -74,6 +76,7 @@ import (
"image" "image"
"io" "io"
"runtime" "runtime"
"runtime/cgo"
"runtime/debug" "runtime/debug"
"strings" "strings"
"time" "time"
@@ -110,8 +113,6 @@ type window struct {
var mainWindow = newWindowRendezvous() var mainWindow = newWindowRendezvous()
var views = make(map[C.CFTypeRef]*window)
func init() { func init() {
// Darwin requires UI operations happen on the main thread only. // Darwin requires UI operations happen on the main thread only.
runtime.LockOSThread() runtime.LockOSThread()
@@ -135,15 +136,19 @@ func onCreate(view, controller C.CFTypeRef) {
return return
} }
w.displayLink = dl w.displayLink = dl
views[view] = w C.gio_viewSetHandle(view, C.uintptr_t(cgo.NewHandle(w)))
w.Configure(wopts.options) w.Configure(wopts.options)
w.ProcessEvent(StageEvent{Stage: StageRunning}) w.ProcessEvent(StageEvent{Stage: StageRunning})
w.ProcessEvent(ViewEvent{ViewController: uintptr(controller)}) w.ProcessEvent(ViewEvent{ViewController: uintptr(controller)})
} }
func viewFor(h C.uintptr_t) *window {
return cgo.Handle(h).Value().(*window)
}
//export gio_onDraw //export gio_onDraw
func gio_onDraw(view C.CFTypeRef) { func gio_onDraw(h C.uintptr_t) {
w := views[view] w := viewFor(h)
w.draw(true) w.draw(true)
} }
@@ -181,34 +186,34 @@ func (w *window) draw(sync bool) {
} }
//export onStop //export onStop
func onStop(view C.CFTypeRef) { func onStop(h C.uintptr_t) {
w := views[view] w := viewFor(h)
w.hidden = true w.hidden = true
w.ProcessEvent(StageEvent{Stage: StagePaused}) w.ProcessEvent(StageEvent{Stage: StagePaused})
} }
//export onStart //export onStart
func onStart(view C.CFTypeRef) { func onStart(h C.uintptr_t) {
w := views[view] w := viewFor(h)
w.hidden = false w.hidden = false
w.ProcessEvent(StageEvent{Stage: StageRunning}) w.ProcessEvent(StageEvent{Stage: StageRunning})
w.draw(true) w.draw(true)
} }
//export onDestroy //export onDestroy
func onDestroy(view C.CFTypeRef) { func onDestroy(h C.uintptr_t) {
w := views[view] w := viewFor(h)
w.ProcessEvent(ViewEvent{}) w.ProcessEvent(ViewEvent{})
w.ProcessEvent(DestroyEvent{}) w.ProcessEvent(DestroyEvent{})
w.displayLink.Close() w.displayLink.Close()
w.displayLink = nil w.displayLink = nil
delete(views, view) cgo.Handle(h).Delete()
w.view = 0 w.view = 0
} }
//export onFocus //export onFocus
func onFocus(view C.CFTypeRef, focus int) { func onFocus(h C.uintptr_t, focus int) {
w := views[view] w := viewFor(h)
w.ProcessEvent(key.FocusEvent{Focus: focus != 0}) w.ProcessEvent(key.FocusEvent{Focus: focus != 0})
} }
@@ -219,38 +224,38 @@ func onLowMemory() {
} }
//export onUpArrow //export onUpArrow
func onUpArrow(view C.CFTypeRef) { func onUpArrow(h C.uintptr_t) {
views[view].onKeyCommand(key.NameUpArrow) viewFor(h).onKeyCommand(key.NameUpArrow)
} }
//export onDownArrow //export onDownArrow
func onDownArrow(view C.CFTypeRef) { func onDownArrow(h C.uintptr_t) {
views[view].onKeyCommand(key.NameDownArrow) viewFor(h).onKeyCommand(key.NameDownArrow)
} }
//export onLeftArrow //export onLeftArrow
func onLeftArrow(view C.CFTypeRef) { func onLeftArrow(h C.uintptr_t) {
views[view].onKeyCommand(key.NameLeftArrow) viewFor(h).onKeyCommand(key.NameLeftArrow)
} }
//export onRightArrow //export onRightArrow
func onRightArrow(view C.CFTypeRef) { func onRightArrow(h C.uintptr_t) {
views[view].onKeyCommand(key.NameRightArrow) viewFor(h).onKeyCommand(key.NameRightArrow)
} }
//export onDeleteBackward //export onDeleteBackward
func onDeleteBackward(view C.CFTypeRef) { func onDeleteBackward(h C.uintptr_t) {
views[view].onKeyCommand(key.NameDeleteBackward) viewFor(h).onKeyCommand(key.NameDeleteBackward)
} }
//export onText //export onText
func onText(view, str C.CFTypeRef) { func onText(h C.uintptr_t, str C.CFTypeRef) {
w := views[view] w := viewFor(h)
w.w.EditorInsert(nsstringToString(str)) w.w.EditorInsert(nsstringToString(str))
} }
//export onTouch //export onTouch
func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.CGFloat, ti C.double) { func onTouch(h C.uintptr_t, last C.int, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.CGFloat, ti C.double) {
var kind pointer.Kind var kind pointer.Kind
switch phase { switch phase {
case C.UITouchPhaseBegan: case C.UITouchPhaseBegan:
@@ -264,7 +269,7 @@ func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.C
default: default:
return return
} }
w := views[view] w := viewFor(h)
t := time.Duration(float64(ti) * float64(time.Second)) t := time.Duration(float64(ti) * float64(time.Second))
p := f32.Point{X: float32(x), Y: float32(y)} p := f32.Point{X: float32(x), Y: float32(y)}
w.ProcessEvent(pointer.Event{ w.ProcessEvent(pointer.Event{
+26 -21
View File
@@ -11,6 +11,7 @@
__attribute__ ((visibility ("hidden"))) Class gio_layerClass(void); __attribute__ ((visibility ("hidden"))) Class gio_layerClass(void);
@interface GioView: UIView <UIKeyInput> @interface GioView: UIView <UIKeyInput>
@property uintptr_t handle;
@end @end
@implementation GioViewController @implementation GioViewController
@@ -54,33 +55,33 @@ CGFloat _keyboardHeight;
} }
- (void)applicationWillEnterForeground:(UIApplication *)application { - (void)applicationWillEnterForeground:(UIApplication *)application {
UIView *drawView = self.view.subviews[0]; GioView *view = (GioView *)self.view.subviews[0];
if (drawView != nil) { if (view != nil) {
onStart((__bridge CFTypeRef)drawView); onStart(view.handle);
} }
} }
- (void)applicationDidEnterBackground:(UIApplication *)application { - (void)applicationDidEnterBackground:(UIApplication *)application {
UIView *drawView = self.view.subviews[0]; GioView *view = (GioView *)self.view.subviews[0];
if (drawView != nil) { if (view != nil) {
onStop((__bridge CFTypeRef)drawView); onStop(view.handle);
} }
} }
- (void)viewDidDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated]; [super viewDidDisappear:animated];
CFTypeRef viewRef = (__bridge CFTypeRef)self.view.subviews[0]; GioView *view = (GioView *)self.view.subviews[0];
onDestroy(viewRef); onDestroy(view.handle);
} }
- (void)viewDidLayoutSubviews { - (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews]; [super viewDidLayoutSubviews];
UIView *view = self.view.subviews[0]; GioView *view = (GioView *)self.view.subviews[0];
CGRect frame = self.view.bounds; CGRect frame = self.view.bounds;
// Adjust view bounds to make room for the keyboard. // Adjust view bounds to make room for the keyboard.
frame.size.height -= _keyboardHeight; frame.size.height -= _keyboardHeight;
view.frame = frame; view.frame = frame;
gio_onDraw((__bridge CFTypeRef)view); gio_onDraw(view.handle);
} }
- (void)didReceiveMemoryWarning { - (void)didReceiveMemoryWarning {
@@ -101,11 +102,10 @@ CGFloat _keyboardHeight;
} }
@end @end
static void handleTouches(int last, UIView *view, NSSet<UITouch *> *touches, UIEvent *event) { static void handleTouches(int last, GioView *view, NSSet<UITouch *> *touches, UIEvent *event) {
CGFloat scale = view.contentScaleFactor; CGFloat scale = view.contentScaleFactor;
NSUInteger i = 0; NSUInteger i = 0;
NSUInteger n = [touches count]; NSUInteger n = [touches count];
CFTypeRef viewRef = (__bridge CFTypeRef)view;
for (UITouch *touch in touches) { for (UITouch *touch in touches) {
CFTypeRef touchRef = (__bridge CFTypeRef)touch; CFTypeRef touchRef = (__bridge CFTypeRef)touch;
i++; i++;
@@ -116,7 +116,7 @@ static void handleTouches(int last, UIView *view, NSSet<UITouch *> *touches, UIE
CGPoint loc = [coalescedTouch locationInView:view]; CGPoint loc = [coalescedTouch locationInView:view];
j++; j++;
int lastTouch = last && i == n && j == m; int lastTouch = last && i == n && j == m;
onTouch(lastTouch, viewRef, touchRef, touch.phase, loc.x*scale, loc.y*scale, [coalescedTouch timestamp]); onTouch(view.handle, lastTouch, touchRef, touch.phase, loc.x*scale, loc.y*scale, [coalescedTouch timestamp]);
} }
} }
} }
@@ -151,13 +151,13 @@ NSArray<UIKeyCommand *> *_keyCommands;
- (void)onWindowDidBecomeKey:(NSNotification *)note { - (void)onWindowDidBecomeKey:(NSNotification *)note {
if (self.isFirstResponder) { if (self.isFirstResponder) {
onFocus((__bridge CFTypeRef)self, YES); onFocus(self.handle, YES);
} }
} }
- (void)onWindowDidResignKey:(NSNotification *)note { - (void)onWindowDidResignKey:(NSNotification *)note {
if (self.isFirstResponder) { if (self.isFirstResponder) {
onFocus((__bridge CFTypeRef)self, NO); onFocus(self.handle, NO);
} }
} }
@@ -178,7 +178,7 @@ NSArray<UIKeyCommand *> *_keyCommands;
} }
- (void)insertText:(NSString *)text { - (void)insertText:(NSString *)text {
onText((__bridge CFTypeRef)self, (__bridge CFTypeRef)text); onText(self.handle, (__bridge CFTypeRef)text);
} }
- (BOOL)canBecomeFirstResponder { - (BOOL)canBecomeFirstResponder {
@@ -190,23 +190,23 @@ NSArray<UIKeyCommand *> *_keyCommands;
} }
- (void)deleteBackward { - (void)deleteBackward {
onDeleteBackward((__bridge CFTypeRef)self); onDeleteBackward(self.handle);
} }
- (void)onUpArrow { - (void)onUpArrow {
onUpArrow((__bridge CFTypeRef)self); onUpArrow(self.handle);
} }
- (void)onDownArrow { - (void)onDownArrow {
onDownArrow((__bridge CFTypeRef)self); onDownArrow(self.handle);
} }
- (void)onLeftArrow { - (void)onLeftArrow {
onLeftArrow((__bridge CFTypeRef)self); onLeftArrow(self.handle);
} }
- (void)onRightArrow { - (void)onRightArrow {
onRightArrow((__bridge CFTypeRef)self); onRightArrow(self.handle);
} }
- (NSArray<UIKeyCommand *> *)keyCommands { - (NSArray<UIKeyCommand *> *)keyCommands {
@@ -271,3 +271,8 @@ void gio_showCursor() {
void gio_setCursor(NSUInteger curID) { void gio_setCursor(NSUInteger curID) {
// Not supported. // Not supported.
} }
void gio_viewSetHandle(CFTypeRef viewRef, uintptr_t handle) {
GioView *v = (__bridge GioView *)viewRef;
v.handle = handle;
}