gl_macos.m raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 // +build darwin,!ios
4
5 @import AppKit;
6
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <OpenGL/OpenGL.h>
9 #include <OpenGL/gl3.h>
10 #include "_cgo_export.h"
11
12 static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFloat dy) {
13 NSPoint p = [view convertPoint:[event locationInWindow] fromView:nil];
14 if (!event.hasPreciseScrollingDeltas) {
15 // dx and dy are in rows and columns.
16 dx *= 10;
17 dy *= 10;
18 }
19 gio_onMouse((__bridge CFTypeRef)view, typ, [NSEvent pressedMouseButtons], p.x, p.y, dx, dy, [event timestamp], [event modifierFlags]);
20 }
21
22 @interface GioView : NSOpenGLView
23 @end
24
25 @implementation GioView
26 - (instancetype)initWithFrame:(NSRect)frameRect
27 pixelFormat:(NSOpenGLPixelFormat *)format {
28 return [super initWithFrame:frameRect pixelFormat:format];
29 }
30 - (void)prepareOpenGL {
31 [super prepareOpenGL];
32 // Bind a default VBA to emulate OpenGL ES 2.
33 GLuint defVBA;
34 glGenVertexArrays(1, &defVBA);
35 glBindVertexArray(defVBA);
36 glEnable(GL_FRAMEBUFFER_SRGB);
37 }
38 - (BOOL)isFlipped {
39 return YES;
40 }
41 - (void)update {
42 [super update];
43 [self setNeedsDisplay:YES];
44 }
45 - (void)drawRect:(NSRect)r {
46 gio_onDraw((__bridge CFTypeRef)self);
47 }
48 - (void)mouseDown:(NSEvent *)event {
49 handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
50 }
51 - (void)mouseUp:(NSEvent *)event {
52 handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
53 }
54 - (void)middleMouseDown:(NSEvent *)event {
55 handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
56 }
57 - (void)middletMouseUp:(NSEvent *)event {
58 handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
59 }
60 - (void)rightMouseDown:(NSEvent *)event {
61 handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
62 }
63 - (void)rightMouseUp:(NSEvent *)event {
64 handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
65 }
66 - (void)mouseMoved:(NSEvent *)event {
67 handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
68 }
69 - (void)mouseDragged:(NSEvent *)event {
70 handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
71 }
72 - (void)scrollWheel:(NSEvent *)event {
73 CGFloat dx = -event.scrollingDeltaX;
74 CGFloat dy = -event.scrollingDeltaY;
75 handleMouse(self, event, GIO_MOUSE_SCROLL, dx, dy);
76 }
77 - (void)keyDown:(NSEvent *)event {
78 NSString *keys = [event charactersIgnoringModifiers];
79 gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], true);
80 [self interpretKeyEvents:[NSArray arrayWithObject:event]];
81 }
82 - (void)keyUp:(NSEvent *)event {
83 NSString *keys = [event charactersIgnoringModifiers];
84 gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], false);
85 }
86 - (void)insertText:(id)string {
87 const char *utf8 = [string UTF8String];
88 gio_onText((__bridge CFTypeRef)self, (char *)utf8);
89 }
90 - (void)doCommandBySelector:(SEL)sel {
91 // Don't pass commands up the responder chain.
92 // They will end up in a beep.
93 }
94 @end
95
96 CFTypeRef gio_createGLView(void) {
97 @autoreleasepool {
98 NSOpenGLPixelFormatAttribute attr[] = {
99 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
100 NSOpenGLPFAColorSize, 24,
101 NSOpenGLPFADepthSize, 16,
102 NSOpenGLPFAAccelerated,
103 // Opt-in to automatic GPU switching. CGL-only property.
104 kCGLPFASupportsAutomaticGraphicsSwitching,
105 NSOpenGLPFAAllowOfflineRenderers,
106 0
107 };
108 id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
109
110 NSRect frame = NSMakeRect(0, 0, 0, 0);
111 GioView* view = [[GioView alloc] initWithFrame:frame pixelFormat:pixFormat];
112
113 [view setWantsBestResolutionOpenGLSurface:YES];
114 [view setWantsLayer:YES]; // The default in Mojave.
115
116 return CFBridgingRetain(view);
117 }
118 }
119
120 void gio_setNeedsDisplay(CFTypeRef viewRef) {
121 NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
122 [view setNeedsDisplay:YES];
123 }
124
125 CFTypeRef gio_contextForView(CFTypeRef viewRef) {
126 NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
127 return (__bridge CFTypeRef)view.openGLContext;
128 }
129
130 void gio_clearCurrentContext(void) {
131 [NSOpenGLContext clearCurrentContext];
132 }
133
134 void gio_makeCurrentContext(CFTypeRef ctxRef) {
135 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
136 [ctx makeCurrentContext];
137 }
138
139 void gio_lockContext(CFTypeRef ctxRef) {
140 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
141 CGLLockContext([ctx CGLContextObj]);
142 }
143
144 void gio_unlockContext(CFTypeRef ctxRef) {
145 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
146 CGLUnlockContext([ctx CGLContextObj]);
147 }
148