darwin_ios.m (5117B)
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 ios 7 8 #include "_cgo_export.h" 9 #include <pthread.h> 10 #include <stdio.h> 11 #include <sys/utsname.h> 12 13 #import <UIKit/UIKit.h> 14 #import <GLKit/GLKit.h> 15 16 struct utsname sysInfo; 17 18 @interface GoAppAppController : GLKViewController<UIContentContainer, GLKViewDelegate> 19 @end 20 21 @interface GoAppAppDelegate : UIResponder<UIApplicationDelegate> 22 @property (strong, nonatomic) UIWindow *window; 23 @property (strong, nonatomic) GoAppAppController *controller; 24 @end 25 26 @implementation GoAppAppDelegate 27 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 28 lifecycleAlive(); 29 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 30 self.controller = [[GoAppAppController alloc] initWithNibName:nil bundle:nil]; 31 self.window.rootViewController = self.controller; 32 [self.window makeKeyAndVisible]; 33 return YES; 34 } 35 36 - (void)applicationDidBecomeActive:(UIApplication * )application { 37 lifecycleFocused(); 38 } 39 40 - (void)applicationWillResignActive:(UIApplication *)application { 41 lifecycleVisible(); 42 } 43 44 - (void)applicationDidEnterBackground:(UIApplication *)application { 45 lifecycleAlive(); 46 } 47 48 - (void)applicationWillTerminate:(UIApplication *)application { 49 lifecycleDead(); 50 } 51 @end 52 53 @interface GoAppAppController () 54 @property (strong, nonatomic) EAGLContext *context; 55 @property (strong, nonatomic) GLKView *glview; 56 @end 57 58 @implementation GoAppAppController 59 - (void)viewWillAppear:(BOOL)animated 60 { 61 // TODO: replace by swapping out GLKViewController for a UIVIewController. 62 [super viewWillAppear:animated]; 63 self.paused = YES; 64 } 65 66 - (void)viewDidLoad { 67 [super viewDidLoad]; 68 self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 69 self.glview = (GLKView*)self.view; 70 self.glview.drawableDepthFormat = GLKViewDrawableDepthFormat24; 71 self.glview.multipleTouchEnabled = true; // TODO expose setting to user. 72 self.glview.context = self.context; 73 self.glview.userInteractionEnabled = YES; 74 self.glview.enableSetNeedsDisplay = YES; // only invoked once 75 76 // Do not use the GLKViewController draw loop. 77 self.paused = YES; 78 self.resumeOnDidBecomeActive = NO; 79 self.preferredFramesPerSecond = 0; 80 81 int scale = 1; 82 if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]) { 83 scale = (int)[UIScreen mainScreen].scale; // either 1.0, 2.0, or 3.0. 84 } 85 setScreen(scale); 86 87 CGSize size = [UIScreen mainScreen].bounds.size; 88 UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 89 updateConfig((int)size.width, (int)size.height, orientation); 90 } 91 92 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { 93 [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { 94 // TODO(crawshaw): come up with a plan to handle animations. 95 } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { 96 UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 97 updateConfig((int)size.width, (int)size.height, orientation); 98 }]; 99 } 100 101 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { 102 // Now that we have been asked to do the first draw, disable any 103 // future draw and hand control over to the Go paint.Event cycle. 104 self.glview.enableSetNeedsDisplay = NO; 105 startloop((GLintptr)self.context); 106 } 107 108 #define TOUCH_TYPE_BEGIN 0 // touch.TypeBegin 109 #define TOUCH_TYPE_MOVE 1 // touch.TypeMove 110 #define TOUCH_TYPE_END 2 // touch.TypeEnd 111 112 static void sendTouches(int change, NSSet* touches) { 113 CGFloat scale = [UIScreen mainScreen].scale; 114 for (UITouch* touch in touches) { 115 CGPoint p = [touch locationInView:touch.view]; 116 sendTouch((GoUintptr)touch, (GoUintptr)change, p.x*scale, p.y*scale); 117 } 118 } 119 120 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { 121 sendTouches(TOUCH_TYPE_BEGIN, touches); 122 } 123 124 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { 125 sendTouches(TOUCH_TYPE_MOVE, touches); 126 } 127 128 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { 129 sendTouches(TOUCH_TYPE_END, touches); 130 } 131 132 - (void)touchesCanceled:(NSSet*)touches withEvent:(UIEvent*)event { 133 sendTouches(TOUCH_TYPE_END, touches); 134 } 135 @end 136 137 void runApp(void) { 138 @autoreleasepool { 139 UIApplicationMain(0, nil, nil, NSStringFromClass([GoAppAppDelegate class])); 140 } 141 } 142 143 void makeCurrentContext(GLintptr context) { 144 EAGLContext* ctx = (EAGLContext*)context; 145 if (![EAGLContext setCurrentContext:ctx]) { 146 // TODO(crawshaw): determine how terrible this is. Exit? 147 NSLog(@"failed to set current context"); 148 } 149 } 150 151 void swapBuffers(GLintptr context) { 152 __block EAGLContext* ctx = (EAGLContext*)context; 153 dispatch_sync(dispatch_get_main_queue(), ^{ 154 [EAGLContext setCurrentContext:ctx]; 155 [ctx presentRenderbuffer:GL_RENDERBUFFER]; 156 }); 157 } 158 159 uint64_t threadID() { 160 uint64_t id; 161 if (pthread_threadid_np(pthread_self(), &id)) { 162 abort(); 163 } 164 return id; 165 }