gioui.org/ui@v0.0.0-20190926171558-ce74bc0cbaea/app/gl_macos.m (about) 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 "os_macos.h" 11 #include "gl_macos.h" 12 #include "_cgo_export.h" 13 14 static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFloat dy) { 15 NSPoint p = [view convertPoint:[event locationInWindow] fromView:nil]; 16 if (!event.hasPreciseScrollingDeltas) { 17 // dx and dy are in rows and columns. 18 dx *= 10; 19 dy *= 10; 20 } 21 gio_onMouse((__bridge CFTypeRef)view, typ, p.x, p.y, dx, dy, [event timestamp]); 22 } 23 24 static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) { 25 CFTypeRef view = (CFTypeRef *)displayLinkContext; 26 gio_onFrameCallback(view); 27 return kCVReturnSuccess; 28 } 29 30 @interface GioView : NSOpenGLView 31 @end 32 33 @implementation GioView { 34 CVDisplayLinkRef displayLink; 35 } 36 - (instancetype)initWithFrame:(NSRect)frameRect 37 pixelFormat:(NSOpenGLPixelFormat *)format { 38 self = [super initWithFrame:frameRect pixelFormat:format]; 39 if (self) { 40 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); 41 CVDisplayLinkSetOutputCallback(displayLink, displayLinkCallback, (__bridge void*)self); 42 } 43 return self; 44 } 45 - (void)dealloc { 46 CVDisplayLinkRelease(displayLink); 47 } 48 - (void)setAnimating:(BOOL)anim { 49 if (anim) { 50 CVDisplayLinkStart(displayLink); 51 } else { 52 CVDisplayLinkStop(displayLink); 53 } 54 } 55 - (void)updateDisplay:(CGDirectDisplayID)dispID { 56 CVDisplayLinkSetCurrentCGDisplay(displayLink, dispID); 57 } 58 - (void)prepareOpenGL { 59 [super prepareOpenGL]; 60 // Bind a default VBA to emulate OpenGL ES 2. 61 GLuint defVBA; 62 glGenVertexArrays(1, &defVBA); 63 glBindVertexArray(defVBA); 64 glEnable(GL_FRAMEBUFFER_SRGB); 65 } 66 - (BOOL)isFlipped { 67 return YES; 68 } 69 - (void)update { 70 [super update]; 71 [self setNeedsDisplay:YES]; 72 } 73 - (void)drawRect:(NSRect)r { 74 gio_onDraw((__bridge CFTypeRef)self); 75 } 76 - (void)mouseDown:(NSEvent *)event { 77 handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0); 78 } 79 - (void)mouseUp:(NSEvent *)event { 80 handleMouse(self, event, GIO_MOUSE_UP, 0, 0); 81 } 82 - (void)mouseMoved:(NSEvent *)event { 83 handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0); 84 } 85 - (void)mouseDragged:(NSEvent *)event { 86 handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0); 87 } 88 - (void)scrollWheel:(NSEvent *)event { 89 CGFloat dx = -event.scrollingDeltaX; 90 CGFloat dy = -event.scrollingDeltaY; 91 handleMouse(self, event, GIO_MOUSE_MOVE, dx, dy); 92 } 93 - (void)keyDown:(NSEvent *)event { 94 NSString *keys = [event charactersIgnoringModifiers]; 95 gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags]); 96 [self interpretKeyEvents:[NSArray arrayWithObject:event]]; 97 } 98 - (void)insertText:(id)string { 99 const char *utf8 = [string UTF8String]; 100 gio_onText((__bridge CFTypeRef)self, (char *)utf8); 101 } 102 - (void)doCommandBySelector:(SEL)sel { 103 // Don't pass commands up the responder chain. 104 // They will end up in a beep. 105 } 106 @end 107 108 CFTypeRef gio_createGLView(void) { 109 @autoreleasepool { 110 NSOpenGLPixelFormatAttribute attr[] = { 111 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 112 NSOpenGLPFAColorSize, 24, 113 NSOpenGLPFADepthSize, 16, 114 NSOpenGLPFAAccelerated, 115 // Opt-in to automatic GPU switching. CGL-only property. 116 kCGLPFASupportsAutomaticGraphicsSwitching, 117 NSOpenGLPFAAllowOfflineRenderers, 118 0 119 }; 120 id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; 121 122 NSRect frame = NSMakeRect(0, 0, 0, 0); 123 GioView* view = [[GioView alloc] initWithFrame:frame pixelFormat:pixFormat]; 124 125 [view setWantsBestResolutionOpenGLSurface:YES]; 126 [view setWantsLayer:YES]; // The default in Mojave. 127 128 return CFBridgingRetain(view); 129 } 130 } 131 132 void gio_updateDisplayLink(CFTypeRef viewRef, CGDirectDisplayID dispID) { 133 GioView *view = (__bridge GioView *)viewRef; 134 [view updateDisplay:dispID]; 135 } 136 137 void gio_setAnimating(CFTypeRef viewRef, BOOL anim) { 138 GioView *view = (__bridge GioView *)viewRef; 139 dispatch_async(dispatch_get_main_queue(), ^{ 140 [view setAnimating:anim]; 141 }); 142 } 143 144 CFTypeRef gio_contextForView(CFTypeRef viewRef) { 145 NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef; 146 return (__bridge CFTypeRef)view.openGLContext; 147 } 148 149 void gio_clearCurrentContext(void) { 150 [NSOpenGLContext clearCurrentContext]; 151 } 152 153 void gio_makeCurrentContext(CFTypeRef ctxRef) { 154 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; 155 return [ctx makeCurrentContext]; 156 } 157 158 void gio_lockContext(CFTypeRef ctxRef) { 159 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; 160 CGLLockContext([ctx CGLContextObj]); 161 } 162 163 void gio_unlockContext(CFTypeRef ctxRef) { 164 NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef; 165 CGLUnlockContext([ctx CGLContextObj]); 166 }