mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
app/internal/window: [macOS] support more than one window
Updates #19 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -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];
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user