2022-08-17 18:39:34 +02:00
|
|
|
// Copyright 2022 The Ebitengine Authors
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package cocoa
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/ebitengine/purego/objc"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
class_NSInvocation = objc.GetClass("NSInvocation")
|
|
|
|
class_NSMethodSignature = objc.GetClass("NSMethodSignature")
|
|
|
|
class_NSAutoreleasePool = objc.GetClass("NSAutoreleasePool")
|
|
|
|
class_NSString = objc.GetClass("NSString")
|
2022-09-16 04:53:46 +02:00
|
|
|
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")
|
2022-08-17 18:39:34 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
sel_alloc = objc.RegisterName("alloc")
|
|
|
|
sel_new = objc.RegisterName("new")
|
|
|
|
sel_release = objc.RegisterName("release")
|
|
|
|
sel_invocationWithMethodSignature = objc.RegisterName("invocationWithMethodSignature:")
|
|
|
|
sel_setSelector = objc.RegisterName("setSelector:")
|
|
|
|
sel_setTarget = objc.RegisterName("setTarget:")
|
|
|
|
sel_setArgumentAtIndex = objc.RegisterName("setArgument:atIndex:")
|
|
|
|
sel_getReturnValue = objc.RegisterName("getReturnValue:")
|
|
|
|
sel_invoke = objc.RegisterName("invoke")
|
2022-09-16 04:53:46 +02:00
|
|
|
sel_invokeWithTarget = objc.RegisterName("invokeWithTarget:")
|
2022-08-17 18:39:34 +02:00
|
|
|
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")
|
2022-09-16 04:53:46 +02:00
|
|
|
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")
|
2022-08-17 18:39:34 +02:00
|
|
|
)
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
const NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
|
|
|
|
|
|
|
|
const (
|
|
|
|
NSWindowStyleMaskResizable = 1 << 3
|
|
|
|
NSWindowStyleMaskFullScreen = 1 << 14
|
|
|
|
)
|
|
|
|
|
|
|
|
type CGFloat = float64
|
2022-08-17 18:39:34 +02:00
|
|
|
|
|
|
|
type CGSize struct {
|
|
|
|
Width, Height CGFloat
|
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
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
|
|
|
|
|
2022-08-17 18:39:34 +02:00
|
|
|
type NSError struct {
|
|
|
|
objc.ID
|
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-17 18:39:34 +02:00
|
|
|
// 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 {
|
|
|
|
objc.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func NSInvocation_invocationWithMethodSignature(sig NSMethodSignature) NSInvocation {
|
|
|
|
return NSInvocation{objc.ID(class_NSInvocation).Send(sel_invocationWithMethodSignature, sig.ID)}
|
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (i NSInvocation) SetSelector(cmd objc.SEL) {
|
|
|
|
i.Send(sel_setSelector, cmd)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (i NSInvocation) SetTarget(target objc.ID) {
|
|
|
|
i.Send(sel_setTarget, target)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (i NSInvocation) SetArgumentAtIndex(arg unsafe.Pointer, idx int) {
|
|
|
|
i.Send(sel_setArgumentAtIndex, arg, idx)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (i NSInvocation) GetReturnValue(ret unsafe.Pointer) {
|
|
|
|
i.Send(sel_getReturnValue, ret)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (i NSInvocation) Invoke() {
|
|
|
|
i.Send(sel_invoke)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i NSInvocation) InvokeWithTarget(target objc.ID) {
|
|
|
|
i.Send(sel_invokeWithTarget, target)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type NSMethodSignature struct {
|
|
|
|
objc.ID
|
|
|
|
}
|
|
|
|
|
2022-09-15 19:32:05 +02:00
|
|
|
func NSMethodSignature_instanceMethodSignatureForSelector(self objc.ID, cmd objc.SEL) NSMethodSignature {
|
|
|
|
return NSMethodSignature{self.Send(sel_instanceMethodSignatureForSelector, cmd)}
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// NSMethodSignature_signatureWithObjCTypes takes a string that represents the type signature of a method.
|
|
|
|
// It follows the encoding specified in the Apple Docs.
|
|
|
|
//
|
|
|
|
// [Apple Docs]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
|
|
|
|
func NSMethodSignature_signatureWithObjCTypes(types string) NSMethodSignature {
|
|
|
|
return NSMethodSignature{objc.ID(class_NSMethodSignature).Send(sel_signatureWithObjCTypes, types)}
|
|
|
|
}
|
|
|
|
|
|
|
|
type NSAutoreleasePool struct {
|
|
|
|
objc.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func NSAutoreleasePool_new() NSAutoreleasePool {
|
|
|
|
return NSAutoreleasePool{objc.ID(class_NSAutoreleasePool).Send(sel_new)}
|
|
|
|
}
|
|
|
|
|
2022-09-16 04:53:46 +02:00
|
|
|
func (p NSAutoreleasePool) Release() {
|
|
|
|
p.Send(sel_release)
|
2022-08-17 18:39:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type NSString struct {
|
|
|
|
objc.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func NSString_alloc() NSString {
|
|
|
|
return NSString{objc.ID(class_NSString).Send(sel_alloc)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s NSString) InitWithUTF8String(utf8 string) NSString {
|
|
|
|
return NSString{s.Send(sel_initWithUTF8String, utf8)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s NSString) String() string {
|
|
|
|
// this will be nicer with unsafe.Slice once ebitengine requires 1.17
|
|
|
|
// reflect.SliceHeader is used because it will force Go to copy the string
|
|
|
|
// into Go memory when casted to a string
|
|
|
|
var b []byte
|
|
|
|
header := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
|
|
header.Data = uintptr(s.Send(sel_UTF8String))
|
|
|
|
header.Len = int(s.Send(sel_length))
|
|
|
|
header.Cap = header.Len
|
|
|
|
return string(b)
|
|
|
|
}
|
2022-09-16 04:53:46 +02:00
|
|
|
|
|
|
|
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))
|
|
|
|
}
|