##// END OF EJS Templates
Fixed two bugs in inputhook.
Brian Granger -
Show More
@@ -1,226 +1,233 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Inputhook management for GUI event loop integration.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import ctypes
19 19 import sys
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Code
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 class InputHookManager(object):
27 27 """Manage PyOS_InputHook for different GUI toolkits.
28 28
29 29 This class installs various hooks under ``PyOSInputHook`` to handle
30 30 GUI event loop integration.
31 31 """
32 32
33 33 def __init__(self):
34 34 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
35 35 self._reset()
36 36
37 37 def _reset(self):
38 38 self._callback_pyfunctype = None
39 39 self._callback = None
40 40 self._installed = False
41 41 self._current_gui = None
42 42
43 43 def get_pyos_inputhook(self):
44 44 """Return the current PyOS_InputHook as a ctypes.c_void_p.
45 45 """
46 46 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
47 47
48 48 def get_pyos_inputhook_as_func(self):
49 49 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE.
50 50 """
51 51 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
52 52
53 53 def set_inputhook(self, callback):
54 54 """Set PyOS_InputHook to callback and return the previous one.
55 55 """
56 56 self._callback = callback
57 57 self._callback_pyfunctype = self.PYFUNC(callback)
58 58 pyos_inputhook_ptr = self.get_pyos_inputhook()
59 59 original = self.get_pyos_inputhook_as_func()
60 60 pyos_inputhook_ptr.value = \
61 61 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
62 62 self._installed = True
63 63 return original
64 64
65 65 def clear_inputhook(self):
66 66 """Set PyOS_InputHook to NULL and return the previous one.
67 67 """
68 68 pyos_inputhook_ptr = self.get_pyos_inputhook()
69 69 original = self.get_pyos_inputhook_as_func()
70 70 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
71 71 self._reset()
72 72 return original
73 73
74 74 def enable_wx(self, app=False):
75 75 """Enable event loop integration with wxPython.
76 76
77 77 Parameters
78 78 ----------
79 79 app : bool
80 80 Create a running application object or not.
81 81
82 82 Notes
83 83 -----
84 84 This methods sets the PyOS_InputHook for wxPython, which allows
85 85 the wxPython to integrate with terminal based applications like
86 86 IPython.
87 87
88 88 Once this has been called, you can use wx interactively by doing::
89 89
90 90 >>> import wx
91 91 >>> app = wx.App(redirect=False, clearSigInt=False)
92 92
93 93 Both options this constructor are important for things to work
94 94 properly in an interactive context.
95 95
96 96 But, *don't start the event loop*. That is handled automatically by
97 97 PyOS_InputHook.
98 98 """
99 99 from IPython.lib.inputhookwx import inputhook_wx
100 100 self.set_inputhook(inputhook_wx)
101 101 self._current_gui = 'wx'
102 102 if app:
103 103 import wx
104 104 app = wx.App(redirect=False, clearSigInt=False)
105 # The import of wx on Linux sets the handler for signal.SIGINT
106 # to 0. This is a bug in wx or gtk. We fix by just setting it
107 # back to the Python default.
108 import signal
109 if not callable(signal.getsignal(signal.SIGINT)):
110 signal.signal(signal.SIGINT, signal.default_int_handler)
105 111 return app
106 112
107 113 def disable_wx(self):
108 114 """Disable event loop integration with wxPython.
109 115
110 116 This merely sets PyOS_InputHook to NULL.
111 117 """
112 118 self.clear_inputhook()
113 119
114 120 def enable_qt4(self, app=False):
115 121 """Enable event loop integration with PyQt4.
116 122
117 123 Parameters
118 124 ----------
119 125 app : bool
120 126 Create a running application object or not.
121 127
122 128 Notes
123 129 -----
124 130 This methods sets the PyOS_InputHook for wxPython, which allows
125 131 the PyQt4 to integrate with terminal based applications like
126 132 IPython.
127 133
128 134 Once this has been called, you can simply create a QApplication and
129 135 use it. But, *don't start the event loop*. That is handled
130 136 automatically by PyOS_InputHook.
131 137 """
132 138 from PyQt4 import QtCore
133 139 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
134 140 # was set when QtCore was imported, but if it ever got removed,
135 141 # you couldn't reset it. For earlier versions we can
136 142 # probably implement a ctypes version.
137 143 try:
138 144 QtCore.pyqtRestoreInputHook()
139 145 except AttributeError:
140 146 pass
141 147 self._current_gui = 'qt4'
142 148 if app:
143 149 from PyQt4 import QtGui
144 150 app = QtGui.QApplication(sys.argv)
145 151 return app
146 152
147 153 def disable_qt4(self):
148 154 """Disable event loop integration with PyQt4.
149 155
150 156 This merely sets PyOS_InputHook to NULL.
151 157 """
152 158 self.clear_inputhook()
153 159
154 160 def enable_gtk(self, app=False):
155 161 """Enable event loop integration with PyGTK.
156 162
157 163 Parameters
158 164 ----------
159 165 app : bool
160 166 Create a running application object or not.
161 167
162 168 Notes
163 169 -----
164 170 This methods sets the PyOS_InputHook for PyGTK, which allows
165 171 the PyGTK to integrate with terminal based applications like
166 172 IPython.
167 173
168 174 Once this has been called, you can simple create PyGTK objects and
169 175 use them. But, *don't start the event loop*. That is handled
170 176 automatically by PyOS_InputHook.
171 177 """
172 178 import gtk
173 179 try:
174 180 gtk.set_interactive(True)
175 181 self._current_gui = 'gtk'
176 182 except AttributeError:
177 183 # For older versions of gtk, use our own ctypes version
178 184 from IPython.lib.inputhookgtk import inputhook_gtk
179 add_inputhook(inputhook_gtk)
185 self.set_inputhook(inputhook_gtk)
186 self._current_gui = 'gtk'
180 187
181 188 def disable_gtk(self):
182 189 """Disable event loop integration with PyGTK.
183 190
184 191 This merely sets PyOS_InputHook to NULL.
185 192 """
186 193 self.clear_inputhook()
187 194
188 195 def enable_tk(self, app=False):
189 196 """Enable event loop integration with Tk.
190 197
191 198 Parameters
192 199 ----------
193 200 app : bool
194 201 Create a running application object or not.
195 202
196 203 Notes
197 204 -----
198 205 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
199 206 sets ``PyOS_InputHook``.
200 207 """
201 208 self._current_gui = 'tk'
202 209
203 210 def disable_tk(self):
204 211 """Disable event loop integration with Tkinter.
205 212
206 213 This merely sets PyOS_InputHook to NULL.
207 214 """
208 215 self.clear_inputhook()
209 216
210 217 def current_gui(self):
211 218 """Return a string indicating the currently active GUI or None."""
212 219 return self._current_gui
213 220
214 221 inputhook_manager = InputHookManager()
215 222
216 223 enable_wx = inputhook_manager.enable_wx
217 224 disable_wx = inputhook_manager.disable_wx
218 225 enable_qt4 = inputhook_manager.enable_qt4
219 226 disable_qt4 = inputhook_manager.disable_qt4
220 227 enable_gtk = inputhook_manager.enable_gtk
221 228 disable_gtk = inputhook_manager.disable_gtk
222 229 enable_tk = inputhook_manager.enable_tk
223 230 disable_tk = inputhook_manager.disable_tk
224 231 clear_inputhook = inputhook_manager.clear_inputhook
225 232 set_inputhook = inputhook_manager.set_inputhook
226 233 current_gui = inputhook_manager.current_gui No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now