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