| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- //go:build darwin && !ios
- // +build darwin
- // +build !ios
- #include "_cgo_export.h"
- #include <pthread.h>
- #include <stdio.h>
- #import <Cocoa/Cocoa.h>
- #import <Foundation/Foundation.h>
- #import <OpenGL/gl3.h>
- void makeCurrentContext(GLintptr context) {
- NSOpenGLContext* ctx = (NSOpenGLContext*)context;
- [ctx makeCurrentContext];
- }
- uint64 threadID() {
- uint64 id;
- if (pthread_threadid_np(pthread_self(), &id)) {
- abort();
- }
- return id;
- }
- @interface MobileGLView : NSOpenGLView<NSApplicationDelegate, NSWindowDelegate>
- {
- }
- @end
- @implementation MobileGLView
- - (void)prepareOpenGL {
- [super prepareOpenGL];
- [self setWantsBestResolutionOpenGLSurface:YES];
- GLint swapInt = 1;
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
- #pragma clang diagnostic pop
- // Using attribute arrays in OpenGL 3.3 requires the use of a VBA.
- // But VBAs don't exist in ES 2. So we bind a default one.
- GLuint vba;
- glGenVertexArrays(1, &vba);
- glBindVertexArray(vba);
- startloop((GLintptr)[self openGLContext]);
- }
- - (void)reshape {
- [super reshape];
- // Calculate screen PPI.
- //
- // Note that the backingScaleFactor converts from logical
- // pixels to actual pixels, but both of these units vary
- // independently from real world size. E.g.
- //
- // 13" Retina Macbook Pro, 2560x1600, 227ppi, backingScaleFactor=2, scale=3.15
- // 15" Retina Macbook Pro, 2880x1800, 220ppi, backingScaleFactor=2, scale=3.06
- // 27" iMac, 2560x1440, 109ppi, backingScaleFactor=1, scale=1.51
- // 27" Retina iMac, 5120x2880, 218ppi, backingScaleFactor=2, scale=3.03
- NSScreen *screen = [NSScreen mainScreen];
- double screenPixW = [screen frame].size.width * [screen backingScaleFactor];
- CGDirectDisplayID display = (CGDirectDisplayID)[[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue];
- CGSize screenSizeMM = CGDisplayScreenSize(display); // in millimeters
- float ppi = 25.4 * screenPixW / screenSizeMM.width;
- float pixelsPerPt = ppi/72.0;
- // The width and height reported to the geom package are the
- // bounds of the OpenGL view. Several steps are necessary.
- // First, [self bounds] gives us the number of logical pixels
- // in the view. Multiplying this by the backingScaleFactor
- // gives us the number of actual pixels.
- NSRect r = [self bounds];
- int w = r.size.width * [screen backingScaleFactor];
- int h = r.size.height * [screen backingScaleFactor];
- setGeom(pixelsPerPt, w, h);
- }
- - (void)drawRect:(NSRect)theRect {
- // Called during resize. This gets rid of flicker when resizing.
- drawgl();
- }
- - (void)mouseDown:(NSEvent *)theEvent {
- double scale = [[NSScreen mainScreen] backingScaleFactor];
- NSPoint p = [theEvent locationInWindow];
- eventMouseDown(p.x * scale, p.y * scale);
- }
- - (void)mouseUp:(NSEvent *)theEvent {
- double scale = [[NSScreen mainScreen] backingScaleFactor];
- NSPoint p = [theEvent locationInWindow];
- eventMouseEnd(p.x * scale, p.y * scale);
- }
- - (void)mouseDragged:(NSEvent *)theEvent {
- double scale = [[NSScreen mainScreen] backingScaleFactor];
- NSPoint p = [theEvent locationInWindow];
- eventMouseDragged(p.x * scale, p.y * scale);
- }
- - (void)windowDidBecomeKey:(NSNotification *)notification {
- lifecycleFocused();
- }
- - (void)windowDidResignKey:(NSNotification *)notification {
- if (![NSApp isHidden]) {
- lifecycleVisible();
- }
- }
- - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
- lifecycleAlive();
- [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
- [self.window makeKeyAndOrderFront:self];
- lifecycleVisible();
- }
- - (void)applicationWillTerminate:(NSNotification *)aNotification {
- lifecycleDead();
- }
- - (void)applicationDidHide:(NSNotification *)aNotification {
- lifecycleAlive();
- }
- - (void)applicationWillUnhide:(NSNotification *)notification {
- lifecycleVisible();
- }
- - (void)windowWillClose:(NSNotification *)notification {
- lifecycleAlive();
- }
- @end
- @interface MobileResponder : NSResponder
- {
- }
- @end
- @implementation MobileResponder
- - (void)keyDown:(NSEvent *)theEvent {
- [self key:theEvent];
- }
- - (void)keyUp:(NSEvent *)theEvent {
- [self key:theEvent];
- }
- - (void)key:(NSEvent *)theEvent {
- NSRange range = [theEvent.characters rangeOfComposedCharacterSequenceAtIndex:0];
- uint8_t buf[4] = {0, 0, 0, 0};
- if (![theEvent.characters getBytes:buf
- maxLength:4
- usedLength:nil
- encoding:NSUTF32LittleEndianStringEncoding
- options:NSStringEncodingConversionAllowLossy
- range:range
- remainingRange:nil]) {
- NSLog(@"failed to read key event %@", theEvent);
- return;
- }
- uint32_t rune = (uint32_t)buf[0]<<0 | (uint32_t)buf[1]<<8 | (uint32_t)buf[2]<<16 | (uint32_t)buf[3]<<24;
- uint8_t direction;
- if ([theEvent isARepeat]) {
- direction = 0;
- } else if (theEvent.type == NSEventTypeKeyDown) {
- direction = 1;
- } else {
- direction = 2;
- }
- eventKey((int32_t)rune, direction, theEvent.keyCode, theEvent.modifierFlags);
- }
- - (void)flagsChanged:(NSEvent *)theEvent {
- eventFlags(theEvent.modifierFlags);
- }
- @end
- void
- runApp(void) {
- [NSAutoreleasePool new];
- [NSApplication sharedApplication];
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- id menuBar = [[NSMenu new] autorelease];
- id menuItem = [[NSMenuItem new] autorelease];
- [menuBar addItem:menuItem];
- [NSApp setMainMenu:menuBar];
- id menu = [[NSMenu new] autorelease];
- id name = [[NSProcessInfo processInfo] processName];
- id hideMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Hide"
- action:@selector(hide:) keyEquivalent:@"h"]
- autorelease];
- [menu addItem:hideMenuItem];
- id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
- action:@selector(terminate:) keyEquivalent:@"q"]
- autorelease];
- [menu addItem:quitMenuItem];
- [menuItem setSubmenu:menu];
- NSRect rect = NSMakeRect(0, 0, 600, 800);
- NSWindow* window = [[[NSWindow alloc] initWithContentRect:rect
- styleMask:NSWindowStyleMaskTitled
- backing:NSBackingStoreBuffered
- defer:NO]
- autorelease];
- window.styleMask |= NSWindowStyleMaskResizable;
- window.styleMask |= NSWindowStyleMaskMiniaturizable;
- window.styleMask |= NSWindowStyleMaskClosable;
- window.title = name;
- [window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
- NSOpenGLPixelFormatAttribute attr[] = {
- NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
- NSOpenGLPFAColorSize, 24,
- NSOpenGLPFAAlphaSize, 8,
- NSOpenGLPFADepthSize, 16,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFADoubleBuffer,
- NSOpenGLPFAAllowOfflineRenderers,
- 0
- };
- id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
- MobileGLView* view = [[MobileGLView alloc] initWithFrame:rect pixelFormat:pixFormat];
- [window setContentView:view];
- [window setDelegate:view];
- [NSApp setDelegate:view];
- window.nextResponder = [[[MobileResponder alloc] init] autorelease];
- [NSApp run];
- }
- void stopApp(void) {
- [NSApp terminate:nil];
- }
|