##// END OF EJS Templates
Remove the Event '_triggered' in osx.py to fix hangs. (#14125)...
Min RK -
r28345:292e3a23 merge
parent child Browse files
Show More
@@ -1,157 +1,147 b''
1 1 """Inputhook for OS X
2 2
3 3 Calls NSApp / CoreFoundation APIs via ctypes.
4 4 """
5 5
6 6 # obj-c boilerplate from appnope, used under BSD 2-clause
7 7
8 8 import ctypes
9 9 import ctypes.util
10 10 from threading import Event
11 11
12 12 objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) # type: ignore
13 13
14 14 void_p = ctypes.c_void_p
15 15
16 16 objc.objc_getClass.restype = void_p
17 17 objc.sel_registerName.restype = void_p
18 18 objc.objc_msgSend.restype = void_p
19 19 objc.objc_msgSend.argtypes = [void_p, void_p]
20 20
21 21 msg = objc.objc_msgSend
22 22
23 23 def _utf8(s):
24 24 """ensure utf8 bytes"""
25 25 if not isinstance(s, bytes):
26 26 s = s.encode('utf8')
27 27 return s
28 28
29 29 def n(name):
30 30 """create a selector name (for ObjC methods)"""
31 31 return objc.sel_registerName(_utf8(name))
32 32
33 33 def C(classname):
34 34 """get an ObjC Class by name"""
35 35 return objc.objc_getClass(_utf8(classname))
36 36
37 37 # end obj-c boilerplate from appnope
38 38
39 39 # CoreFoundation C-API calls we will use:
40 40 CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type: ignore
41 41
42 42 CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
43 43 CFFileDescriptorCreate.restype = void_p
44 44 CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p, void_p]
45 45
46 46 CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
47 47 CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
48 48 CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
49 49
50 50 CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
51 51 CFFileDescriptorEnableCallBacks.restype = None
52 52 CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
53 53
54 54 CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
55 55 CFFileDescriptorCreateRunLoopSource.restype = void_p
56 56 CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
57 57
58 58 CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
59 59 CFRunLoopGetCurrent.restype = void_p
60 60
61 61 CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
62 62 CFRunLoopAddSource.restype = None
63 63 CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
64 64
65 65 CFRelease = CoreFoundation.CFRelease
66 66 CFRelease.restype = None
67 67 CFRelease.argtypes = [void_p]
68 68
69 69 CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
70 70 CFFileDescriptorInvalidate.restype = None
71 71 CFFileDescriptorInvalidate.argtypes = [void_p]
72 72
73 73 # From CFFileDescriptor.h
74 74 kCFFileDescriptorReadCallBack = 1
75 75 kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
76 76
77 77
78 78 def _NSApp():
79 79 """Return the global NSApplication instance (NSApp)"""
80 80 objc.objc_msgSend.argtypes = [void_p, void_p]
81 81 return msg(C('NSApplication'), n('sharedApplication'))
82 82
83 83
84 84 def _wake(NSApp):
85 85 """Wake the Application"""
86 86 objc.objc_msgSend.argtypes = [
87 87 void_p,
88 88 void_p,
89 89 void_p,
90 90 void_p,
91 91 void_p,
92 92 void_p,
93 93 void_p,
94 94 void_p,
95 95 void_p,
96 96 void_p,
97 97 void_p,
98 98 ]
99 99 event = msg(
100 100 C("NSEvent"),
101 101 n(
102 102 "otherEventWithType:location:modifierFlags:"
103 103 "timestamp:windowNumber:context:subtype:data1:data2:"
104 104 ),
105 105 15, # Type
106 106 0, # location
107 107 0, # flags
108 108 0, # timestamp
109 109 0, # window
110 110 None, # context
111 111 0, # subtype
112 112 0, # data1
113 113 0, # data2
114 114 )
115 115 objc.objc_msgSend.argtypes = [void_p, void_p, void_p, void_p]
116 116 msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
117 117
118 118
119 _triggered = Event()
120
121 119 def _input_callback(fdref, flags, info):
122 120 """Callback to fire when there's input to be read"""
123 _triggered.set()
124 121 CFFileDescriptorInvalidate(fdref)
125 122 CFRelease(fdref)
126 123 NSApp = _NSApp()
127 124 objc.objc_msgSend.argtypes = [void_p, void_p, void_p]
128 125 msg(NSApp, n('stop:'), NSApp)
129 126 _wake(NSApp)
130 127
131 128 _c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
132 129 _c_input_callback = _c_callback_func_type(_input_callback)
133 130
134 131
135 132 def _stop_on_read(fd):
136 133 """Register callback to stop eventloop when there's data on fd"""
137 _triggered.clear()
138 134 fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
139 135 CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
140 136 source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
141 137 loop = CFRunLoopGetCurrent()
142 138 CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
143 139 CFRelease(source)
144 140
145 141
146 142 def inputhook(context):
147 143 """Inputhook for Cocoa (NSApp)"""
148 144 NSApp = _NSApp()
149 145 _stop_on_read(context.fileno())
150 146 objc.objc_msgSend.argtypes = [void_p, void_p]
151 147 msg(NSApp, n('run'))
152 if not _triggered.is_set():
153 # app closed without firing callback,
154 # probably due to last window being closed.
155 # Run the loop manually in this case,
156 # since there may be events still to process (#9734)
157 CoreFoundation.CFRunLoopRun()
General Comments 0
You need to be logged in to leave comments. Login now