##// END OF EJS Templates
Small fix to docstring and qt example.
Fernando Perez -
Show More
@@ -1,147 +1,149 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # coding: utf-8
2 # coding: utf-8
3 """
3 """
4 Support for creating GUI apps and starting event loops.
4 Support for creating GUI apps and starting event loops.
5
5
6 IPython's GUI integration allows interative plotting and GUI usage in IPython
6 IPython's GUI integration allows interative plotting and GUI usage in IPython
7 session. IPython has two different types of GUI integration:
7 session. IPython has two different types of GUI integration:
8
8
9 1. The terminal based IPython supports GUI event loops through Python's
9 1. The terminal based IPython supports GUI event loops through Python's
10 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
10 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
11 whenever raw_input is waiting for a user to type code. We implement GUI
11 whenever raw_input is waiting for a user to type code. We implement GUI
12 support in the terminal by setting PyOS_InputHook to a function that
12 support in the terminal by setting PyOS_InputHook to a function that
13 iterates the event loop for a short while. It is important to note that
13 iterates the event loop for a short while. It is important to note that
14 in this situation, the real GUI event loop is NOT run in the normal
14 in this situation, the real GUI event loop is NOT run in the normal
15 manner, so you can't use the normal means to detect that it is running.
15 manner, so you can't use the normal means to detect that it is running.
16 2. In the two process IPython kernel/frontend, the GUI event loop is run in
16 2. In the two process IPython kernel/frontend, the GUI event loop is run in
17 the kernel. In this case, the event loop is run in the normal manner by
17 the kernel. In this case, the event loop is run in the normal manner by
18 calling the function or method of the GUI toolkit that starts the event
18 calling the function or method of the GUI toolkit that starts the event
19 loop.
19 loop.
20
20
21 In addition to starting the GUI event loops in one of these two ways, IPython
21 In addition to starting the GUI event loops in one of these two ways, IPython
22 will *always* create an appropriate GUI application object when GUi
22 will *always* create an appropriate GUI application object when GUi
23 integration is enabled.
23 integration is enabled.
24
24
25 If you want your GUI apps to run in IPython you need to do two things:
25 If you want your GUI apps to run in IPython you need to do two things:
26
26
27 1. Test to see if there is already an existing main application object. If
27 1. Test to see if there is already an existing main application object. If
28 there is, you should use it. If there is not an existing application object
28 there is, you should use it. If there is not an existing application object
29 you should create one.
29 you should create one.
30 2. Test to see if the GUI event loop is running. If it is, you should not
30 2. Test to see if the GUI event loop is running. If it is, you should not
31 start it. If the event loop is not running you may start it.
31 start it. If the event loop is not running you may start it.
32
32
33 This module contains functions for each toolkit that perform these things
33 This module contains functions for each toolkit that perform these things
34 in a consistent manner. Because of how PyOS_InputHook runs the event loop
34 in a consistent manner. Because of how PyOS_InputHook runs the event loop
35 you cannot detect if the event loop is running using the traditional calls
35 you cannot detect if the event loop is running using the traditional calls
36 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
36 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
37 set These methods will return a false negative. That is, they will say the
37 set These methods will return a false negative. That is, they will say the
38 event loop is not running, when is actually is. To work around this limitation
38 event loop is not running, when is actually is. To work around this limitation
39 we proposed the following informal protocol:
39 we proposed the following informal protocol:
40
40
41 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
41 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
42 attribute of the main application object to ``True``. This should be done
42 attribute of the main application object to ``True``. This should be done
43 regardless of how the event loop is actually run.
43 regardless of how the event loop is actually run.
44 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
44 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
45 attribute of the main application object to ``False``.
45 attribute of the main application object to ``False``.
46 * If you want to see if the event loop is running, you *must* use ``hasattr``
46 * If you want to see if the event loop is running, you *must* use ``hasattr``
47 to see if ``_in_event_loop`` attribute has been set. If it is set, you
47 to see if ``_in_event_loop`` attribute has been set. If it is set, you
48 *must* use its value. If it has not been set, you can query the toolkit
48 *must* use its value. If it has not been set, you can query the toolkit
49 in the normal manner.
49 in the normal manner.
50 * If you want GUI support and no one else has created an application or
50 * If you want GUI support and no one else has created an application or
51 started the event loop you *must* do this. We don't want projects to
51 started the event loop you *must* do this. We don't want projects to
52 attempt to defer these things to someone else if they themselves need it.
52 attempt to defer these things to someone else if they themselves need it.
53
53
54 The functions below implement this logic for each GUI toolkit. If you need
54 The functions below implement this logic for each GUI toolkit. If you need
55 to create custom application subclasses, you will likely have to modify this
55 to create custom application subclasses, you will likely have to modify this
56 code for your own purposes. This code can be copied into your own project
56 code for your own purposes. This code can be copied into your own project
57 so you don't have to depend on IPython.
57 so you don't have to depend on IPython.
58
58
59 """
59 """
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Copyright (C) 2008-2010 The IPython Development Team
62 # Copyright (C) 2008-2010 The IPython Development Team
63 #
63 #
64 # Distributed under the terms of the BSD License. The full license is in
64 # Distributed under the terms of the BSD License. The full license is in
65 # the file COPYING, distributed as part of this software.
65 # the file COPYING, distributed as part of this software.
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67
67
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69 # Imports
69 # Imports
70 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
71
71
72 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
73 # wx
73 # wx
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75
75
76 def get_app_wx(*args, **kwargs):
76 def get_app_wx(*args, **kwargs):
77 """Create a new wx app or return an exiting one."""
77 """Create a new wx app or return an exiting one."""
78 import wx
78 import wx
79 app = wx.GetApp()
79 app = wx.GetApp()
80 if app is None:
80 if app is None:
81 if not kwargs.has_key('redirect'):
81 if not kwargs.has_key('redirect'):
82 kwargs['redirect'] = False
82 kwargs['redirect'] = False
83 app = wx.PySimpleApp(*args, **kwargs)
83 app = wx.PySimpleApp(*args, **kwargs)
84 return app
84 return app
85
85
86 def is_event_loop_running_wx(app=None):
86 def is_event_loop_running_wx(app=None):
87 """Is the wx event loop running."""
87 """Is the wx event loop running."""
88 if app is None:
88 if app is None:
89 app = get_app_wx()
89 app = get_app_wx()
90 if hasattr(app, '_in_event_loop'):
90 if hasattr(app, '_in_event_loop'):
91 return app._in_event_loop
91 return app._in_event_loop
92 else:
92 else:
93 return app.IsMainLoopRunning()
93 return app.IsMainLoopRunning()
94
94
95 def start_event_loop_wx(app=None):
95 def start_event_loop_wx(app=None):
96 """Start the wx event loop in a consistent manner."""
96 """Start the wx event loop in a consistent manner."""
97 if app is None:
97 if app is None:
98 app = get_app_wx()
98 app = get_app_wx()
99 if not is_event_loop_running_wx(app):
99 if not is_event_loop_running_wx(app):
100 app._in_event_loop = True
100 app._in_event_loop = True
101 app.MainLoop()
101 app.MainLoop()
102 app._in_event_loop = False
102 app._in_event_loop = False
103 else:
103 else:
104 app._in_event_loop = True
104 app._in_event_loop = True
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # qt4
107 # qt4
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 def get_app_qt4(*args, **kwargs):
110 def get_app_qt4(*args, **kwargs):
111 """Create a new qt4 app or return an existing one."""
111 """Create a new qt4 app or return an existing one."""
112 from IPython.external.qt_for_kernel import QtGui
112 from IPython.external.qt_for_kernel import QtGui
113 app = QtGui.QApplication.instance()
113 app = QtGui.QApplication.instance()
114 if app is None:
114 if app is None:
115 if not args:
115 if not args:
116 args = ([''],)
116 args = ([''],)
117 app = QtGui.QApplication(*args, **kwargs)
117 app = QtGui.QApplication(*args, **kwargs)
118 return app
118 return app
119
119
120 def is_event_loop_running_qt4(app=None):
120 def is_event_loop_running_qt4(app=None):
121 """Is the qt4 event loop running."""
121 """Is the qt4 event loop running."""
122 if app is None:
122 if app is None:
123 app = get_app_qt4([''])
123 app = get_app_qt4([''])
124 if hasattr(app, '_in_event_loop'):
124 if hasattr(app, '_in_event_loop'):
125 return app._in_event_loop
125 return app._in_event_loop
126 else:
126 else:
127 # Does qt4 provide a other way to detect this?
127 # Does qt4 provide a other way to detect this?
128 return False
128 return False
129
129
130 def start_event_loop_qt4(app=None):
130 def start_event_loop_qt4(app=None):
131 """Start the qt4 event loop in a consistent manner."""
131 """Start the qt4 event loop in a consistent manner."""
132 if app is None:
132 if app is None:
133 app = get_app_qt4([''])
133 app = get_app_qt4([''])
134 if not is_event_loop_running_qt4(app):
134 if not is_event_loop_running_qt4(app):
135 from .inputhook import enable_qt4
136 #enable_qt4(app)
135 app._in_event_loop = True
137 app._in_event_loop = True
136 app.exec_()
138 app.exec_()
137 app._in_event_loop = False
139 app._in_event_loop = False
138 else:
140 else:
139 app._in_event_loop = True
141 app._in_event_loop = True
140
142
141 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
142 # Tk
144 # Tk
143 #-----------------------------------------------------------------------------
145 #-----------------------------------------------------------------------------
144
146
145 #-----------------------------------------------------------------------------
147 #-----------------------------------------------------------------------------
146 # gtk
148 # gtk
147 #-----------------------------------------------------------------------------
149 #-----------------------------------------------------------------------------
@@ -1,345 +1,345 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # coding: utf-8
2 # coding: utf-8
3 """
3 """
4 Inputhook management for GUI event loop integration.
4 Inputhook management for GUI event loop integration.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import ctypes
18 import ctypes
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
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Utility classes
35 # Utility classes
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Main InputHookManager class
40 # Main InputHookManager class
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 class InputHookManager(object):
44 class InputHookManager(object):
45 """Manage PyOS_InputHook for different GUI toolkits.
45 """Manage PyOS_InputHook for different GUI toolkits.
46
46
47 This class installs various hooks under ``PyOSInputHook`` to handle
47 This class installs various hooks under ``PyOSInputHook`` to handle
48 GUI event loop integration.
48 GUI event loop integration.
49 """
49 """
50
50
51 def __init__(self):
51 def __init__(self):
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
53 self._apps = {}
53 self._apps = {}
54 self._reset()
54 self._reset()
55
55
56 def _reset(self):
56 def _reset(self):
57 self._callback_pyfunctype = None
57 self._callback_pyfunctype = None
58 self._callback = None
58 self._callback = None
59 self._installed = False
59 self._installed = False
60 self._current_gui = None
60 self._current_gui = None
61
61
62 def get_pyos_inputhook(self):
62 def get_pyos_inputhook(self):
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
65
65
66 def get_pyos_inputhook_as_func(self):
66 def get_pyos_inputhook_as_func(self):
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
69
69
70 def set_inputhook(self, callback):
70 def set_inputhook(self, callback):
71 """Set PyOS_InputHook to callback and return the previous one."""
71 """Set PyOS_InputHook to callback and return the previous one."""
72 self._callback = callback
72 self._callback = callback
73 self._callback_pyfunctype = self.PYFUNC(callback)
73 self._callback_pyfunctype = self.PYFUNC(callback)
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
75 original = self.get_pyos_inputhook_as_func()
75 original = self.get_pyos_inputhook_as_func()
76 pyos_inputhook_ptr.value = \
76 pyos_inputhook_ptr.value = \
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
78 self._installed = True
78 self._installed = True
79 return original
79 return original
80
80
81 def clear_inputhook(self, app=None):
81 def clear_inputhook(self, app=None):
82 """Set PyOS_InputHook to NULL and return the previous one.
82 """Set PyOS_InputHook to NULL and return the previous one.
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 app : optional, ignored
86 app : optional, ignored
87 This parameter is allowed only so that clear_inputhook() can be
87 This parameter is allowed only so that clear_inputhook() can be
88 called with a similar interface as all the ``enable_*`` methods. But
88 called with a similar interface as all the ``enable_*`` methods. But
89 the actual value of the parameter is ignored. This uniform interface
89 the actual value of the parameter is ignored. This uniform interface
90 makes it easier to have user-level entry points in the main IPython
90 makes it easier to have user-level entry points in the main IPython
91 app like :meth:`enable_gui`."""
91 app like :meth:`enable_gui`."""
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
93 original = self.get_pyos_inputhook_as_func()
93 original = self.get_pyos_inputhook_as_func()
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
95 self._reset()
95 self._reset()
96 return original
96 return original
97
97
98 def clear_app_refs(self, gui=None):
98 def clear_app_refs(self, gui=None):
99 """Clear IPython's internal reference to an application instance.
99 """Clear IPython's internal reference to an application instance.
100
100
101 Whenever we create an app for a user on qt4 or wx, we hold a
101 Whenever we create an app for a user on qt4 or wx, we hold a
102 reference to the app. This is needed because in some cases bad things
102 reference to the app. This is needed because in some cases bad things
103 can happen if a user doesn't hold a reference themselves. This
103 can happen if a user doesn't hold a reference themselves. This
104 method is provided to clear the references we are holding.
104 method is provided to clear the references we are holding.
105
105
106 Parameters
106 Parameters
107 ----------
107 ----------
108 gui : None or str
108 gui : None or str
109 If None, clear all app references. If ('wx', 'qt4') clear
109 If None, clear all app references. If ('wx', 'qt4') clear
110 the app for that toolkit. References are not held for gtk or tk
110 the app for that toolkit. References are not held for gtk or tk
111 as those toolkits don't have the notion of an app.
111 as those toolkits don't have the notion of an app.
112 """
112 """
113 if gui is None:
113 if gui is None:
114 self._apps = {}
114 self._apps = {}
115 elif self._apps.has_key(gui):
115 elif self._apps.has_key(gui):
116 del self._apps[gui]
116 del self._apps[gui]
117
117
118 def enable_wx(self, app=None):
118 def enable_wx(self, app=None):
119 """Enable event loop integration with wxPython.
119 """Enable event loop integration with wxPython.
120
120
121 Parameters
121 Parameters
122 ----------
122 ----------
123 app : WX Application, optional.
123 app : WX Application, optional.
124 Running application to use. If not given, we probe WX for an
124 Running application to use. If not given, we probe WX for an
125 existing application object, and create a new one if none is found.
125 existing application object, and create a new one if none is found.
126
126
127 Notes
127 Notes
128 -----
128 -----
129 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
129 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
130 the wxPython to integrate with terminal based applications like
130 the wxPython to integrate with terminal based applications like
131 IPython.
131 IPython.
132
132
133 If ``app`` is not given we probe for an existing one, and return it if
133 If ``app`` is not given we probe for an existing one, and return it if
134 found. If no existing app is found, we create an :class:`wx.App` as
134 found. If no existing app is found, we create an :class:`wx.App` as
135 follows::
135 follows::
136
136
137 import wx
137 import wx
138 app = wx.App(redirect=False, clearSigInt=False)
138 app = wx.App(redirect=False, clearSigInt=False)
139 """
139 """
140 from IPython.lib.inputhookwx import inputhook_wx
140 from IPython.lib.inputhookwx import inputhook_wx
141 self.set_inputhook(inputhook_wx)
141 self.set_inputhook(inputhook_wx)
142 self._current_gui = GUI_WX
142 self._current_gui = GUI_WX
143 import wx
143 import wx
144 if app is None:
144 if app is None:
145 app = wx.GetApp()
145 app = wx.GetApp()
146 if app is None:
146 if app is None:
147 app = wx.App(redirect=False, clearSigInt=False)
147 app = wx.App(redirect=False, clearSigInt=False)
148 app._in_event_loop = True
148 app._in_event_loop = True
149 self._apps[GUI_WX] = app
149 self._apps[GUI_WX] = app
150 return app
150 return app
151
151
152 def disable_wx(self):
152 def disable_wx(self):
153 """Disable event loop integration with wxPython.
153 """Disable event loop integration with wxPython.
154
154
155 This merely sets PyOS_InputHook to NULL.
155 This merely sets PyOS_InputHook to NULL.
156 """
156 """
157 if self._apps.has_key(GUI_WX):
157 if self._apps.has_key(GUI_WX):
158 self._apps[GUI_WX]._in_event_loop = False
158 self._apps[GUI_WX]._in_event_loop = False
159 self.clear_inputhook()
159 self.clear_inputhook()
160
160
161 def enable_qt4(self, app=None):
161 def enable_qt4(self, app=None):
162 """Enable event loop integration with PyQt4.
162 """Enable event loop integration with PyQt4.
163
163
164 Parameters
164 Parameters
165 ----------
165 ----------
166 app : Qt Application, optional.
166 app : Qt Application, optional.
167 Running application to use. If not given, we probe Qt for an
167 Running application to use. If not given, we probe Qt for an
168 existing application object, and create a new one if none is found.
168 existing application object, and create a new one if none is found.
169
169
170 Notes
170 Notes
171 -----
171 -----
172 This methods sets the PyOS_InputHook for PyQt4, which allows
172 This methods sets the PyOS_InputHook for PyQt4, which allows
173 the PyQt4 to integrate with terminal based applications like
173 the PyQt4 to integrate with terminal based applications like
174 IPython.
174 IPython.
175
175
176 If ``app`` is not given we probe for an existing one, and return it if
176 If ``app`` is not given we probe for an existing one, and return it if
177 found. If no existing app is found, we create an :class:`QApplication`
177 found. If no existing app is found, we create an :class:`QApplication`
178 as follows::
178 as follows::
179
179
180 from PyQt4 import QtCore
180 from PyQt4 import QtCore
181 app = QtGui.QApplication(sys.argv)
181 app = QtGui.QApplication(sys.argv)
182 """
182 """
183 from IPython.external.qt_for_kernel import QtCore, QtGui
183 from IPython.external.qt_for_kernel import QtCore, QtGui
184
184
185 if 'pyreadline' in sys.modules:
185 if 'pyreadline' in sys.modules:
186 # see IPython GitHub Issue #281 for more info on this issue
186 # see IPython GitHub Issue #281 for more info on this issue
187 # Similar intermittent behavior has been reported on OSX,
187 # Similar intermittent behavior has been reported on OSX,
188 # but not consistently reproducible
188 # but not consistently reproducible
189 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
189 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
190 in interactive input. If you do see this issue, we recommend using another GUI
190 in interactive input. If you do see this issue, we recommend using another GUI
191 toolkit if you can, or disable readline with the configuration option
191 toolkit if you can, or disable readline with the configuration option
192 'TerminalInteractiveShell.readline_use=False', specified in a config file or
192 'TerminalInteractiveShell.readline_use=False', specified in a config file or
193 at the command-line""",
193 at the command-line""",
194 RuntimeWarning)
194 RuntimeWarning)
195
195
196 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
196 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
197 # was set when QtCore was imported, but if it ever got removed,
197 # was set when QtCore was imported, but if it ever got removed,
198 # you couldn't reset it. For earlier versions we can
198 # you couldn't reset it. For earlier versions we can
199 # probably implement a ctypes version.
199 # probably implement a ctypes version.
200 try:
200 try:
201 QtCore.pyqtRestoreInputHook()
201 QtCore.pyqtRestoreInputHook()
202 except AttributeError:
202 except AttributeError:
203 pass
203 pass
204
204
205 self._current_gui = GUI_QT4
205 self._current_gui = GUI_QT4
206 if app is None:
206 if app is None:
207 app = QtCore.QCoreApplication.instance()
207 app = QtCore.QCoreApplication.instance()
208 if app is None:
208 if app is None:
209 app = QtGui.QApplication([" "])
209 app = QtGui.QApplication([" "])
210 app._in_event_loop = True
210 app._in_event_loop = True
211 self._apps[GUI_QT4] = app
211 self._apps[GUI_QT4] = app
212 return app
212 return app
213
213
214 def disable_qt4(self):
214 def disable_qt4(self):
215 """Disable event loop integration with PyQt4.
215 """Disable event loop integration with PyQt4.
216
216
217 This merely sets PyOS_InputHook to NULL.
217 This merely sets PyOS_InputHook to NULL.
218 """
218 """
219 if self._apps.has_key(GUI_QT4):
219 if self._apps.has_key(GUI_QT4):
220 self._apps[GUI_QT4]._in_event_loop = False
220 self._apps[GUI_QT4]._in_event_loop = False
221 self.clear_inputhook()
221 self.clear_inputhook()
222
222
223 def enable_gtk(self, app=None):
223 def enable_gtk(self, app=None):
224 """Enable event loop integration with PyGTK.
224 """Enable event loop integration with PyGTK.
225
225
226 Parameters
226 Parameters
227 ----------
227 ----------
228 app : ignored
228 app : ignored
229 Ignored, it's only a placeholder to keep the call signature of all
229 Ignored, it's only a placeholder to keep the call signature of all
230 gui activation methods consistent, which simplifies the logic of
230 gui activation methods consistent, which simplifies the logic of
231 supporting magics.
231 supporting magics.
232
232
233 Notes
233 Notes
234 -----
234 -----
235 This methods sets the PyOS_InputHook for PyGTK, which allows
235 This methods sets the PyOS_InputHook for PyGTK, which allows
236 the PyGTK to integrate with terminal based applications like
236 the PyGTK to integrate with terminal based applications like
237 IPython.
237 IPython.
238 """
238 """
239 import gtk
239 import gtk
240 try:
240 try:
241 gtk.set_interactive(True)
241 gtk.set_interactive(True)
242 self._current_gui = GUI_GTK
242 self._current_gui = GUI_GTK
243 except AttributeError:
243 except AttributeError:
244 # For older versions of gtk, use our own ctypes version
244 # For older versions of gtk, use our own ctypes version
245 from IPython.lib.inputhookgtk import inputhook_gtk
245 from IPython.lib.inputhookgtk import inputhook_gtk
246 self.set_inputhook(inputhook_gtk)
246 self.set_inputhook(inputhook_gtk)
247 self._current_gui = GUI_GTK
247 self._current_gui = GUI_GTK
248
248
249 def disable_gtk(self):
249 def disable_gtk(self):
250 """Disable event loop integration with PyGTK.
250 """Disable event loop integration with PyGTK.
251
251
252 This merely sets PyOS_InputHook to NULL.
252 This merely sets PyOS_InputHook to NULL.
253 """
253 """
254 self.clear_inputhook()
254 self.clear_inputhook()
255
255
256 def enable_tk(self, app=None):
256 def enable_tk(self, app=None):
257 """Enable event loop integration with Tk.
257 """Enable event loop integration with Tk.
258
258
259 Parameters
259 Parameters
260 ----------
260 ----------
261 app : toplevel :class:`Tkinter.Tk` widget, optional.
261 app : toplevel :class:`Tkinter.Tk` widget, optional.
262 Running application to use. If not given, we probe Qt for an
262 Running toplevel widget to use. If not given, we probe Tk for an
263 existing application object, and create a new one if none is found.
263 existing one, and create a new one if none is found.
264
264
265 Notes
265 Notes
266 -----
266 -----
267 If you have already created a :class:`Tkinter.Tk` object, the only
267 If you have already created a :class:`Tkinter.Tk` object, the only
268 thing done by this method is to register with the
268 thing done by this method is to register with the
269 :class:`InputHookManager`, since creating that object automatically
269 :class:`InputHookManager`, since creating that object automatically
270 sets ``PyOS_InputHook``.
270 sets ``PyOS_InputHook``.
271 """
271 """
272 self._current_gui = GUI_TK
272 self._current_gui = GUI_TK
273 if app is None:
273 if app is None:
274 import Tkinter
274 import Tkinter
275 app = Tkinter.Tk()
275 app = Tkinter.Tk()
276 app.withdraw()
276 app.withdraw()
277 self._apps[GUI_TK] = app
277 self._apps[GUI_TK] = app
278 return app
278 return app
279
279
280 def disable_tk(self):
280 def disable_tk(self):
281 """Disable event loop integration with Tkinter.
281 """Disable event loop integration with Tkinter.
282
282
283 This merely sets PyOS_InputHook to NULL.
283 This merely sets PyOS_InputHook to NULL.
284 """
284 """
285 self.clear_inputhook()
285 self.clear_inputhook()
286
286
287 def current_gui(self):
287 def current_gui(self):
288 """Return a string indicating the currently active GUI or None."""
288 """Return a string indicating the currently active GUI or None."""
289 return self._current_gui
289 return self._current_gui
290
290
291 inputhook_manager = InputHookManager()
291 inputhook_manager = InputHookManager()
292
292
293 enable_wx = inputhook_manager.enable_wx
293 enable_wx = inputhook_manager.enable_wx
294 disable_wx = inputhook_manager.disable_wx
294 disable_wx = inputhook_manager.disable_wx
295 enable_qt4 = inputhook_manager.enable_qt4
295 enable_qt4 = inputhook_manager.enable_qt4
296 disable_qt4 = inputhook_manager.disable_qt4
296 disable_qt4 = inputhook_manager.disable_qt4
297 enable_gtk = inputhook_manager.enable_gtk
297 enable_gtk = inputhook_manager.enable_gtk
298 disable_gtk = inputhook_manager.disable_gtk
298 disable_gtk = inputhook_manager.disable_gtk
299 enable_tk = inputhook_manager.enable_tk
299 enable_tk = inputhook_manager.enable_tk
300 disable_tk = inputhook_manager.disable_tk
300 disable_tk = inputhook_manager.disable_tk
301 clear_inputhook = inputhook_manager.clear_inputhook
301 clear_inputhook = inputhook_manager.clear_inputhook
302 set_inputhook = inputhook_manager.set_inputhook
302 set_inputhook = inputhook_manager.set_inputhook
303 current_gui = inputhook_manager.current_gui
303 current_gui = inputhook_manager.current_gui
304 clear_app_refs = inputhook_manager.clear_app_refs
304 clear_app_refs = inputhook_manager.clear_app_refs
305
305
306
306
307 # Convenience function to switch amongst them
307 # Convenience function to switch amongst them
308 def enable_gui(gui=None, app=None):
308 def enable_gui(gui=None, app=None):
309 """Switch amongst GUI input hooks by name.
309 """Switch amongst GUI input hooks by name.
310
310
311 This is just a utility wrapper around the methods of the InputHookManager
311 This is just a utility wrapper around the methods of the InputHookManager
312 object.
312 object.
313
313
314 Parameters
314 Parameters
315 ----------
315 ----------
316 gui : optional, string or None
316 gui : optional, string or None
317 If None, clears input hook, otherwise it must be one of the recognized
317 If None, clears input hook, otherwise it must be one of the recognized
318 GUI names (see ``GUI_*`` constants in module).
318 GUI names (see ``GUI_*`` constants in module).
319
319
320 app : optional, existing application object.
320 app : optional, existing application object.
321 For toolkits that have the concept of a global app, you can supply an
321 For toolkits that have the concept of a global app, you can supply an
322 existing one. If not given, the toolkit will be probed for one, and if
322 existing one. If not given, the toolkit will be probed for one, and if
323 none is found, a new one will be created. Note that GTK does not have
323 none is found, a new one will be created. Note that GTK does not have
324 this concept, and passing an app if `gui`=="GTK" will raise an error.
324 this concept, and passing an app if `gui`=="GTK" will raise an error.
325
325
326 Returns
326 Returns
327 -------
327 -------
328 The output of the underlying gui switch routine, typically the actual
328 The output of the underlying gui switch routine, typically the actual
329 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
329 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
330 one.
330 one.
331 """
331 """
332 guis = {None: clear_inputhook,
332 guis = {None: clear_inputhook,
333 GUI_OSX: lambda app=False: None,
333 GUI_OSX: lambda app=False: None,
334 GUI_TK: enable_tk,
334 GUI_TK: enable_tk,
335 GUI_GTK: enable_gtk,
335 GUI_GTK: enable_gtk,
336 GUI_WX: enable_wx,
336 GUI_WX: enable_wx,
337 GUI_QT: enable_qt4, # qt3 not supported
337 GUI_QT: enable_qt4, # qt3 not supported
338 GUI_QT4: enable_qt4 }
338 GUI_QT4: enable_qt4 }
339 try:
339 try:
340 gui_hook = guis[gui]
340 gui_hook = guis[gui]
341 except KeyError:
341 except KeyError:
342 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
342 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
343 raise ValueError(e)
343 raise ValueError(e)
344 return gui_hook(app)
344 return gui_hook(app)
345
345
General Comments 0
You need to be logged in to leave comments. Login now