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