mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-24 18:02:02 +01:00
internal/ui: remove Cgo on darwin in ui_glfw_darwin.go (#2329)
Updates #1162
This commit is contained in:
parent
45b2bd7b2b
commit
043397c20e
@ -26,6 +26,11 @@ var (
|
||||
class_NSMethodSignature = objc.GetClass("NSMethodSignature")
|
||||
class_NSAutoreleasePool = objc.GetClass("NSAutoreleasePool")
|
||||
class_NSString = objc.GetClass("NSString")
|
||||
class_NSProcessInfo = objc.GetClass("NSProcessInfo")
|
||||
class_NSColor = objc.GetClass("NSColor")
|
||||
class_NSWindow = objc.GetClass("NSWindow")
|
||||
class_NSView = objc.GetClass("NSView")
|
||||
class_NSScreen = objc.GetClass("NSScreen")
|
||||
)
|
||||
|
||||
var (
|
||||
@ -38,23 +43,165 @@ var (
|
||||
sel_setArgumentAtIndex = objc.RegisterName("setArgument:atIndex:")
|
||||
sel_getReturnValue = objc.RegisterName("getReturnValue:")
|
||||
sel_invoke = objc.RegisterName("invoke")
|
||||
sel_invokeWithTarget = objc.RegisterName("invokeWithTarget:")
|
||||
sel_instanceMethodSignatureForSelector = objc.RegisterName("instanceMethodSignatureForSelector:")
|
||||
sel_signatureWithObjCTypes = objc.RegisterName("signatureWithObjCTypes:")
|
||||
sel_initWithUTF8String = objc.RegisterName("initWithUTF8String:")
|
||||
sel_UTF8String = objc.RegisterName("UTF8String")
|
||||
sel_length = objc.RegisterName("length")
|
||||
sel_processInfo = objc.RegisterName("processInfo")
|
||||
sel_isOperatingSystemAtLeastVersion = objc.RegisterName("isOperatingSystemAtLeastVersion:")
|
||||
sel_frame = objc.RegisterName("frame")
|
||||
sel_contentView = objc.RegisterName("contentView")
|
||||
sel_setBackgroundColor = objc.RegisterName("setBackgroundColor:")
|
||||
sel_colorWithSRGBRedGreenBlueAlpha = objc.RegisterName("colorWithSRGBRed:green:blue:alpha:")
|
||||
sel_setFrameSize = objc.RegisterName("setFrameSize:")
|
||||
sel_object = objc.RegisterName("object")
|
||||
sel_styleMask = objc.RegisterName("styleMask")
|
||||
sel_setStyleMask = objc.RegisterName("setStyleMask:")
|
||||
sel_mainScreen = objc.RegisterName("mainScreen")
|
||||
sel_screen = objc.RegisterName("screen")
|
||||
sel_isVisible = objc.RegisterName("isVisible")
|
||||
sel_deviceDescription = objc.RegisterName("deviceDescription")
|
||||
sel_objectForKey = objc.RegisterName("objectForKey:")
|
||||
sel_unsignedIntValue = objc.RegisterName("unsignedIntValue")
|
||||
)
|
||||
|
||||
type CGFloat float64
|
||||
const NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
|
||||
|
||||
const (
|
||||
NSWindowStyleMaskResizable = 1 << 3
|
||||
NSWindowStyleMaskFullScreen = 1 << 14
|
||||
)
|
||||
|
||||
type CGFloat = float64
|
||||
|
||||
type CGSize struct {
|
||||
Width, Height CGFloat
|
||||
}
|
||||
|
||||
type CGPoint struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
type CGRect struct {
|
||||
Origin CGPoint
|
||||
Size CGSize
|
||||
}
|
||||
|
||||
type NSUInteger = uint
|
||||
type NSInteger = int
|
||||
|
||||
type NSPoint = CGPoint
|
||||
type NSRect = CGRect
|
||||
type NSSize = CGSize
|
||||
|
||||
type NSError struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
type NSColor struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func NSColor_colorWithSRGBRedGreenBlueAlpha(red, green, blue, alpha CGFloat) (color NSColor) {
|
||||
sig := NSMethodSignature_signatureWithObjCTypes("@@:ffff")
|
||||
inv := NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetSelector(sel_colorWithSRGBRedGreenBlueAlpha)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&red), 2)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&green), 3)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&blue), 4)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&alpha), 5)
|
||||
inv.InvokeWithTarget(objc.ID(class_NSColor))
|
||||
inv.GetReturnValue(unsafe.Pointer(&color))
|
||||
return color
|
||||
}
|
||||
|
||||
type NSOperatingSystemVersion struct {
|
||||
Major, Minor, Patch NSInteger
|
||||
}
|
||||
|
||||
type NSProcessInfo struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func NSProcessInfo_processInfo() NSProcessInfo {
|
||||
return NSProcessInfo{objc.ID(class_NSProcessInfo).Send(sel_processInfo)}
|
||||
}
|
||||
|
||||
func (p NSProcessInfo) IsOperatingSystemAtLeastVersion(version NSOperatingSystemVersion) bool {
|
||||
sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSProcessInfo), sel_isOperatingSystemAtLeastVersion)
|
||||
inv := NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetTarget(p.ID)
|
||||
inv.SetSelector(sel_isOperatingSystemAtLeastVersion)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&version), 2)
|
||||
inv.Invoke()
|
||||
var ret int
|
||||
inv.GetReturnValue(unsafe.Pointer(&ret))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
type NSWindow struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func (w NSWindow) StyleMask() NSUInteger {
|
||||
return NSUInteger(w.Send(sel_styleMask))
|
||||
}
|
||||
|
||||
func (w NSWindow) SetStyleMask(styleMask NSUInteger) {
|
||||
w.Send(sel_setStyleMask, styleMask)
|
||||
}
|
||||
|
||||
func (w NSWindow) SetBackgroundColor(color NSColor) {
|
||||
w.Send(sel_setBackgroundColor, color.ID)
|
||||
}
|
||||
|
||||
func (w NSWindow) IsVisibile() bool {
|
||||
return w.Send(sel_isVisible) != 0
|
||||
}
|
||||
|
||||
func (w NSWindow) Screen() NSScreen {
|
||||
return NSScreen{w.Send(sel_screen)}
|
||||
}
|
||||
|
||||
func (w NSWindow) Frame() NSRect {
|
||||
sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSWindow), sel_frame)
|
||||
inv := NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetTarget(w.ID)
|
||||
inv.SetSelector(sel_frame)
|
||||
inv.Invoke()
|
||||
var rect NSRect
|
||||
inv.GetReturnValue(unsafe.Pointer(&rect))
|
||||
return rect
|
||||
}
|
||||
|
||||
func (w NSWindow) ContentView() NSView {
|
||||
return NSView{w.Send(sel_contentView)}
|
||||
}
|
||||
|
||||
type NSView struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func (v NSView) SetFrameSize(size CGSize) {
|
||||
sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSView), sel_setFrameSize)
|
||||
inv := NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetSelector(sel_setFrameSize)
|
||||
inv.SetArgumentAtIndex(unsafe.Pointer(&size), 2)
|
||||
inv.InvokeWithTarget(v.ID)
|
||||
}
|
||||
|
||||
func (v NSView) Frame() NSRect {
|
||||
sig := NSMethodSignature_instanceMethodSignatureForSelector(objc.ID(class_NSView), sel_frame)
|
||||
inv := NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetSelector(sel_frame)
|
||||
inv.InvokeWithTarget(v.ID)
|
||||
var rect NSRect
|
||||
inv.GetReturnValue(unsafe.Pointer(&rect))
|
||||
return rect
|
||||
}
|
||||
|
||||
// NSInvocation is being used to call functions that can't be called directly with purego.SyscallN.
|
||||
// See the downsides of that function for what it cannot do.
|
||||
type NSInvocation struct {
|
||||
@ -65,24 +212,28 @@ func NSInvocation_invocationWithMethodSignature(sig NSMethodSignature) NSInvocat
|
||||
return NSInvocation{objc.ID(class_NSInvocation).Send(sel_invocationWithMethodSignature, sig.ID)}
|
||||
}
|
||||
|
||||
func (inv NSInvocation) SetSelector(cmd objc.SEL) {
|
||||
inv.Send(sel_setSelector, cmd)
|
||||
func (i NSInvocation) SetSelector(cmd objc.SEL) {
|
||||
i.Send(sel_setSelector, cmd)
|
||||
}
|
||||
|
||||
func (inv NSInvocation) SetTarget(target objc.ID) {
|
||||
inv.Send(sel_setTarget, target)
|
||||
func (i NSInvocation) SetTarget(target objc.ID) {
|
||||
i.Send(sel_setTarget, target)
|
||||
}
|
||||
|
||||
func (inv NSInvocation) SetArgumentAtIndex(arg unsafe.Pointer, idx int) {
|
||||
inv.Send(sel_setArgumentAtIndex, arg, idx)
|
||||
func (i NSInvocation) SetArgumentAtIndex(arg unsafe.Pointer, idx int) {
|
||||
i.Send(sel_setArgumentAtIndex, arg, idx)
|
||||
}
|
||||
|
||||
func (inv NSInvocation) GetReturnValue(ret unsafe.Pointer) {
|
||||
inv.Send(sel_getReturnValue, ret)
|
||||
func (i NSInvocation) GetReturnValue(ret unsafe.Pointer) {
|
||||
i.Send(sel_getReturnValue, ret)
|
||||
}
|
||||
|
||||
func (inv NSInvocation) Invoke() {
|
||||
inv.Send(sel_invoke)
|
||||
func (i NSInvocation) Invoke() {
|
||||
i.Send(sel_invoke)
|
||||
}
|
||||
|
||||
func (i NSInvocation) InvokeWithTarget(target objc.ID) {
|
||||
i.Send(sel_invokeWithTarget, target)
|
||||
}
|
||||
|
||||
type NSMethodSignature struct {
|
||||
@ -109,8 +260,8 @@ func NSAutoreleasePool_new() NSAutoreleasePool {
|
||||
return NSAutoreleasePool{objc.ID(class_NSAutoreleasePool).Send(sel_new)}
|
||||
}
|
||||
|
||||
func (pool NSAutoreleasePool) Release() {
|
||||
pool.Send(sel_release)
|
||||
func (p NSAutoreleasePool) Release() {
|
||||
p.Send(sel_release)
|
||||
}
|
||||
|
||||
type NSString struct {
|
||||
@ -136,3 +287,39 @@ func (s NSString) String() string {
|
||||
header.Cap = header.Len
|
||||
return string(b)
|
||||
}
|
||||
|
||||
type NSNotification struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func (n NSNotification) Object() objc.ID {
|
||||
return n.Send(sel_object)
|
||||
}
|
||||
|
||||
type NSScreen struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func NSScreen_mainScreen() NSScreen {
|
||||
return NSScreen{objc.ID(class_NSScreen).Send(sel_mainScreen)}
|
||||
}
|
||||
|
||||
func (s NSScreen) DeviceDescription() NSDictionary {
|
||||
return NSDictionary{s.Send(sel_deviceDescription)}
|
||||
}
|
||||
|
||||
type NSDictionary struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func (d NSDictionary) ObjectForKey(object objc.ID) objc.ID {
|
||||
return d.Send(sel_objectForKey, object)
|
||||
}
|
||||
|
||||
type NSNumber struct {
|
||||
objc.ID
|
||||
}
|
||||
|
||||
func (n NSNumber) UnsignedIntValue() uint {
|
||||
return uint(n.Send(sel_unsignedIntValue))
|
||||
}
|
||||
|
@ -17,3 +17,7 @@ package glfw
|
||||
func (w *Window) GetCocoaWindow() uintptr {
|
||||
return uintptr(w.w.GetCocoaWindow())
|
||||
}
|
||||
|
||||
func (m *Monitor) GetCocoaMonitor() uintptr {
|
||||
return m.m.GetCocoaMonitor()
|
||||
}
|
||||
|
@ -17,224 +17,107 @@
|
||||
|
||||
package ui
|
||||
|
||||
// #cgo CFLAGS: -x objective-c
|
||||
// #cgo LDFLAGS: -framework AppKit
|
||||
//
|
||||
// #import <AppKit/AppKit.h>
|
||||
//
|
||||
// @interface EbitengineWindowDelegate : NSObject <NSWindowDelegate>
|
||||
// @end
|
||||
//
|
||||
// @implementation EbitengineWindowDelegate {
|
||||
// id<NSWindowDelegate> origDelegate_;
|
||||
// bool origResizable_;
|
||||
// }
|
||||
//
|
||||
// - (instancetype)initWithOrigDelegate:(id<NSWindowDelegate>)origDelegate {
|
||||
// self = [super init];
|
||||
// if (self != nil) {
|
||||
// origDelegate_ = origDelegate;
|
||||
// }
|
||||
// return self;
|
||||
// }
|
||||
//
|
||||
// // The method set of origDelegate_ must sync with GLFWWindowDelegate's implementation.
|
||||
// // See cocoa_window.m in GLFW.
|
||||
// - (BOOL)windowShouldClose:(id)sender {
|
||||
// return [origDelegate_ windowShouldClose:sender];
|
||||
// }
|
||||
// - (void)windowDidResize:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidResize:notification];
|
||||
// }
|
||||
// - (void)windowDidMove:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidMove:notification];
|
||||
// }
|
||||
// - (void)windowDidMiniaturize:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidMiniaturize:notification];
|
||||
// }
|
||||
// - (void)windowDidDeminiaturize:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidDeminiaturize:notification];
|
||||
// }
|
||||
// - (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidBecomeKey:notification];
|
||||
// }
|
||||
// - (void)windowDidResignKey:(NSNotification *)notification {
|
||||
// [origDelegate_ windowDidResignKey:notification];
|
||||
// }
|
||||
// - (void)windowDidChangeOcclusionState:(NSNotification* )notification {
|
||||
// [origDelegate_ windowDidChangeOcclusionState:notification];
|
||||
// }
|
||||
//
|
||||
// - (void)pushResizableState:(NSWindow*)window {
|
||||
// origResizable_ = window.styleMask & NSWindowStyleMaskResizable;
|
||||
// if (!origResizable_) {
|
||||
// window.styleMask |= NSWindowStyleMaskResizable;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// - (void)popResizableState:(NSWindow*)window {
|
||||
// if (!origResizable_) {
|
||||
// window.styleMask &= ~NSWindowStyleMaskResizable;
|
||||
// }
|
||||
// origResizable_ = false;
|
||||
// }
|
||||
//
|
||||
// - (void)windowWillEnterFullScreen:(NSNotification *)notification {
|
||||
// NSWindow* window = (NSWindow*)[notification object];
|
||||
// [self pushResizableState:window];
|
||||
// }
|
||||
//
|
||||
// - (void)windowDidEnterFullScreen:(NSNotification *)notification {
|
||||
// NSWindow* window = (NSWindow*)[notification object];
|
||||
// [self popResizableState:window];
|
||||
// }
|
||||
//
|
||||
// - (void)windowWillExitFullScreen:(NSNotification *)notification {
|
||||
// NSWindow* window = (NSWindow*)[notification object];
|
||||
// [self pushResizableState:window];
|
||||
// }
|
||||
//
|
||||
// - (void)windowDidExitFullScreen:(NSNotification *)notification {
|
||||
// NSWindow* window = (NSWindow*)[notification object];
|
||||
// [self popResizableState:window];
|
||||
// // Do not call setFrame here (#2295). setFrame here causes unexpected results.
|
||||
// }
|
||||
//
|
||||
// @end
|
||||
//
|
||||
// static void initializeWindow(uintptr_t windowPtr) {
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// // This delegate is never released. This assumes that the window lives until the process lives.
|
||||
// window.delegate = [[EbitengineWindowDelegate alloc] initWithOrigDelegate:window.delegate];
|
||||
// }
|
||||
//
|
||||
// static void currentMonitorPos(uintptr_t windowPtr, int* x, int* y) {
|
||||
// @autoreleasepool {
|
||||
// NSScreen* screen = [NSScreen mainScreen];
|
||||
// if (windowPtr) {
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// if ([window isVisible]) {
|
||||
// // When the window is visible, the window is already initialized.
|
||||
// // [NSScreen mainScreen] sometimes tells a lie when the window is put across monitors (#703).
|
||||
// screen = [window screen];
|
||||
// }
|
||||
// }
|
||||
// NSDictionary* screenDictionary = [screen deviceDescription];
|
||||
// NSNumber* screenID = [screenDictionary objectForKey:@"NSScreenNumber"];
|
||||
// CGDirectDisplayID aID = [screenID unsignedIntValue];
|
||||
// const CGRect bounds = CGDisplayBounds(aID);
|
||||
// *x = bounds.origin.x;
|
||||
// *y = bounds.origin.y;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// static bool isNativeFullscreen(uintptr_t windowPtr) {
|
||||
// if (!windowPtr) {
|
||||
// return false;
|
||||
// }
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// return (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
||||
// }
|
||||
//
|
||||
// static void setNativeFullscreen(uintptr_t windowPtr, bool fullscreen) {
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// if (((window.styleMask & NSWindowStyleMaskFullScreen) != 0) == fullscreen) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Even though EbitengineWindowDelegate is used, this hack is still required.
|
||||
// // toggleFullscreen doesn't work when the window is not resizable.
|
||||
// bool origFullscreen = window.collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
// if (!origFullscreen) {
|
||||
// window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
// }
|
||||
// [window toggleFullScreen:nil];
|
||||
// if (!origFullscreen) {
|
||||
// window.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// static void adjustViewSize(uintptr_t windowPtr) {
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// if ((window.styleMask & NSWindowStyleMaskFullScreen) == 0) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Apparently, adjusting the view size is not needed as of macOS 12 (#1745).
|
||||
// static int majorVersion = 0;
|
||||
// if (majorVersion == 0) {
|
||||
// majorVersion = [[NSProcessInfo processInfo] operatingSystemVersion].majorVersion;
|
||||
// }
|
||||
// if (majorVersion >= 12) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Reduce the view height (#1745).
|
||||
// // https://stackoverflow.com/questions/27758027/sprite-kit-serious-fps-issue-in-full-screen-mode-on-os-x
|
||||
// CGSize windowSize = [window frame].size;
|
||||
// NSView* view = [window contentView];
|
||||
// CGSize viewSize = [view frame].size;
|
||||
// if (windowSize.width != viewSize.width || windowSize.height != viewSize.height) {
|
||||
// return;
|
||||
// }
|
||||
// viewSize.width--;
|
||||
// [view setFrameSize:viewSize];
|
||||
//
|
||||
// // NSColor.blackColor (0, 0, 0, 1) didn't work.
|
||||
// // Use the transparent color instead.
|
||||
// [window setBackgroundColor: [NSColor colorWithSRGBRed:0 green:0 blue:0 alpha:0]];
|
||||
// }
|
||||
//
|
||||
// static void setNativeCursor(int cursorID) {
|
||||
// id cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
|
||||
// switch (cursorID) {
|
||||
// case 0:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
|
||||
// break;
|
||||
// case 1:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(IBeamCursor)];
|
||||
// break;
|
||||
// case 2:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(crosshairCursor)];
|
||||
// break;
|
||||
// case 3:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(pointingHandCursor)];
|
||||
// break;
|
||||
// case 4:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(_windowResizeEastWestCursor)];
|
||||
// break;
|
||||
// case 5:
|
||||
// cursor = [[NSCursor class] performSelector:@selector(_windowResizeNorthSouthCursor)];
|
||||
// break;
|
||||
// }
|
||||
// [cursor push];
|
||||
// }
|
||||
//
|
||||
// static void currentMouseLocation(int* x, int* y) {
|
||||
// NSPoint location = [NSEvent mouseLocation];
|
||||
// *x = (int)(location.x);
|
||||
// *y = (int)(location.y);
|
||||
// }
|
||||
//
|
||||
// static void setAllowFullscreen(uintptr_t windowPtr, bool allowFullscreen) {
|
||||
// NSWindow* window = (NSWindow*)windowPtr;
|
||||
// if (allowFullscreen) {
|
||||
// window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
// } else {
|
||||
// window.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
// }
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
|
||||
)
|
||||
|
||||
var class_EbitengineWindowDelegate objc.Class
|
||||
|
||||
func init() {
|
||||
class_EbitengineWindowDelegate = objc.AllocateClassPair(objc.GetClass("NSObject"), "EbitengineWindowDelegate", 0)
|
||||
protocol := objc.GetProtocol("NSWindowDelegate")
|
||||
class_EbitengineWindowDelegate.AddProtocol(protocol)
|
||||
// TODO: remove these Ivars and place them in Go since there is only ever one instance of this class
|
||||
class_EbitengineWindowDelegate.AddIvar("origDelegate", objc.ID(0), "@")
|
||||
class_EbitengineWindowDelegate.AddIvar("origResizable", false, "B")
|
||||
origDelegateOffset := class_EbitengineWindowDelegate.InstanceVariable("origDelegate").Offset()
|
||||
origResizableOffset := class_EbitengineWindowDelegate.InstanceVariable("origResizable").Offset()
|
||||
getOrigDelegate := func(self objc.ID) objc.ID {
|
||||
selfPtr := *(**uintptr)(unsafe.Pointer(&self))
|
||||
return *(*objc.ID)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origDelegateOffset))
|
||||
}
|
||||
getResizable := func(self objc.ID) bool {
|
||||
selfPtr := *(**uintptr)(unsafe.Pointer(&self))
|
||||
return *(*bool)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origResizableOffset))
|
||||
}
|
||||
setResizable := func(self objc.ID, resizable bool) {
|
||||
selfPtr := *(**uintptr)(unsafe.Pointer(&self))
|
||||
*(*bool)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origResizableOffset)) = resizable
|
||||
}
|
||||
pushResizableState := func(self, w objc.ID) {
|
||||
window := cocoa.NSWindow{ID: w}
|
||||
setResizable(self, window.StyleMask()&cocoa.NSWindowStyleMaskResizable != 0)
|
||||
if !getResizable(self) {
|
||||
window.SetStyleMask(window.StyleMask() | cocoa.NSWindowStyleMaskResizable)
|
||||
}
|
||||
}
|
||||
popResizableState := func(self, w objc.ID) {
|
||||
window := cocoa.NSWindow{ID: w}
|
||||
if !getResizable(self) {
|
||||
window.SetStyleMask(window.StyleMask() & ^uint(cocoa.NSWindowStyleMaskResizable))
|
||||
}
|
||||
setResizable(self, false)
|
||||
}
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("initWithOrigDelegate:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, origDelegate objc.ID) objc.ID {
|
||||
self = self.SendSuper(objc.RegisterName("init"))
|
||||
if self != 0 {
|
||||
selfPtr := *(**uintptr)(unsafe.Pointer(&self))
|
||||
*(*objc.ID)(unsafe.Pointer(uintptr(unsafe.Pointer(selfPtr)) + origDelegateOffset)) = origDelegate
|
||||
}
|
||||
return self
|
||||
}), "@@:B")
|
||||
// The method set of origDelegate_ must sync with GLFWWindowDelegate's implementation.
|
||||
// See cocoa_window.m in GLFW.
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowShouldClose:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) int {
|
||||
return int(getOrigDelegate(self).Send(objc.RegisterName("windowShouldClose:"), notification))
|
||||
}), "B@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidResize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidMove:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidMiniaturize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidDeminiaturize:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidBecomeKey:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidResignKey:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidChangeOcclusionState:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
getOrigDelegate(self).Send(cmd, notification)
|
||||
}), "v@:@")
|
||||
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowWillEnterFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
pushResizableState(self, cocoa.NSNotification{ID: notification}.Object())
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidEnterFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
popResizableState(self, cocoa.NSNotification{ID: notification}.Object())
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowWillExitFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
pushResizableState(self, cocoa.NSNotification{ID: notification}.Object())
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.AddMethod(objc.RegisterName("windowDidExitFullScreen:"), objc.NewIMP(func(self objc.ID, cmd objc.SEL, notification objc.ID) {
|
||||
popResizableState(self, cocoa.NSNotification{ID: notification}.Object())
|
||||
// Do not call setFrame here (#2295). setFrame here causes unexpected results.
|
||||
}), "v@:@")
|
||||
class_EbitengineWindowDelegate.Register()
|
||||
}
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
transparent bool
|
||||
}
|
||||
@ -300,10 +183,22 @@ func flipY(y int) int {
|
||||
return y
|
||||
}
|
||||
|
||||
var class_NSEvent = objc.GetClass("NSEvent")
|
||||
var sel_mouseLocation = objc.RegisterName("mouseLocation")
|
||||
|
||||
func currentMouseLocation() (x, y int) {
|
||||
sig := cocoa.NSMethodSignature_signatureWithObjCTypes("{NSPoint=dd}@:")
|
||||
inv := cocoa.NSInvocation_invocationWithMethodSignature(sig)
|
||||
inv.SetTarget(objc.ID(class_NSEvent))
|
||||
inv.SetSelector(sel_mouseLocation)
|
||||
inv.Invoke()
|
||||
var point cocoa.NSPoint
|
||||
inv.GetReturnValue(unsafe.Pointer(&point))
|
||||
return int(point.X), int(point.Y)
|
||||
}
|
||||
|
||||
func initialMonitorByOS() (*glfw.Monitor, error) {
|
||||
var cx, cy C.int
|
||||
C.currentMouseLocation(&cx, &cy)
|
||||
x, y := int(cx), flipY(int(cy))
|
||||
x, y := currentMouseLocation()
|
||||
|
||||
// Find the monitor including the cursor.
|
||||
for _, m := range ensureMonitors() {
|
||||
@ -317,10 +212,20 @@ func initialMonitorByOS() (*glfw.Monitor, error) {
|
||||
}
|
||||
|
||||
func monitorFromWindowByOS(w *glfw.Window) *glfw.Monitor {
|
||||
var x, y C.int
|
||||
C.currentMonitorPos(C.uintptr_t(w.GetCocoaWindow()), &x, &y)
|
||||
window := cocoa.NSWindow{ID: objc.ID(w.GetCocoaWindow())}
|
||||
pool := cocoa.NSAutoreleasePool_new()
|
||||
screen := cocoa.NSScreen_mainScreen()
|
||||
if window.ID != 0 && window.IsVisibile() {
|
||||
// When the window is visible, the window is already initialized.
|
||||
// [NSScreen mainScreen] sometimes tells a lie when the window is put across monitors (#703).
|
||||
screen = window.Screen()
|
||||
}
|
||||
screenDictionary := screen.DeviceDescription()
|
||||
screenID := cocoa.NSNumber{ID: screenDictionary.ObjectForKey(cocoa.NSString_alloc().InitWithUTF8String("NSScreenNumber").ID)}
|
||||
aID := uintptr(screenID.UnsignedIntValue()) // CGDirectDisplayID
|
||||
pool.Release()
|
||||
for _, m := range ensureMonitors() {
|
||||
if int(x) == m.x && int(y) == m.y {
|
||||
if m.m.GetCocoaMonitor() == aID {
|
||||
return m.m
|
||||
}
|
||||
}
|
||||
@ -332,11 +237,29 @@ func (u *userInterfaceImpl) nativeWindow() uintptr {
|
||||
}
|
||||
|
||||
func (u *userInterfaceImpl) isNativeFullscreen() bool {
|
||||
return bool(C.isNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow())))
|
||||
return cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())}.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0
|
||||
}
|
||||
|
||||
func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) {
|
||||
C.setNativeCursor(C.int(shape))
|
||||
class_NSCursor := objc.GetClass("NSCursor")
|
||||
NSCursor := objc.ID(class_NSCursor).Send(objc.RegisterName("class"))
|
||||
sel_performSelector := objc.RegisterName("performSelector:")
|
||||
cursor := NSCursor.Send(sel_performSelector, objc.RegisterName("arrowCursor"))
|
||||
switch shape {
|
||||
case 0:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("arrowCursor"))
|
||||
case 1:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("IBeamCursor"))
|
||||
case 2:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("crosshairCursor"))
|
||||
case 3:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("pointHandCursor"))
|
||||
case 4:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("_windowResizeEastWestCursor"))
|
||||
case 5:
|
||||
cursor = NSCursor.Send(sel_performSelector, objc.RegisterName("_windowResizeNorthSouthCursor"))
|
||||
}
|
||||
cursor.Send(objc.RegisterName("push"))
|
||||
}
|
||||
|
||||
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
||||
@ -345,27 +268,75 @@ func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var sel_collectionBehavior = objc.RegisterName("collectionBehavior")
|
||||
var sel_setCollectionBehavior = objc.RegisterName("setCollectionBehavior:")
|
||||
|
||||
func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) {
|
||||
// Toggling fullscreen might ignore events like keyUp. Ensure that events are fired.
|
||||
glfw.WaitEventsTimeout(0.1)
|
||||
C.setNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow()), C.bool(fullscreen))
|
||||
window := cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())}
|
||||
if window.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0 == fullscreen {
|
||||
return
|
||||
}
|
||||
// Even though EbitengineWindowDelegate is used, this hack is still required.
|
||||
// toggleFullscreen doesn't work when the window is not resizable.
|
||||
origFullScreen := window.Send(sel_collectionBehavior)&cocoa.NSWindowCollectionBehaviorFullScreenPrimary != 0
|
||||
if !origFullScreen {
|
||||
window.Send(sel_setCollectionBehavior, window.Send(sel_collectionBehavior)|cocoa.NSWindowCollectionBehaviorFullScreenPrimary)
|
||||
}
|
||||
window.Send(objc.RegisterName("toggleFullScreen:"), 0)
|
||||
if !origFullScreen {
|
||||
window.Send(sel_setCollectionBehavior, window.Send(sel_collectionBehavior)&cocoa.NSWindowCollectionBehaviorFullScreenPrimary)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *userInterfaceImpl) adjustViewSize() {
|
||||
if u.graphicsDriver.IsGL() {
|
||||
return
|
||||
}
|
||||
C.adjustViewSize(C.uintptr_t(u.window.GetCocoaWindow()))
|
||||
window := cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())}
|
||||
if window.StyleMask()&cocoa.NSWindowStyleMaskFullScreen == 0 {
|
||||
return
|
||||
}
|
||||
// Apparently, adjusting the view size is not needed as of macOS 12 (#1745).
|
||||
if cocoa.NSProcessInfo_processInfo().IsOperatingSystemAtLeastVersion(cocoa.NSOperatingSystemVersion{
|
||||
Major: 12,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
// Reduce the view height (#1745).
|
||||
// https://stackoverflow.com/questions/27758027/sprite-kit-serious-fps-issue-in-full-screen-mode-on-os-x
|
||||
windowSize := window.Frame().Size
|
||||
view := window.ContentView()
|
||||
viewSize := view.Frame().Size
|
||||
if windowSize.Width != viewSize.Width || windowSize.Height != viewSize.Height {
|
||||
return
|
||||
}
|
||||
viewSize.Width--
|
||||
view.SetFrameSize(viewSize)
|
||||
// NSColor.blackColor (0, 0, 0, 1) didn't work.
|
||||
// Use the transparent color instead.
|
||||
window.SetBackgroundColor(cocoa.NSColor_colorWithSRGBRedGreenBlueAlpha(0, 0, 0, 0))
|
||||
}
|
||||
|
||||
func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) {
|
||||
allowFullscreen := mode == WindowResizingModeOnlyFullscreenEnabled ||
|
||||
mode == WindowResizingModeEnabled
|
||||
C.setAllowFullscreen(C.uintptr_t(u.window.GetCocoaWindow()), C.bool(allowFullscreen))
|
||||
collectionBehavior := int(objc.ID(u.window.GetCocoaWindow()).Send(sel_collectionBehavior))
|
||||
if allowFullscreen {
|
||||
collectionBehavior |= cocoa.NSWindowCollectionBehaviorFullScreenPrimary
|
||||
} else {
|
||||
collectionBehavior &^= cocoa.NSWindowCollectionBehaviorFullScreenPrimary
|
||||
}
|
||||
objc.ID(u.window.GetCocoaWindow()).Send(objc.RegisterName("setCollectionBehavior:"), collectionBehavior)
|
||||
}
|
||||
|
||||
func initializeWindowAfterCreation(w *glfw.Window) {
|
||||
// TODO: Register NSWindowWillEnterFullScreenNotification and so on.
|
||||
// Enable resizing temporary before making the window fullscreen.
|
||||
C.initializeWindow(C.uintptr_t(w.GetCocoaWindow()))
|
||||
nswindow := objc.ID(w.GetCocoaWindow())
|
||||
sel_delegate := objc.RegisterName("delegate")
|
||||
delegate := objc.ID(class_EbitengineWindowDelegate).Send(objc.RegisterName("alloc")).Send(objc.RegisterName("initWithOrigDelegate:"), nswindow.Send(sel_delegate))
|
||||
nswindow.Send(objc.RegisterName("setDelegate:"), delegate)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user