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