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