diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:24:06 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:41:34 +0300 |
commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py | |
parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
download | ydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz |
add ydb deps
Diffstat (limited to 'contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py')
-rw-r--r-- | contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py new file mode 100644 index 0000000000..2754820efc --- /dev/null +++ b/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py @@ -0,0 +1,157 @@ +"""Inputhook for OS X + +Calls NSApp / CoreFoundation APIs via ctypes. +""" + +# obj-c boilerplate from appnope, used under BSD 2-clause + +import ctypes +import ctypes.util +from threading import Event + +objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) # type: ignore + +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): + """create a selector name (for ObjC methods)""" + return objc.sel_registerName(_utf8(name)) + +def C(classname): + """get an ObjC Class by name""" + return objc.objc_getClass(_utf8(classname)) + +# end obj-c boilerplate from appnope + +# CoreFoundation C-API calls we will use: +CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type: ignore + +CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate +CFFileDescriptorCreate.restype = void_p +CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p, 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') + + +def _NSApp(): + """Return the global NSApplication instance (NSApp)""" + objc.objc_msgSend.argtypes = [void_p, void_p] + return msg(C('NSApplication'), n('sharedApplication')) + + +def _wake(NSApp): + """Wake the Application""" + objc.objc_msgSend.argtypes = [ + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + void_p, + ] + 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 + ) + objc.objc_msgSend.argtypes = [void_p, void_p, void_p, void_p] + msg(NSApp, n('postEvent:atStart:'), void_p(event), True) + + +_triggered = Event() + +def _input_callback(fdref, flags, info): + """Callback to fire when there's input to be read""" + _triggered.set() + CFFileDescriptorInvalidate(fdref) + CFRelease(fdref) + NSApp = _NSApp() + objc.objc_msgSend.argtypes = [void_p, void_p, void_p] + msg(NSApp, n('stop:'), NSApp) + _wake(NSApp) + +_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p) +_c_input_callback = _c_callback_func_type(_input_callback) + + +def _stop_on_read(fd): + """Register callback to stop eventloop when there's data on fd""" + _triggered.clear() + fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None) + CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack) + source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0) + loop = CFRunLoopGetCurrent() + CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes) + CFRelease(source) + + +def inputhook(context): + """Inputhook for Cocoa (NSApp)""" + NSApp = _NSApp() + _stop_on_read(context.fileno()) + objc.objc_msgSend.argtypes = [void_p, void_p] + msg(NSApp, n('run')) + 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() |