##// END OF EJS Templates
More work on the Tk and GTK gui integration.
Brian Granger -
Show More
@@ -0,0 +1,35 b''
1 #!/usr/bin/env python
2 """Simple GTK example to manually test event loop integration.
3
4 This is meant to run tests manually in ipython as:
5
6 In [5]: %gui gtk
7
8 In [6]: %run gui-gtk.py
9 """
10
11
12 import pygtk
13 pygtk.require('2.0')
14 import gtk
15
16
17 def hello_world(wigdet, data=None):
18 print "Hello World"
19
20 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
21 button = gtk.Button("Hello World")
22 button.connect("clicked", hello_world, None)
23
24 window.add(self.button)
25 button.show()
26 window.show()
27
28 try:
29 from IPython.lib.inputhook import appstart_gtk
30 appstart_gtk()
31 except ImportError:
32 gtk.main()
33
34
35
@@ -0,0 +1,32 b''
1 #!/usr/bin/env python
2 """Simple Tk example to manually test event loop integration.
3
4 This is meant to run tests manually in ipython as:
5
6 In [5]: %gui tk
7
8 In [6]: %run gui-tk.py
9 """
10
11 from Tkinter import *
12
13 class MyApp:
14
15 def __init__(self, root):
16 frame = Frame(root)
17 frame.pack()
18
19 self.button = Button(frame, text="Hello", command=self.hello_world)
20 self.button.pack(side=LEFT)
21
22 def hello_world(self):
23 print "Hello World!"
24
25 root = Tk()
26
27 app = MyApp(root)
28
29 try:
30 from IPython import appstart_tk; appstart_tk(root)
31 except ImportError:
32 root.mainloop()
@@ -1,86 +1,87 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 IPython -- An enhanced Interactive Python
3 IPython -- An enhanced Interactive Python
4
4
5 One of Python's nicest features is its interactive interpreter. This allows
5 One of Python's nicest features is its interactive interpreter. This allows
6 very fast testing of ideas without the overhead of creating test files as is
6 very fast testing of ideas without the overhead of creating test files as is
7 typical in most programming languages. However, the interpreter supplied with
7 typical in most programming languages. However, the interpreter supplied with
8 the standard Python distribution is fairly primitive (and IDLE isn't really
8 the standard Python distribution is fairly primitive (and IDLE isn't really
9 much better).
9 much better).
10
10
11 IPython tries to:
11 IPython tries to:
12
12
13 i - provide an efficient environment for interactive work in Python
13 i - provide an efficient environment for interactive work in Python
14 programming. It tries to address what we see as shortcomings of the standard
14 programming. It tries to address what we see as shortcomings of the standard
15 Python prompt, and adds many features to make interactive work much more
15 Python prompt, and adds many features to make interactive work much more
16 efficient.
16 efficient.
17
17
18 ii - offer a flexible framework so that it can be used as the base
18 ii - offer a flexible framework so that it can be used as the base
19 environment for other projects and problems where Python can be the
19 environment for other projects and problems where Python can be the
20 underlying language. Specifically scientific environments like Mathematica,
20 underlying language. Specifically scientific environments like Mathematica,
21 IDL and Mathcad inspired its design, but similar ideas can be useful in many
21 IDL and Mathcad inspired its design, but similar ideas can be useful in many
22 fields. Python is a fabulous language for implementing this kind of system
22 fields. Python is a fabulous language for implementing this kind of system
23 (due to its dynamic and introspective features), and with suitable libraries
23 (due to its dynamic and introspective features), and with suitable libraries
24 entire systems could be built leveraging Python's power.
24 entire systems could be built leveraging Python's power.
25
25
26 iii - serve as an embeddable, ready to go interpreter for your own programs.
26 iii - serve as an embeddable, ready to go interpreter for your own programs.
27
27
28 IPython requires Python 2.4 or newer.
28 IPython requires Python 2.4 or newer.
29 """
29 """
30
30
31 #*****************************************************************************
31 #*****************************************************************************
32 # Copyright (C) 2008-2009 The IPython Development Team
32 # Copyright (C) 2008-2009 The IPython Development Team
33 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
33 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
34 #
34 #
35 # Distributed under the terms of the BSD License. The full license is in
35 # Distributed under the terms of the BSD License. The full license is in
36 # the file COPYING, distributed as part of this software.
36 # the file COPYING, distributed as part of this software.
37 #*****************************************************************************
37 #*****************************************************************************
38
38
39 # Enforce proper version requirements
39 # Enforce proper version requirements
40 import sys
40 import sys
41
41
42 if sys.version[0:3] < '2.4':
42 if sys.version[0:3] < '2.4':
43 raise ImportError('Python Version 2.4 or above is required for IPython.')
43 raise ImportError('Python Version 2.4 or above is required for IPython.')
44
44
45 # Make it easy to import extensions - they are always directly on pythonpath.
45 # Make it easy to import extensions - they are always directly on pythonpath.
46 # Therefore, non-IPython modules can be added to extensions directory
46 # Therefore, non-IPython modules can be added to extensions directory
47 import os
47 import os
48 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
48 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
49
49
50 # Define what gets imported with a 'from IPython import *'
50 # Define what gets imported with a 'from IPython import *'
51 __all__ = ['IPython.core.ipapi','utils.generics','utils.ipstruct',
51 __all__ = ['IPython.core.ipapi','utils.generics','utils.ipstruct',
52 'core.release','core.shell']
52 'core.release','core.shell']
53
53
54 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
54 # Load __all__ in IPython namespace so that a simple 'import IPython' gives
55 # access to them via IPython.<name>
55 # access to them via IPython.<name>
56 glob,loc = globals(),locals()
56 glob,loc = globals(),locals()
57 for name in __all__:
57 for name in __all__:
58 #print 'Importing: ',name # dbg
58 #print 'Importing: ',name # dbg
59 __import__(name,glob,loc,[])
59 __import__(name,glob,loc,[])
60
60
61 from IPython.core import shell
61 from IPython.core import shell
62 Shell = shell
62 Shell = shell
63 from IPython.core import ipapi
63 from IPython.core import ipapi
64 from IPython.core import iplib
64 from IPython.core import iplib
65
65
66 from IPython.lib import (
66 from IPython.lib import (
67 enable_wx, disable_wx,
67 enable_wx, disable_wx,
68 enable_gtk, disable_gtk,
68 enable_gtk, disable_gtk,
69 enable_qt4, disable_qt4,
69 enable_qt4, disable_qt4,
70 enable_tk, disable_tk,
70 enable_tk, disable_tk,
71 set_inputhook, clear_inputhook,
71 set_inputhook, clear_inputhook,
72 current_gui, spin,
72 current_gui, spin,
73 appstart_qt4, appstart_wx
73 appstart_qt4, appstart_wx,
74 appstart_gtk, appstart_tk
74 )
75 )
75
76
76 # Release data
77 # Release data
77 from IPython.core import release # do it explicitly so pydoc can see it - pydoc bug
78 from IPython.core import release # do it explicitly so pydoc can see it - pydoc bug
78 __author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \
79 __author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \
79 ( release.authors['Fernando'] + release.authors['Janko'] + \
80 ( release.authors['Fernando'] + release.authors['Janko'] + \
80 release.authors['Nathan'] )
81 release.authors['Nathan'] )
81 __license__ = release.license
82 __license__ = release.license
82 __version__ = release.version
83 __version__ = release.version
83 __revision__ = release.revision
84 __revision__ = release.revision
84
85
85 # Namespace cleanup
86 # Namespace cleanup
86 del name,glob,loc
87 del name,glob,loc
@@ -1,30 +1,31 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Extra capabilities for IPython
4 Extra capabilities for IPython
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 from IPython.lib.inputhook import (
18 from IPython.lib.inputhook import (
19 enable_wx, disable_wx,
19 enable_wx, disable_wx,
20 enable_gtk, disable_gtk,
20 enable_gtk, disable_gtk,
21 enable_qt4, disable_qt4,
21 enable_qt4, disable_qt4,
22 enable_tk, disable_tk,
22 enable_tk, disable_tk,
23 set_inputhook, clear_inputhook,
23 set_inputhook, clear_inputhook,
24 current_gui, spin,
24 current_gui, spin,
25 appstart_qt4, appstart_wx
25 appstart_qt4, appstart_wx,
26 appstart_gtk, appstart_tk
26 )
27 )
27
28
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
29 # Code
30 # Code
30 #----------------------------------------------------------------------------- No newline at end of file
31 #-----------------------------------------------------------------------------
@@ -1,470 +1,525 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: 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
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Constants
22 # Constants
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 # Constants for identifying the GUI toolkits.
25 # Constants for identifying the GUI toolkits.
26 GUI_WX = 'wx'
26 GUI_WX = 'wx'
27 GUI_QT4 = 'qt4'
27 GUI_QT4 = 'qt4'
28 GUI_GTK = 'gtk'
28 GUI_GTK = 'gtk'
29 GUI_TK = 'tk'
29 GUI_TK = 'tk'
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Utility classes
32 # Utility classes
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35
35
36 class _DummyMainloop(object):
36 class _DummyMainloop(object):
37 """A special manager to hijack GUI mainloops that is mostly a no-op.
37 """A special manager to hijack GUI mainloops that is mostly a no-op.
38
38
39 We are not using this class currently as it breaks GUI code that calls
39 We are not using this class currently as it breaks GUI code that calls
40 a mainloop function after the app has started to process pending events.
40 a mainloop function after the app has started to process pending events.
41 """
41 """
42 def __init__(self, ml, ihm, gui_type):
42 def __init__(self, ml, ihm, gui_type):
43 self.ml = ml
43 self.ml = ml
44 self.ihm = ihm
44 self.ihm = ihm
45 self.gui_type = gui_type
45 self.gui_type = gui_type
46
46
47 def __call__(self, *args, **kw):
47 def __call__(self, *args, **kw):
48 if self.ihm.current_gui() == self.gui_type:
48 if self.ihm.current_gui() == self.gui_type:
49 pass
49 pass
50 else:
50 else:
51 self.ml(*args, **kw)
51 self.ml(*args, **kw)
52
52
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Appstart and spin functions
55 # Appstart and spin functions
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58
58
59 def appstart_qt4(app):
59 def appstart_qt4(app):
60 """Start the qt4 event loop in a way that plays with IPython.
60 """Start the qt4 event loop in a way that plays with IPython.
61
61
62 When a qt4 app is run interactively in IPython, the event loop should
62 When a qt4 app is run interactively in IPython, the event loop should
63 not be started. This function checks to see if IPython's qt4 integration
63 not be started. This function checks to see if IPython's qt4 integration
64 is activated and if so, it passes. If not, it will call the :meth:`exec_`
64 is activated and if so, it passes. If not, it will call the :meth:`exec_`
65 method of the main qt4 app.
65 method of the main qt4 app.
66
66
67 This function should be used by users who want their qt4 scripts to work
67 This function should be used by users who want their qt4 scripts to work
68 both at the command line and in IPython. These users should put the
68 both at the command line and in IPython. These users should put the
69 following logic at the bottom on their script, after they create a
69 following logic at the bottom on their script, after they create a
70 :class:`QApplication` instance (called ``app`` here)::
70 :class:`QApplication` instance (called ``app`` here)::
71
71
72 try:
72 try:
73 from IPython.lib.inputhook import appstart_qt4
73 from IPython.lib.inputhook import appstart_qt4
74 appstart_qt4(app)
74 appstart_qt4(app)
75 except ImportError:
75 except ImportError:
76 app.exec_()
76 app.exec_()
77 """
77 """
78 from PyQt4 import QtCore, QtGui
78 from PyQt4 import QtCore, QtGui
79
79
80 assert isinstance(app, QtCore.QCoreApplication)
80 assert isinstance(app, QtCore.QCoreApplication)
81 if app is not None:
81 if app is not None:
82 if current_gui() == GUI_QT4:
82 if current_gui() == GUI_QT4:
83 pass
83 pass
84 else:
84 else:
85 app.exec_()
85 app.exec_()
86
86
87
87
88 def appstart_wx(app):
88 def appstart_wx(app):
89 """Start the wx event loop in a way that plays with IPython.
89 """Start the wx event loop in a way that plays with IPython.
90
90
91 When a wx app is run interactively in IPython, the event loop should
91 When a wx app is run interactively in IPython, the event loop should
92 not be started. This function checks to see if IPython's wx integration
92 not be started. This function checks to see if IPython's wx integration
93 is activated and if so, it passes. If not, it will call the
93 is activated and if so, it passes. If not, it will call the
94 :meth:`MainLoop` method of the main qt4 app.
94 :meth:`MainLoop` method of the main qt4 app.
95
95
96 This function should be used by users who want their wx scripts to work
96 This function should be used by users who want their wx scripts to work
97 both at the command line and in IPython. These users should put the
97 both at the command line and in IPython. These users should put the
98 following logic at the bottom on their script, after they create a
98 following logic at the bottom on their script, after they create a
99 :class:`App` instance (called ``app`` here)::
99 :class:`App` instance (called ``app`` here)::
100
100
101 try:
101 try:
102 from IPython.lib.inputhook import appstart_wx
102 from IPython.lib.inputhook import appstart_wx
103 appstart_wx(app)
103 appstart_wx(app)
104 except ImportError:
104 except ImportError:
105 app.MainLoop()
105 app.MainLoop()
106 """
106 """
107 import wx
107 import wx
108
108
109 assert isinstance(app, wx.App)
109 assert isinstance(app, wx.App)
110 if app is not None:
110 if app is not None:
111 if current_gui() == GUI_WX:
111 if current_gui() == GUI_WX:
112 pass
112 pass
113 else:
113 else:
114 app.MainLoop()
114 app.MainLoop()
115
115
116
116
117 def appstart_tk(app):
118 """Start the tk event loop in a way that plays with IPython.
119
120 When a tk app is run interactively in IPython, the event loop should
121 not be started. This function checks to see if IPython's tk integration
122 is activated and if so, it passes. If not, it will call the
123 :meth:`mainloop` method of the tk object passed to this method.
124
125 This function should be used by users who want their tk scripts to work
126 both at the command line and in IPython. These users should put the
127 following logic at the bottom on their script, after they create a
128 :class:`Tk` instance (called ``app`` here)::
129
130 try:
131 from IPython.lib.inputhook import appstart_tk
132 appstart_tk(app)
133 except ImportError:
134 app.mainloop()
135 """
136 if app is not None:
137 if current_gui() == GUI_TK:
138 pass
139 else:
140 app.mainloop()
141
142 def appstart_gtk():
143 """Start the gtk event loop in a way that plays with IPython.
144
145 When a gtk app is run interactively in IPython, the event loop should
146 not be started. This function checks to see if IPython's gtk integration
147 is activated and if so, it passes. If not, it will call
148 :func:`gtk.main`. Unlike the other appstart implementations, this does
149 not take an ``app`` argument.
150
151 This function should be used by users who want their gtk scripts to work
152 both at the command line and in IPython. These users should put the
153 following logic at the bottom on their script::
154
155 try:
156 from IPython.lib.inputhook import appstart_gtk
157 appstart_gtk()
158 except ImportError:
159 gtk.main()
160 """
161 import gtk
162 if current_gui() == GUI_GTK:
163 pass
164 else:
165 gtk.main()
166
117 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
118 # Main InputHookManager class
168 # Main InputHookManager class
119 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
120
170
121
171
122 class InputHookManager(object):
172 class InputHookManager(object):
123 """Manage PyOS_InputHook for different GUI toolkits.
173 """Manage PyOS_InputHook for different GUI toolkits.
124
174
125 This class installs various hooks under ``PyOSInputHook`` to handle
175 This class installs various hooks under ``PyOSInputHook`` to handle
126 GUI event loop integration.
176 GUI event loop integration.
127 """
177 """
128
178
129 def __init__(self):
179 def __init__(self):
130 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
180 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
131 self._apps = {}
181 self._apps = {}
132 self._spinner_dict = {
182 self._spinner_dict = {
133 GUI_QT4 : self._spin_qt4,
183 GUI_QT4 : self._spin_qt4,
134 GUI_WX : self._spin_wx,
184 GUI_WX : self._spin_wx,
135 GUI_GTK : self._spin_gtk,
185 GUI_GTK : self._spin_gtk,
136 GUI_TK : self._spin_tk}
186 GUI_TK : self._spin_tk}
137 self._reset()
187 self._reset()
138
188
139 def _reset(self):
189 def _reset(self):
140 self._callback_pyfunctype = None
190 self._callback_pyfunctype = None
141 self._callback = None
191 self._callback = None
142 self._installed = False
192 self._installed = False
143 self._current_gui = None
193 self._current_gui = None
144
194
145 def _hijack_wx(self):
195 def _hijack_wx(self):
146 """Hijack the wx mainloop so a user calling it won't cause badness.
196 """Hijack the wx mainloop so a user calling it won't cause badness.
147
197
148 We are not currently using this as it breaks GUI code that calls a
198 We are not currently using this as it breaks GUI code that calls a
149 mainloop at anytime but startup.
199 mainloop at anytime but startup.
150 """
200 """
151 import wx
201 import wx
152 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
202 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
153 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
203 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
154 else: raise AttributeError('Could not find wx core module')
204 else: raise AttributeError('Could not find wx core module')
155 orig_mainloop = core.PyApp_MainLoop
205 orig_mainloop = core.PyApp_MainLoop
156 core.PyApp_MainLoop = _DummyMainloop
206 core.PyApp_MainLoop = _DummyMainloop
157 return orig_mainloop
207 return orig_mainloop
158
208
159 def _hijack_qt4(self):
209 def _hijack_qt4(self):
160 """Hijack the qt4 mainloop so a user calling it won't cause badness.
210 """Hijack the qt4 mainloop so a user calling it won't cause badness.
161
211
162 We are not currently using this as it breaks GUI code that calls a
212 We are not currently using this as it breaks GUI code that calls a
163 mainloop at anytime but startup.
213 mainloop at anytime but startup.
164 """
214 """
165 from PyQt4 import QtGui, QtCore
215 from PyQt4 import QtGui, QtCore
166 orig_mainloop = QtGui.qApp.exec_
216 orig_mainloop = QtGui.qApp.exec_
167 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_QT4)
217 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_QT4)
168 QtGui.qApp.exec_ = dumb_ml
218 QtGui.qApp.exec_ = dumb_ml
169 QtGui.QApplication.exec_ = dumb_ml
219 QtGui.QApplication.exec_ = dumb_ml
170 QtCore.QCoreApplication.exec_ = dumb_ml
220 QtCore.QCoreApplication.exec_ = dumb_ml
171 return orig_mainloop
221 return orig_mainloop
172
222
173 def _hijack_gtk(self):
223 def _hijack_gtk(self):
174 """Hijack the gtk mainloop so a user calling it won't cause badness.
224 """Hijack the gtk mainloop so a user calling it won't cause badness.
175
225
176 We are not currently using this as it breaks GUI code that calls a
226 We are not currently using this as it breaks GUI code that calls a
177 mainloop at anytime but startup.
227 mainloop at anytime but startup.
178 """
228 """
179 import gtk
229 import gtk
180 orig_mainloop = gtk.main
230 orig_mainloop = gtk.main
181 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_GTK)
231 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_GTK)
182 gtk.mainloop = dumb_ml
232 gtk.mainloop = dumb_ml
183 gtk.main = dumb_ml
233 gtk.main = dumb_ml
184 return orig_mainloop
234 return orig_mainloop
185
235
186 def _hijack_tk(self):
236 def _hijack_tk(self):
187 """Hijack the tk mainloop so a user calling it won't cause badness.
237 """Hijack the tk mainloop so a user calling it won't cause badness.
188
238
189 We are not currently using this as it breaks GUI code that calls a
239 We are not currently using this as it breaks GUI code that calls a
190 mainloop at anytime but startup.
240 mainloop at anytime but startup.
191 """
241 """
192 import Tkinter
242 import Tkinter
193 orig_mainloop = gtk.main
243 orig_mainloop = gtk.main
194 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_TK)
244 dumb_ml = _DummyMainloop(orig_mainloop, self, GUI_TK)
195 Tkinter.Misc.mainloop = dumb_ml
245 Tkinter.Misc.mainloop = dumb_ml
196 Tkinter.mainloop = dumb_ml
246 Tkinter.mainloop = dumb_ml
197
247
198 def _spin_qt4(self):
248 def _spin_qt4(self):
199 """Process all pending events in the qt4 event loop.
249 """Process all pending events in the qt4 event loop.
200
250
201 This is for internal IPython use only and user code should not call this.
251 This is for internal IPython use only and user code should not call this.
202 Instead, they should issue the raw GUI calls themselves.
252 Instead, they should issue the raw GUI calls themselves.
203 """
253 """
204 from PyQt4 import QtCore, QtGui
254 from PyQt4 import QtCore, QtGui
205
255
206 app = QtCore.QCoreApplication.instance()
256 app = QtCore.QCoreApplication.instance()
207 if app is not None:
257 if app is not None:
208 QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents)
258 QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents)
209
259
210 def _spin_wx(self):
260 def _spin_wx(self):
211 """Process all pending events in the wx event loop.
261 """Process all pending events in the wx event loop.
212
262
213 This is for internal IPython use only and user code should not call this.
263 This is for internal IPython use only and user code should not call this.
214 Instead, they should issue the raw GUI calls themselves.
264 Instead, they should issue the raw GUI calls themselves.
215 """
265 """
216 import wx
266 import wx
217 app = wx.GetApp()
267 app = wx.GetApp()
218 if app is not None and wx.Thread_IsMain():
268 if app is not None and wx.Thread_IsMain():
219 evtloop = wx.EventLoop()
269 evtloop = wx.EventLoop()
220 ea = wx.EventLoopActivator(evtloop)
270 ea = wx.EventLoopActivator(evtloop)
221 while evtloop.Pending():
271 while evtloop.Pending():
222 evtloop.Dispatch()
272 evtloop.Dispatch()
223 app.ProcessIdle()
273 app.ProcessIdle()
224 del ea
274 del ea
225
275
226 def _spin_gtk(self):
276 def _spin_gtk(self):
227 """Process all pending events in the gtk event loop.
277 """Process all pending events in the gtk event loop.
228
278
229 This is for internal IPython use only and user code should not call this.
279 This is for internal IPython use only and user code should not call this.
230 Instead, they should issue the raw GUI calls themselves.
280 Instead, they should issue the raw GUI calls themselves.
231 """
281 """
232 pass
282 import gtk
283 gtk.gdk.threads_enter()
284 while gtk.events_pending():
285 gtk.main_iteration(False)
286 gtk.gdk.flush()
287 gtk.gdk.threads_leave()
233
288
234 def _spin_tk(self):
289 def _spin_tk(self):
235 """Process all pending events in the tk event loop.
290 """Process all pending events in the tk event loop.
236
291
237 This is for internal IPython use only and user code should not call this.
292 This is for internal IPython use only and user code should not call this.
238 Instead, they should issue the raw GUI calls themselves.
293 Instead, they should issue the raw GUI calls themselves.
239 """
294 """
240 app = self._apps.get(GUI_TK)
295 app = self._apps.get(GUI_TK)
241 if app is not None:
296 if app is not None:
242 app.update()
297 app.update()
243
298
244 def spin(self):
299 def spin(self):
245 """Process pending events in the current gui.
300 """Process pending events in the current gui.
246
301
247 This method is just provided for IPython to use internally if needed
302 This method is just provided for IPython to use internally if needed
248 for things like testing. Third party projects should not call this
303 for things like testing. Third party projects should not call this
249 method, but instead should call the underlying GUI toolkit methods
304 method, but instead should call the underlying GUI toolkit methods
250 that we are calling.
305 that we are calling.
251 """
306 """
252 spinner = self._spinner_dict.get(self._current_gui, lambda: None)
307 spinner = self._spinner_dict.get(self._current_gui, lambda: None)
253 spinner()
308 spinner()
254
309
255 def get_pyos_inputhook(self):
310 def get_pyos_inputhook(self):
256 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
311 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
257 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
312 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
258
313
259 def get_pyos_inputhook_as_func(self):
314 def get_pyos_inputhook_as_func(self):
260 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
315 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
261 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
316 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
262
317
263 def set_inputhook(self, callback):
318 def set_inputhook(self, callback):
264 """Set PyOS_InputHook to callback and return the previous one."""
319 """Set PyOS_InputHook to callback and return the previous one."""
265 self._callback = callback
320 self._callback = callback
266 self._callback_pyfunctype = self.PYFUNC(callback)
321 self._callback_pyfunctype = self.PYFUNC(callback)
267 pyos_inputhook_ptr = self.get_pyos_inputhook()
322 pyos_inputhook_ptr = self.get_pyos_inputhook()
268 original = self.get_pyos_inputhook_as_func()
323 original = self.get_pyos_inputhook_as_func()
269 pyos_inputhook_ptr.value = \
324 pyos_inputhook_ptr.value = \
270 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
325 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
271 self._installed = True
326 self._installed = True
272 return original
327 return original
273
328
274 def clear_inputhook(self):
329 def clear_inputhook(self):
275 """Set PyOS_InputHook to NULL and return the previous one."""
330 """Set PyOS_InputHook to NULL and return the previous one."""
276 pyos_inputhook_ptr = self.get_pyos_inputhook()
331 pyos_inputhook_ptr = self.get_pyos_inputhook()
277 original = self.get_pyos_inputhook_as_func()
332 original = self.get_pyos_inputhook_as_func()
278 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
333 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
279 self._reset()
334 self._reset()
280 return original
335 return original
281
336
282 def clear_app_refs(self, gui=None):
337 def clear_app_refs(self, gui=None):
283 """Clear IPython's internal reference to an application instance.
338 """Clear IPython's internal reference to an application instance.
284
339
285 Whenever we create an app for a user on qt4 or wx, we hold a
340 Whenever we create an app for a user on qt4 or wx, we hold a
286 reference to the app. This is needed because in some cases bad things
341 reference to the app. This is needed because in some cases bad things
287 can happen if a user doesn't hold a reference themselves. This
342 can happen if a user doesn't hold a reference themselves. This
288 method is provided to clear the references we are holding.
343 method is provided to clear the references we are holding.
289
344
290 Parameters
345 Parameters
291 ----------
346 ----------
292 gui : None or str
347 gui : None or str
293 If None, clear all app references. If ('wx', 'qt4') clear
348 If None, clear all app references. If ('wx', 'qt4') clear
294 the app for that toolkit. References are not held for gtk or tk
349 the app for that toolkit. References are not held for gtk or tk
295 as those toolkits don't have the notion of an app.
350 as those toolkits don't have the notion of an app.
296 """
351 """
297 if gui is None:
352 if gui is None:
298 self._apps = {}
353 self._apps = {}
299 elif self._apps.has_key(gui):
354 elif self._apps.has_key(gui):
300 del self._apps[gui]
355 del self._apps[gui]
301
356
302 def enable_wx(self, app=False):
357 def enable_wx(self, app=False):
303 """Enable event loop integration with wxPython.
358 """Enable event loop integration with wxPython.
304
359
305 Parameters
360 Parameters
306 ----------
361 ----------
307 app : bool
362 app : bool
308 Create a running application object or not.
363 Create a running application object or not.
309
364
310 Notes
365 Notes
311 -----
366 -----
312 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
367 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
313 the wxPython to integrate with terminal based applications like
368 the wxPython to integrate with terminal based applications like
314 IPython.
369 IPython.
315
370
316 If ``app`` is True, we create an :class:`wx.App` as follows::
371 If ``app`` is True, we create an :class:`wx.App` as follows::
317
372
318 import wx
373 import wx
319 app = wx.App(redirect=False, clearSigInt=False)
374 app = wx.App(redirect=False, clearSigInt=False)
320
375
321 Both options this constructor are important for things to work
376 Both options this constructor are important for things to work
322 properly in an interactive context.
377 properly in an interactive context.
323
378
324 But, we first check to see if an application has already been
379 But, we first check to see if an application has already been
325 created. If so, we simply return that instance.
380 created. If so, we simply return that instance.
326 """
381 """
327 from IPython.lib.inputhookwx import inputhook_wx
382 from IPython.lib.inputhookwx import inputhook_wx
328 self.set_inputhook(inputhook_wx)
383 self.set_inputhook(inputhook_wx)
329 self._current_gui = GUI_WX
384 self._current_gui = GUI_WX
330 if app:
385 if app:
331 import wx
386 import wx
332 app = wx.GetApp()
387 app = wx.GetApp()
333 if app is None:
388 if app is None:
334 app = wx.App(redirect=False, clearSigInt=False)
389 app = wx.App(redirect=False, clearSigInt=False)
335 self._apps[GUI_WX] = app
390 self._apps[GUI_WX] = app
336 return app
391 return app
337
392
338 def disable_wx(self):
393 def disable_wx(self):
339 """Disable event loop integration with wxPython.
394 """Disable event loop integration with wxPython.
340
395
341 This merely sets PyOS_InputHook to NULL.
396 This merely sets PyOS_InputHook to NULL.
342 """
397 """
343 self.clear_inputhook()
398 self.clear_inputhook()
344
399
345 def enable_qt4(self, app=False):
400 def enable_qt4(self, app=False):
346 """Enable event loop integration with PyQt4.
401 """Enable event loop integration with PyQt4.
347
402
348 Parameters
403 Parameters
349 ----------
404 ----------
350 app : bool
405 app : bool
351 Create a running application object or not.
406 Create a running application object or not.
352
407
353 Notes
408 Notes
354 -----
409 -----
355 This methods sets the PyOS_InputHook for PyQt4, which allows
410 This methods sets the PyOS_InputHook for PyQt4, which allows
356 the PyQt4 to integrate with terminal based applications like
411 the PyQt4 to integrate with terminal based applications like
357 IPython.
412 IPython.
358
413
359 If ``app`` is True, we create an :class:`QApplication` as follows::
414 If ``app`` is True, we create an :class:`QApplication` as follows::
360
415
361 from PyQt4 import QtCore
416 from PyQt4 import QtCore
362 app = QtGui.QApplication(sys.argv)
417 app = QtGui.QApplication(sys.argv)
363
418
364 But, we first check to see if an application has already been
419 But, we first check to see if an application has already been
365 created. If so, we simply return that instance.
420 created. If so, we simply return that instance.
366 """
421 """
367 from PyQt4 import QtCore
422 from PyQt4 import QtCore
368 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
423 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
369 # was set when QtCore was imported, but if it ever got removed,
424 # was set when QtCore was imported, but if it ever got removed,
370 # you couldn't reset it. For earlier versions we can
425 # you couldn't reset it. For earlier versions we can
371 # probably implement a ctypes version.
426 # probably implement a ctypes version.
372 try:
427 try:
373 QtCore.pyqtRestoreInputHook()
428 QtCore.pyqtRestoreInputHook()
374 except AttributeError:
429 except AttributeError:
375 pass
430 pass
376 self._current_gui = GUI_QT4
431 self._current_gui = GUI_QT4
377 if app:
432 if app:
378 from PyQt4 import QtGui
433 from PyQt4 import QtGui
379 app = QtCore.QCoreApplication.instance()
434 app = QtCore.QCoreApplication.instance()
380 if app is None:
435 if app is None:
381 app = QtGui.QApplication(sys.argv)
436 app = QtGui.QApplication(sys.argv)
382 self._apps[GUI_QT4] = app
437 self._apps[GUI_QT4] = app
383 return app
438 return app
384
439
385 def disable_qt4(self):
440 def disable_qt4(self):
386 """Disable event loop integration with PyQt4.
441 """Disable event loop integration with PyQt4.
387
442
388 This merely sets PyOS_InputHook to NULL.
443 This merely sets PyOS_InputHook to NULL.
389 """
444 """
390 self.clear_inputhook()
445 self.clear_inputhook()
391
446
392 def enable_gtk(self, app=False):
447 def enable_gtk(self, app=False):
393 """Enable event loop integration with PyGTK.
448 """Enable event loop integration with PyGTK.
394
449
395 Parameters
450 Parameters
396 ----------
451 ----------
397 app : bool
452 app : bool
398 Create a running application object or not. Because gtk does't
453 Create a running application object or not. Because gtk does't
399 have an app class, this does nothing.
454 have an app class, this does nothing.
400
455
401 Notes
456 Notes
402 -----
457 -----
403 This methods sets the PyOS_InputHook for PyGTK, which allows
458 This methods sets the PyOS_InputHook for PyGTK, which allows
404 the PyGTK to integrate with terminal based applications like
459 the PyGTK to integrate with terminal based applications like
405 IPython.
460 IPython.
406 """
461 """
407 import gtk
462 import gtk
408 try:
463 try:
409 gtk.set_interactive(True)
464 gtk.set_interactive(True)
410 self._current_gui = GUI_GTK
465 self._current_gui = GUI_GTK
411 except AttributeError:
466 except AttributeError:
412 # For older versions of gtk, use our own ctypes version
467 # For older versions of gtk, use our own ctypes version
413 from IPython.lib.inputhookgtk import inputhook_gtk
468 from IPython.lib.inputhookgtk import inputhook_gtk
414 self.set_inputhook(inputhook_gtk)
469 self.set_inputhook(inputhook_gtk)
415 self._current_gui = GUI_GTK
470 self._current_gui = GUI_GTK
416
471
417 def disable_gtk(self):
472 def disable_gtk(self):
418 """Disable event loop integration with PyGTK.
473 """Disable event loop integration with PyGTK.
419
474
420 This merely sets PyOS_InputHook to NULL.
475 This merely sets PyOS_InputHook to NULL.
421 """
476 """
422 self.clear_inputhook()
477 self.clear_inputhook()
423
478
424 def enable_tk(self, app=False):
479 def enable_tk(self, app=False):
425 """Enable event loop integration with Tk.
480 """Enable event loop integration with Tk.
426
481
427 Parameters
482 Parameters
428 ----------
483 ----------
429 app : bool
484 app : bool
430 Create a running application object or not.
485 Create a running application object or not.
431
486
432 Notes
487 Notes
433 -----
488 -----
434 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
489 Currently this is a no-op as creating a :class:`Tkinter.Tk` object
435 sets ``PyOS_InputHook``.
490 sets ``PyOS_InputHook``.
436 """
491 """
437 self._current_gui = GUI_TK
492 self._current_gui = GUI_TK
438 if app:
493 if app:
439 import Tkinter
494 import Tkinter
440 app = Tkinter.Tk()
495 app = Tkinter.Tk()
441 app.withdraw()
496 app.withdraw()
442 self._apps[GUI_TK] = app
497 self._apps[GUI_TK] = app
443 return app
498 return app
444
499
445 def disable_tk(self):
500 def disable_tk(self):
446 """Disable event loop integration with Tkinter.
501 """Disable event loop integration with Tkinter.
447
502
448 This merely sets PyOS_InputHook to NULL.
503 This merely sets PyOS_InputHook to NULL.
449 """
504 """
450 self.clear_inputhook()
505 self.clear_inputhook()
451
506
452 def current_gui(self):
507 def current_gui(self):
453 """Return a string indicating the currently active GUI or None."""
508 """Return a string indicating the currently active GUI or None."""
454 return self._current_gui
509 return self._current_gui
455
510
456 inputhook_manager = InputHookManager()
511 inputhook_manager = InputHookManager()
457
512
458 enable_wx = inputhook_manager.enable_wx
513 enable_wx = inputhook_manager.enable_wx
459 disable_wx = inputhook_manager.disable_wx
514 disable_wx = inputhook_manager.disable_wx
460 enable_qt4 = inputhook_manager.enable_qt4
515 enable_qt4 = inputhook_manager.enable_qt4
461 disable_qt4 = inputhook_manager.disable_qt4
516 disable_qt4 = inputhook_manager.disable_qt4
462 enable_gtk = inputhook_manager.enable_gtk
517 enable_gtk = inputhook_manager.enable_gtk
463 disable_gtk = inputhook_manager.disable_gtk
518 disable_gtk = inputhook_manager.disable_gtk
464 enable_tk = inputhook_manager.enable_tk
519 enable_tk = inputhook_manager.enable_tk
465 disable_tk = inputhook_manager.disable_tk
520 disable_tk = inputhook_manager.disable_tk
466 clear_inputhook = inputhook_manager.clear_inputhook
521 clear_inputhook = inputhook_manager.clear_inputhook
467 set_inputhook = inputhook_manager.set_inputhook
522 set_inputhook = inputhook_manager.set_inputhook
468 current_gui = inputhook_manager.current_gui
523 current_gui = inputhook_manager.current_gui
469 clear_app_refs = inputhook_manager.clear_app_refs
524 clear_app_refs = inputhook_manager.clear_app_refs
470 spin = inputhook_manager.spin
525 spin = inputhook_manager.spin
General Comments 0
You need to be logged in to leave comments. Login now