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  }