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