aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-09-29 12:24:06 +0300
committernkozlovskiy <nmk@ydb.tech>2023-09-29 12:41:34 +0300
commite0e3e1717e3d33762ce61950504f9637a6e669ed (patch)
treebca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/osx.py
parent38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff)
downloadydb-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.py157
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()