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