##// END OF EJS Templates
Get GitHub stats since 5.1.0, and deduplicate mails in .mailmap...
Get GitHub stats since 5.1.0, and deduplicate mails in .mailmap (forward port of 94209687855db35455b84415fcc460d559585889)

File last commit:

r23167:260e9884
r23270:9641191d
Show More
osx.py
137 lines | 4.2 KiB | text/x-python | PythonLexer
Min RK
tidy, docstrings
r22161 """Inputhook for OS X
Calls NSApp / CoreFoundation APIs via ctypes.
"""
Min RK
Add OS X input hook...
r22159
# obj-c boilerplate from appnope, used under BSD 2-clause
import ctypes
import ctypes.util
Min RK
run CFRunLoopRun if NSApp:run finishes on its own...
r22776 from threading import Event
Min RK
Add OS X input hook...
r22159
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
void_p = ctypes.c_void_p
objc.objc_getClass.restype = void_p
objc.sel_registerName.restype = void_p
objc.objc_msgSend.restype = void_p
objc.objc_msgSend.argtypes = [void_p, void_p]
msg = objc.objc_msgSend
def _utf8(s):
"""ensure utf8 bytes"""
if not isinstance(s, bytes):
s = s.encode('utf8')
return s
def n(name):
Min RK
Wake the main loop with an event
r22160 """create a selector name (for ObjC methods)"""
Min RK
Add OS X input hook...
r22159 return objc.sel_registerName(_utf8(name))
def C(classname):
"""get an ObjC Class by name"""
return objc.objc_getClass(_utf8(classname))
Min RK
tidy, docstrings
r22161 # end obj-c boilerplate from appnope
# CoreFoundation C-API calls we will use:
CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
Min RK
Add OS X input hook...
r22159 CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
CFFileDescriptorCreate.restype = void_p
CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p]
CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
CFFileDescriptorEnableCallBacks.restype = None
CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
CFFileDescriptorCreateRunLoopSource.restype = void_p
CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
CFRunLoopGetCurrent.restype = void_p
CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
CFRunLoopAddSource.restype = None
CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
CFRelease = CoreFoundation.CFRelease
CFRelease.restype = None
CFRelease.argtypes = [void_p]
CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
CFFileDescriptorInvalidate.restype = None
CFFileDescriptorInvalidate.argtypes = [void_p]
# From CFFileDescriptor.h
kCFFileDescriptorReadCallBack = 1
kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
Min RK
tidy, docstrings
r22161
Min RK
Add OS X input hook...
r22159 def _NSApp():
"""Return the global NSApplication instance (NSApp)"""
return msg(C('NSApplication'), n('sharedApplication'))
Min RK
tidy, docstrings
r22161
Min RK
Wake the main loop with an event
r22160 def _wake(NSApp):
"""Wake the Application"""
event = msg(C('NSEvent'),
n('otherEventWithType:location:modifierFlags:'
'timestamp:windowNumber:context:subtype:data1:data2:'),
15, # Type
0, # location
0, # flags
0, # timestamp
0, # window
None, # context
0, # subtype
0, # data1
0, # data2
)
msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
Min RK
tidy, docstrings
r22161
Min RK
run CFRunLoopRun if NSApp:run finishes on its own...
r22776 _triggered = Event()
Min RK
Add OS X input hook...
r22159 def _input_callback(fdref, flags, info):
"""Callback to fire when there's input to be read"""
Min RK
run CFRunLoopRun if NSApp:run finishes on its own...
r22776 _triggered.set()
Min RK
Add OS X input hook...
r22159 CFFileDescriptorInvalidate(fdref)
CFRelease(fdref)
NSApp = _NSApp()
msg(NSApp, n('stop:'), NSApp)
Min RK
Wake the main loop with an event
r22160 _wake(NSApp)
Min RK
Add OS X input hook...
r22159
_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
Min RK
Wake the main loop with an event
r22160 _c_input_callback = _c_callback_func_type(_input_callback)
Min RK
Add OS X input hook...
r22159
Min RK
tidy, docstrings
r22161
Min RK
Add OS X input hook...
r22159 def _stop_on_read(fd):
"""Register callback to stop eventloop when there's data on fd"""
Min RK
run CFRunLoopRun if NSApp:run finishes on its own...
r22776 _triggered.clear()
Min RK
Wake the main loop with an event
r22160 fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
Min RK
Add OS X input hook...
r22159 CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
loop = CFRunLoopGetCurrent()
CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
CFRelease(source)
Min RK
tidy, docstrings
r22161
Min RK
Add OS X input hook...
r22159 def inputhook(context):
"""Inputhook for Cocoa (NSApp)"""
NSApp = _NSApp()
_stop_on_read(context.fileno())
msg(NSApp, n('run'))
Min RK
run CFRunLoopRun if NSApp:run finishes on its own...
r22776 if not _triggered.is_set():
# app closed without firing callback,
# probably due to last window being closed.
# Run the loop manually in this case,
# since there may be events still to process (#9734)
CoreFoundation.CFRunLoopRun()