github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/gldriver/cocoa.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 // +build 386 amd64 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(uintptr_t context) { 18 NSOpenGLContext* ctx = (NSOpenGLContext*)context; 19 [ctx makeCurrentContext]; 20 } 21 22 void flushContext(uintptr_t context) { 23 NSOpenGLContext* ctx = (NSOpenGLContext*)context; 24 [ctx flushBuffer]; 25 } 26 27 uint64 threadID() { 28 uint64 id; 29 if (pthread_threadid_np(pthread_self(), &id)) { 30 abort(); 31 } 32 return id; 33 } 34 35 @interface ScreenGLView : NSOpenGLView<NSWindowDelegate> 36 { 37 } 38 @end 39 40 @implementation ScreenGLView 41 - (void)prepareOpenGL { 42 [self setWantsBestResolutionOpenGLSurface:YES]; 43 GLint swapInt = 1; 44 NSOpenGLContext *ctx = [self openGLContext]; 45 [ctx setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 46 47 // Using attribute arrays in OpenGL 3.3 requires the use of a VBA. 48 // But VBAs don't exist in ES 2. So we bind a default one. 49 GLuint vba; 50 glGenVertexArrays(1, &vba); 51 glBindVertexArray(vba); 52 53 preparedOpenGL((GoUintptr)self, (GoUintptr)ctx, (GoUintptr)vba); 54 } 55 56 - (void)callSetGeom { 57 // Calculate screen PPI. 58 // 59 // Note that the backingScaleFactor converts from logical 60 // pixels to actual pixels, but both of these units vary 61 // independently from real world size. E.g. 62 // 63 // 13" Retina Macbook Pro, 2560x1600, 227ppi, backingScaleFactor=2, scale=3.15 64 // 15" Retina Macbook Pro, 2880x1800, 220ppi, backingScaleFactor=2, scale=3.06 65 // 27" iMac, 2560x1440, 109ppi, backingScaleFactor=1, scale=1.51 66 // 27" Retina iMac, 5120x2880, 218ppi, backingScaleFactor=2, scale=3.03 67 NSScreen *screen = self.window.screen; 68 double screenPixW = [screen frame].size.width * [screen backingScaleFactor]; 69 70 CGDirectDisplayID display = (CGDirectDisplayID)[[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue]; 71 CGSize screenSizeMM = CGDisplayScreenSize(display); // in millimeters 72 float ppi = 25.4 * screenPixW / screenSizeMM.width; 73 float pixelsPerPt = ppi/72.0; 74 75 // The width and height reported to the geom package are the 76 // bounds of the OpenGL view. Several steps are necessary. 77 // First, [self bounds] gives us the number of logical pixels 78 // in the view. Multiplying this by the backingScaleFactor 79 // gives us the number of actual pixels. 80 NSRect r = [self bounds]; 81 int w = r.size.width * [screen backingScaleFactor]; 82 int h = r.size.height * [screen backingScaleFactor]; 83 84 setGeom((GoUintptr)self, pixelsPerPt, w, h); 85 } 86 87 - (void)reshape { 88 [super reshape]; 89 [self callSetGeom]; 90 } 91 92 - (void)drawRect:(NSRect)theRect { 93 // Called during resize. Do an extra draw if we are visible. 94 // This gets rid of flicker when resizing. 95 drawgl((GoUintptr)self); 96 } 97 98 - (void)mouseEventNS:(NSEvent *)theEvent { 99 NSPoint p = [theEvent locationInWindow]; 100 double h = self.frame.size.height; 101 102 // Both h and p are measured in Cocoa pixels, which are a fraction of 103 // physical pixels, so we multiply by backingScaleFactor. 104 double scale = [self.window.screen backingScaleFactor]; 105 106 double x = p.x * scale; 107 double y = (h - p.y) * scale - 1; // flip origin from bottom-left to top-left. 108 109 mouseEvent((GoUintptr)self, x, y, theEvent.type, theEvent.buttonNumber, theEvent.modifierFlags); 110 } 111 112 - (void)mouseDown:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 113 - (void)mouseUp:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 114 - (void)mouseDragged:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 115 - (void)rightMouseDown:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 116 - (void)rightMouseUp:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 117 - (void)rightMouseDragged:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 118 - (void)otherMouseDown:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 119 - (void)otherMouseUp:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 120 - (void)otherMouseDragged:(NSEvent *)theEvent { [self mouseEventNS:theEvent]; } 121 122 - (void)windowDidChangeScreenProfile:(NSNotification *)notification { 123 [self callSetGeom]; 124 } 125 126 - (void)windowDidExpose:(NSNotification *)notification { 127 lifecycleVisible((GoUintptr)self); 128 } 129 130 - (void)windowDidBecomeKey:(NSNotification *)notification { 131 lifecycleFocused((GoUintptr)self); 132 } 133 134 - (void)windowDidResignKey:(NSNotification *)notification { 135 if (![NSApp isHidden]) { 136 lifecycleVisible((GoUintptr)self); 137 } 138 } 139 140 - (void)windowWillClose:(NSNotification *)notification { 141 if (self.window.nextResponder == NULL) { 142 return; // already called close 143 } 144 windowClosing((GoUintptr)self); 145 [self.window.nextResponder release]; 146 self.window.nextResponder = NULL; 147 } 148 @end 149 150 @interface WindowResponder : NSResponder 151 { 152 } 153 @end 154 155 @implementation WindowResponder 156 { 157 uintptr_t windowID; 158 } 159 160 - (id)initWithWindowID:(uintptr_t)id { 161 windowID = id; 162 return self; 163 } 164 165 - (void)keyDown:(NSEvent *)theEvent { 166 [self key:theEvent]; 167 } 168 - (void)keyUp:(NSEvent *)theEvent { 169 [self key:theEvent]; 170 } 171 - (void)key:(NSEvent *)theEvent { 172 NSRange range = [theEvent.characters rangeOfComposedCharacterSequenceAtIndex:0]; 173 174 uint8_t buf[4] = {0, 0, 0, 0}; 175 if (![theEvent.characters getBytes:buf 176 maxLength:4 177 usedLength:nil 178 encoding:NSUTF32LittleEndianStringEncoding 179 options:NSStringEncodingConversionAllowLossy 180 range:range 181 remainingRange:nil]) { 182 NSLog(@"failed to read key event %@", theEvent); 183 return; 184 } 185 186 uint32_t rune = (uint32_t)buf[0]<<0 | (uint32_t)buf[1]<<8 | (uint32_t)buf[2]<<16 | (uint32_t)buf[3]<<24; 187 188 uint8_t direction; 189 if ([theEvent isARepeat]) { 190 direction = 0; 191 } else if (theEvent.type == NSKeyDown) { 192 direction = 1; 193 } else { 194 direction = 2; 195 } 196 keyEvent((GoUintptr)windowID, (int32_t)rune, direction, theEvent.keyCode, theEvent.modifierFlags); 197 } 198 199 - (void)flagsChanged:(NSEvent *)theEvent { 200 flagEvent((GoUintptr)windowID, theEvent.modifierFlags); 201 } 202 @end 203 204 @interface AppDelegate : NSObject<NSApplicationDelegate> 205 { 206 } 207 @end 208 209 @implementation AppDelegate 210 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 211 driverStarted(); 212 [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; 213 } 214 215 - (void)applicationWillTerminate:(NSNotification *)aNotification { 216 lifecycleDeadAll(); 217 } 218 219 - (void)applicationWillHide:(NSNotification *)aNotification { 220 lifecycleAliveAll(); 221 } 222 @end 223 224 uintptr_t doNewWindow(int width, int height) { 225 NSScreen *screen = [NSScreen mainScreen]; 226 double w = (double)width / [screen backingScaleFactor]; 227 double h = (double)height / [screen backingScaleFactor]; 228 __block ScreenGLView* view = NULL; 229 230 dispatch_sync(dispatch_get_main_queue(), ^{ 231 id menuBar = [NSMenu new]; 232 id menuItem = [NSMenuItem new]; 233 [menuBar addItem:menuItem]; 234 [NSApp setMainMenu:menuBar]; 235 236 id menu = [NSMenu new]; 237 NSString* name = [[NSProcessInfo processInfo] processName]; 238 239 id hideMenuItem = [[NSMenuItem alloc] initWithTitle:@"Hide" 240 action:@selector(hide:) keyEquivalent:@"h"]; 241 [menu addItem:hideMenuItem]; 242 243 id quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit" 244 action:@selector(terminate:) keyEquivalent:@"q"]; 245 [menu addItem:quitMenuItem]; 246 [menuItem setSubmenu:menu]; 247 248 NSRect rect = NSMakeRect(0, 0, w, h); 249 250 NSWindow* window = [[NSWindow alloc] initWithContentRect:rect 251 styleMask:NSTitledWindowMask 252 backing:NSBackingStoreBuffered 253 defer:NO]; 254 window.styleMask |= NSResizableWindowMask; 255 window.styleMask |= NSMiniaturizableWindowMask ; 256 window.styleMask |= NSClosableWindowMask; 257 window.title = name; 258 window.displaysWhenScreenProfileChanges = YES; 259 [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; 260 261 NSOpenGLPixelFormatAttribute attr[] = { 262 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 263 NSOpenGLPFAColorSize, 24, 264 NSOpenGLPFAAlphaSize, 8, 265 NSOpenGLPFADepthSize, 16, 266 NSOpenGLPFAAccelerated, 267 NSOpenGLPFADoubleBuffer, 268 NSOpenGLPFAAllowOfflineRenderers, 269 0 270 }; 271 id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; 272 view = [[ScreenGLView alloc] initWithFrame:rect pixelFormat:pixFormat]; 273 [window setContentView:view]; 274 [window setDelegate:view]; 275 276 window.nextResponder = [[WindowResponder alloc] initWithWindowID:(uintptr_t)view]; 277 }); 278 279 return (uintptr_t)view; 280 } 281 282 void doShowWindow(uintptr_t viewID) { 283 ScreenGLView* view = (ScreenGLView*)viewID; 284 dispatch_async(dispatch_get_main_queue(), ^{ 285 [view.window makeKeyAndOrderFront:view.window]; 286 }); 287 } 288 289 void doCloseWindow(uintptr_t viewID) { 290 ScreenGLView* view = (ScreenGLView*)viewID; 291 dispatch_sync(dispatch_get_main_queue(), ^{ 292 [view.window performClose:view]; 293 }); 294 } 295 296 void startDriver() { 297 [NSAutoreleasePool new]; 298 [NSApplication sharedApplication]; 299 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 300 AppDelegate* delegate = [[AppDelegate alloc] init]; 301 [NSApp setDelegate:delegate]; 302 [NSApp run]; 303 } 304 305 void stopDriver() { 306 dispatch_async(dispatch_get_main_queue(), ^{ 307 [NSApp terminate:nil]; 308 }); 309 }