这是什么?pyglet更新? pick一下
This commit is contained in:
parent
b2d9357234
commit
9a46d948c3
@ -91,6 +91,8 @@ class CocoaEventLoop(PlatformEventLoop):
|
||||
# Using distantFuture as untilDate means that nextEventMatchingMask
|
||||
# will wait until the next event comes along.
|
||||
timeout_date = NSDate.distantFuture()
|
||||
elif timeout == 0.0:
|
||||
timeout_date = NSDate.distantPast()
|
||||
else:
|
||||
timeout_date = NSDate.dateWithTimeIntervalSinceNow_(timeout)
|
||||
|
||||
|
@ -28,22 +28,12 @@
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
from contextlib import contextmanager
|
||||
|
||||
from .runtime import objc, send_message, send_super
|
||||
from .runtime import objc, send_message, send_super, AutoReleasePool
|
||||
from .runtime import get_selector
|
||||
from .runtime import ObjCClass, ObjCInstance, ObjCSubclass
|
||||
|
||||
from .cocoatypes import *
|
||||
from .cocoalibs import *
|
||||
|
||||
NSAutoreleasePool = ObjCClass('NSAutoreleasePool')
|
||||
|
||||
class AutoReleasePool:
|
||||
"""Helper context function to more easily manage NSAutoreleasePool"""
|
||||
def __enter__(self):
|
||||
self.pool = NSAutoreleasePool.alloc().init()
|
||||
return self.pool
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.pool.drain()
|
||||
del self.pool
|
||||
|
@ -28,10 +28,11 @@
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import ctypes
|
||||
import sys
|
||||
import platform
|
||||
import struct
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ctypes import *
|
||||
from ctypes import util
|
||||
@ -56,6 +57,11 @@ if lib is None:
|
||||
lib = '/usr/lib/libobjc.dylib'
|
||||
|
||||
objc = cdll.LoadLibrary(lib)
|
||||
libc = cdll.LoadLibrary(util.find_library('c'))
|
||||
|
||||
# void free(void *)
|
||||
libc.free.restype = None
|
||||
libc.free.argtypes = [c_void_p]
|
||||
|
||||
######################################################################
|
||||
|
||||
@ -213,7 +219,7 @@ objc.method_copyArgumentType.argtypes = [c_void_p, c_uint]
|
||||
|
||||
# char * method_copyReturnType(Method method)
|
||||
# You must free() the returned string.
|
||||
objc.method_copyReturnType.restype = c_char_p
|
||||
objc.method_copyReturnType.restype = POINTER(c_char)
|
||||
objc.method_copyReturnType.argtypes = [c_void_p]
|
||||
|
||||
# void method_exchangeImplementations(Method m1, Method m2)
|
||||
@ -409,6 +415,15 @@ objc.sel_isEqual.argtypes = [c_void_p, c_void_p]
|
||||
objc.sel_registerName.restype = c_void_p
|
||||
objc.sel_registerName.argtypes = [c_char_p]
|
||||
|
||||
######################################################################
|
||||
# void *objc_autoreleasePoolPush(void)
|
||||
objc.objc_autoreleasePoolPush.restype = c_void_p
|
||||
objc.objc_autoreleasePoolPush.argtypes = []
|
||||
|
||||
# void objc_autoreleasePoolPop(void *pool)
|
||||
objc.objc_autoreleasePoolPop.restype = None
|
||||
objc.objc_autoreleasePoolPop.argtypes = [c_void_p]
|
||||
|
||||
######################################################################
|
||||
# Constants
|
||||
OBJC_ASSOCIATION_ASSIGN = 0 # Weak reference to the associated object.
|
||||
@ -621,8 +636,8 @@ def parse_type_encoding(encoding):
|
||||
def cfunctype_for_encoding(encoding):
|
||||
# Check if we've already created a CFUNCTYPE for this encoding.
|
||||
# If so, then return the cached CFUNCTYPE.
|
||||
if encoding in cfunctype_table:
|
||||
return cfunctype_table[encoding]
|
||||
#if encoding in cfunctype_table:
|
||||
# return cfunctype_table[encoding]
|
||||
|
||||
# Otherwise, create a new CFUNCTYPE for the encoding.
|
||||
typecodes = {b'c': c_char, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
|
||||
@ -645,7 +660,7 @@ def cfunctype_for_encoding(encoding):
|
||||
# Cache the new CFUNCTYPE in the cfunctype_table.
|
||||
# We do this mainly because it prevents the CFUNCTYPE
|
||||
# from being garbage-collected while we need it.
|
||||
cfunctype_table[encoding] = cfunctype
|
||||
#cfunctype_table[encoding] = cfunctype
|
||||
return cfunctype
|
||||
|
||||
|
||||
@ -722,7 +737,10 @@ class ObjCMethod:
|
||||
self.name = objc.sel_getName(self.selector)
|
||||
self.pyname = self.name.replace(b':', b'_')
|
||||
self.encoding = objc.method_getTypeEncoding(method)
|
||||
self.return_type = objc.method_copyReturnType(method)
|
||||
|
||||
return_type_ptr = objc.method_copyReturnType(method)
|
||||
self.return_type = cast(return_type_ptr, c_char_p).value
|
||||
|
||||
self.nargs = objc.method_getNumberOfArguments(method)
|
||||
self.imp = c_void_p(objc.method_getImplementation(method))
|
||||
self.argument_types = []
|
||||
@ -730,6 +748,7 @@ class ObjCMethod:
|
||||
buffer = c_buffer(512)
|
||||
objc.method_getArgumentType(method, i, buffer, len(buffer))
|
||||
self.argument_types.append(buffer.value)
|
||||
|
||||
# Get types for all the arguments.
|
||||
try:
|
||||
self.argtypes = [self.ctype_for_encoding(t) for t in self.argument_types]
|
||||
@ -737,6 +756,7 @@ class ObjCMethod:
|
||||
# print('no argtypes encoding for %s (%s)' % (self.name, self.argument_types))
|
||||
self.argtypes = None
|
||||
# Get types for the return type.
|
||||
|
||||
try:
|
||||
if self.return_type == b'@':
|
||||
self.restype = ObjCInstance
|
||||
@ -747,8 +767,12 @@ class ObjCMethod:
|
||||
except:
|
||||
# print('no restype encoding for %s (%s)' % (self.name, self.return_type))
|
||||
self.restype = None
|
||||
|
||||
self.func = None
|
||||
|
||||
libc.free(return_type_ptr)
|
||||
|
||||
|
||||
def ctype_for_encoding(self, encoding):
|
||||
"""Return ctypes type for an encoded Objective-C type."""
|
||||
if encoding in self.typecodes:
|
||||
@ -801,11 +825,13 @@ class ObjCMethod:
|
||||
f = self.get_callable()
|
||||
try:
|
||||
result = f(objc_id, self.selector, *args)
|
||||
|
||||
# Convert result to python type if it is a instance or class pointer.
|
||||
if self.restype == ObjCInstance:
|
||||
result = ObjCInstance(result)
|
||||
elif self.restype == ObjCClass:
|
||||
result = ObjCClass(result)
|
||||
#print("result", self, result, self.restype)
|
||||
return result
|
||||
except ArgumentError as error:
|
||||
# Add more useful info to argument error exceptions, then reraise.
|
||||
@ -892,11 +918,14 @@ class ObjCClass:
|
||||
implemented by this class (but does not find methods of superclass)."""
|
||||
count = c_uint()
|
||||
method_array = objc.class_copyMethodList(self.ptr, byref(count))
|
||||
|
||||
for i in range(count.value):
|
||||
method = c_void_p(method_array[i])
|
||||
objc_method = ObjCMethod(method)
|
||||
self.instance_methods[objc_method.pyname] = objc_method
|
||||
|
||||
libc.free(method_array)
|
||||
|
||||
def cache_class_methods(self):
|
||||
"""Create and store python representations of all class methods
|
||||
implemented by this class (but does not find methods of superclass)."""
|
||||
@ -907,6 +936,8 @@ class ObjCClass:
|
||||
objc_method = ObjCMethod(method)
|
||||
self.class_methods[objc_method.pyname] = objc_method
|
||||
|
||||
libc.free(method_array)
|
||||
|
||||
def get_instance_method(self, name):
|
||||
"""Returns a python representation of the named instance method,
|
||||
either by looking it up in the cached list of methods or by searching
|
||||
@ -1040,11 +1071,7 @@ class ObjCInstance:
|
||||
|
||||
# Creation of NSAutoreleasePool instance does not technically mean it was allocated and initialized, but
|
||||
# it's standard practice, so this should not be an issue.
|
||||
if objc_instance.objc_class.name == b"NSAutoreleasePool":
|
||||
_arp_manager.create(objc_instance)
|
||||
objc_instance.pool = _arp_manager.current
|
||||
_set_dealloc_observer(object_ptr)
|
||||
elif _arp_manager.current:
|
||||
if _arp_manager.current:
|
||||
objc_instance.pool = _arp_manager.current
|
||||
else:
|
||||
_set_dealloc_observer(object_ptr)
|
||||
@ -1255,6 +1282,8 @@ class ObjCSubclass:
|
||||
result = result.ptr.value
|
||||
elif isinstance(result, ObjCInstance):
|
||||
result = result.ptr.value
|
||||
|
||||
print("objc_class_method", py_cls)
|
||||
return result
|
||||
|
||||
name = f.__name__.replace('_', ':')
|
||||
@ -1312,13 +1341,11 @@ def _obj_observer_dealloc(objc_obs, selector_name):
|
||||
if objc_ptr:
|
||||
objc.objc_setAssociatedObject(objc_ptr, objc_obs, None, OBJC_ASSOCIATION_ASSIGN)
|
||||
objc_i = ObjCInstance._cached_objects.pop(objc_ptr, None)
|
||||
if objc_i:
|
||||
_clear_arp_objects(objc_i)
|
||||
|
||||
send_super(objc_obs, selector_name)
|
||||
|
||||
|
||||
def _clear_arp_objects(objc_i: ObjCInstance):
|
||||
def _clear_arp_objects(pool_id):
|
||||
"""Cleanup any ObjCInstance's created during an AutoreleasePool creation.
|
||||
See discussion and investigation thanks to mrJean with leaks regarding pools:
|
||||
https://github.com/mrJean1/PyCocoa/issues/6
|
||||
@ -1329,11 +1356,28 @@ def _clear_arp_objects(objc_i: ObjCInstance):
|
||||
2) Some objects such as ObjCSubclass's must be retained.
|
||||
3) When a pool is drained and dealloc'd, clear all ObjCInstances in that pool that are not retained.
|
||||
"""
|
||||
if objc_i.objc_class.name == b"NSAutoreleasePool":
|
||||
pool_id = objc_i.pool
|
||||
for cobjc_ptr in list(ObjCInstance._cached_objects.keys()):
|
||||
cobjc_i = ObjCInstance._cached_objects[cobjc_ptr]
|
||||
if cobjc_i.retained is False and cobjc_i.pool == pool_id:
|
||||
del ObjCInstance._cached_objects[cobjc_ptr]
|
||||
#if objc_i.objc_class.name == b"NSAutoreleasePool":
|
||||
for cobjc_ptr in list(ObjCInstance._cached_objects.keys()):
|
||||
cobjc_i = ObjCInstance._cached_objects[cobjc_ptr]
|
||||
if cobjc_i.retained is False and cobjc_i.pool == pool_id:
|
||||
#if cobjc_i.objc_class.name != b"__NSTaggedDate":
|
||||
# print("DELETING", cobjc_i, cobjc_i.retained, c_objc_i.type())
|
||||
del ObjCInstance._cached_objects[cobjc_ptr]
|
||||
|
||||
_arp_manager.delete(objc_i)
|
||||
|
||||
@contextmanager
|
||||
def AutoReleasePool():
|
||||
"""Use objc_autoreleasePoolPush/Pop because NSAutoreleasePool is no longer recommended:
|
||||
https://developer.apple.com/documentation/foundation/nsautoreleasepool
|
||||
@autoreleasepool blocks are compiled into the below function calls behind the scenes.
|
||||
Call them directly to mimic the Objective C behavior.
|
||||
"""
|
||||
pool = objc.objc_autoreleasePoolPush()
|
||||
_arp_manager.create(pool)
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_clear_arp_objects(_arp_manager.pools.index(pool))
|
||||
objc.objc_autoreleasePoolPop(pool)
|
||||
_arp_manager.delete(pool)
|
||||
|
Loading…
Reference in New Issue
Block a user