chore(v2): vendor dependencies for offline/China builds
go mod vendor pins onnxruntime_go v1.12.1, Gio and the rest into v2/vendor so go run/build work without hitting proxy.golang.org (blocked/slow in China). Verified: CGO_ENABLED=1 go build -mod=vendor ./internal/spike and GOOS=windows go build -mod=vendor ./internal/ui both pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+265
@@ -0,0 +1,265 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
|
||||
/*
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) void gio_runOnMain(uintptr_t h);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createDisplayLink(void);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_releaseDisplayLink(CFTypeRef dl);
|
||||
__attribute__ ((visibility ("hidden"))) int gio_startDisplayLink(CFTypeRef dl);
|
||||
__attribute__ ((visibility ("hidden"))) int gio_stopDisplayLink(CFTypeRef dl);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did);
|
||||
__attribute__ ((visibility ("hidden"))) void gio_hideCursor();
|
||||
__attribute__ ((visibility ("hidden"))) void gio_showCursor();
|
||||
__attribute__ ((visibility ("hidden"))) void gio_setCursor(NSUInteger curID);
|
||||
|
||||
static bool isMainThread() {
|
||||
return [NSThread isMainThread];
|
||||
}
|
||||
|
||||
static NSUInteger nsstringLength(CFTypeRef cstr) {
|
||||
NSString *str = (__bridge NSString *)cstr;
|
||||
return [str length];
|
||||
}
|
||||
|
||||
static void nsstringGetCharacters(CFTypeRef cstr, unichar *chars, NSUInteger loc, NSUInteger length) {
|
||||
NSString *str = (__bridge NSString *)cstr;
|
||||
[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 (
|
||||
"errors"
|
||||
"runtime/cgo"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"gioui.org/io/pointer"
|
||||
)
|
||||
|
||||
// displayLink is the state for a display link (CVDisplayLinkRef on macOS,
|
||||
// CADisplayLink on iOS). It runs a state-machine goroutine that keeps the
|
||||
// display link running for a while after being stopped to avoid the thread
|
||||
// start/stop overhead and because the CVDisplayLink sometimes fails to
|
||||
// start, stop and start again within a short duration.
|
||||
type displayLink struct {
|
||||
callback func()
|
||||
// states is for starting or stopping the display link.
|
||||
states chan bool
|
||||
// done is closed when the display link is destroyed.
|
||||
done chan struct{}
|
||||
// dids receives the display id when the callback owner is moved
|
||||
// to a different screen.
|
||||
dids chan uint64
|
||||
// running tracks the desired state of the link. running is accessed
|
||||
// with atomic.
|
||||
running uint32
|
||||
}
|
||||
|
||||
// displayLinks maps CFTypeRefs to *displayLinks.
|
||||
var displayLinks sync.Map
|
||||
|
||||
func isMainThread() bool {
|
||||
return bool(C.isMainThread())
|
||||
}
|
||||
|
||||
// runOnMain runs the function on the main thread.
|
||||
func runOnMain(f func()) {
|
||||
if isMainThread() {
|
||||
f()
|
||||
return
|
||||
}
|
||||
C.gio_runOnMain(C.uintptr_t(cgo.NewHandle(f)))
|
||||
}
|
||||
|
||||
//export gio_runFunc
|
||||
func gio_runFunc(h C.uintptr_t) {
|
||||
handle := cgo.Handle(h)
|
||||
defer handle.Delete()
|
||||
f := handle.Value().(func())
|
||||
f()
|
||||
}
|
||||
|
||||
// nsstringToString converts a NSString to a Go string.
|
||||
func nsstringToString(str C.CFTypeRef) string {
|
||||
if str == 0 {
|
||||
return ""
|
||||
}
|
||||
n := C.nsstringLength(str)
|
||||
if n == 0 {
|
||||
return ""
|
||||
}
|
||||
chars := make([]uint16, n)
|
||||
C.nsstringGetCharacters(str, (*C.unichar)(unsafe.Pointer(&chars[0])), 0, n)
|
||||
utf8 := utf16.Decode(chars)
|
||||
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) {
|
||||
d := &displayLink{
|
||||
callback: callback,
|
||||
done: make(chan struct{}),
|
||||
states: make(chan bool),
|
||||
dids: make(chan uint64),
|
||||
}
|
||||
dl := C.gio_createDisplayLink()
|
||||
if dl == 0 {
|
||||
return nil, errors.New("app: failed to create display link")
|
||||
}
|
||||
go d.run(dl)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *displayLink) run(dl C.CFTypeRef) {
|
||||
defer C.gio_releaseDisplayLink(dl)
|
||||
displayLinks.Store(dl, d)
|
||||
defer displayLinks.Delete(dl)
|
||||
var stopTimer *time.Timer
|
||||
var tchan <-chan time.Time
|
||||
started := false
|
||||
for {
|
||||
select {
|
||||
case <-tchan:
|
||||
tchan = nil
|
||||
started = false
|
||||
C.gio_stopDisplayLink(dl)
|
||||
case start := <-d.states:
|
||||
switch {
|
||||
case !start && tchan == nil:
|
||||
// stopTimeout is the delay before stopping the display link to
|
||||
// avoid the overhead of frequently starting and stopping the
|
||||
// link thread.
|
||||
const stopTimeout = 500 * time.Millisecond
|
||||
if stopTimer == nil {
|
||||
stopTimer = time.NewTimer(stopTimeout)
|
||||
} else {
|
||||
// stopTimer is always drained when tchan == nil.
|
||||
stopTimer.Reset(stopTimeout)
|
||||
}
|
||||
tchan = stopTimer.C
|
||||
atomic.StoreUint32(&d.running, 0)
|
||||
case start:
|
||||
if tchan != nil && !stopTimer.Stop() {
|
||||
<-tchan
|
||||
}
|
||||
tchan = nil
|
||||
atomic.StoreUint32(&d.running, 1)
|
||||
if !started {
|
||||
started = true
|
||||
C.gio_startDisplayLink(dl)
|
||||
}
|
||||
}
|
||||
case did := <-d.dids:
|
||||
C.gio_setDisplayLinkDisplay(dl, C.uint64_t(did))
|
||||
case <-d.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *displayLink) Start() {
|
||||
d.states <- true
|
||||
}
|
||||
|
||||
func (d *displayLink) Stop() {
|
||||
d.states <- false
|
||||
}
|
||||
|
||||
func (d *displayLink) Close() {
|
||||
close(d.done)
|
||||
}
|
||||
|
||||
func (d *displayLink) SetDisplayID(did uint64) {
|
||||
d.dids <- did
|
||||
}
|
||||
|
||||
//export gio_onFrameCallback
|
||||
func gio_onFrameCallback(ref C.CFTypeRef) {
|
||||
d, exists := displayLinks.Load(ref)
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
dl := d.(*displayLink)
|
||||
if atomic.LoadUint32(&dl.running) != 0 {
|
||||
dl.callback()
|
||||
}
|
||||
}
|
||||
|
||||
var macosCursorID = [...]byte{
|
||||
pointer.CursorDefault: 0,
|
||||
pointer.CursorNone: 1,
|
||||
pointer.CursorText: 2,
|
||||
pointer.CursorVerticalText: 3,
|
||||
pointer.CursorPointer: 4,
|
||||
pointer.CursorCrosshair: 5,
|
||||
pointer.CursorAllScroll: 6,
|
||||
pointer.CursorColResize: 7,
|
||||
pointer.CursorRowResize: 8,
|
||||
pointer.CursorGrab: 9,
|
||||
pointer.CursorGrabbing: 10,
|
||||
pointer.CursorNotAllowed: 11,
|
||||
pointer.CursorWait: 12,
|
||||
pointer.CursorProgress: 13,
|
||||
pointer.CursorNorthWestResize: 14,
|
||||
pointer.CursorNorthEastResize: 15,
|
||||
pointer.CursorSouthWestResize: 16,
|
||||
pointer.CursorSouthEastResize: 17,
|
||||
pointer.CursorNorthSouthResize: 18,
|
||||
pointer.CursorEastWestResize: 19,
|
||||
pointer.CursorWestResize: 20,
|
||||
pointer.CursorEastResize: 21,
|
||||
pointer.CursorNorthResize: 22,
|
||||
pointer.CursorSouthResize: 23,
|
||||
pointer.CursorNorthEastSouthWestResize: 24,
|
||||
pointer.CursorNorthWestSouthEastResize: 25,
|
||||
}
|
||||
|
||||
// windowSetCursor updates the cursor from the current one to a new one
|
||||
// and returns the new one.
|
||||
func windowSetCursor(from, to pointer.Cursor) pointer.Cursor {
|
||||
if from == to {
|
||||
return to
|
||||
}
|
||||
if to == pointer.CursorNone {
|
||||
C.gio_hideCursor()
|
||||
return to
|
||||
}
|
||||
if from == pointer.CursorNone {
|
||||
C.gio_showCursor()
|
||||
}
|
||||
C.gio_setCursor(C.NSUInteger(macosCursorID[to]))
|
||||
return to
|
||||
}
|
||||
|
||||
func (w *window) wakeup() {
|
||||
runOnMain(func() {
|
||||
w.loop.Wakeup()
|
||||
w.loop.FlushEvents()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user