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