From c0c25b777b1e3a394156dac5f6acfca4f62d6fd4 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 2 Mar 2022 17:24:46 +0100 Subject: [PATCH] app: replace C-to-Go handle maps with cgo.Handle Signed-off-by: Elias Naur --- app/os_android.go | 72 +++++++++++++++++++++++------------------------ app/os_darwin.go | 27 ++++++++---------- app/os_ios.m | 23 +++++++++++---- app/os_macos.m | 8 +++--- 4 files changed, 67 insertions(+), 63 deletions(-) diff --git a/app/os_android.go b/app/os_android.go index 982bae08..b79fdf39 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -127,6 +127,7 @@ import ( "os" "path/filepath" "runtime" + "runtime/cgo" "runtime/debug" "sync" "time" @@ -148,7 +149,8 @@ import ( type window struct { callbacks *callbacks - view C.jobject + view C.jobject + handle cgo.Handle dpi int fontScale float32 @@ -275,9 +277,6 @@ var android struct { } } -// view maps from GioView JNI refenreces to windows. -var views = make(map[C.jlong]*window) - var windows = make(map[*callbacks]*window) var mainWindow = newWindowRendezvous() @@ -491,33 +490,32 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j w.detach(env) } w.view = view + w.handle = cgo.NewHandle(w) w.callbacks.SetDriver(w) - handle := C.jlong(view) - views[handle] = w w.loadConfig(env, class) w.Configure(wopts.options) w.SetInputHint(key.HintAny) w.setStage(system.StagePaused) w.callbacks.Event(ViewEvent{View: uintptr(view)}) - return handle + return C.jlong(w.handle) } //export Java_org_gioui_GioView_onDestroyView func Java_org_gioui_GioView_onDestroyView(env *C.JNIEnv, class C.jclass, handle C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.detach(env) } //export Java_org_gioui_GioView_onStopView func Java_org_gioui_GioView_onStopView(env *C.JNIEnv, class C.jclass, handle C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.started = false w.setStage(system.StagePaused) } //export Java_org_gioui_GioView_onStartView func Java_org_gioui_GioView_onStartView(env *C.JNIEnv, class C.jclass, handle C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.started = true if w.win != nil { w.setVisible(env) @@ -526,14 +524,14 @@ func Java_org_gioui_GioView_onStartView(env *C.JNIEnv, class C.jclass, handle C. //export Java_org_gioui_GioView_onSurfaceDestroyed func Java_org_gioui_GioView_onSurfaceDestroyed(env *C.JNIEnv, class C.jclass, handle C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.win = nil w.setStage(system.StagePaused) } //export Java_org_gioui_GioView_onSurfaceChanged func Java_org_gioui_GioView_onSurfaceChanged(env *C.JNIEnv, class C.jclass, handle C.jlong, surf C.jobject) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.win = C.ANativeWindow_fromSurface(env, surf) if w.started { w.setVisible(env) @@ -548,7 +546,7 @@ func Java_org_gioui_GioView_onLowMemory(env *C.JNIEnv, class C.jclass) { //export Java_org_gioui_GioView_onConfigurationChanged func Java_org_gioui_GioView_onConfigurationChanged(env *C.JNIEnv, class C.jclass, view C.jlong) { - w := views[view] + w := cgo.Handle(view).Value().(*window) w.loadConfig(env, class) if w.stage >= system.StageRunning { w.draw(env, true) @@ -557,7 +555,7 @@ func Java_org_gioui_GioView_onConfigurationChanged(env *C.JNIEnv, class C.jclass //export Java_org_gioui_GioView_onFrameCallback func Java_org_gioui_GioView_onFrameCallback(env *C.JNIEnv, class C.jclass, view C.jlong) { - w, exist := views[view] + w, exist := cgo.Handle(view).Value().(*window) if !exist { return } @@ -574,7 +572,7 @@ func Java_org_gioui_GioView_onFrameCallback(env *C.JNIEnv, class C.jclass, view //export Java_org_gioui_GioView_onBack func Java_org_gioui_GioView_onBack(env *C.JNIEnv, class C.jclass, view C.jlong) C.jboolean { - w := views[view] + w := cgo.Handle(view).Value().(*window) ev := &system.CommandEvent{Type: system.CommandBack} w.callbacks.Event(ev) if ev.Cancel { @@ -585,13 +583,13 @@ func Java_org_gioui_GioView_onBack(env *C.JNIEnv, class C.jclass, view C.jlong) //export Java_org_gioui_GioView_onFocusChange func Java_org_gioui_GioView_onFocusChange(env *C.JNIEnv, class C.jclass, view C.jlong, focus C.jboolean) { - w := views[view] + w := cgo.Handle(view).Value().(*window) w.callbacks.Event(key.FocusEvent{Focus: focus == C.JNI_TRUE}) } //export Java_org_gioui_GioView_onWindowInsets func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C.jlong, top, right, bottom, left C.jint) { - w := views[view] + w := cgo.Handle(view).Value().(*window) w.insets = system.Insets{ Top: unit.Px(float32(top)), Bottom: unit.Px(float32(bottom)), @@ -605,7 +603,7 @@ func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C //export Java_org_gioui_GioView_initializeAccessibilityNodeInfo func Java_org_gioui_GioView_initializeAccessibilityNodeInfo(env *C.JNIEnv, class C.jclass, view C.jlong, virtID, screenX, screenY C.jint, info C.jobject) C.jobject { - w := views[view] + w := cgo.Handle(view).Value().(*window) semID := w.semIDFor(virtID) sem, found := w.callbacks.LookupSemantic(semID) if found { @@ -619,7 +617,7 @@ func Java_org_gioui_GioView_initializeAccessibilityNodeInfo(env *C.JNIEnv, class //export Java_org_gioui_GioView_onTouchExploration func Java_org_gioui_GioView_onTouchExploration(env *C.JNIEnv, class C.jclass, view C.jlong, x, y C.jfloat) { - w := views[view] + w := cgo.Handle(view).Value().(*window) semID, _ := w.callbacks.SemanticAt(f32.Pt(float32(x), float32(y))) if w.semantic.hoverID == semID { return @@ -636,7 +634,7 @@ func Java_org_gioui_GioView_onTouchExploration(env *C.JNIEnv, class C.jclass, vi //export Java_org_gioui_GioView_onExitTouchExploration func Java_org_gioui_GioView_onExitTouchExploration(env *C.JNIEnv, class C.jclass, view C.jlong) { - w := views[view] + w := cgo.Handle(view).Value().(*window) if w.semantic.hoverID != 0 { callVoidMethod(env, w.view, gioView.sendA11yEvent, TYPE_VIEW_HOVER_EXIT, jvalue(w.virtualIDFor(w.semantic.hoverID))) w.semantic.hoverID = 0 @@ -645,7 +643,7 @@ func Java_org_gioui_GioView_onExitTouchExploration(env *C.JNIEnv, class C.jclass //export Java_org_gioui_GioView_onA11yFocus func Java_org_gioui_GioView_onA11yFocus(env *C.JNIEnv, class C.jclass, view C.jlong, virtID C.jint) { - w := views[view] + w := cgo.Handle(view).Value().(*window) if semID := w.semIDFor(virtID); semID != w.semantic.focusID { w.semantic.focusID = semID // Android needs invalidate to refresh the TalkBack focus indicator. @@ -655,7 +653,7 @@ func Java_org_gioui_GioView_onA11yFocus(env *C.JNIEnv, class C.jclass, view C.jl //export Java_org_gioui_GioView_onClearA11yFocus func Java_org_gioui_GioView_onClearA11yFocus(env *C.JNIEnv, class C.jclass, view C.jlong, virtID C.jint) { - w := views[view] + w := cgo.Handle(view).Value().(*window) if w.semantic.focusID == w.semIDFor(virtID) { w.semantic.focusID = 0 } @@ -768,7 +766,7 @@ func (w *window) detach(env *C.JNIEnv) { callVoidMethod(env, w.view, gioView.unregister) w.callbacks.Event(ViewEvent{}) w.callbacks.SetDriver(nil) - delete(views, C.jlong(w.view)) + w.handle.Delete() C.jni_DeleteGlobalRef(env, w.view) w.view = 0 } @@ -920,7 +918,7 @@ func convertKeyCode(code C.jint) (string, bool) { //export Java_org_gioui_GioView_onKeyEvent func Java_org_gioui_GioView_onKeyEvent(env *C.JNIEnv, class C.jclass, handle C.jlong, keyCode, r C.jint, pressed C.jboolean, t C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) if pressed == C.JNI_TRUE { switch keyCode { case C.AKEYCODE_DPAD_UP: @@ -949,7 +947,7 @@ func Java_org_gioui_GioView_onKeyEvent(env *C.JNIEnv, class C.jclass, handle C.j //export Java_org_gioui_GioView_onTouchEvent func Java_org_gioui_GioView_onTouchEvent(env *C.JNIEnv, class C.jclass, handle C.jlong, action, pointerID, tool C.jint, x, y, scrollX, scrollY C.jfloat, jbtns C.jint, t C.jlong) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) var typ pointer.Type switch action { case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN: @@ -1003,7 +1001,7 @@ func Java_org_gioui_GioView_onTouchEvent(env *C.JNIEnv, class C.jclass, handle C //export Java_org_gioui_GioView_imeSelectionStart func Java_org_gioui_GioView_imeSelectionStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) sel := w.callbacks.EditorState().Selection start := sel.Start if sel.End < sel.Start { @@ -1014,7 +1012,7 @@ func Java_org_gioui_GioView_imeSelectionStart(env *C.JNIEnv, class C.jclass, han //export Java_org_gioui_GioView_imeSelectionEnd func Java_org_gioui_GioView_imeSelectionEnd(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) sel := w.callbacks.EditorState().Selection end := sel.End if sel.End < sel.Start { @@ -1025,7 +1023,7 @@ func Java_org_gioui_GioView_imeSelectionEnd(env *C.JNIEnv, class C.jclass, handl //export Java_org_gioui_GioView_imeComposingStart func Java_org_gioui_GioView_imeComposingStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) comp := w.callbacks.EditorState().compose start := comp.Start if e := comp.End; e < start { @@ -1036,7 +1034,7 @@ func Java_org_gioui_GioView_imeComposingStart(env *C.JNIEnv, class C.jclass, han //export Java_org_gioui_GioView_imeComposingEnd func Java_org_gioui_GioView_imeComposingEnd(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) comp := w.callbacks.EditorState().compose end := comp.End if s := comp.Start; s > end { @@ -1047,34 +1045,34 @@ func Java_org_gioui_GioView_imeComposingEnd(env *C.JNIEnv, class C.jclass, handl //export Java_org_gioui_GioView_imeSnippet func Java_org_gioui_GioView_imeSnippet(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jstring { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) snip := w.callbacks.EditorState().Snippet.Text return javaString(env, snip) } //export Java_org_gioui_GioView_imeSnippetStart func Java_org_gioui_GioView_imeSnippetStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) return C.jint(w.callbacks.EditorState().Snippet.Start) } //export Java_org_gioui_GioView_imeSetSnippet func Java_org_gioui_GioView_imeSetSnippet(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) r := key.Range{Start: int(start), End: int(end)} w.callbacks.SetEditorSnippet(r) } //export Java_org_gioui_GioView_imeSetSelection func Java_org_gioui_GioView_imeSetSelection(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) r := key.Range{Start: int(start), End: int(end)} w.callbacks.SetEditorSelection(r) } //export Java_org_gioui_GioView_imeSetComposingRegion func Java_org_gioui_GioView_imeSetComposingRegion(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) w.callbacks.SetComposingRegion(key.Range{ Start: int(start), End: int(end), @@ -1083,7 +1081,7 @@ func Java_org_gioui_GioView_imeSetComposingRegion(env *C.JNIEnv, class C.jclass, //export Java_org_gioui_GioView_imeReplace func Java_org_gioui_GioView_imeReplace(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint, jtext C.jstring) { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) r := key.Range{Start: int(start), End: int(end)} text := goString(env, jtext) w.callbacks.EditorReplace(r, text) @@ -1091,14 +1089,14 @@ func Java_org_gioui_GioView_imeReplace(env *C.JNIEnv, class C.jclass, handle C.j //export Java_org_gioui_GioView_imeToRunes func Java_org_gioui_GioView_imeToRunes(env *C.JNIEnv, class C.jclass, handle C.jlong, chars C.jint) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) state := w.callbacks.EditorState() return C.jint(state.RunesIndex(int(chars))) } //export Java_org_gioui_GioView_imeToUTF16 func Java_org_gioui_GioView_imeToUTF16(env *C.JNIEnv, class C.jclass, handle C.jlong, runes C.jint) C.jint { - w := views[handle] + w := cgo.Handle(handle).Value().(*window) state := w.callbacks.EditorState() return C.jint(state.UTF16Index(int(runes))) } diff --git a/app/os_darwin.go b/app/os_darwin.go index c89d4dcf..fb96eaf2 100644 --- a/app/os_darwin.go +++ b/app/os_darwin.go @@ -6,7 +6,7 @@ package app #include __attribute__ ((visibility ("hidden"))) void gio_wakeupMainThread(void); -__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createDisplayLink(void); +__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createDisplayLink(uintptr_t handle); __attribute__ ((visibility ("hidden"))) void gio_releaseDisplayLink(CFTypeRef dl); __attribute__ ((visibility ("hidden"))) int gio_startDisplayLink(CFTypeRef dl); __attribute__ ((visibility ("hidden"))) int gio_stopDisplayLink(CFTypeRef dl); @@ -42,7 +42,7 @@ static CFTypeRef newNSString(unichar *chars, NSUInteger length) { import "C" import ( "errors" - "sync" + "runtime/cgo" "sync/atomic" "time" "unicode/utf16" @@ -70,9 +70,6 @@ type displayLink struct { running uint32 } -// displayLinks maps CFTypeRefs to *displayLinks. -var displayLinks sync.Map - var mainFuncs = make(chan func(), 1) // runOnMain runs the function on the main thread. @@ -131,18 +128,18 @@ func NewDisplayLink(callback func()) (*displayLink, error) { states: make(chan bool), dids: make(chan uint64), } - dl := C.gio_createDisplayLink() + h := cgo.NewHandle(d) + dl := C.gio_createDisplayLink(C.uintptr_t(h)) if dl == 0 { return nil, errors.New("app: failed to create display link") } - go d.run(dl) + go d.run(dl, h) return d, nil } -func (d *displayLink) run(dl C.CFTypeRef) { +func (d *displayLink) run(dl C.CFTypeRef, h cgo.Handle) { defer C.gio_releaseDisplayLink(dl) - displayLinks.Store(dl, d) - defer displayLinks.Delete(dl) + defer h.Delete() var stopTimer *time.Timer var tchan <-chan time.Time started := false @@ -203,12 +200,10 @@ func (d *displayLink) SetDisplayID(did uint64) { } //export gio_onFrameCallback -func gio_onFrameCallback(dl C.CFTypeRef) { - if d, exists := displayLinks.Load(dl); exists { - d := d.(*displayLink) - if atomic.LoadUint32(&d.running) != 0 { - d.callback() - } +func gio_onFrameCallback(dl C.CFTypeRef, handle C.uintptr_t) { + d := cgo.Handle(handle).Value().(*displayLink) + if atomic.LoadUint32(&d.running) != 0 { + d.callback() } } diff --git a/app/os_ios.m b/app/os_ios.m index 0bb0b1a1..3ca4892e 100644 --- a/app/os_ios.m +++ b/app/os_ios.m @@ -123,10 +123,6 @@ static void handleTouches(int last, UIView *view, NSSet *touches, UIE @implementation GioView NSArray *_keyCommands; -+ (void)onFrameCallback:(CADisplayLink *)link { - gio_onFrameCallback((__bridge CFTypeRef)link); -} - + (Class)layerClass { return gio_layerClass(); } @@ -231,8 +227,23 @@ NSArray *_keyCommands; } @end -CFTypeRef gio_createDisplayLink(void) { - CADisplayLink *dl = [CADisplayLink displayLinkWithTarget:[GioView class] selector:@selector(onFrameCallback:)]; +@interface DisplayLinkHandle : NSObject { +} +@property uintptr_t handle; +@end + +@implementation DisplayLinkHandle { +} + +- (void)onFrameCallback:(CADisplayLink *)link { + gio_onFrameCallback((__bridge CFTypeRef)link, _handle); +} +@end + +CFTypeRef gio_createDisplayLink(uintptr_t handle) { + DisplayLinkHandle *h = [DisplayLinkHandle alloc]; + h.handle = handle; + CADisplayLink *dl = [CADisplayLink displayLinkWithTarget:h selector:@selector(onFrameCallback:)]; dl.paused = YES; NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; [dl addToRunLoop:runLoop forMode:[runLoop currentMode]]; diff --git a/app/os_macos.m b/app/os_macos.m index ac6e18a0..5fe2d99d 100644 --- a/app/os_macos.m +++ b/app/os_macos.m @@ -192,15 +192,15 @@ static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFlo // keep a single global reference instead. static GioWindowDelegate *globalWindowDel; -static CVReturn displayLinkCallback(CVDisplayLinkRef dl, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { - gio_onFrameCallback(dl); +static CVReturn displayLinkCallback(CVDisplayLinkRef dl, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *handle) { + gio_onFrameCallback(dl, (uintptr_t)handle); return kCVReturnSuccess; } -CFTypeRef gio_createDisplayLink(void) { +CFTypeRef gio_createDisplayLink(uintptr_t handle) { CVDisplayLinkRef dl; CVDisplayLinkCreateWithActiveCGDisplays(&dl); - CVDisplayLinkSetOutputCallback(dl, displayLinkCallback, nil); + CVDisplayLinkSetOutputCallback(dl, displayLinkCallback, (void *)(handle)); return dl; }