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