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