github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/app/internal/window/os_ios.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 // +build darwin,ios 4 5 package window 6 7 /* 8 #cgo CFLAGS: -DGLES_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c 9 10 #include <CoreGraphics/CoreGraphics.h> 11 #include <UIKit/UIKit.h> 12 #include <stdint.h> 13 #include "os_ios.h" 14 15 */ 16 import "C" 17 18 import ( 19 "image" 20 "runtime" 21 "runtime/debug" 22 "sync/atomic" 23 "time" 24 25 "github.com/gop9/olt/gio/f32" 26 "github.com/gop9/olt/gio/io/key" 27 "github.com/gop9/olt/gio/io/pointer" 28 "github.com/gop9/olt/gio/io/system" 29 "github.com/gop9/olt/gio/unit" 30 ) 31 32 type window struct { 33 view C.CFTypeRef 34 w Callbacks 35 36 layer C.CFTypeRef 37 visible atomic.Value 38 39 pointerMap []C.CFTypeRef 40 } 41 42 var mainWindow = newWindowRendezvous() 43 44 var layerFactory func() uintptr 45 46 var views = make(map[C.CFTypeRef]*window) 47 48 func init() { 49 // Darwin requires UI operations happen on the main thread only. 50 runtime.LockOSThread() 51 } 52 53 //export onCreate 54 func onCreate(view C.CFTypeRef) { 55 w := &window{ 56 view: view, 57 } 58 wopts := <-mainWindow.out 59 w.w = wopts.window 60 w.w.SetDriver(w) 61 w.visible.Store(false) 62 w.layer = C.CFTypeRef(layerFactory()) 63 C.gio_addLayerToView(view, w.layer) 64 views[view] = w 65 w.w.Event(system.StageEvent{Stage: system.StagePaused}) 66 } 67 68 //export onDraw 69 func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, top, right, bottom, left C.CGFloat) { 70 if width == 0 || height == 0 { 71 return 72 } 73 w := views[view] 74 wasVisible := w.isVisible() 75 w.visible.Store(true) 76 C.gio_updateView(view, w.layer) 77 if !wasVisible { 78 w.w.Event(system.StageEvent{Stage: system.StageRunning}) 79 } 80 isSync := false 81 if sync != 0 { 82 isSync = true 83 } 84 const inchPrDp = 1.0 / 163 85 w.w.Event(FrameEvent{ 86 FrameEvent: system.FrameEvent{ 87 Size: image.Point{ 88 X: int(width + .5), 89 Y: int(height + .5), 90 }, 91 Insets: system.Insets{ 92 Top: unit.Px(float32(top)), 93 Right: unit.Px(float32(right)), 94 Bottom: unit.Px(float32(bottom)), 95 Left: unit.Px(float32(left)), 96 }, 97 Config: &config{ 98 pxPerDp: float32(dpi) * inchPrDp, 99 pxPerSp: float32(sdpi) * inchPrDp, 100 now: time.Now(), 101 }, 102 }, 103 Sync: isSync, 104 }) 105 } 106 107 //export onStop 108 func onStop(view C.CFTypeRef) { 109 w := views[view] 110 w.visible.Store(false) 111 w.w.Event(system.StageEvent{Stage: system.StagePaused}) 112 } 113 114 //export onDestroy 115 func onDestroy(view C.CFTypeRef) { 116 w := views[view] 117 delete(views, view) 118 w.w.Event(system.DestroyEvent{}) 119 C.gio_removeLayer(w.layer) 120 C.CFRelease(w.layer) 121 w.layer = 0 122 w.view = 0 123 } 124 125 //export onFocus 126 func onFocus(view C.CFTypeRef, focus int) { 127 w := views[view] 128 w.w.Event(key.FocusEvent{Focus: focus != 0}) 129 } 130 131 //export onLowMemory 132 func onLowMemory() { 133 runtime.GC() 134 debug.FreeOSMemory() 135 } 136 137 //export onUpArrow 138 func onUpArrow(view C.CFTypeRef) { 139 views[view].onKeyCommand(key.NameUpArrow) 140 } 141 142 //export onDownArrow 143 func onDownArrow(view C.CFTypeRef) { 144 views[view].onKeyCommand(key.NameDownArrow) 145 } 146 147 //export onLeftArrow 148 func onLeftArrow(view C.CFTypeRef) { 149 views[view].onKeyCommand(key.NameLeftArrow) 150 } 151 152 //export onRightArrow 153 func onRightArrow(view C.CFTypeRef) { 154 views[view].onKeyCommand(key.NameRightArrow) 155 } 156 157 //export onDeleteBackward 158 func onDeleteBackward(view C.CFTypeRef) { 159 views[view].onKeyCommand(key.NameDeleteBackward) 160 } 161 162 //export onText 163 func onText(view C.CFTypeRef, str *C.char) { 164 w := views[view] 165 w.w.Event(key.EditEvent{ 166 Text: C.GoString(str), 167 }) 168 } 169 170 //export onTouch 171 func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.CGFloat, ti C.double) { 172 var typ pointer.Type 173 switch phase { 174 case C.UITouchPhaseBegan: 175 typ = pointer.Press 176 case C.UITouchPhaseMoved: 177 typ = pointer.Move 178 case C.UITouchPhaseEnded: 179 typ = pointer.Release 180 case C.UITouchPhaseCancelled: 181 typ = pointer.Cancel 182 default: 183 return 184 } 185 w := views[view] 186 t := time.Duration(float64(ti) * float64(time.Second)) 187 p := f32.Point{X: float32(x), Y: float32(y)} 188 w.w.Event(pointer.Event{ 189 Type: typ, 190 Source: pointer.Touch, 191 PointerID: w.lookupTouch(last != 0, touchRef), 192 Position: p, 193 Time: t, 194 }) 195 } 196 197 func (w *window) SetAnimating(anim bool) { 198 if w.view == 0 { 199 return 200 } 201 var animi C.int 202 if anim { 203 animi = 1 204 } 205 C.gio_setAnimating(w.view, animi) 206 } 207 208 func (w *window) onKeyCommand(name string) { 209 w.w.Event(key.Event{ 210 Name: name, 211 }) 212 } 213 214 // lookupTouch maps an UITouch pointer value to an index. If 215 // last is set, the map is cleared. 216 func (w *window) lookupTouch(last bool, touch C.CFTypeRef) pointer.ID { 217 id := -1 218 for i, ref := range w.pointerMap { 219 if ref == touch { 220 id = i 221 break 222 } 223 } 224 if id == -1 { 225 id = len(w.pointerMap) 226 w.pointerMap = append(w.pointerMap, touch) 227 } 228 if last { 229 w.pointerMap = w.pointerMap[:0] 230 } 231 return pointer.ID(id) 232 } 233 234 func (w *window) contextLayer() uintptr { 235 return uintptr(w.layer) 236 } 237 238 func (w *window) isVisible() bool { 239 return w.visible.Load().(bool) 240 } 241 242 func (w *window) ShowTextInput(show bool) { 243 if w.view == 0 { 244 return 245 } 246 if show { 247 C.gio_showTextInput(w.view) 248 } else { 249 C.gio_hideTextInput(w.view) 250 } 251 } 252 253 func NewWindow(win Callbacks, opts *Options) error { 254 mainWindow.in <- windowAndOptions{win, opts} 255 return <-mainWindow.errs 256 } 257 258 func Main() { 259 }