aboutsummaryrefslogtreecommitdiff
path: root/vendor/gioui.org/app/os_ios.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gioui.org/app/os_ios.go')
-rw-r--r--vendor/gioui.org/app/os_ios.go358
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() {}