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