updated ebiten version from 2.7.9 to 2.9.9
This commit is contained in:
+193
-60
@@ -11,41 +11,59 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
"github.com/ebitengine/purego/internal/strings"
|
||||
)
|
||||
|
||||
// TODO: support try/catch?
|
||||
// https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime
|
||||
var (
|
||||
objc_msgSend_fn uintptr
|
||||
objc_msgSend func(obj ID, cmd SEL, args ...interface{}) ID
|
||||
objc_msgSendSuper2_fn uintptr
|
||||
objc_msgSendSuper2 func(super *objc_super, cmd SEL, args ...interface{}) ID
|
||||
objc_getClass func(name string) Class
|
||||
objc_getProtocol func(name string) *Protocol
|
||||
objc_allocateClassPair func(super Class, name string, extraBytes uintptr) Class
|
||||
objc_registerClassPair func(class Class)
|
||||
sel_registerName func(name string) SEL
|
||||
class_getSuperclass func(class Class) Class
|
||||
class_getInstanceVariable func(class Class, name string) Ivar
|
||||
class_getInstanceSize func(class Class) uintptr
|
||||
class_addMethod func(class Class, name SEL, imp IMP, types string) bool
|
||||
class_addIvar func(class Class, name string, size uintptr, alignment uint8, types string) bool
|
||||
class_addProtocol func(class Class, protocol *Protocol) bool
|
||||
ivar_getOffset func(ivar Ivar) uintptr
|
||||
ivar_getName func(ivar Ivar) string
|
||||
object_getClass func(obj ID) Class
|
||||
object_getIvar func(obj ID, ivar Ivar) ID
|
||||
object_setIvar func(obj ID, ivar Ivar, value ID)
|
||||
protocol_getName func(protocol *Protocol) string
|
||||
protocol_isEqual func(p *Protocol, p2 *Protocol) bool
|
||||
objc_msgSend_fn uintptr
|
||||
objc_msgSend_stret_fn uintptr
|
||||
objc_msgSend func(obj ID, cmd SEL, args ...any) ID
|
||||
objc_msgSendSuper2_fn uintptr
|
||||
objc_msgSendSuper2_stret_fn uintptr
|
||||
objc_msgSendSuper2 func(super *objc_super, cmd SEL, args ...any) ID
|
||||
objc_getClass func(name string) Class
|
||||
objc_getProtocol func(name string) *Protocol
|
||||
objc_allocateProtocol func(name string) *Protocol
|
||||
objc_registerProtocol func(protocol *Protocol)
|
||||
objc_allocateClassPair func(super Class, name string, extraBytes uintptr) Class
|
||||
objc_registerClassPair func(class Class)
|
||||
sel_registerName func(name string) SEL
|
||||
class_getSuperclass func(class Class) Class
|
||||
class_getInstanceVariable func(class Class, name string) Ivar
|
||||
class_getInstanceSize func(class Class) uintptr
|
||||
class_addMethod func(class Class, name SEL, imp IMP, types string) bool
|
||||
class_addIvar func(class Class, name string, size uintptr, alignment uint8, types string) bool
|
||||
class_addProtocol func(class Class, protocol *Protocol) bool
|
||||
ivar_getOffset func(ivar Ivar) uintptr
|
||||
ivar_getName func(ivar Ivar) string
|
||||
object_getClass func(obj ID) Class
|
||||
object_getIvar func(obj ID, ivar Ivar) ID
|
||||
object_setIvar func(obj ID, ivar Ivar, value ID)
|
||||
protocol_getName func(protocol *Protocol) string
|
||||
protocol_isEqual func(p *Protocol, p2 *Protocol) bool
|
||||
protocol_addMethodDescription func(p *Protocol, name SEL, types string, isRequiredMethod bool, isInstanceMethod bool)
|
||||
protocol_copyMethodDescriptionList func(p *Protocol, isRequiredMethod bool, isInstanceMethod bool, outCount *uint32) *MethodDescription
|
||||
protocol_copyProtocolList func(p *Protocol, outCount *uint32) **Protocol
|
||||
protocol_copyPropertyList2 func(p *Protocol, outCount *uint32, isRequiredProperty, isInstanceProperty bool) *Property
|
||||
protocol_addProtocol func(p *Protocol, p2 *Protocol)
|
||||
protocol_addProperty func(p *Protocol, name string, attributes []PropertyAttribute, attributeCount uint32, isRequiredProperty bool, isInstanceProperty bool)
|
||||
property_getName func(p Property) string
|
||||
property_getAttributes func(p Property) string
|
||||
|
||||
free func(ptr unsafe.Pointer)
|
||||
_Block_copy func(Block) Block
|
||||
_Block_release func(Block)
|
||||
)
|
||||
|
||||
func init() {
|
||||
objc, err := purego.Dlopen("/usr/lib/libobjc.A.dylib", purego.RTLD_GLOBAL)
|
||||
objc, err := purego.Dlopen("/usr/lib/libobjc.A.dylib", purego.RTLD_GLOBAL|purego.RTLD_NOW)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("objc: %w", err))
|
||||
}
|
||||
@@ -53,6 +71,16 @@ func init() {
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("objc: %w", err))
|
||||
}
|
||||
if runtime.GOARCH == "amd64" {
|
||||
objc_msgSend_stret_fn, err = purego.Dlsym(objc, "objc_msgSend_stret")
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("objc: %w", err))
|
||||
}
|
||||
objc_msgSendSuper2_stret_fn, err = purego.Dlsym(objc, "objc_msgSendSuper2_stret")
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("objc: %w", err))
|
||||
}
|
||||
}
|
||||
purego.RegisterFunc(&objc_msgSend, objc_msgSend_fn)
|
||||
objc_msgSendSuper2_fn, err = purego.Dlsym(objc, "objc_msgSendSuper2")
|
||||
if err != nil {
|
||||
@@ -62,6 +90,8 @@ func init() {
|
||||
purego.RegisterLibFunc(&object_getClass, objc, "object_getClass")
|
||||
purego.RegisterLibFunc(&objc_getClass, objc, "objc_getClass")
|
||||
purego.RegisterLibFunc(&objc_getProtocol, objc, "objc_getProtocol")
|
||||
purego.RegisterLibFunc(&objc_allocateProtocol, objc, "objc_allocateProtocol")
|
||||
purego.RegisterLibFunc(&objc_registerProtocol, objc, "objc_registerProtocol")
|
||||
purego.RegisterLibFunc(&objc_allocateClassPair, objc, "objc_allocateClassPair")
|
||||
purego.RegisterLibFunc(&objc_registerClassPair, objc, "objc_registerClassPair")
|
||||
purego.RegisterLibFunc(&sel_registerName, objc, "sel_registerName")
|
||||
@@ -75,8 +105,21 @@ func init() {
|
||||
purego.RegisterLibFunc(&ivar_getName, objc, "ivar_getName")
|
||||
purego.RegisterLibFunc(&protocol_getName, objc, "protocol_getName")
|
||||
purego.RegisterLibFunc(&protocol_isEqual, objc, "protocol_isEqual")
|
||||
purego.RegisterLibFunc(&protocol_addMethodDescription, objc, "protocol_addMethodDescription")
|
||||
purego.RegisterLibFunc(&protocol_copyMethodDescriptionList, objc, "protocol_copyMethodDescriptionList")
|
||||
purego.RegisterLibFunc(&protocol_copyProtocolList, objc, "protocol_copyProtocolList")
|
||||
purego.RegisterLibFunc(&protocol_addProtocol, objc, "protocol_addProtocol")
|
||||
purego.RegisterLibFunc(&protocol_addProperty, objc, "protocol_addProperty")
|
||||
purego.RegisterLibFunc(&protocol_copyPropertyList2, objc, "protocol_copyPropertyList2")
|
||||
purego.RegisterLibFunc(&property_getName, objc, "property_getName")
|
||||
purego.RegisterLibFunc(&property_getAttributes, objc, "property_getAttributes")
|
||||
purego.RegisterLibFunc(&object_getIvar, objc, "object_getIvar")
|
||||
purego.RegisterLibFunc(&object_setIvar, objc, "object_setIvar")
|
||||
purego.RegisterLibFunc(&free, purego.RTLD_DEFAULT, "free")
|
||||
|
||||
purego.RegisterLibFunc(&_Block_copy, objc, "_Block_copy")
|
||||
purego.RegisterLibFunc(&_Block_release, objc, "_Block_release")
|
||||
theBlocksCache = newBlockCache()
|
||||
}
|
||||
|
||||
// ID is an opaque pointer to some Objective-C object
|
||||
@@ -90,7 +133,7 @@ func (id ID) Class() Class {
|
||||
// Send is a convenience method for sending messages to objects. This function takes a SEL
|
||||
// instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result
|
||||
// of RegisterName.
|
||||
func (id ID) Send(sel SEL, args ...interface{}) ID {
|
||||
func (id ID) Send(sel SEL, args ...any) ID {
|
||||
return objc_msgSend(id, sel, args...)
|
||||
}
|
||||
|
||||
@@ -104,12 +147,22 @@ func (id ID) SetIvar(ivar Ivar, value ID) {
|
||||
object_setIvar(id, ivar, value)
|
||||
}
|
||||
|
||||
// keep in sync with func.go
|
||||
const maxRegAllocStructSize = 16
|
||||
|
||||
// Send is a convenience method for sending messages to objects that can return any type.
|
||||
// This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock.
|
||||
// It is best to cache the result of RegisterName.
|
||||
func Send[T any](id ID, sel SEL, args ...any) T {
|
||||
var fn func(id ID, sel SEL, args ...any) T
|
||||
purego.RegisterFunc(&fn, objc_msgSend_fn)
|
||||
var zero T
|
||||
if runtime.GOARCH == "amd64" &&
|
||||
reflect.ValueOf(zero).Kind() == reflect.Struct &&
|
||||
reflect.ValueOf(zero).Type().Size() > maxRegAllocStructSize {
|
||||
purego.RegisterFunc(&fn, objc_msgSend_stret_fn)
|
||||
} else {
|
||||
purego.RegisterFunc(&fn, objc_msgSend_fn)
|
||||
}
|
||||
return fn(id, sel, args...)
|
||||
}
|
||||
|
||||
@@ -124,7 +177,7 @@ type objc_super struct {
|
||||
// SendSuper is a convenience method for sending message to object's super. This function takes a SEL
|
||||
// instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result
|
||||
// of RegisterName.
|
||||
func (id ID) SendSuper(sel SEL, args ...interface{}) ID {
|
||||
func (id ID) SendSuper(sel SEL, args ...any) ID {
|
||||
super := &objc_super{
|
||||
receiver: id,
|
||||
superClass: id.Class(),
|
||||
@@ -141,7 +194,14 @@ func SendSuper[T any](id ID, sel SEL, args ...any) T {
|
||||
superClass: id.Class(),
|
||||
}
|
||||
var fn func(objcSuper *objc_super, sel SEL, args ...any) T
|
||||
purego.RegisterFunc(&fn, objc_msgSendSuper2_fn)
|
||||
var zero T
|
||||
if runtime.GOARCH == "amd64" &&
|
||||
reflect.ValueOf(zero).Kind() == reflect.Struct &&
|
||||
reflect.ValueOf(zero).Type().Size() > maxRegAllocStructSize {
|
||||
purego.RegisterFunc(&fn, objc_msgSendSuper2_stret_fn)
|
||||
} else {
|
||||
purego.RegisterFunc(&fn, objc_msgSendSuper2_fn)
|
||||
}
|
||||
return fn(super, sel, args...)
|
||||
}
|
||||
|
||||
@@ -163,13 +223,6 @@ func GetClass(name string) Class {
|
||||
return objc_getClass(name)
|
||||
}
|
||||
|
||||
// AllocateClassPair creates a new class and metaclass. Then returns the new class, or Nil if the class could not be created
|
||||
//
|
||||
// Deprecated: use RegisterClass instead
|
||||
func AllocateClassPair(super Class, name string, extraBytes uintptr) Class {
|
||||
return objc_allocateClassPair(super, name, extraBytes)
|
||||
}
|
||||
|
||||
// MethodDef represents the Go function and the selector that ObjC uses to access that function.
|
||||
type MethodDef struct {
|
||||
Cmd SEL
|
||||
@@ -360,7 +413,7 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
|
||||
switch typ {
|
||||
case reflect.TypeOf(Class(0)):
|
||||
return encClass, nil
|
||||
case reflect.TypeOf(ID(0)):
|
||||
case reflect.TypeOf(ID(0)), reflect.TypeOf(Block(0)):
|
||||
return encId, nil
|
||||
case reflect.TypeOf(SEL(0)):
|
||||
return encSelector, nil
|
||||
@@ -414,7 +467,7 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
|
||||
}
|
||||
encoding += tmp
|
||||
}
|
||||
encoding = encStructEnd
|
||||
encoding += encStructEnd
|
||||
return encoding, nil
|
||||
case reflect.UnsafePointer:
|
||||
return encUnsafePtr, nil
|
||||
@@ -426,7 +479,7 @@ func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
|
||||
}
|
||||
|
||||
// encodeFunc returns a functions type as if it was given to @encode(fn)
|
||||
func encodeFunc(fn interface{}) (string, error) {
|
||||
func encodeFunc(fn any) (string, error) {
|
||||
typ := reflect.TypeOf(fn)
|
||||
if typ.Kind() != reflect.Func {
|
||||
return "", errors.New("not a func")
|
||||
@@ -476,20 +529,6 @@ func (c Class) AddMethod(name SEL, imp IMP, types string) bool {
|
||||
return class_addMethod(c, name, imp, types)
|
||||
}
|
||||
|
||||
// AddIvar adds a new instance variable to a class.
|
||||
// It may only be called after AllocateClassPair and before Register.
|
||||
// Adding an instance variable to an existing class is not supported.
|
||||
// The class must not be a metaclass. Adding an instance variable to a metaclass is not supported.
|
||||
// It takes the instance of the type of the Ivar and a string representing the type.
|
||||
//
|
||||
// Deprecated: use RegisterClass instead
|
||||
func (c Class) AddIvar(name string, ty interface{}, types string) bool {
|
||||
typeOf := reflect.TypeOf(ty)
|
||||
size := typeOf.Size()
|
||||
alignment := uint8(math.Log2(float64(typeOf.Align())))
|
||||
return class_addIvar(c, name, size, alignment, types)
|
||||
}
|
||||
|
||||
// AddProtocol adds a protocol to a class.
|
||||
// Returns true if the protocol was added successfully, otherwise false (for example,
|
||||
// the class already conforms to that protocol).
|
||||
@@ -507,14 +546,6 @@ func (c Class) InstanceVariable(name string) Ivar {
|
||||
return class_getInstanceVariable(c, name)
|
||||
}
|
||||
|
||||
// Register registers a class that was allocated using AllocateClassPair.
|
||||
// It can now be used to make objects by sending it either alloc and init or new.
|
||||
//
|
||||
// Deprecated: use RegisterClass instead
|
||||
func (c Class) Register() {
|
||||
objc_registerClassPair(c)
|
||||
}
|
||||
|
||||
// Ivar an opaque type that represents an instance variable.
|
||||
type Ivar uintptr
|
||||
|
||||
@@ -530,6 +561,39 @@ func (i Ivar) Name() string {
|
||||
return ivar_getName(i)
|
||||
}
|
||||
|
||||
// MethodDescription holds the name and type definition of a method.
|
||||
type MethodDescription struct {
|
||||
name, types uintptr
|
||||
}
|
||||
|
||||
// Name returns the name of this method.
|
||||
func (m MethodDescription) Name() string {
|
||||
return strings.GoString(m.name)
|
||||
}
|
||||
|
||||
// Types returns the OBJC runtime encoded type description.
|
||||
func (m MethodDescription) Types() string {
|
||||
return strings.GoString(m.types)
|
||||
}
|
||||
|
||||
// PropertyAttribute contains the null-terminated Name and Value pair of a Properties internal description.
|
||||
type PropertyAttribute struct {
|
||||
Name, Value *byte
|
||||
}
|
||||
|
||||
// Property is an opaque type for Objective-C property metadata.
|
||||
type Property uintptr
|
||||
|
||||
// Name returns the name of this property.
|
||||
func (p Property) Name() string {
|
||||
return property_getName(p)
|
||||
}
|
||||
|
||||
// Attributes returns a comma separated list of PropertyAttribute
|
||||
func (p Property) Attributes() string {
|
||||
return property_getAttributes(p)
|
||||
}
|
||||
|
||||
// Protocol is a type that declares methods that can be implemented by any class.
|
||||
type Protocol [0]func()
|
||||
|
||||
@@ -538,11 +602,69 @@ func GetProtocol(name string) *Protocol {
|
||||
return objc_getProtocol(name)
|
||||
}
|
||||
|
||||
// AllocateProtocol creates a new protocol in the OBJC runtime or nil if the protocol already exists.
|
||||
func AllocateProtocol(name string) *Protocol {
|
||||
return objc_allocateProtocol(name)
|
||||
}
|
||||
|
||||
// Register registers the protocol created using AllocateProtocol with the runtime. This must be done
|
||||
// before it is used anywhere and can only be called once.
|
||||
func (p *Protocol) Register() {
|
||||
objc_registerProtocol(p)
|
||||
}
|
||||
|
||||
// CopyMethodDescriptionList returns a list of methods that this protocol has given it isRequiredMethod and isInstanceMethod.
|
||||
func (p *Protocol) CopyMethodDescriptionList(isRequiredMethod, isInstanceMethod bool) []MethodDescription {
|
||||
count := uint32(0)
|
||||
desc := protocol_copyMethodDescriptionList(p, isRequiredMethod, isInstanceMethod, &count)
|
||||
methods := clone(unsafe.Slice(desc, count))
|
||||
free(unsafe.Pointer(desc))
|
||||
return methods
|
||||
}
|
||||
|
||||
// CopyProtocolList returns a list of the protocols that this protocol inherits from.
|
||||
func (p *Protocol) CopyProtocolList() []*Protocol {
|
||||
count := uint32(0)
|
||||
desc := protocol_copyProtocolList(p, &count)
|
||||
protocols := clone(unsafe.Slice(desc, count))
|
||||
free(unsafe.Pointer(desc))
|
||||
return protocols
|
||||
}
|
||||
|
||||
// CopyPropertyList returns a list of properties that this protocol has given it isRequiredProperty and isInstanceProperty.
|
||||
func (p *Protocol) CopyPropertyList(isRequiredProperty, isInstanceProperty bool) []Property {
|
||||
count := uint32(0)
|
||||
desc := protocol_copyPropertyList2(p, &count, isRequiredProperty, isInstanceProperty)
|
||||
protocols := clone(unsafe.Slice(desc, count))
|
||||
free(unsafe.Pointer(desc))
|
||||
return protocols
|
||||
}
|
||||
|
||||
// Name returns the name of this protocol.
|
||||
func (p *Protocol) Name() string {
|
||||
return protocol_getName(p)
|
||||
}
|
||||
|
||||
// Equals return true if the two protocols are the same.
|
||||
func (p *Protocol) Equals(p2 *Protocol) bool {
|
||||
return protocol_isEqual(p, p2)
|
||||
}
|
||||
|
||||
// AddMethodDescription adds a method to a protocol. This can only be called between AllocateProtocol and Protocol.Register.
|
||||
func (p *Protocol) AddMethodDescription(name SEL, types string, isRequiredMethod, isInstanceMethod bool) {
|
||||
protocol_addMethodDescription(p, name, types, isRequiredMethod, isInstanceMethod)
|
||||
}
|
||||
|
||||
// AddProtocol marks the protocol as inheriting from another. This can only be called between AllocateProtocol and Protocol.Register.
|
||||
func (p *Protocol) AddProtocol(protocol *Protocol) {
|
||||
protocol_addProtocol(p, protocol)
|
||||
}
|
||||
|
||||
// AddProperty adds a property to the protocol. This can only be called between AllocateProtocol and Protocol.Register.
|
||||
func (p *Protocol) AddProperty(name string, attributes []PropertyAttribute, isRequiredProperty, isInstanceProperty bool) {
|
||||
protocol_addProperty(p, name, attributes, uint32(len(attributes)), isRequiredProperty, isInstanceProperty)
|
||||
}
|
||||
|
||||
// IMP is a function pointer that can be called by Objective-C code.
|
||||
type IMP uintptr
|
||||
|
||||
@@ -550,7 +672,7 @@ type IMP uintptr
|
||||
// It returns an IMP function pointer that can be called by Objective-C code.
|
||||
// The function panics if an error occurs.
|
||||
// The function pointer is never deallocated.
|
||||
func NewIMP(fn interface{}) IMP {
|
||||
func NewIMP(fn any) IMP {
|
||||
ty := reflect.TypeOf(fn)
|
||||
if ty.Kind() != reflect.Func {
|
||||
panic("objc: not a function")
|
||||
@@ -567,3 +689,14 @@ func NewIMP(fn interface{}) IMP {
|
||||
}
|
||||
return IMP(purego.NewCallback(fn))
|
||||
}
|
||||
|
||||
// TODO: remove and use slices.Clone when minimum version for purego is 1.21
|
||||
func clone[S ~[]E, E any](s S) S {
|
||||
// Preserve nilness in case it matters.
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
// Avoid s[:0:0] as it leads to unwanted liveness when cloning a
|
||||
// zero-length slice of a large array; see https://go.dev/issue/68488.
|
||||
return append(S{}, s...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user