mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
app/internal/wm: [macOS] use NSView+NSOpenGLContext, not NSOpenGLContextView
NSOpenGLContextView couples the window manager logic tightly with OpenGL. Use generic NSViews, and attach NSOpenGLContext just like the other platforms. This change prepares for supporting GPU contexts created by clients as well as a future Metal port. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+24
-19
@@ -5,6 +5,8 @@
|
|||||||
package wm
|
package wm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"gioui.org/gpu"
|
"gioui.org/gpu"
|
||||||
"gioui.org/internal/gl"
|
"gioui.org/internal/gl"
|
||||||
)
|
)
|
||||||
@@ -15,8 +17,9 @@ import (
|
|||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
#include <OpenGL/gl3.h>
|
#include <OpenGL/gl3.h>
|
||||||
|
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLView(void);
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createGLContext(void);
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_contextForView(CFTypeRef viewRef);
|
__attribute__ ((visibility ("hidden"))) void gio_prepareContext(void);
|
||||||
|
__attribute__ ((visibility ("hidden"))) void gio_setContextView(CFTypeRef ctx, CFTypeRef view);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx);
|
__attribute__ ((visibility ("hidden"))) void gio_makeCurrentContext(CFTypeRef ctx);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx);
|
__attribute__ ((visibility ("hidden"))) void gio_flushContextBuffer(CFTypeRef ctx);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void);
|
__attribute__ ((visibility ("hidden"))) void gio_clearCurrentContext(void);
|
||||||
@@ -26,20 +29,23 @@ __attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef)
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
c *gl.Functions
|
c *gl.Functions
|
||||||
ctx C.CFTypeRef
|
ctx C.CFTypeRef
|
||||||
view C.CFTypeRef
|
view C.CFTypeRef
|
||||||
}
|
prepared bool
|
||||||
|
|
||||||
func init() {
|
|
||||||
viewFactory = func() C.CFTypeRef {
|
|
||||||
return C.gio_createGLView()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext(w *window) (*context, error) {
|
func newContext(w *window) (*context, error) {
|
||||||
view := w.contextView()
|
view := w.contextView()
|
||||||
ctx := C.gio_contextForView(view)
|
ctx := C.gio_createGLContext()
|
||||||
|
if ctx == 0 {
|
||||||
|
return nil, errors.New("gl: failed to create NSOpenGLContext")
|
||||||
|
}
|
||||||
|
// [NSOpenGLContext setView] must run on the main thread. Fortunately,
|
||||||
|
// newContext is only called during a [NSView draw] on the main thread.
|
||||||
|
w.w.Func(func() {
|
||||||
|
C.gio_setContextView(ctx, view)
|
||||||
|
})
|
||||||
c := &context{
|
c := &context{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
view: view,
|
view: view,
|
||||||
@@ -52,14 +58,9 @@ func (c *context) API() gpu.API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Release() {
|
func (c *context) Release() {
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
C.gio_clearCurrentContext()
|
C.gio_clearCurrentContext()
|
||||||
// We could release the context with [view clearGLContext]
|
C.CFRelease(c.ctx)
|
||||||
// and rely on [view openGLContext] auto-creating a new context.
|
c.ctx = 0
|
||||||
// However that second context is not properly set up by
|
|
||||||
// OpenGLContextView, so we'll stay on the safe side and keep
|
|
||||||
// the first context around.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Present() error {
|
func (c *context) Present() error {
|
||||||
@@ -80,6 +81,10 @@ func (c *context) MakeCurrent() error {
|
|||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
C.gio_makeCurrentContext(c.ctx)
|
C.gio_makeCurrentContext(c.ctx)
|
||||||
|
if !c.prepared {
|
||||||
|
c.prepared = true
|
||||||
|
C.gio_prepareContext()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
-102
@@ -9,91 +9,21 @@
|
|||||||
#include <OpenGL/gl3.h>
|
#include <OpenGL/gl3.h>
|
||||||
#include "_cgo_export.h"
|
#include "_cgo_export.h"
|
||||||
|
|
||||||
static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFloat dy) {
|
@interface GioGLContext : NSOpenGLContext
|
||||||
NSPoint p = [view convertPoint:[event locationInWindow] fromView:nil];
|
|
||||||
if (!event.hasPreciseScrollingDeltas) {
|
|
||||||
// dx and dy are in rows and columns.
|
|
||||||
dx *= 10;
|
|
||||||
dy *= 10;
|
|
||||||
}
|
|
||||||
gio_onMouse((__bridge CFTypeRef)view, typ, [NSEvent pressedMouseButtons], p.x, p.y, dx, dy, [event timestamp], [event modifierFlags]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface GioView : NSOpenGLView
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation GioView
|
@implementation GioGLContext
|
||||||
- (instancetype)initWithFrame:(NSRect)frameRect
|
- (void) notifyUpdate:(NSNotification*)notification {
|
||||||
pixelFormat:(NSOpenGLPixelFormat *)format {
|
CGLLockContext([self CGLContextObj]);
|
||||||
return [super initWithFrame:frameRect pixelFormat:format];
|
[self update];
|
||||||
|
CGLUnlockContext([self CGLContextObj]);
|
||||||
}
|
}
|
||||||
- (void)prepareOpenGL {
|
- (void)dealloc {
|
||||||
[super prepareOpenGL];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
// Bind a default VBA to emulate OpenGL ES 2.
|
|
||||||
GLuint defVBA;
|
|
||||||
glGenVertexArrays(1, &defVBA);
|
|
||||||
glBindVertexArray(defVBA);
|
|
||||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
|
||||||
}
|
|
||||||
- (BOOL)isFlipped {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
- (void)update {
|
|
||||||
[super update];
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
|
||||||
- (void)drawRect:(NSRect)r {
|
|
||||||
gio_onDraw((__bridge CFTypeRef)self);
|
|
||||||
}
|
|
||||||
- (void)mouseDown:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)mouseUp:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)middleMouseDown:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)middletMouseUp:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)rightMouseDown:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)rightMouseUp:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)mouseMoved:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)mouseDragged:(NSEvent *)event {
|
|
||||||
handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
|
|
||||||
}
|
|
||||||
- (void)scrollWheel:(NSEvent *)event {
|
|
||||||
CGFloat dx = -event.scrollingDeltaX;
|
|
||||||
CGFloat dy = -event.scrollingDeltaY;
|
|
||||||
handleMouse(self, event, GIO_MOUSE_SCROLL, dx, dy);
|
|
||||||
}
|
|
||||||
- (void)keyDown:(NSEvent *)event {
|
|
||||||
NSString *keys = [event charactersIgnoringModifiers];
|
|
||||||
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], true);
|
|
||||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
|
||||||
}
|
|
||||||
- (void)keyUp:(NSEvent *)event {
|
|
||||||
NSString *keys = [event charactersIgnoringModifiers];
|
|
||||||
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], false);
|
|
||||||
}
|
|
||||||
- (void)insertText:(id)string {
|
|
||||||
const char *utf8 = [string UTF8String];
|
|
||||||
gio_onText((__bridge CFTypeRef)self, (char *)utf8);
|
|
||||||
}
|
|
||||||
- (void)doCommandBySelector:(SEL)sel {
|
|
||||||
// Don't pass commands up the responder chain.
|
|
||||||
// They will end up in a beep.
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
CFTypeRef gio_createGLView(void) {
|
CFTypeRef gio_createGLContext(void) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSOpenGLPixelFormatAttribute attr[] = {
|
NSOpenGLPixelFormatAttribute attr[] = {
|
||||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||||
@@ -105,43 +35,54 @@ CFTypeRef gio_createGLView(void) {
|
|||||||
NSOpenGLPFAAllowOfflineRenderers,
|
NSOpenGLPFAAllowOfflineRenderers,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
|
NSOpenGLPixelFormat *pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
|
||||||
|
|
||||||
NSRect frame = NSMakeRect(0, 0, 0, 0);
|
GioGLContext *ctx = [[GioGLContext alloc] initWithFormat:pixFormat shareContext: nil];
|
||||||
GioView* view = [[GioView alloc] initWithFrame:frame pixelFormat:pixFormat];
|
return CFBridgingRetain(ctx);
|
||||||
|
|
||||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
|
||||||
[view setWantsLayer:YES]; // The default in Mojave.
|
|
||||||
|
|
||||||
return CFBridgingRetain(view);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gio_setNeedsDisplay(CFTypeRef viewRef) {
|
void gio_setContextView(CFTypeRef ctxRef, CFTypeRef viewRef) {
|
||||||
NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
|
GioGLContext *ctx = (__bridge GioGLContext *)ctxRef;
|
||||||
[view setNeedsDisplay:YES];
|
NSView *view = (__bridge NSView *)viewRef;
|
||||||
}
|
[ctx setView:view];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:ctx
|
||||||
CFTypeRef gio_contextForView(CFTypeRef viewRef) {
|
selector:@selector(notifyUpdate:)
|
||||||
NSOpenGLView *view = (__bridge NSOpenGLView *)viewRef;
|
name:NSViewGlobalFrameDidChangeNotification
|
||||||
return (__bridge CFTypeRef)view.openGLContext;
|
object:view];
|
||||||
}
|
}
|
||||||
|
|
||||||
void gio_clearCurrentContext(void) {
|
void gio_clearCurrentContext(void) {
|
||||||
[NSOpenGLContext clearCurrentContext];
|
@autoreleasepool {
|
||||||
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gio_makeCurrentContext(CFTypeRef ctxRef) {
|
void gio_makeCurrentContext(CFTypeRef ctxRef) {
|
||||||
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
@autoreleasepool {
|
||||||
[ctx makeCurrentContext];
|
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
||||||
|
[ctx makeCurrentContext];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gio_lockContext(CFTypeRef ctxRef) {
|
void gio_lockContext(CFTypeRef ctxRef) {
|
||||||
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
@autoreleasepool {
|
||||||
CGLLockContext([ctx CGLContextObj]);
|
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
||||||
|
CGLLockContext([ctx CGLContextObj]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gio_unlockContext(CFTypeRef ctxRef) {
|
void gio_unlockContext(CFTypeRef ctxRef) {
|
||||||
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
@autoreleasepool {
|
||||||
CGLUnlockContext([ctx CGLContextObj]);
|
NSOpenGLContext *ctx = (__bridge NSOpenGLContext *)ctxRef;
|
||||||
|
CGLUnlockContext([ctx CGLContextObj]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gio_prepareContext(void) {
|
||||||
|
// Bind a default VBA to emulate OpenGL ES 2.
|
||||||
|
GLuint defVBA;
|
||||||
|
glGenVertexArrays(1, &defVBA);
|
||||||
|
glBindVertexArray(defVBA);
|
||||||
|
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void);
|
|||||||
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
|
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
|
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_toggleFullScreen(CFTypeRef windowRef);
|
__attribute__ ((visibility ("hidden"))) void gio_toggleFullScreen(CFTypeRef windowRef);
|
||||||
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createView(void);
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
|
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
|
||||||
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
|
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
|
||||||
@@ -73,8 +74,6 @@ type window struct {
|
|||||||
// viewMap is the mapping from Cocoa NSViews to Go windows.
|
// viewMap is the mapping from Cocoa NSViews to Go windows.
|
||||||
var viewMap = make(map[C.CFTypeRef]*window)
|
var viewMap = make(map[C.CFTypeRef]*window)
|
||||||
|
|
||||||
var viewFactory func() C.CFTypeRef
|
|
||||||
|
|
||||||
// launched is closed when applicationDidFinishLaunching is called.
|
// launched is closed when applicationDidFinishLaunching is called.
|
||||||
var launched = make(chan struct{})
|
var launched = make(chan struct{})
|
||||||
|
|
||||||
@@ -401,7 +400,7 @@ func NewWindow(win Callbacks, opts *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newWindow(opts *Options) (*window, error) {
|
func newWindow(opts *Options) (*window, error) {
|
||||||
view := viewFactory()
|
view := C.gio_createView()
|
||||||
if view == 0 {
|
if view == 0 {
|
||||||
return nil, errors.New("CreateWindow: failed to create view")
|
return nil, errors.New("CreateWindow: failed to create view")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,73 @@
|
|||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFloat dy) {
|
||||||
|
NSPoint p = [view convertPoint:[event locationInWindow] fromView:nil];
|
||||||
|
if (!event.hasPreciseScrollingDeltas) {
|
||||||
|
// dx and dy are in rows and columns.
|
||||||
|
dx *= 10;
|
||||||
|
dy *= 10;
|
||||||
|
}
|
||||||
|
gio_onMouse((__bridge CFTypeRef)view, typ, [NSEvent pressedMouseButtons], p.x, p.y, dx, dy, [event timestamp], [event modifierFlags]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface GioView : NSView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GioView
|
||||||
|
- (BOOL)isFlipped {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
- (void)drawRect:(NSRect)r {
|
||||||
|
gio_onDraw((__bridge CFTypeRef)self);
|
||||||
|
}
|
||||||
|
- (void)mouseDown:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)mouseUp:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)middleMouseDown:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)middletMouseUp:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)rightMouseDown:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_DOWN, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)rightMouseUp:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_UP, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)mouseMoved:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)mouseDragged:(NSEvent *)event {
|
||||||
|
handleMouse(self, event, GIO_MOUSE_MOVE, 0, 0);
|
||||||
|
}
|
||||||
|
- (void)scrollWheel:(NSEvent *)event {
|
||||||
|
CGFloat dx = -event.scrollingDeltaX;
|
||||||
|
CGFloat dy = -event.scrollingDeltaY;
|
||||||
|
handleMouse(self, event, GIO_MOUSE_SCROLL, dx, dy);
|
||||||
|
}
|
||||||
|
- (void)keyDown:(NSEvent *)event {
|
||||||
|
NSString *keys = [event charactersIgnoringModifiers];
|
||||||
|
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], true);
|
||||||
|
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||||
|
}
|
||||||
|
- (void)keyUp:(NSEvent *)event {
|
||||||
|
NSString *keys = [event charactersIgnoringModifiers];
|
||||||
|
gio_onKeys((__bridge CFTypeRef)self, (char *)[keys UTF8String], [event timestamp], [event modifierFlags], false);
|
||||||
|
}
|
||||||
|
- (void)insertText:(id)string {
|
||||||
|
const char *utf8 = [string UTF8String];
|
||||||
|
gio_onText((__bridge CFTypeRef)self, (char *)utf8);
|
||||||
|
}
|
||||||
|
- (void)doCommandBySelector:(SEL)sel {
|
||||||
|
// Don't pass commands up the responder chain.
|
||||||
|
// They will end up in a beep.
|
||||||
|
}
|
||||||
|
@end
|
||||||
// Delegates are weakly referenced from their peers. Nothing
|
// Delegates are weakly referenced from their peers. Nothing
|
||||||
// else holds a strong reference to our window delegate, so
|
// else holds a strong reference to our window delegate, so
|
||||||
// keep a single global reference instead.
|
// keep a single global reference instead.
|
||||||
@@ -86,6 +153,11 @@ CGFloat gio_getViewBackingScale(CFTypeRef viewRef) {
|
|||||||
return [view.window backingScaleFactor];
|
return [view.window backingScaleFactor];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gio_setNeedsDisplay(CFTypeRef viewRef) {
|
||||||
|
NSView *view = (__bridge NSView *)viewRef;
|
||||||
|
[view setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
void gio_hideCursor() {
|
void gio_hideCursor() {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
[NSCursor hide];
|
[NSCursor hide];
|
||||||
@@ -229,6 +301,16 @@ void gio_setTitle(CFTypeRef windowRef, const char *title) {
|
|||||||
window.title = [NSString stringWithUTF8String: title];
|
window.title = [NSString stringWithUTF8String: title];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFTypeRef gio_createView(void) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSRect frame = NSMakeRect(0, 0, 0, 0);
|
||||||
|
GioView* view = [[GioView alloc] initWithFrame:frame];
|
||||||
|
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||||
|
[view setWantsLayer:YES]; // The default in Mojave.
|
||||||
|
return CFBridgingRetain(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@implementation GioAppDelegate
|
@implementation GioAppDelegate
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ type FrameEvent struct {
|
|||||||
type Callbacks interface {
|
type Callbacks interface {
|
||||||
SetDriver(d Driver)
|
SetDriver(d Driver)
|
||||||
Event(e event.Event)
|
Event(e event.Event)
|
||||||
|
// Func runs a function during an Event. This is required for platforms
|
||||||
|
// that require coordination between the rendering goroutine and the system
|
||||||
|
// main thread.
|
||||||
|
Func(f func())
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context interface {
|
type Context interface {
|
||||||
|
|||||||
+15
-2
@@ -56,7 +56,8 @@ type Window struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type callbacks struct {
|
type callbacks struct {
|
||||||
w *Window
|
w *Window
|
||||||
|
funcs chan func()
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue is an event.Queue implementation that distributes system events
|
// queue is an event.Queue implementation that distributes system events
|
||||||
@@ -104,6 +105,7 @@ func NewWindow(options ...Option) *Window {
|
|||||||
driverFuncs: make(chan func()),
|
driverFuncs: make(chan func()),
|
||||||
dead: make(chan struct{}),
|
dead: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
w.callbacks.funcs = make(chan func())
|
||||||
w.callbacks.w = w
|
w.callbacks.w = w
|
||||||
go w.run(opts)
|
go w.run(opts)
|
||||||
return w
|
return w
|
||||||
@@ -299,11 +301,22 @@ func (c *callbacks) SetDriver(d wm.Driver) {
|
|||||||
func (c *callbacks) Event(e event.Event) {
|
func (c *callbacks) Event(e event.Event) {
|
||||||
select {
|
select {
|
||||||
case c.w.in <- e:
|
case c.w.in <- e:
|
||||||
<-c.w.ack
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.w.ack:
|
||||||
|
return
|
||||||
|
case f := <-c.funcs:
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
case <-c.w.dead:
|
case <-c.w.dead:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *callbacks) Func(f func()) {
|
||||||
|
c.funcs <- f
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Window) waitAck() {
|
func (w *Window) waitAck() {
|
||||||
// Send a dummy event; when it gets through we
|
// Send a dummy event; when it gets through we
|
||||||
// know the application has processed the previous event.
|
// know the application has processed the previous event.
|
||||||
|
|||||||
Reference in New Issue
Block a user