app/internal/window: [macOS] support more than one window

Updates #19

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-06-03 21:33:05 +02:00
parent 476bf8d263
commit 4408c2a695
3 changed files with 73 additions and 70 deletions
+1 -2
View File
@@ -22,8 +22,7 @@ static void handleMouse(NSView *view, NSEvent *event, int typ, CGFloat dx, CGFlo
@interface GioView : NSOpenGLView @interface GioView : NSOpenGLView
@end @end
@implementation GioView { @implementation GioView
}
- (instancetype)initWithFrame:(NSRect)frameRect - (instancetype)initWithFrame:(NSRect)frameRect
pixelFormat:(NSOpenGLPixelFormat *)format { pixelFormat:(NSOpenGLPixelFormat *)format {
return [super initWithFrame:frameRect pixelFormat:format]; return [super initWithFrame:frameRect pixelFormat:format];
+52 -41
View File
@@ -31,15 +31,15 @@ import (
#define GIO_MOUSE_DOWN 3 #define GIO_MOUSE_DOWN 3
#define GIO_MOUSE_SCROLL 4 #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_viewWidth(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) CGFloat gio_viewHeight(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) CGFloat gio_viewHeight(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) CGFloat gio_getViewBackingScale(CFTypeRef viewRef); __attribute__ ((visibility ("hidden"))) CGFloat gio_getViewBackingScale(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void); __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_makeKeyAndOrderFront(CFTypeRef viewRef);
__attribute__ ((visibility ("hidden"))) void gio_appTerminate(void); __attribute__ ((visibility ("hidden"))) void gio_appTerminate(void);
__attribute__ ((visibility ("hidden"))) void gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height);
*/ */
import "C" import "C"
@@ -60,16 +60,17 @@ 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 mainWindow = newWindowRendezvous()
var viewFactory func() C.CFTypeRef 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 // mustView is like lookoupView, except that it panics
// if the view isn't mapped. // if the view isn't mapped.
func mustView(view C.CFTypeRef) *window { func mustView(view C.CFTypeRef) *window {
w, ok := lookupView(view) w, ok := lookupView(view)
if !ok { if !ok {
panic("no window view view") panic("no window for view")
} }
return w return w
} }
@@ -246,6 +247,8 @@ func gio_onClose(view C.CFTypeRef) {
w.displayLink.Close() w.displayLink.Close()
deleteView(view) deleteView(view)
w.w.Event(system.DestroyEvent{}) w.w.Event(system.DestroyEvent{})
w.view = 0
C.CFRelease(view)
if len(viewMap) == 0 { if len(viewMap) == 0 {
C.gio_appTerminate() C.gio_appTerminate()
} }
@@ -277,8 +280,34 @@ func gio_onAppShow() {
} }
} }
//export gio_onCreate //export gio_onFinishLaunching
func gio_onCreate(view C.CFTypeRef) { 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)) scale := float32(C.gio_getViewBackingScale(view))
w := &window{ w := &window{
view: view, view: view,
@@ -286,48 +315,30 @@ func gio_onCreate(view C.CFTypeRef) {
} }
dl, err := NewDisplayLink(func() { dl, err := NewDisplayLink(func() {
runOnMain(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 w.displayLink = dl
wopts := <-mainWindow.out if err != nil {
w.w = wopts.window C.CFRelease(view)
w.w.SetDriver(w) return nil, err
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"))
} }
// Window sizes is in unscaled screen coordinates, not device pixels. // Window sizes is in unscaled screen coordinates, not device pixels.
cfg := configFor(1.0) cfg := configFor(1.0)
opts := wopts.opts width := cfg.Px(opts.Width)
w := cfg.Px(opts.Width) height := cfg.Px(opts.Height)
h := cfg.Px(opts.Height)
w = int(float32(w))
h = int(float32(h))
title := C.CString(opts.Title) title := C.CString(opts.Title)
defer C.free(unsafe.Pointer(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) { func convertKey(k rune) (string, bool) {
+20 -27
View File
@@ -12,18 +12,6 @@
@interface GioWindowDelegate : NSObject<NSWindowDelegate> @interface GioWindowDelegate : NSObject<NSWindowDelegate>
@end @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 @implementation GioWindowDelegate
- (void)windowWillMiniaturize:(NSNotification *)notification { - (void)windowWillMiniaturize:(NSNotification *)notification {
NSWindow *window = (NSWindow *)[notification object]; NSWindow *window = (NSWindow *)[notification object];
@@ -122,7 +110,7 @@ void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did) {
CVDisplayLinkSetCurrentCGDisplay((CVDisplayLinkRef)dl, (CGDirectDisplayID)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 { @autoreleasepool {
NSRect rect = NSMakeRect(0, 0, width, height); NSRect rect = NSMakeRect(0, 0, width, height);
NSUInteger styleMask = NSTitledWindowMask | NSUInteger styleMask = NSTitledWindowMask |
@@ -136,29 +124,39 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width,
defer:NO]; defer:NO];
[window setAcceptsMouseMovedEvents:YES]; [window setAcceptsMouseMovedEvents:YES];
window.title = [NSString stringWithUTF8String: title]; window.title = [NSString stringWithUTF8String: title];
NSView *view = (NSView *)CFBridgingRelease(viewRef); NSView *view = (__bridge NSView *)viewRef;
[window setContentView:view]; [window setContentView:view];
[window makeFirstResponder:view]; [window makeFirstResponder:view];
window.releasedWhenClosed = NO;
window.delegate = globalWindowDel; window.delegate = globalWindowDel;
gio_onCreate((__bridge CFTypeRef)view); [window makeKeyAndOrderFront:nil];
return (__bridge_retained CFTypeRef)window;
} }
} }
void gio_makeKeyAndOrderFront(CFTypeRef viewRef) {
NSView *view = (__bridge NSView *)viewRef;
[view.window makeKeyAndOrderFront:nil];
}
void gio_appTerminate(void) { void gio_appTerminate(void) {
@autoreleasepool { @autoreleasepool {
[NSApp terminate:nil]; [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 { @autoreleasepool {
[NSApplication sharedApplication]; [NSApplication sharedApplication];
GioAppDelegate *del = [[GioAppDelegate alloc] init];
[NSApp setDelegate:del];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
NSMenuItem *mainMenu = [NSMenuItem new]; NSMenuItem *mainMenu = [NSMenuItem new];
@@ -177,12 +175,7 @@ void gio_main(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat heigh
[menuBar addItem:mainMenu]; [menuBar addItem:mainMenu];
[NSApp setMainMenu:menuBar]; [NSApp setMainMenu:menuBar];
GioAppDelegate *del = [[GioAppDelegate alloc] init];
globalWindowDel = [[GioWindowDelegate alloc] init]; globalWindowDel = [[GioWindowDelegate alloc] init];
NSWindow *window = (__bridge NSWindow *)gio_createWindow(viewRef, title, width, height);
[NSApp setDelegate:del];
[NSApp run]; [NSApp run];
} }