github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/app/darwin_amd64.m (about) 1 // Copyright 2014 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 7 #include "_cgo_export.h" 8 #include <pthread.h> 9 #include <stdio.h> 10 11 #import <Cocoa/Cocoa.h> 12 #import <Foundation/Foundation.h> 13 #import <OpenGL/gl3.h> 14 #import <QuartzCore/CVReturn.h> 15 #import <QuartzCore/CVBase.h> 16 17 static CVReturn displayLinkDraw(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) 18 { 19 drawgl(); 20 return kCVReturnSuccess; 21 } 22 23 void makeCurrentContext(GLintptr context) { 24 NSOpenGLContext* ctx = (NSOpenGLContext*)context; 25 [ctx makeCurrentContext]; 26 } 27 28 uint64 threadID() { 29 uint64 id; 30 if (pthread_threadid_np(pthread_self(), &id)) { 31 abort(); 32 } 33 return id; 34 } 35 36 37 @interface MobileGLView : NSOpenGLView<NSApplicationDelegate, NSWindowDelegate> 38 { 39 CVDisplayLinkRef displayLink; 40 } 41 @end 42 43 @implementation MobileGLView 44 - (void)prepareOpenGL { 45 [self setWantsBestResolutionOpenGLSurface:YES]; 46 GLint swapInt = 1; 47 [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 48 49 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); 50 CVDisplayLinkSetOutputCallback(displayLink, &displayLinkDraw, self); 51 52 CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; 53 CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; 54 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); 55 56 // Using attribute arrays in OpenGL 3.3 requires the use of a VBA. 57 // But VBAs don't exist in ES 2. So we bind a default one. 58 GLuint vba; 59 glGenVertexArrays(1, &vba); 60 glBindVertexArray(vba); 61 62 startloop((GLintptr)[self openGLContext]); 63 } 64 65 - (void)reshape { 66 [super reshape]; 67 68 // Calculate screen PPI. 69 // 70 // Note that the backingScaleFactor converts from logical 71 // pixels to actual pixels, but both of these units vary 72 // independently from real world size. E.g. 73 // 74 // 13" Retina Macbook Pro, 2560x1600, 227ppi, backingScaleFactor=2, scale=3.15 75 // 15" Retina Macbook Pro, 2880x1800, 220ppi, backingScaleFactor=2, scale=3.06 76 // 27" iMac, 2560x1440, 109ppi, backingScaleFactor=1, scale=1.51 77 // 27" Retina iMac, 5120x2880, 218ppi, backingScaleFactor=2, scale=3.03 78 NSScreen *screen = [NSScreen mainScreen]; 79 double screenPixW = [screen frame].size.width * [screen backingScaleFactor]; 80 81 CGDirectDisplayID display = (CGDirectDisplayID)[[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue]; 82 CGSize screenSizeMM = CGDisplayScreenSize(display); // in millimeters 83 float ppi = 25.4 * screenPixW / screenSizeMM.width; 84 float pixelsPerPt = ppi/72.0; 85 86 // The width and height reported to the geom package are the 87 // bounds of the OpenGL view. Several steps are necessary. 88 // First, [self bounds] gives us the number of logical pixels 89 // in the view. Multiplying this by the backingScaleFactor 90 // gives us the number of actual pixels. 91 NSRect r = [self bounds]; 92 int w = r.size.width * [screen backingScaleFactor]; 93 int h = r.size.height * [screen backingScaleFactor]; 94 95 setGeom(pixelsPerPt, w, h); 96 } 97 98 - (void)drawRect:(NSRect)theRect { 99 // Called during resize. Do an extra draw if we are visible. 100 // This gets rid of flicker when resizing. 101 if (CVDisplayLinkIsRunning(displayLink)) { 102 drawgl(); 103 } 104 } 105 106 - (void)mouseDown:(NSEvent *)theEvent { 107 double scale = [[NSScreen mainScreen] backingScaleFactor]; 108 NSPoint p = [theEvent locationInWindow]; 109 eventMouseDown(p.x * scale, p.y * scale); 110 } 111 112 - (void)mouseUp:(NSEvent *)theEvent { 113 double scale = [[NSScreen mainScreen] backingScaleFactor]; 114 NSPoint p = [theEvent locationInWindow]; 115 eventMouseEnd(p.x * scale, p.y * scale); 116 } 117 118 - (void)mouseDragged:(NSEvent *)theEvent { 119 double scale = [[NSScreen mainScreen] backingScaleFactor]; 120 NSPoint p = [theEvent locationInWindow]; 121 eventMouseDragged(p.x * scale, p.y * scale); 122 } 123 124 - (void)windowDidBecomeKey:(NSNotification *)notification { 125 lifecycleFocused(); 126 } 127 128 - (void)windowDidResignKey:(NSNotification *)notification { 129 if (![NSApp isHidden]) { 130 lifecycleVisible(); 131 } 132 } 133 134 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 135 lifecycleAlive(); 136 [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; 137 [self.window makeKeyAndOrderFront:self]; 138 lifecycleVisible(); 139 CVDisplayLinkStart(displayLink); 140 } 141 142 - (void)applicationWillTerminate:(NSNotification *)aNotification { 143 lifecycleDead(); 144 } 145 146 - (void)applicationDidHide:(NSNotification *)aNotification { 147 CVDisplayLinkStop(displayLink); 148 lifecycleAlive(); 149 } 150 151 - (void)applicationWillUnhide:(NSNotification *)notification { 152 lifecycleVisible(); 153 CVDisplayLinkStart(displayLink); 154 } 155 156 - (void)windowWillClose:(NSNotification *)notification { 157 CVDisplayLinkStop(displayLink); 158 lifecycleAlive(); 159 } 160 @end 161 162 @interface MobileResponder : NSResponder 163 { 164 } 165 @end 166 167 @implementation MobileResponder 168 - (void)keyDown:(NSEvent *)theEvent { 169 [self key:theEvent]; 170 } 171 - (void)keyUp:(NSEvent *)theEvent { 172 [self key:theEvent]; 173 } 174 - (void)key:(NSEvent *)theEvent { 175 NSRange range = [theEvent.characters rangeOfComposedCharacterSequenceAtIndex:0]; 176 177 uint8_t buf[4] = {0, 0, 0, 0}; 178 if (![theEvent.characters getBytes:buf 179 maxLength:4 180 usedLength:nil 181 encoding:NSUTF32LittleEndianStringEncoding 182 options:NSStringEncodingConversionAllowLossy 183 range:range 184 remainingRange:nil]) { 185 NSLog(@"failed to read key event %@", theEvent); 186 return; 187 } 188 189 uint32_t rune = (uint32_t)buf[0]<<0 | (uint32_t)buf[1]<<8 | (uint32_t)buf[2]<<16 | (uint32_t)buf[3]<<24; 190 191 uint8_t direction; 192 if ([theEvent isARepeat]) { 193 direction = 0; 194 } else if (theEvent.type == NSKeyDown) { 195 direction = 1; 196 } else { 197 direction = 2; 198 } 199 eventKey((int32_t)rune, direction, theEvent.keyCode, theEvent.modifierFlags); 200 } 201 202 - (void)flagsChanged:(NSEvent *)theEvent { 203 eventFlags(theEvent.modifierFlags); 204 } 205 @end 206 207 208 void 209 runApp(void) { 210 [NSAutoreleasePool new]; 211 [NSApplication sharedApplication]; 212 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 213 214 id menuBar = [[NSMenu new] autorelease]; 215 id menuItem = [[NSMenuItem new] autorelease]; 216 [menuBar addItem:menuItem]; 217 [NSApp setMainMenu:menuBar]; 218 219 id menu = [[NSMenu new] autorelease]; 220 id name = [[NSProcessInfo processInfo] processName]; 221 222 id hideMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Hide" 223 action:@selector(hide:) keyEquivalent:@"h"] 224 autorelease]; 225 [menu addItem:hideMenuItem]; 226 227 id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" 228 action:@selector(terminate:) keyEquivalent:@"q"] 229 autorelease]; 230 [menu addItem:quitMenuItem]; 231 [menuItem setSubmenu:menu]; 232 233 NSRect rect = NSMakeRect(0, 0, 400, 400); 234 235 NSWindow* window = [[[NSWindow alloc] initWithContentRect:rect 236 styleMask:NSTitledWindowMask 237 backing:NSBackingStoreBuffered 238 defer:NO] 239 autorelease]; 240 window.styleMask |= NSResizableWindowMask; 241 window.styleMask |= NSMiniaturizableWindowMask ; 242 window.styleMask |= NSClosableWindowMask; 243 window.title = name; 244 [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; 245 246 NSOpenGLPixelFormatAttribute attr[] = { 247 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 248 NSOpenGLPFAColorSize, 24, 249 NSOpenGLPFAAlphaSize, 8, 250 NSOpenGLPFADepthSize, 16, 251 NSOpenGLPFAAccelerated, 252 NSOpenGLPFADoubleBuffer, 253 NSOpenGLPFAAllowOfflineRenderers, 254 0 255 }; 256 id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; 257 MobileGLView* view = [[MobileGLView alloc] initWithFrame:rect pixelFormat:pixFormat]; 258 [window setContentView:view]; 259 [window setDelegate:view]; 260 [NSApp setDelegate:view]; 261 262 window.nextResponder = [[[MobileResponder alloc] init] autorelease]; 263 264 [NSApp run]; 265 } 266 267 void stopApp(void) { 268 [NSApp terminate:nil]; 269 }