diff --git a/app/internal/window/gl_macos.m b/app/internal/window/gl_macos.m index 38ee5de2..0d7f772b 100644 --- a/app/internal/window/gl_macos.m +++ b/app/internal/window/gl_macos.m @@ -22,8 +22,7 @@ static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFlo @interface GioView : NSOpenGLView @end -@implementation GioView { -} +@implementation GioView - (instancetype)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format { return [super initWithFrame:frameRect pixelFormat:format]; diff --git a/app/internal/window/os_macos.go b/app/internal/window/os_macos.go index 2e915200..accfe298 100644 --- a/app/internal/window/os_macos.go +++ b/app/internal/window/os_macos.go @@ -31,15 +31,15 @@ import ( #define GIO_MOUSE_DOWN 3 #define GIO_MOUSE_SCROLL 4 -__attribute__ ((visibility ("hidden"))) void gio_main(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height); +__attribute__ ((visibility ("hidden"))) void gio_main(void); __attribute__ ((visibility ("hidden"))) CGFloat gio_viewWidth(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) CGFloat gio_viewHeight(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) CGFloat gio_getViewBackingScale(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void); __attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length); __attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef); -__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) void gio_appTerminate(void); +__attribute__ ((visibility ("hidden"))) void gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height); */ import "C" @@ -60,16 +60,17 @@ type window struct { // viewMap is the mapping from Cocoa NSViews to Go windows. var viewMap = make(map[C.CFTypeRef]*window) -var mainWindow = newWindowRendezvous() - var viewFactory func() C.CFTypeRef +// launched is closed when applicationDidFinishLaunching is called. +var launched = make(chan struct{}) + // mustView is like lookoupView, except that it panics // if the view isn't mapped. func mustView(view C.CFTypeRef) *window { w, ok := lookupView(view) if !ok { - panic("no window view view") + panic("no window for view") } return w } @@ -246,6 +247,8 @@ func gio_onClose(view C.CFTypeRef) { w.displayLink.Close() deleteView(view) w.w.Event(system.DestroyEvent{}) + w.view = 0 + C.CFRelease(view) if len(viewMap) == 0 { C.gio_appTerminate() } @@ -277,8 +280,34 @@ func gio_onAppShow() { } } -//export gio_onCreate -func gio_onCreate(view C.CFTypeRef) { +//export gio_onFinishLaunching +func gio_onFinishLaunching() { + close(launched) +} + +func NewWindow(win Callbacks, opts *Options) error { + <-launched + errch := make(chan error) + var window *window + runOnMain(func() { + w, err := newWindow(win, opts) + window = w + errch <- err + }) + if err := <-errch; err != nil { + return err + } + go func() { + win.SetDriver(window) + }() + return nil +} + +func newWindow(win Callbacks, opts *Options) (*window, error) { + view := viewFactory() + if view == 0 { + return nil, errors.New("CreateWindow: failed to create view") + } scale := float32(C.gio_getViewBackingScale(view)) w := &window{ view: view, @@ -286,48 +315,30 @@ func gio_onCreate(view C.CFTypeRef) { } dl, err := NewDisplayLink(func() { runOnMain(func() { - C.gio_setNeedsDisplay(w.view) + if w.view != 0 { + C.gio_setNeedsDisplay(w.view) + } }) }) - if err != nil { - panic(err) - } w.displayLink = dl - wopts := <-mainWindow.out - w.w = wopts.window - w.w.SetDriver(w) - insertView(view, w) - if len(viewMap) == 1 { - C.CFRetain(view) - runOnMain(func() { - defer C.CFRelease(view) - C.gio_makeKeyAndOrderFront(view) - }) - } -} - -func NewWindow(win Callbacks, opts *Options) error { - mainWindow.in <- windowAndOptions{win, opts} - return <-mainWindow.errs -} - -func Main() { - wopts := <-mainWindow.out - view := viewFactory() - if view == 0 { - // TODO: return this error from CreateWindow. - panic(errors.New("CreateWindow: failed to create view")) + if err != nil { + C.CFRelease(view) + return nil, err } // Window sizes is in unscaled screen coordinates, not device pixels. cfg := configFor(1.0) - opts := wopts.opts - w := cfg.Px(opts.Width) - h := cfg.Px(opts.Height) - w = int(float32(w)) - h = int(float32(h)) + width := cfg.Px(opts.Width) + height := cfg.Px(opts.Height) title := C.CString(opts.Title) defer C.free(unsafe.Pointer(title)) - C.gio_main(view, title, C.CGFloat(w), C.CGFloat(h)) + C.gio_createWindow(view, title, C.CGFloat(width), C.CGFloat(height)) + w.w = win + insertView(view, w) + return w, nil +} + +func Main() { + C.gio_main() } func convertKey(k rune) (string, bool) { diff --git a/app/internal/window/os_macos.m b/app/internal/window/os_macos.m index bd7fb6e3..fc54eb6c 100644 --- a/app/internal/window/os_macos.m +++ b/app/internal/window/os_macos.m @@ -12,18 +12,6 @@ @interface GioWindowDelegate : NSObject @end -@implementation GioAppDelegate -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; -} -- (void)applicationDidHide:(NSNotification *)aNotification { - gio_onAppHide(); -} -- (void)applicationWillUnhide:(NSNotification *)notification { - gio_onAppShow(); -} -@end - @implementation GioWindowDelegate - (void)windowWillMiniaturize:(NSNotification *)notification { NSWindow *window = (NSWindow *)[notification object]; @@ -122,7 +110,7 @@ void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did) { CVDisplayLinkSetCurrentCGDisplay((CVDisplayLinkRef)dl, (CGDirectDisplayID)did); } -CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height) { +void gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height) { @autoreleasepool { NSRect rect = NSMakeRect(0, 0, width, height); NSUInteger styleMask = NSTitledWindowMask | @@ -136,29 +124,39 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, defer:NO]; [window setAcceptsMouseMovedEvents:YES]; window.title = [NSString stringWithUTF8String: title]; - NSView *view = (NSView *)CFBridgingRelease(viewRef); + NSView *view = (__bridge NSView *)viewRef; [window setContentView:view]; [window makeFirstResponder:view]; + window.releasedWhenClosed = NO; window.delegate = globalWindowDel; - gio_onCreate((__bridge CFTypeRef)view); - return (__bridge_retained CFTypeRef)window; + [window makeKeyAndOrderFront:nil]; } } -void gio_makeKeyAndOrderFront(CFTypeRef viewRef) { - NSView *view = (__bridge NSView *)viewRef; - [view.window makeKeyAndOrderFront:nil]; -} - void gio_appTerminate(void) { @autoreleasepool { [NSApp terminate:nil]; } } -void gio_main(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height) { +@implementation GioAppDelegate +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; + gio_onFinishLaunching(); +} +- (void)applicationDidHide:(NSNotification *)aNotification { + gio_onAppHide(); +} +- (void)applicationWillUnhide:(NSNotification *)notification { + gio_onAppShow(); +} +@end + +void gio_main() { @autoreleasepool { [NSApplication sharedApplication]; + GioAppDelegate *del = [[GioAppDelegate alloc] init]; + [NSApp setDelegate:del]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; NSMenuItem *mainMenu = [NSMenuItem new]; @@ -177,12 +175,7 @@ void gio_main(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat heigh [menuBar addItem:mainMenu]; [NSApp setMainMenu:menuBar]; - GioAppDelegate *del = [[GioAppDelegate alloc] init]; - globalWindowDel = [[GioWindowDelegate alloc] init]; - NSWindow *window = (__bridge NSWindow *)gio_createWindow(viewRef, title, width, height); - - [NSApp setDelegate:del]; [NSApp run]; }