##// END OF EJS Templates
Add OS X input hook...
Min RK -
Show More
@@ -0,0 +1,104 b''
1
2 # obj-c boilerplate from appnope, used under BSD 2-clause
3
4 import ctypes
5 import ctypes.util
6
7 objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
8 CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
9 # Cocoa = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Cocoa'))
10
11 void_p = ctypes.c_void_p
12
13 objc.objc_getClass.restype = void_p
14 objc.sel_registerName.restype = void_p
15 objc.objc_msgSend.restype = void_p
16 objc.objc_msgSend.argtypes = [void_p, void_p]
17
18 msg = objc.objc_msgSend
19
20 def _utf8(s):
21 """ensure utf8 bytes"""
22 if not isinstance(s, bytes):
23 s = s.encode('utf8')
24 return s
25
26 def n(name):
27 """create a selector name (for methods)"""
28 return objc.sel_registerName(_utf8(name))
29
30 def C(classname):
31 """get an ObjC Class by name"""
32 return objc.objc_getClass(_utf8(classname))
33
34 # CoreFoundation calls we will use:
35 CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
36 CFFileDescriptorCreate.restype = void_p
37 CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p]
38
39 CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
40 CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
41 CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
42
43 CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
44 CFFileDescriptorEnableCallBacks.restype = None
45 CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
46
47 CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
48 CFFileDescriptorCreateRunLoopSource.restype = void_p
49 CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
50
51 CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
52 CFRunLoopGetCurrent.restype = void_p
53
54 CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
55 CFRunLoopAddSource.restype = None
56 CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
57
58 CFRelease = CoreFoundation.CFRelease
59 CFRelease.restype = None
60 CFRelease.argtypes = [void_p]
61
62 CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
63 CFFileDescriptorInvalidate.restype = None
64 CFFileDescriptorInvalidate.argtypes = [void_p]
65
66
67 # From CFFileDescriptor.h
68 kCFFileDescriptorReadCallBack = 1
69 kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
70
71 def _NSApp():
72 """Return the global NSApplication instance (NSApp)"""
73 return msg(C('NSApplication'), n('sharedApplication'))
74
75 def _input_callback(fdref, flags, info):
76 """Callback to fire when there's input to be read"""
77 CFFileDescriptorInvalidate(fdref)
78 CFRelease(fdref)
79 NSApp = _NSApp()
80 msg(NSApp, n('stop:'), NSApp)
81
82 _c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
83 _c_callback = _c_callback_func_type(_input_callback)
84
85 def _stop_on_read(fd):
86 """Register callback to stop eventloop when there's data on fd"""
87 fdref = CFFileDescriptorCreate(None, fd, False, _c_callback, None)
88 CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
89 source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
90 loop = CFRunLoopGetCurrent()
91 CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
92 CFRelease(source)
93
94 def inputhook(context):
95 """Inputhook for Cocoa (NSApp)"""
96 NSApp = _NSApp()
97 window_count = msg(
98 msg(NSApp, n('windows')),
99 n('count')
100 )
101 if not window_count:
102 return
103 _stop_on_read(context.fileno())
104 msg(NSApp, n('run'))
@@ -1,38 +1,39 b''
1 import importlib
1 import importlib
2 import os
2 import os
3
3
4 aliases = {
4 aliases = {
5 'qt4': 'qt',
5 'qt4': 'qt',
6 'gtk2': 'gtk',
6 'gtk2': 'gtk',
7 }
7 }
8
8
9 backends = [
9 backends = [
10 'qt', 'qt4', 'qt5',
10 'qt', 'qt4', 'qt5',
11 'gtk', 'gtk2', 'gtk3',
11 'gtk', 'gtk2', 'gtk3',
12 'tk',
12 'tk',
13 'wx',
13 'wx',
14 'pyglet', 'glut',
14 'pyglet', 'glut',
15 'osx',
15 ]
16 ]
16
17
17 class UnknownBackend(KeyError):
18 class UnknownBackend(KeyError):
18 def __init__(self, name):
19 def __init__(self, name):
19 self.name = name
20 self.name = name
20
21
21 def __str__(self):
22 def __str__(self):
22 return ("No event loop integration for {!r}. "
23 return ("No event loop integration for {!r}. "
23 "Supported event loops are: {}").format(self.name,
24 "Supported event loops are: {}").format(self.name,
24 ', '.join(backends))
25 ', '.join(backends))
25
26
26 def get_inputhook_func(gui):
27 def get_inputhook_func(gui):
27 if gui not in backends:
28 if gui not in backends:
28 raise UnknownBackend(gui)
29 raise UnknownBackend(gui)
29
30
30 if gui in aliases:
31 if gui in aliases:
31 return get_inputhook_func(aliases[gui])
32 return get_inputhook_func(aliases[gui])
32
33
33 if gui == 'qt5':
34 if gui == 'qt5':
34 os.environ['QT_API'] = 'pyqt5'
35 os.environ['QT_API'] = 'pyqt5'
35 gui = 'qt'
36 gui = 'qt'
36
37
37 mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui)
38 mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui)
38 return mod.inputhook
39 return mod.inputhook
General Comments 0
You need to be logged in to leave comments. Login now