##// END OF EJS Templates
inputhook: improve CTRL+C handling with qt4...
Christian Boos -
Show More
@@ -1,464 +1,483 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Inputhook management for GUI event loop integration.
3 Inputhook management for GUI event loop integration.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import ctypes
17 import ctypes
18 import os
18 import os
19 import sys
19 import sys
20 import warnings
20 import warnings
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Constants
23 # Constants
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 # Constants for identifying the GUI toolkits.
26 # Constants for identifying the GUI toolkits.
27 GUI_WX = 'wx'
27 GUI_WX = 'wx'
28 GUI_QT = 'qt'
28 GUI_QT = 'qt'
29 GUI_QT4 = 'qt4'
29 GUI_QT4 = 'qt4'
30 GUI_GTK = 'gtk'
30 GUI_GTK = 'gtk'
31 GUI_TK = 'tk'
31 GUI_TK = 'tk'
32 GUI_OSX = 'osx'
32 GUI_OSX = 'osx'
33 GUI_GLUT = 'glut'
33 GUI_GLUT = 'glut'
34 GUI_PYGLET = 'pyglet'
34 GUI_PYGLET = 'pyglet'
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Utilities
37 # Utilities
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 def stdin_ready():
40 def stdin_ready():
41 if os.name == 'posix':
41 if os.name == 'posix':
42 import select
42 import select
43 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
43 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
44 if infds:
44 if infds:
45 return True
45 return True
46 else:
46 else:
47 return False
47 return False
48 elif os.name == 'nt':
48 elif os.name == 'nt':
49 import msvcrt
49 import msvcrt
50 return msvcrt.kbhit()
50 return msvcrt.kbhit()
51 return True # assume there's something so that we won't wait forever
51 return True # assume there's something so that we won't wait forever
52
52
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Main InputHookManager class
55 # Main InputHookManager class
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58
58
59 class InputHookManager(object):
59 class InputHookManager(object):
60 """Manage PyOS_InputHook for different GUI toolkits.
60 """Manage PyOS_InputHook for different GUI toolkits.
61
61
62 This class installs various hooks under ``PyOSInputHook`` to handle
62 This class installs various hooks under ``PyOSInputHook`` to handle
63 GUI event loop integration.
63 GUI event loop integration.
64 """
64 """
65
65
66 def __init__(self):
66 def __init__(self):
67 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
67 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
68 self._apps = {}
68 self._apps = {}
69 self._reset()
69 self._reset()
70
70
71 def _reset(self):
71 def _reset(self):
72 self._callback_pyfunctype = None
72 self._callback_pyfunctype = None
73 self._callback = None
73 self._callback = None
74 self._installed = False
74 self._installed = False
75 self._current_gui = None
75 self._current_gui = None
76
76
77 def get_pyos_inputhook(self):
77 def get_pyos_inputhook(self):
78 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
78 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
79 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
79 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
80
80
81 def get_pyos_inputhook_as_func(self):
81 def get_pyos_inputhook_as_func(self):
82 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
82 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
83 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
83 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
84
84
85 def set_inputhook(self, callback):
85 def set_inputhook(self, callback):
86 """Set PyOS_InputHook to callback and return the previous one."""
86 """Set PyOS_InputHook to callback and return the previous one."""
87 self._callback = callback
87 self._callback = callback
88 self._callback_pyfunctype = self.PYFUNC(callback)
88 self._callback_pyfunctype = self.PYFUNC(callback)
89 pyos_inputhook_ptr = self.get_pyos_inputhook()
89 pyos_inputhook_ptr = self.get_pyos_inputhook()
90 original = self.get_pyos_inputhook_as_func()
90 original = self.get_pyos_inputhook_as_func()
91 pyos_inputhook_ptr.value = \
91 pyos_inputhook_ptr.value = \
92 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
92 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
93 self._installed = True
93 self._installed = True
94 return original
94 return original
95
95
96 def clear_inputhook(self, app=None):
96 def clear_inputhook(self, app=None):
97 """Set PyOS_InputHook to NULL and return the previous one.
97 """Set PyOS_InputHook to NULL and return the previous one.
98
98
99 Parameters
99 Parameters
100 ----------
100 ----------
101 app : optional, ignored
101 app : optional, ignored
102 This parameter is allowed only so that clear_inputhook() can be
102 This parameter is allowed only so that clear_inputhook() can be
103 called with a similar interface as all the ``enable_*`` methods. But
103 called with a similar interface as all the ``enable_*`` methods. But
104 the actual value of the parameter is ignored. This uniform interface
104 the actual value of the parameter is ignored. This uniform interface
105 makes it easier to have user-level entry points in the main IPython
105 makes it easier to have user-level entry points in the main IPython
106 app like :meth:`enable_gui`."""
106 app like :meth:`enable_gui`."""
107 pyos_inputhook_ptr = self.get_pyos_inputhook()
107 pyos_inputhook_ptr = self.get_pyos_inputhook()
108 original = self.get_pyos_inputhook_as_func()
108 original = self.get_pyos_inputhook_as_func()
109 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
109 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
110 self._reset()
110 self._reset()
111 return original
111 return original
112
112
113 def clear_app_refs(self, gui=None):
113 def clear_app_refs(self, gui=None):
114 """Clear IPython's internal reference to an application instance.
114 """Clear IPython's internal reference to an application instance.
115
115
116 Whenever we create an app for a user on qt4 or wx, we hold a
116 Whenever we create an app for a user on qt4 or wx, we hold a
117 reference to the app. This is needed because in some cases bad things
117 reference to the app. This is needed because in some cases bad things
118 can happen if a user doesn't hold a reference themselves. This
118 can happen if a user doesn't hold a reference themselves. This
119 method is provided to clear the references we are holding.
119 method is provided to clear the references we are holding.
120
120
121 Parameters
121 Parameters
122 ----------
122 ----------
123 gui : None or str
123 gui : None or str
124 If None, clear all app references. If ('wx', 'qt4') clear
124 If None, clear all app references. If ('wx', 'qt4') clear
125 the app for that toolkit. References are not held for gtk or tk
125 the app for that toolkit. References are not held for gtk or tk
126 as those toolkits don't have the notion of an app.
126 as those toolkits don't have the notion of an app.
127 """
127 """
128 if gui is None:
128 if gui is None:
129 self._apps = {}
129 self._apps = {}
130 elif self._apps.has_key(gui):
130 elif self._apps.has_key(gui):
131 del self._apps[gui]
131 del self._apps[gui]
132
132
133 def enable_wx(self, app=None):
133 def enable_wx(self, app=None):
134 """Enable event loop integration with wxPython.
134 """Enable event loop integration with wxPython.
135
135
136 Parameters
136 Parameters
137 ----------
137 ----------
138 app : WX Application, optional.
138 app : WX Application, optional.
139 Running application to use. If not given, we probe WX for an
139 Running application to use. If not given, we probe WX for an
140 existing application object, and create a new one if none is found.
140 existing application object, and create a new one if none is found.
141
141
142 Notes
142 Notes
143 -----
143 -----
144 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
144 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
145 the wxPython to integrate with terminal based applications like
145 the wxPython to integrate with terminal based applications like
146 IPython.
146 IPython.
147
147
148 If ``app`` is not given we probe for an existing one, and return it if
148 If ``app`` is not given we probe for an existing one, and return it if
149 found. If no existing app is found, we create an :class:`wx.App` as
149 found. If no existing app is found, we create an :class:`wx.App` as
150 follows::
150 follows::
151
151
152 import wx
152 import wx
153 app = wx.App(redirect=False, clearSigInt=False)
153 app = wx.App(redirect=False, clearSigInt=False)
154 """
154 """
155 from IPython.lib.inputhookwx import inputhook_wx
155 from IPython.lib.inputhookwx import inputhook_wx
156 self.set_inputhook(inputhook_wx)
156 self.set_inputhook(inputhook_wx)
157 self._current_gui = GUI_WX
157 self._current_gui = GUI_WX
158 import wx
158 import wx
159 if app is None:
159 if app is None:
160 app = wx.GetApp()
160 app = wx.GetApp()
161 if app is None:
161 if app is None:
162 app = wx.App(redirect=False, clearSigInt=False)
162 app = wx.App(redirect=False, clearSigInt=False)
163 app._in_event_loop = True
163 app._in_event_loop = True
164 self._apps[GUI_WX] = app
164 self._apps[GUI_WX] = app
165 return app
165 return app
166
166
167 def disable_wx(self):
167 def disable_wx(self):
168 """Disable event loop integration with wxPython.
168 """Disable event loop integration with wxPython.
169
169
170 This merely sets PyOS_InputHook to NULL.
170 This merely sets PyOS_InputHook to NULL.
171 """
171 """
172 if self._apps.has_key(GUI_WX):
172 if self._apps.has_key(GUI_WX):
173 self._apps[GUI_WX]._in_event_loop = False
173 self._apps[GUI_WX]._in_event_loop = False
174 self.clear_inputhook()
174 self.clear_inputhook()
175
175
176 def enable_qt4(self, app=None):
176 def enable_qt4(self, app=None):
177 """Enable event loop integration with PyQt4.
177 """Enable event loop integration with PyQt4.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 app : Qt Application, optional.
181 app : Qt Application, optional.
182 Running application to use. If not given, we probe Qt for an
182 Running application to use. If not given, we probe Qt for an
183 existing application object, and create a new one if none is found.
183 existing application object, and create a new one if none is found.
184
184
185 Notes
185 Notes
186 -----
186 -----
187 This methods sets the PyOS_InputHook for PyQt4, which allows
187 This methods sets the PyOS_InputHook for PyQt4, which allows
188 the PyQt4 to integrate with terminal based applications like
188 the PyQt4 to integrate with terminal based applications like
189 IPython.
189 IPython.
190
190
191 If ``app`` is not given we probe for an existing one, and return it if
191 If ``app`` is not given we probe for an existing one, and return it if
192 found. If no existing app is found, we create an :class:`QApplication`
192 found. If no existing app is found, we create an :class:`QApplication`
193 as follows::
193 as follows::
194
194
195 from PyQt4 import QtCore
195 from PyQt4 import QtCore
196 app = QtGui.QApplication(sys.argv)
196 app = QtGui.QApplication(sys.argv)
197 """
197 """
198 from IPython.external.qt_for_kernel import QtCore, QtGui
198 from IPython.external.qt_for_kernel import QtCore, QtGui
199 from IPython.core import ipapi
199
200
200 if app is None:
201 if app is None:
201 app = QtCore.QCoreApplication.instance()
202 app = QtCore.QCoreApplication.instance()
202 if app is None:
203 if app is None:
203 app = QtGui.QApplication([" "])
204 app = QtGui.QApplication([" "])
204
205
205 # Always use the following input hook instead of PyQt4's
206 # Always use a custom input hook instead of PyQt4's default
206 # default one, as it interacts better with readline packages
207 # one, as it interacts better with readline packages (issue
207 # (issue #481)
208 # #481).
209
210 # Note that we can't let KeyboardInterrupt escape from that
211 # hook, (no exception can't be raised from within a ctypes
212 # python callback). We need to make a compromise: a trapped
213 # KeyboardInterrupt will prevent the input hook to re-enter
214 # the exec loop, until we start over with a new prompt line.
215 # This means one needs a double CTRL+C to get back to the
216 # prompt.
217
218 got_kbdint = [False]
219
220 def preprompthook_qt4(self):
221 got_kbdint[0] = False
222 ipapi.get().set_hook('pre_prompt_hook', preprompthook_qt4)
208
223
209 def inputhook_qt4():
224 def inputhook_qt4():
210 try:
225 try:
226 if got_kbdint[0]:
227 return 0
211 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
228 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
212 if not stdin_ready():
229 if not stdin_ready():
213 timer = QtCore.QTimer()
230 timer = QtCore.QTimer()
214 timer.timeout.connect(app.quit)
231 timer.timeout.connect(app.quit)
215 while not stdin_ready():
232 while not stdin_ready():
216 timer.start(50)
233 timer.start(50)
217 app.exec_()
234 app.exec_()
218 timer.stop()
235 timer.stop()
219 except KeyboardInterrupt:
236 except KeyboardInterrupt:
220 pass
237 got_kbdint[0] = True
238 print("\n(event loop interrupted - "
239 "hit CTRL+C again to clear the prompt)")
221 return 0
240 return 0
222 self.set_inputhook(inputhook_qt4)
241 self.set_inputhook(inputhook_qt4)
223
242
224 self._current_gui = GUI_QT4
243 self._current_gui = GUI_QT4
225 app._in_event_loop = True
244 app._in_event_loop = True
226 self._apps[GUI_QT4] = app
245 self._apps[GUI_QT4] = app
227 return app
246 return app
228
247
229 def disable_qt4(self):
248 def disable_qt4(self):
230 """Disable event loop integration with PyQt4.
249 """Disable event loop integration with PyQt4.
231
250
232 This merely sets PyOS_InputHook to NULL.
251 This merely sets PyOS_InputHook to NULL.
233 """
252 """
234 if self._apps.has_key(GUI_QT4):
253 if self._apps.has_key(GUI_QT4):
235 self._apps[GUI_QT4]._in_event_loop = False
254 self._apps[GUI_QT4]._in_event_loop = False
236 self.clear_inputhook()
255 self.clear_inputhook()
237
256
238 def enable_gtk(self, app=None):
257 def enable_gtk(self, app=None):
239 """Enable event loop integration with PyGTK.
258 """Enable event loop integration with PyGTK.
240
259
241 Parameters
260 Parameters
242 ----------
261 ----------
243 app : ignored
262 app : ignored
244 Ignored, it's only a placeholder to keep the call signature of all
263 Ignored, it's only a placeholder to keep the call signature of all
245 gui activation methods consistent, which simplifies the logic of
264 gui activation methods consistent, which simplifies the logic of
246 supporting magics.
265 supporting magics.
247
266
248 Notes
267 Notes
249 -----
268 -----
250 This methods sets the PyOS_InputHook for PyGTK, which allows
269 This methods sets the PyOS_InputHook for PyGTK, which allows
251 the PyGTK to integrate with terminal based applications like
270 the PyGTK to integrate with terminal based applications like
252 IPython.
271 IPython.
253 """
272 """
254 import gtk
273 import gtk
255 try:
274 try:
256 gtk.set_interactive(True)
275 gtk.set_interactive(True)
257 self._current_gui = GUI_GTK
276 self._current_gui = GUI_GTK
258 except AttributeError:
277 except AttributeError:
259 # For older versions of gtk, use our own ctypes version
278 # For older versions of gtk, use our own ctypes version
260 from IPython.lib.inputhookgtk import inputhook_gtk
279 from IPython.lib.inputhookgtk import inputhook_gtk
261 self.set_inputhook(inputhook_gtk)
280 self.set_inputhook(inputhook_gtk)
262 self._current_gui = GUI_GTK
281 self._current_gui = GUI_GTK
263
282
264 def disable_gtk(self):
283 def disable_gtk(self):
265 """Disable event loop integration with PyGTK.
284 """Disable event loop integration with PyGTK.
266
285
267 This merely sets PyOS_InputHook to NULL.
286 This merely sets PyOS_InputHook to NULL.
268 """
287 """
269 self.clear_inputhook()
288 self.clear_inputhook()
270
289
271 def enable_tk(self, app=None):
290 def enable_tk(self, app=None):
272 """Enable event loop integration with Tk.
291 """Enable event loop integration with Tk.
273
292
274 Parameters
293 Parameters
275 ----------
294 ----------
276 app : toplevel :class:`Tkinter.Tk` widget, optional.
295 app : toplevel :class:`Tkinter.Tk` widget, optional.
277 Running toplevel widget to use. If not given, we probe Tk for an
296 Running toplevel widget to use. If not given, we probe Tk for an
278 existing one, and create a new one if none is found.
297 existing one, and create a new one if none is found.
279
298
280 Notes
299 Notes
281 -----
300 -----
282 If you have already created a :class:`Tkinter.Tk` object, the only
301 If you have already created a :class:`Tkinter.Tk` object, the only
283 thing done by this method is to register with the
302 thing done by this method is to register with the
284 :class:`InputHookManager`, since creating that object automatically
303 :class:`InputHookManager`, since creating that object automatically
285 sets ``PyOS_InputHook``.
304 sets ``PyOS_InputHook``.
286 """
305 """
287 self._current_gui = GUI_TK
306 self._current_gui = GUI_TK
288 if app is None:
307 if app is None:
289 import Tkinter
308 import Tkinter
290 app = Tkinter.Tk()
309 app = Tkinter.Tk()
291 app.withdraw()
310 app.withdraw()
292 self._apps[GUI_TK] = app
311 self._apps[GUI_TK] = app
293 return app
312 return app
294
313
295 def disable_tk(self):
314 def disable_tk(self):
296 """Disable event loop integration with Tkinter.
315 """Disable event loop integration with Tkinter.
297
316
298 This merely sets PyOS_InputHook to NULL.
317 This merely sets PyOS_InputHook to NULL.
299 """
318 """
300 self.clear_inputhook()
319 self.clear_inputhook()
301
320
302
321
303 def enable_glut(self, app=None):
322 def enable_glut(self, app=None):
304 """ Enable event loop integration with GLUT.
323 """ Enable event loop integration with GLUT.
305
324
306 Parameters
325 Parameters
307 ----------
326 ----------
308
327
309 app : ignored
328 app : ignored
310 Ignored, it's only a placeholder to keep the call signature of all
329 Ignored, it's only a placeholder to keep the call signature of all
311 gui activation methods consistent, which simplifies the logic of
330 gui activation methods consistent, which simplifies the logic of
312 supporting magics.
331 supporting magics.
313
332
314 Notes
333 Notes
315 -----
334 -----
316
335
317 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
336 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
318 integrate with terminal based applications like IPython. Due to GLUT
337 integrate with terminal based applications like IPython. Due to GLUT
319 limitations, it is currently not possible to start the event loop
338 limitations, it is currently not possible to start the event loop
320 without first creating a window. You should thus not create another
339 without first creating a window. You should thus not create another
321 window but use instead the created one. See 'gui-glut.py' in the
340 window but use instead the created one. See 'gui-glut.py' in the
322 docs/examples/lib directory.
341 docs/examples/lib directory.
323
342
324 The default screen mode is set to:
343 The default screen mode is set to:
325 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
344 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
326 """
345 """
327
346
328 import OpenGL.GLUT as glut
347 import OpenGL.GLUT as glut
329 from IPython.lib.inputhookglut import glut_display_mode, \
348 from IPython.lib.inputhookglut import glut_display_mode, \
330 glut_close, glut_display, \
349 glut_close, glut_display, \
331 glut_idle, inputhook_glut
350 glut_idle, inputhook_glut
332
351
333 if not self._apps.has_key( GUI_GLUT ):
352 if not self._apps.has_key( GUI_GLUT ):
334 glut.glutInit( sys.argv )
353 glut.glutInit( sys.argv )
335 glut.glutInitDisplayMode( glut_display_mode )
354 glut.glutInitDisplayMode( glut_display_mode )
336 # This is specific to freeglut
355 # This is specific to freeglut
337 if bool(glut.glutSetOption):
356 if bool(glut.glutSetOption):
338 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
357 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
339 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
358 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
340 glut.glutCreateWindow( sys.argv[0] )
359 glut.glutCreateWindow( sys.argv[0] )
341 glut.glutReshapeWindow( 1, 1 )
360 glut.glutReshapeWindow( 1, 1 )
342 glut.glutHideWindow( )
361 glut.glutHideWindow( )
343 glut.glutWMCloseFunc( glut_close )
362 glut.glutWMCloseFunc( glut_close )
344 glut.glutDisplayFunc( glut_display )
363 glut.glutDisplayFunc( glut_display )
345 glut.glutIdleFunc( glut_idle )
364 glut.glutIdleFunc( glut_idle )
346 else:
365 else:
347 glut.glutWMCloseFunc( glut_close )
366 glut.glutWMCloseFunc( glut_close )
348 glut.glutDisplayFunc( glut_display )
367 glut.glutDisplayFunc( glut_display )
349 glut.glutIdleFunc( glut_idle)
368 glut.glutIdleFunc( glut_idle)
350 self.set_inputhook( inputhook_glut )
369 self.set_inputhook( inputhook_glut )
351 self._current_gui = GUI_GLUT
370 self._current_gui = GUI_GLUT
352 self._apps[GUI_GLUT] = True
371 self._apps[GUI_GLUT] = True
353
372
354
373
355 def disable_glut(self):
374 def disable_glut(self):
356 """Disable event loop integration with glut.
375 """Disable event loop integration with glut.
357
376
358 This sets PyOS_InputHook to NULL and set the display function to a
377 This sets PyOS_InputHook to NULL and set the display function to a
359 dummy one and set the timer to a dummy timer that will be triggered
378 dummy one and set the timer to a dummy timer that will be triggered
360 very far in the future.
379 very far in the future.
361 """
380 """
362 import OpenGL.GLUT as glut
381 import OpenGL.GLUT as glut
363 from glut_support import glutMainLoopEvent
382 from glut_support import glutMainLoopEvent
364
383
365 glut.glutHideWindow() # This is an event to be processed below
384 glut.glutHideWindow() # This is an event to be processed below
366 glutMainLoopEvent()
385 glutMainLoopEvent()
367 self.clear_inputhook()
386 self.clear_inputhook()
368
387
369 def enable_pyglet(self, app=None):
388 def enable_pyglet(self, app=None):
370 """Enable event loop integration with pyglet.
389 """Enable event loop integration with pyglet.
371
390
372 Parameters
391 Parameters
373 ----------
392 ----------
374 app : ignored
393 app : ignored
375 Ignored, it's only a placeholder to keep the call signature of all
394 Ignored, it's only a placeholder to keep the call signature of all
376 gui activation methods consistent, which simplifies the logic of
395 gui activation methods consistent, which simplifies the logic of
377 supporting magics.
396 supporting magics.
378
397
379 Notes
398 Notes
380 -----
399 -----
381 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
400 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
382 pyglet to integrate with terminal based applications like
401 pyglet to integrate with terminal based applications like
383 IPython.
402 IPython.
384
403
385 """
404 """
386 import pyglet
405 import pyglet
387 from IPython.lib.inputhookpyglet import inputhook_pyglet
406 from IPython.lib.inputhookpyglet import inputhook_pyglet
388 self.set_inputhook(inputhook_pyglet)
407 self.set_inputhook(inputhook_pyglet)
389 self._current_gui = GUI_PYGLET
408 self._current_gui = GUI_PYGLET
390 return app
409 return app
391
410
392 def disable_pyglet(self):
411 def disable_pyglet(self):
393 """Disable event loop integration with pyglet.
412 """Disable event loop integration with pyglet.
394
413
395 This merely sets PyOS_InputHook to NULL.
414 This merely sets PyOS_InputHook to NULL.
396 """
415 """
397 self.clear_inputhook()
416 self.clear_inputhook()
398
417
399 def current_gui(self):
418 def current_gui(self):
400 """Return a string indicating the currently active GUI or None."""
419 """Return a string indicating the currently active GUI or None."""
401 return self._current_gui
420 return self._current_gui
402
421
403 inputhook_manager = InputHookManager()
422 inputhook_manager = InputHookManager()
404
423
405 enable_wx = inputhook_manager.enable_wx
424 enable_wx = inputhook_manager.enable_wx
406 disable_wx = inputhook_manager.disable_wx
425 disable_wx = inputhook_manager.disable_wx
407 enable_qt4 = inputhook_manager.enable_qt4
426 enable_qt4 = inputhook_manager.enable_qt4
408 disable_qt4 = inputhook_manager.disable_qt4
427 disable_qt4 = inputhook_manager.disable_qt4
409 enable_gtk = inputhook_manager.enable_gtk
428 enable_gtk = inputhook_manager.enable_gtk
410 disable_gtk = inputhook_manager.disable_gtk
429 disable_gtk = inputhook_manager.disable_gtk
411 enable_tk = inputhook_manager.enable_tk
430 enable_tk = inputhook_manager.enable_tk
412 disable_tk = inputhook_manager.disable_tk
431 disable_tk = inputhook_manager.disable_tk
413 enable_glut = inputhook_manager.enable_glut
432 enable_glut = inputhook_manager.enable_glut
414 disable_glut = inputhook_manager.disable_glut
433 disable_glut = inputhook_manager.disable_glut
415 enable_pyglet = inputhook_manager.enable_pyglet
434 enable_pyglet = inputhook_manager.enable_pyglet
416 disable_pyglet = inputhook_manager.disable_pyglet
435 disable_pyglet = inputhook_manager.disable_pyglet
417 clear_inputhook = inputhook_manager.clear_inputhook
436 clear_inputhook = inputhook_manager.clear_inputhook
418 set_inputhook = inputhook_manager.set_inputhook
437 set_inputhook = inputhook_manager.set_inputhook
419 current_gui = inputhook_manager.current_gui
438 current_gui = inputhook_manager.current_gui
420 clear_app_refs = inputhook_manager.clear_app_refs
439 clear_app_refs = inputhook_manager.clear_app_refs
421
440
422
441
423 # Convenience function to switch amongst them
442 # Convenience function to switch amongst them
424 def enable_gui(gui=None, app=None):
443 def enable_gui(gui=None, app=None):
425 """Switch amongst GUI input hooks by name.
444 """Switch amongst GUI input hooks by name.
426
445
427 This is just a utility wrapper around the methods of the InputHookManager
446 This is just a utility wrapper around the methods of the InputHookManager
428 object.
447 object.
429
448
430 Parameters
449 Parameters
431 ----------
450 ----------
432 gui : optional, string or None
451 gui : optional, string or None
433 If None, clears input hook, otherwise it must be one of the recognized
452 If None, clears input hook, otherwise it must be one of the recognized
434 GUI names (see ``GUI_*`` constants in module).
453 GUI names (see ``GUI_*`` constants in module).
435
454
436 app : optional, existing application object.
455 app : optional, existing application object.
437 For toolkits that have the concept of a global app, you can supply an
456 For toolkits that have the concept of a global app, you can supply an
438 existing one. If not given, the toolkit will be probed for one, and if
457 existing one. If not given, the toolkit will be probed for one, and if
439 none is found, a new one will be created. Note that GTK does not have
458 none is found, a new one will be created. Note that GTK does not have
440 this concept, and passing an app if `gui`=="GTK" will raise an error.
459 this concept, and passing an app if `gui`=="GTK" will raise an error.
441
460
442 Returns
461 Returns
443 -------
462 -------
444 The output of the underlying gui switch routine, typically the actual
463 The output of the underlying gui switch routine, typically the actual
445 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
464 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
446 one.
465 one.
447 """
466 """
448 guis = {None: clear_inputhook,
467 guis = {None: clear_inputhook,
449 GUI_OSX: lambda app=False: None,
468 GUI_OSX: lambda app=False: None,
450 GUI_TK: enable_tk,
469 GUI_TK: enable_tk,
451 GUI_GTK: enable_gtk,
470 GUI_GTK: enable_gtk,
452 GUI_WX: enable_wx,
471 GUI_WX: enable_wx,
453 GUI_QT: enable_qt4, # qt3 not supported
472 GUI_QT: enable_qt4, # qt3 not supported
454 GUI_QT4: enable_qt4,
473 GUI_QT4: enable_qt4,
455 GUI_GLUT: enable_glut,
474 GUI_GLUT: enable_glut,
456 GUI_PYGLET: enable_pyglet,
475 GUI_PYGLET: enable_pyglet,
457 }
476 }
458 try:
477 try:
459 gui_hook = guis[gui]
478 gui_hook = guis[gui]
460 except KeyError:
479 except KeyError:
461 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
480 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
462 raise ValueError(e)
481 raise ValueError(e)
463 return gui_hook(app)
482 return gui_hook(app)
464
483
General Comments 0
You need to be logged in to leave comments. Login now