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