##// END OF EJS Templates
inputhook: make PyQt4 plays nicer with pyreadline...
Christian Boos -
Show More
@@ -1,464 +1,464 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
199
200 if 'pyreadline' in sys.modules:
201 # see IPython GitHub Issue #281 for more info on this issue
202 # Similar intermittent behavior has been reported on OSX,
203 # but not consistently reproducible
204 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
205 in interactive input. If you do see this issue, we recommend using another GUI
206 toolkit if you can, or disable readline with the configuration option
207 'TerminalInteractiveShell.readline_use=False', specified in a config file or
208 at the command-line""",
209 RuntimeWarning)
210
211 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
212 # was set when QtCore was imported, but if it ever got removed,
213 # you couldn't reset it. For earlier versions we can
214 # probably implement a ctypes version.
215 try:
216 QtCore.pyqtRestoreInputHook()
217 except AttributeError:
218 pass
219
220 self._current_gui = GUI_QT4
221 if app is None:
200 if app is None:
222 app = QtCore.QCoreApplication.instance()
201 app = QtCore.QCoreApplication.instance()
223 if app is None:
202 if app is None:
224 app = QtGui.QApplication([" "])
203 app = QtGui.QApplication([" "])
204
205 # Always use the following input hook instead of PyQt4's
206 # default one, as it interacts better with readline packages
207 # (issue #481)
208
209 def inputhook_qt4():
210 try:
211 app.processEvents(QtCore.QEventLoop.AllEvents, 300)
212 if not stdin_ready():
213 timer = QtCore.QTimer()
214 timer.timeout.connect(app.quit)
215 while not stdin_ready():
216 timer.start(50)
217 app.exec_()
218 timer.stop()
219 except KeyboardInterrupt:
220 pass
221 return 0
222 self.set_inputhook(inputhook_qt4)
223
224 self._current_gui = GUI_QT4
225 app._in_event_loop = True
225 app._in_event_loop = True
226 self._apps[GUI_QT4] = app
226 self._apps[GUI_QT4] = app
227 return app
227 return app
228
228
229 def disable_qt4(self):
229 def disable_qt4(self):
230 """Disable event loop integration with PyQt4.
230 """Disable event loop integration with PyQt4.
231
231
232 This merely sets PyOS_InputHook to NULL.
232 This merely sets PyOS_InputHook to NULL.
233 """
233 """
234 if self._apps.has_key(GUI_QT4):
234 if self._apps.has_key(GUI_QT4):
235 self._apps[GUI_QT4]._in_event_loop = False
235 self._apps[GUI_QT4]._in_event_loop = False
236 self.clear_inputhook()
236 self.clear_inputhook()
237
237
238 def enable_gtk(self, app=None):
238 def enable_gtk(self, app=None):
239 """Enable event loop integration with PyGTK.
239 """Enable event loop integration with PyGTK.
240
240
241 Parameters
241 Parameters
242 ----------
242 ----------
243 app : ignored
243 app : ignored
244 Ignored, it's only a placeholder to keep the call signature of all
244 Ignored, it's only a placeholder to keep the call signature of all
245 gui activation methods consistent, which simplifies the logic of
245 gui activation methods consistent, which simplifies the logic of
246 supporting magics.
246 supporting magics.
247
247
248 Notes
248 Notes
249 -----
249 -----
250 This methods sets the PyOS_InputHook for PyGTK, which allows
250 This methods sets the PyOS_InputHook for PyGTK, which allows
251 the PyGTK to integrate with terminal based applications like
251 the PyGTK to integrate with terminal based applications like
252 IPython.
252 IPython.
253 """
253 """
254 import gtk
254 import gtk
255 try:
255 try:
256 gtk.set_interactive(True)
256 gtk.set_interactive(True)
257 self._current_gui = GUI_GTK
257 self._current_gui = GUI_GTK
258 except AttributeError:
258 except AttributeError:
259 # For older versions of gtk, use our own ctypes version
259 # For older versions of gtk, use our own ctypes version
260 from IPython.lib.inputhookgtk import inputhook_gtk
260 from IPython.lib.inputhookgtk import inputhook_gtk
261 self.set_inputhook(inputhook_gtk)
261 self.set_inputhook(inputhook_gtk)
262 self._current_gui = GUI_GTK
262 self._current_gui = GUI_GTK
263
263
264 def disable_gtk(self):
264 def disable_gtk(self):
265 """Disable event loop integration with PyGTK.
265 """Disable event loop integration with PyGTK.
266
266
267 This merely sets PyOS_InputHook to NULL.
267 This merely sets PyOS_InputHook to NULL.
268 """
268 """
269 self.clear_inputhook()
269 self.clear_inputhook()
270
270
271 def enable_tk(self, app=None):
271 def enable_tk(self, app=None):
272 """Enable event loop integration with Tk.
272 """Enable event loop integration with Tk.
273
273
274 Parameters
274 Parameters
275 ----------
275 ----------
276 app : toplevel :class:`Tkinter.Tk` widget, optional.
276 app : toplevel :class:`Tkinter.Tk` widget, optional.
277 Running toplevel widget to use. If not given, we probe Tk for an
277 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.
278 existing one, and create a new one if none is found.
279
279
280 Notes
280 Notes
281 -----
281 -----
282 If you have already created a :class:`Tkinter.Tk` object, the only
282 If you have already created a :class:`Tkinter.Tk` object, the only
283 thing done by this method is to register with the
283 thing done by this method is to register with the
284 :class:`InputHookManager`, since creating that object automatically
284 :class:`InputHookManager`, since creating that object automatically
285 sets ``PyOS_InputHook``.
285 sets ``PyOS_InputHook``.
286 """
286 """
287 self._current_gui = GUI_TK
287 self._current_gui = GUI_TK
288 if app is None:
288 if app is None:
289 import Tkinter
289 import Tkinter
290 app = Tkinter.Tk()
290 app = Tkinter.Tk()
291 app.withdraw()
291 app.withdraw()
292 self._apps[GUI_TK] = app
292 self._apps[GUI_TK] = app
293 return app
293 return app
294
294
295 def disable_tk(self):
295 def disable_tk(self):
296 """Disable event loop integration with Tkinter.
296 """Disable event loop integration with Tkinter.
297
297
298 This merely sets PyOS_InputHook to NULL.
298 This merely sets PyOS_InputHook to NULL.
299 """
299 """
300 self.clear_inputhook()
300 self.clear_inputhook()
301
301
302
302
303 def enable_glut(self, app=None):
303 def enable_glut(self, app=None):
304 """ Enable event loop integration with GLUT.
304 """ Enable event loop integration with GLUT.
305
305
306 Parameters
306 Parameters
307 ----------
307 ----------
308
308
309 app : ignored
309 app : ignored
310 Ignored, it's only a placeholder to keep the call signature of all
310 Ignored, it's only a placeholder to keep the call signature of all
311 gui activation methods consistent, which simplifies the logic of
311 gui activation methods consistent, which simplifies the logic of
312 supporting magics.
312 supporting magics.
313
313
314 Notes
314 Notes
315 -----
315 -----
316
316
317 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
317 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
318 integrate with terminal based applications like IPython. Due to GLUT
318 integrate with terminal based applications like IPython. Due to GLUT
319 limitations, it is currently not possible to start the event loop
319 limitations, it is currently not possible to start the event loop
320 without first creating a window. You should thus not create another
320 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
321 window but use instead the created one. See 'gui-glut.py' in the
322 docs/examples/lib directory.
322 docs/examples/lib directory.
323
323
324 The default screen mode is set to:
324 The default screen mode is set to:
325 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
325 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
326 """
326 """
327
327
328 import OpenGL.GLUT as glut
328 import OpenGL.GLUT as glut
329 from IPython.lib.inputhookglut import glut_display_mode, \
329 from IPython.lib.inputhookglut import glut_display_mode, \
330 glut_close, glut_display, \
330 glut_close, glut_display, \
331 glut_idle, inputhook_glut
331 glut_idle, inputhook_glut
332
332
333 if not self._apps.has_key( GUI_GLUT ):
333 if not self._apps.has_key( GUI_GLUT ):
334 glut.glutInit( sys.argv )
334 glut.glutInit( sys.argv )
335 glut.glutInitDisplayMode( glut_display_mode )
335 glut.glutInitDisplayMode( glut_display_mode )
336 # This is specific to freeglut
336 # This is specific to freeglut
337 if bool(glut.glutSetOption):
337 if bool(glut.glutSetOption):
338 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
338 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
339 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
339 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
340 glut.glutCreateWindow( sys.argv[0] )
340 glut.glutCreateWindow( sys.argv[0] )
341 glut.glutReshapeWindow( 1, 1 )
341 glut.glutReshapeWindow( 1, 1 )
342 glut.glutHideWindow( )
342 glut.glutHideWindow( )
343 glut.glutWMCloseFunc( glut_close )
343 glut.glutWMCloseFunc( glut_close )
344 glut.glutDisplayFunc( glut_display )
344 glut.glutDisplayFunc( glut_display )
345 glut.glutIdleFunc( glut_idle )
345 glut.glutIdleFunc( glut_idle )
346 else:
346 else:
347 glut.glutWMCloseFunc( glut_close )
347 glut.glutWMCloseFunc( glut_close )
348 glut.glutDisplayFunc( glut_display )
348 glut.glutDisplayFunc( glut_display )
349 glut.glutIdleFunc( glut_idle)
349 glut.glutIdleFunc( glut_idle)
350 self.set_inputhook( inputhook_glut )
350 self.set_inputhook( inputhook_glut )
351 self._current_gui = GUI_GLUT
351 self._current_gui = GUI_GLUT
352 self._apps[GUI_GLUT] = True
352 self._apps[GUI_GLUT] = True
353
353
354
354
355 def disable_glut(self):
355 def disable_glut(self):
356 """Disable event loop integration with glut.
356 """Disable event loop integration with glut.
357
357
358 This sets PyOS_InputHook to NULL and set the display function to a
358 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
359 dummy one and set the timer to a dummy timer that will be triggered
360 very far in the future.
360 very far in the future.
361 """
361 """
362 import OpenGL.GLUT as glut
362 import OpenGL.GLUT as glut
363 from glut_support import glutMainLoopEvent
363 from glut_support import glutMainLoopEvent
364
364
365 glut.glutHideWindow() # This is an event to be processed below
365 glut.glutHideWindow() # This is an event to be processed below
366 glutMainLoopEvent()
366 glutMainLoopEvent()
367 self.clear_inputhook()
367 self.clear_inputhook()
368
368
369 def enable_pyglet(self, app=None):
369 def enable_pyglet(self, app=None):
370 """Enable event loop integration with pyglet.
370 """Enable event loop integration with pyglet.
371
371
372 Parameters
372 Parameters
373 ----------
373 ----------
374 app : ignored
374 app : ignored
375 Ignored, it's only a placeholder to keep the call signature of all
375 Ignored, it's only a placeholder to keep the call signature of all
376 gui activation methods consistent, which simplifies the logic of
376 gui activation methods consistent, which simplifies the logic of
377 supporting magics.
377 supporting magics.
378
378
379 Notes
379 Notes
380 -----
380 -----
381 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
381 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
382 pyglet to integrate with terminal based applications like
382 pyglet to integrate with terminal based applications like
383 IPython.
383 IPython.
384
384
385 """
385 """
386 import pyglet
386 import pyglet
387 from IPython.lib.inputhookpyglet import inputhook_pyglet
387 from IPython.lib.inputhookpyglet import inputhook_pyglet
388 self.set_inputhook(inputhook_pyglet)
388 self.set_inputhook(inputhook_pyglet)
389 self._current_gui = GUI_PYGLET
389 self._current_gui = GUI_PYGLET
390 return app
390 return app
391
391
392 def disable_pyglet(self):
392 def disable_pyglet(self):
393 """Disable event loop integration with pyglet.
393 """Disable event loop integration with pyglet.
394
394
395 This merely sets PyOS_InputHook to NULL.
395 This merely sets PyOS_InputHook to NULL.
396 """
396 """
397 self.clear_inputhook()
397 self.clear_inputhook()
398
398
399 def current_gui(self):
399 def current_gui(self):
400 """Return a string indicating the currently active GUI or None."""
400 """Return a string indicating the currently active GUI or None."""
401 return self._current_gui
401 return self._current_gui
402
402
403 inputhook_manager = InputHookManager()
403 inputhook_manager = InputHookManager()
404
404
405 enable_wx = inputhook_manager.enable_wx
405 enable_wx = inputhook_manager.enable_wx
406 disable_wx = inputhook_manager.disable_wx
406 disable_wx = inputhook_manager.disable_wx
407 enable_qt4 = inputhook_manager.enable_qt4
407 enable_qt4 = inputhook_manager.enable_qt4
408 disable_qt4 = inputhook_manager.disable_qt4
408 disable_qt4 = inputhook_manager.disable_qt4
409 enable_gtk = inputhook_manager.enable_gtk
409 enable_gtk = inputhook_manager.enable_gtk
410 disable_gtk = inputhook_manager.disable_gtk
410 disable_gtk = inputhook_manager.disable_gtk
411 enable_tk = inputhook_manager.enable_tk
411 enable_tk = inputhook_manager.enable_tk
412 disable_tk = inputhook_manager.disable_tk
412 disable_tk = inputhook_manager.disable_tk
413 enable_glut = inputhook_manager.enable_glut
413 enable_glut = inputhook_manager.enable_glut
414 disable_glut = inputhook_manager.disable_glut
414 disable_glut = inputhook_manager.disable_glut
415 enable_pyglet = inputhook_manager.enable_pyglet
415 enable_pyglet = inputhook_manager.enable_pyglet
416 disable_pyglet = inputhook_manager.disable_pyglet
416 disable_pyglet = inputhook_manager.disable_pyglet
417 clear_inputhook = inputhook_manager.clear_inputhook
417 clear_inputhook = inputhook_manager.clear_inputhook
418 set_inputhook = inputhook_manager.set_inputhook
418 set_inputhook = inputhook_manager.set_inputhook
419 current_gui = inputhook_manager.current_gui
419 current_gui = inputhook_manager.current_gui
420 clear_app_refs = inputhook_manager.clear_app_refs
420 clear_app_refs = inputhook_manager.clear_app_refs
421
421
422
422
423 # Convenience function to switch amongst them
423 # Convenience function to switch amongst them
424 def enable_gui(gui=None, app=None):
424 def enable_gui(gui=None, app=None):
425 """Switch amongst GUI input hooks by name.
425 """Switch amongst GUI input hooks by name.
426
426
427 This is just a utility wrapper around the methods of the InputHookManager
427 This is just a utility wrapper around the methods of the InputHookManager
428 object.
428 object.
429
429
430 Parameters
430 Parameters
431 ----------
431 ----------
432 gui : optional, string or None
432 gui : optional, string or None
433 If None, clears input hook, otherwise it must be one of the recognized
433 If None, clears input hook, otherwise it must be one of the recognized
434 GUI names (see ``GUI_*`` constants in module).
434 GUI names (see ``GUI_*`` constants in module).
435
435
436 app : optional, existing application object.
436 app : optional, existing application object.
437 For toolkits that have the concept of a global app, you can supply an
437 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
438 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
439 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.
440 this concept, and passing an app if `gui`=="GTK" will raise an error.
441
441
442 Returns
442 Returns
443 -------
443 -------
444 The output of the underlying gui switch routine, typically the actual
444 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
445 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
446 one.
446 one.
447 """
447 """
448 guis = {None: clear_inputhook,
448 guis = {None: clear_inputhook,
449 GUI_OSX: lambda app=False: None,
449 GUI_OSX: lambda app=False: None,
450 GUI_TK: enable_tk,
450 GUI_TK: enable_tk,
451 GUI_GTK: enable_gtk,
451 GUI_GTK: enable_gtk,
452 GUI_WX: enable_wx,
452 GUI_WX: enable_wx,
453 GUI_QT: enable_qt4, # qt3 not supported
453 GUI_QT: enable_qt4, # qt3 not supported
454 GUI_QT4: enable_qt4,
454 GUI_QT4: enable_qt4,
455 GUI_GLUT: enable_glut,
455 GUI_GLUT: enable_glut,
456 GUI_PYGLET: enable_pyglet,
456 GUI_PYGLET: enable_pyglet,
457 }
457 }
458 try:
458 try:
459 gui_hook = guis[gui]
459 gui_hook = guis[gui]
460 except KeyError:
460 except KeyError:
461 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
461 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
462 raise ValueError(e)
462 raise ValueError(e)
463 return gui_hook(app)
463 return gui_hook(app)
464
464
General Comments 0
You need to be logged in to leave comments. Login now