diff options
Diffstat (limited to 'vendor/gioui.org/app/os_ios.go')
-rw-r--r-- | vendor/gioui.org/app/os_ios.go | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/vendor/gioui.org/app/os_ios.go b/vendor/gioui.org/app/os_ios.go new file mode 100644 index 0000000..f6f6dea --- /dev/null +++ b/vendor/gioui.org/app/os_ios.go @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build darwin && ios +// +build darwin,ios + +package app + +/* +#cgo CFLAGS: -DGLES_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c + +#include <CoreGraphics/CoreGraphics.h> +#include <UIKit/UIKit.h> +#include <stdint.h> + +struct drawParams { + CGFloat dpi, sdpi; + CGFloat width, height; + CGFloat top, right, bottom, left; +}; + +static void writeClipboard(unichar *chars, NSUInteger length) { + @autoreleasepool { + NSString *s = [NSString string]; + if (length > 0) { + s = [NSString stringWithCharacters:chars length:length]; + } + UIPasteboard *p = UIPasteboard.generalPasteboard; + p.string = s; + } +} + +static CFTypeRef readClipboard(void) { + @autoreleasepool { + UIPasteboard *p = UIPasteboard.generalPasteboard; + return (__bridge_retained CFTypeRef)p.string; + } +} + +static void showTextInput(CFTypeRef viewRef) { + UIView *view = (__bridge UIView *)viewRef; + [view becomeFirstResponder]; +} + +static void hideTextInput(CFTypeRef viewRef) { + UIView *view = (__bridge UIView *)viewRef; + [view resignFirstResponder]; +} + +static struct drawParams viewDrawParams(CFTypeRef viewRef) { + UIView *v = (__bridge UIView *)viewRef; + struct drawParams params; + CGFloat scale = v.layer.contentsScale; + // Use 163 as the standard ppi on iOS. + params.dpi = 163*scale; + params.sdpi = params.dpi; + UIEdgeInsets insets = v.layoutMargins; + if (@available(iOS 11.0, tvOS 11.0, *)) { + UIFontMetrics *metrics = [UIFontMetrics defaultMetrics]; + params.sdpi = [metrics scaledValueForValue:params.sdpi]; + insets = v.safeAreaInsets; + } + params.width = v.bounds.size.width*scale; + params.height = v.bounds.size.height*scale; + params.top = insets.top*scale; + params.right = insets.right*scale; + params.bottom = insets.bottom*scale; + params.left = insets.left*scale; + return params; +} +*/ +import "C" + +import ( + "image" + "runtime" + "runtime/debug" + "time" + "unicode/utf16" + "unsafe" + + "gioui.org/f32" + "gioui.org/io/clipboard" + "gioui.org/io/key" + "gioui.org/io/pointer" + "gioui.org/io/system" + "gioui.org/unit" +) + +type ViewEvent struct { + // ViewController is a CFTypeRef for the UIViewController backing a Window. + ViewController uintptr +} + +type window struct { + view C.CFTypeRef + w *callbacks + displayLink *displayLink + + visible bool + cursor pointer.CursorName + + pointerMap []C.CFTypeRef +} + +var mainWindow = newWindowRendezvous() + +var views = make(map[C.CFTypeRef]*window) + +func init() { + // Darwin requires UI operations happen on the main thread only. + runtime.LockOSThread() +} + +//export onCreate +func onCreate(view, controller C.CFTypeRef) { + w := &window{ + view: view, + } + dl, err := NewDisplayLink(func() { + w.draw(false) + }) + if err != nil { + panic(err) + } + w.displayLink = dl + wopts := <-mainWindow.out + w.w = wopts.window + w.w.SetDriver(w) + views[view] = w + w.w.Event(system.StageEvent{Stage: system.StagePaused}) + w.w.Event(ViewEvent{ViewController: uintptr(controller)}) +} + +//export gio_onDraw +func gio_onDraw(view C.CFTypeRef) { + w := views[view] + w.draw(true) +} + +func (w *window) draw(sync bool) { + params := C.viewDrawParams(w.view) + if params.width == 0 || params.height == 0 { + return + } + wasVisible := w.visible + w.visible = true + if !wasVisible { + w.w.Event(system.StageEvent{Stage: system.StageRunning}) + } + const inchPrDp = 1.0 / 163 + w.w.Event(frameEvent{ + FrameEvent: system.FrameEvent{ + Now: time.Now(), + Size: image.Point{ + X: int(params.width + .5), + Y: int(params.height + .5), + }, + Insets: system.Insets{ + Top: unit.Px(float32(params.top)), + Right: unit.Px(float32(params.right)), + Bottom: unit.Px(float32(params.bottom)), + Left: unit.Px(float32(params.left)), + }, + Metric: unit.Metric{ + PxPerDp: float32(params.dpi) * inchPrDp, + PxPerSp: float32(params.sdpi) * inchPrDp, + }, + }, + Sync: sync, + }) +} + +//export onStop +func onStop(view C.CFTypeRef) { + w := views[view] + w.visible = false + w.w.Event(system.StageEvent{Stage: system.StagePaused}) +} + +//export onDestroy +func onDestroy(view C.CFTypeRef) { + w := views[view] + delete(views, view) + w.w.Event(ViewEvent{}) + w.w.Event(system.DestroyEvent{}) + w.displayLink.Close() + w.view = 0 +} + +//export onFocus +func onFocus(view C.CFTypeRef, focus int) { + w := views[view] + w.w.Event(key.FocusEvent{Focus: focus != 0}) +} + +//export onLowMemory +func onLowMemory() { + runtime.GC() + debug.FreeOSMemory() +} + +//export onUpArrow +func onUpArrow(view C.CFTypeRef) { + views[view].onKeyCommand(key.NameUpArrow) +} + +//export onDownArrow +func onDownArrow(view C.CFTypeRef) { + views[view].onKeyCommand(key.NameDownArrow) +} + +//export onLeftArrow +func onLeftArrow(view C.CFTypeRef) { + views[view].onKeyCommand(key.NameLeftArrow) +} + +//export onRightArrow +func onRightArrow(view C.CFTypeRef) { + views[view].onKeyCommand(key.NameRightArrow) +} + +//export onDeleteBackward +func onDeleteBackward(view C.CFTypeRef) { + views[view].onKeyCommand(key.NameDeleteBackward) +} + +//export onText +func onText(view C.CFTypeRef, str *C.char) { + w := views[view] + w.w.Event(key.EditEvent{ + Text: C.GoString(str), + }) +} + +//export onTouch +func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.CGFloat, ti C.double) { + var typ pointer.Type + switch phase { + case C.UITouchPhaseBegan: + typ = pointer.Press + case C.UITouchPhaseMoved: + typ = pointer.Move + case C.UITouchPhaseEnded: + typ = pointer.Release + case C.UITouchPhaseCancelled: + typ = pointer.Cancel + default: + return + } + w := views[view] + t := time.Duration(float64(ti) * float64(time.Second)) + p := f32.Point{X: float32(x), Y: float32(y)} + w.w.Event(pointer.Event{ + Type: typ, + Source: pointer.Touch, + PointerID: w.lookupTouch(last != 0, touchRef), + Position: p, + Time: t, + }) +} + +func (w *window) ReadClipboard() { + content := nsstringToString(C.readClipboard()) + w.w.Event(clipboard.Event{Text: content}) +} + +func (w *window) WriteClipboard(s string) { + u16 := utf16.Encode([]rune(s)) + var chars *C.unichar + if len(u16) > 0 { + chars = (*C.unichar)(unsafe.Pointer(&u16[0])) + } + C.writeClipboard(chars, C.NSUInteger(len(u16))) +} + +func (w *window) Configure([]Option) {} + +func (w *window) Raise() {} + +func (w *window) SetAnimating(anim bool) { + v := w.view + if v == 0 { + return + } + if anim { + w.displayLink.Start() + } else { + w.displayLink.Stop() + } +} + +func (w *window) SetCursor(name pointer.CursorName) { + w.cursor = windowSetCursor(w.cursor, name) +} + +func (w *window) onKeyCommand(name string) { + w.w.Event(key.Event{ + Name: name, + }) +} + +// lookupTouch maps an UITouch pointer value to an index. If +// last is set, the map is cleared. +func (w *window) lookupTouch(last bool, touch C.CFTypeRef) pointer.ID { + id := -1 + for i, ref := range w.pointerMap { + if ref == touch { + id = i + break + } + } + if id == -1 { + id = len(w.pointerMap) + w.pointerMap = append(w.pointerMap, touch) + } + if last { + w.pointerMap = w.pointerMap[:0] + } + return pointer.ID(id) +} + +func (w *window) contextView() C.CFTypeRef { + return w.view +} + +func (w *window) ShowTextInput(show bool) { + if show { + C.showTextInput(w.view) + } else { + C.hideTextInput(w.view) + } +} + +func (w *window) SetInputHint(_ key.InputHint) {} + +// Close the window. Not implemented for iOS. +func (w *window) Close() {} + +// Maximize the window. Not implemented for iOS. +func (w *window) Maximize() {} + +// Center the window. Not implemented for iOS. +func (w *window) Center() {} + +func newWindow(win *callbacks, options []Option) error { + mainWindow.in <- windowAndConfig{win, options} + return <-mainWindow.errs +} + +func osMain() { +} + +//export gio_runMain +func gio_runMain() { + runMain() +} + +func (_ ViewEvent) ImplementsEvent() {} |