github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/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  char* GetFilesDir(void);
    21  void runApp(void);
    22  void setContext(void* context);
    23  uint64_t threadID();
    24  */
    25  import "C"
    26  import (
    27  	"log"
    28  	"runtime"
    29  	"strings"
    30  	"sync"
    31  	"unsafe"
    32  	"github.com/democratic-coin/dcoin-go/packages/dcoin"
    33  	"github.com/c-darwin/mobile/event/lifecycle"
    34  	"github.com/c-darwin/mobile/event/paint"
    35  	"github.com/c-darwin/mobile/event/size"
    36  	"github.com/c-darwin/mobile/event/touch"
    37  	"github.com/c-darwin/mobile/geom"
    38  	"github.com/c-darwin/mobile/gl"
    39  )
    40  
    41  var initThreadID uint64
    42  
    43  //export dcoinStart
    44  func dcoinStart(){
    45  	go dcoin.Start(C.GoString(C.GetFilesDir()), nil);
    46  }
    47  
    48  //export dcoinStop
    49  func dcoinStop(){
    50  	go dcoin.Stop();
    51  }
    52  
    53  //export dcoinStopHTTPServer
    54  func dcoinStopHTTPServer(){
    55  	go dcoin.StopHTTPServer();
    56  }
    57  
    58  func init() {
    59  	// Lock the goroutine responsible for initialization to an OS thread.
    60  	// This means the goroutine running main (and calling the run function
    61  	// below) is locked to the OS thread that started the program. This is
    62  	// necessary for the correct delivery of UIKit events to the process.
    63  	//
    64  	// A discussion on this topic:
    65  	// https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ
    66  	runtime.LockOSThread()
    67  	initThreadID = uint64(C.threadID())
    68  }
    69  
    70  func main(f func(App)) {
    71  	if tid := uint64(C.threadID()); tid != initThreadID {
    72  		log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID)
    73  	}
    74  
    75  	go func() {
    76  		f(app{})
    77  		// TODO(crawshaw): trigger runApp to return
    78  	}()
    79  	C.runApp()
    80  	panic("unexpected return from app.runApp")
    81  }
    82  
    83  var pixelsPerPt float32
    84  var screenScale int // [UIScreen mainScreen].scale, either 1, 2, or 3.
    85  
    86  //export setScreen
    87  func setScreen(scale int) {
    88  	C.uname(&C.sysInfo)
    89  	name := C.GoString(&C.sysInfo.machine[0])
    90  
    91  	var v float32
    92  
    93  	switch {
    94  	case strings.HasPrefix(name, "iPhone"):
    95  		v = 163
    96  	case strings.HasPrefix(name, "iPad"):
    97  		// TODO: is there a better way to distinguish the iPad Mini?
    98  		switch name {
    99  		case "iPad2,5", "iPad2,6", "iPad2,7", "iPad4,4", "iPad4,5", "iPad4,6", "iPad4,7":
   100  			v = 163 // iPad Mini
   101  		default:
   102  			v = 132
   103  		}
   104  	default:
   105  		v = 163 // names like i386 and x86_64 are the simulator
   106  	}
   107  
   108  	if v == 0 {
   109  		log.Printf("unknown machine: %s", name)
   110  		v = 163 // emergency fallback
   111  	}
   112  
   113  	pixelsPerPt = v * float32(scale) / 72
   114  	screenScale = scale
   115  }
   116  
   117  //export updateConfig
   118  func updateConfig(width, height, orientation int32) {
   119  	o := size.OrientationUnknown
   120  	switch orientation {
   121  	case C.UIDeviceOrientationPortrait, C.UIDeviceOrientationPortraitUpsideDown:
   122  		o = size.OrientationPortrait
   123  	case C.UIDeviceOrientationLandscapeLeft, C.UIDeviceOrientationLandscapeRight:
   124  		o = size.OrientationLandscape
   125  	}
   126  	widthPx := screenScale * int(width)
   127  	heightPx := screenScale * int(height)
   128  	eventsIn <- size.Event{
   129  		WidthPx:     widthPx,
   130  		HeightPx:    heightPx,
   131  		WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
   132  		HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
   133  		PixelsPerPt: pixelsPerPt,
   134  		Orientation: o,
   135  	}
   136  }
   137  
   138  var startedgl = false
   139  
   140  // touchIDs is the current active touches. The position in the array
   141  // is the ID, the value is the UITouch* pointer value.
   142  //
   143  // It is widely reported that the iPhone can handle up to 5 simultaneous
   144  // touch events, while the iPad can handle 11.
   145  var touchIDs [11]uintptr
   146  
   147  var touchEvents struct {
   148  	sync.Mutex
   149  	pending []touch.Event
   150  }
   151  
   152  //export sendTouch
   153  func sendTouch(cTouch, cTouchType uintptr, x, y float32) {
   154  	id := -1
   155  	for i, val := range touchIDs {
   156  		if val == cTouch {
   157  			id = i
   158  			break
   159  		}
   160  	}
   161  	if id == -1 {
   162  		for i, val := range touchIDs {
   163  			if val == 0 {
   164  				touchIDs[i] = cTouch
   165  				id = i
   166  				break
   167  			}
   168  		}
   169  		if id == -1 {
   170  			panic("out of touchIDs")
   171  		}
   172  	}
   173  
   174  	t := touch.Type(cTouchType)
   175  	if t == touch.TypeEnd {
   176  		touchIDs[id] = 0
   177  	}
   178  
   179  	eventsIn <- touch.Event{
   180  		X:        x,
   181  		Y:        y,
   182  		Sequence: touch.Sequence(id),
   183  		Type:     t,
   184  	}
   185  }
   186  
   187  //export drawgl
   188  func drawgl(ctx uintptr) {
   189  	if !startedgl {
   190  		startedgl = true
   191  		C.setContext(unsafe.Pointer(ctx))
   192  		// TODO(crawshaw): not just on process start.
   193  		sendLifecycle(lifecycle.StageFocused)
   194  	}
   195  
   196  	eventsIn <- paint.Event{}
   197  
   198  	for {
   199  		select {
   200  		case <-gl.WorkAvailable:
   201  			gl.DoWork()
   202  		case <-endPaint:
   203  			return
   204  		}
   205  	}
   206  }