darwin_desktop.m 7.0 KB

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