github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/app/darwin_armx.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin 6 // +build arm arm64 7 8 package app 9 10 /* 11 #cgo CFLAGS: -x objective-c 12 #cgo LDFLAGS: -framework Foundation -framework UIKit -framework GLKit -framework OpenGLES -framework QuartzCore 13 #include <sys/utsname.h> 14 #include <stdint.h> 15 #include <pthread.h> 16 #include <UIKit/UIDevice.h> 17 18 extern struct utsname sysInfo; 19 20 void runApp(void); 21 void setContext(void* context); 22 uint64_t threadID(); 23 */ 24 import "C" 25 import ( 26 "log" 27 "runtime" 28 "strings" 29 "sync" 30 "unsafe" 31 32 "golang.org/x/mobile/event/lifecycle" 33 "golang.org/x/mobile/event/paint" 34 "golang.org/x/mobile/event/size" 35 "golang.org/x/mobile/event/touch" 36 "golang.org/x/mobile/geom" 37 ) 38 39 var initThreadID uint64 40 41 func init() { 42 // Lock the goroutine responsible for initialization to an OS thread. 43 // This means the goroutine running main (and calling the run function 44 // below) is locked to the OS thread that started the program. This is 45 // necessary for the correct delivery of UIKit events to the process. 46 // 47 // A discussion on this topic: 48 // https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ 49 runtime.LockOSThread() 50 initThreadID = uint64(C.threadID()) 51 } 52 53 func main(f func(App)) { 54 if tid := uint64(C.threadID()); tid != initThreadID { 55 log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID) 56 } 57 58 go func() { 59 f(theApp) 60 // TODO(crawshaw): trigger runApp to return 61 }() 62 C.runApp() 63 panic("unexpected return from app.runApp") 64 } 65 66 var pixelsPerPt float32 67 var screenScale int // [UIScreen mainScreen].scale, either 1, 2, or 3. 68 69 //export setScreen 70 func setScreen(scale int) { 71 C.uname(&C.sysInfo) 72 name := C.GoString(&C.sysInfo.machine[0]) 73 74 var v float32 75 76 switch { 77 case strings.HasPrefix(name, "iPhone"): 78 v = 163 79 case strings.HasPrefix(name, "iPad"): 80 // TODO: is there a better way to distinguish the iPad Mini? 81 switch name { 82 case "iPad2,5", "iPad2,6", "iPad2,7", "iPad4,4", "iPad4,5", "iPad4,6", "iPad4,7": 83 v = 163 // iPad Mini 84 default: 85 v = 132 86 } 87 default: 88 v = 163 // names like i386 and x86_64 are the simulator 89 } 90 91 if v == 0 { 92 log.Printf("unknown machine: %s", name) 93 v = 163 // emergency fallback 94 } 95 96 pixelsPerPt = v * float32(scale) / 72 97 screenScale = scale 98 } 99 100 //export updateConfig 101 func updateConfig(width, height, orientation int32) { 102 o := size.OrientationUnknown 103 switch orientation { 104 case C.UIDeviceOrientationPortrait, C.UIDeviceOrientationPortraitUpsideDown: 105 o = size.OrientationPortrait 106 case C.UIDeviceOrientationLandscapeLeft, C.UIDeviceOrientationLandscapeRight: 107 o = size.OrientationLandscape 108 } 109 widthPx := screenScale * int(width) 110 heightPx := screenScale * int(height) 111 theApp.eventsIn <- size.Event{ 112 WidthPx: widthPx, 113 HeightPx: heightPx, 114 WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt), 115 HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt), 116 PixelsPerPt: pixelsPerPt, 117 Orientation: o, 118 } 119 } 120 121 // touchIDs is the current active touches. The position in the array 122 // is the ID, the value is the UITouch* pointer value. 123 // 124 // It is widely reported that the iPhone can handle up to 5 simultaneous 125 // touch events, while the iPad can handle 11. 126 var touchIDs [11]uintptr 127 128 var touchEvents struct { 129 sync.Mutex 130 pending []touch.Event 131 } 132 133 //export sendTouch 134 func sendTouch(cTouch, cTouchType uintptr, x, y float32) { 135 id := -1 136 for i, val := range touchIDs { 137 if val == cTouch { 138 id = i 139 break 140 } 141 } 142 if id == -1 { 143 for i, val := range touchIDs { 144 if val == 0 { 145 touchIDs[i] = cTouch 146 id = i 147 break 148 } 149 } 150 if id == -1 { 151 panic("out of touchIDs") 152 } 153 } 154 155 t := touch.Type(cTouchType) 156 if t == touch.TypeEnd { 157 touchIDs[id] = 0 158 } 159 160 theApp.eventsIn <- touch.Event{ 161 X: x, 162 Y: y, 163 Sequence: touch.Sequence(id), 164 Type: t, 165 } 166 } 167 168 var workAvailable <-chan struct{} 169 170 //export drawgl 171 func drawgl(ctx uintptr) { 172 if workAvailable == nil { 173 C.setContext(unsafe.Pointer(ctx)) 174 workAvailable = theApp.worker.WorkAvailable() 175 // TODO(crawshaw): not just on process start. 176 theApp.sendLifecycle(lifecycle.StageFocused) 177 } 178 179 // TODO(crawshaw): don't send a paint.Event unconditionally. Only send one 180 // if the window actually needs redrawing. 181 theApp.eventsIn <- paint.Event{} 182 183 for { 184 select { 185 case <-workAvailable: 186 theApp.worker.DoWork() 187 case <-theApp.publish: 188 theApp.publishResult <- PublishResult{} 189 return 190 } 191 } 192 }