##// END OF EJS Templates
Formatting
Emilio Graff -
Show More
@@ -1,155 +1,155 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Support for creating GUI apps and starting event loops.
3 Support for creating GUI apps and starting event loops.
4
4
5 IPython's GUI integration allows interactive plotting and GUI usage in IPython
5 IPython's GUI integration allows interactive plotting and GUI usage in IPython
6 session. IPython has two different types of GUI integration:
6 session. IPython has two different types of GUI integration:
7
7
8 1. The terminal based IPython supports GUI event loops through Python's
8 1. The terminal based IPython supports GUI event loops through Python's
9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
10 whenever raw_input is waiting for a user to type code. We implement GUI
10 whenever raw_input is waiting for a user to type code. We implement GUI
11 support in the terminal by setting PyOS_InputHook to a function that
11 support in the terminal by setting PyOS_InputHook to a function that
12 iterates the event loop for a short while. It is important to note that
12 iterates the event loop for a short while. It is important to note that
13 in this situation, the real GUI event loop is NOT run in the normal
13 in this situation, the real GUI event loop is NOT run in the normal
14 manner, so you can't use the normal means to detect that it is running.
14 manner, so you can't use the normal means to detect that it is running.
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
16 the kernel. In this case, the event loop is run in the normal manner by
16 the kernel. In this case, the event loop is run in the normal manner by
17 calling the function or method of the GUI toolkit that starts the event
17 calling the function or method of the GUI toolkit that starts the event
18 loop.
18 loop.
19
19
20 In addition to starting the GUI event loops in one of these two ways, IPython
20 In addition to starting the GUI event loops in one of these two ways, IPython
21 will *always* create an appropriate GUI application object when GUi
21 will *always* create an appropriate GUI application object when GUi
22 integration is enabled.
22 integration is enabled.
23
23
24 If you want your GUI apps to run in IPython you need to do two things:
24 If you want your GUI apps to run in IPython you need to do two things:
25
25
26 1. Test to see if there is already an existing main application object. If
26 1. Test to see if there is already an existing main application object. If
27 there is, you should use it. If there is not an existing application object
27 there is, you should use it. If there is not an existing application object
28 you should create one.
28 you should create one.
29 2. Test to see if the GUI event loop is running. If it is, you should not
29 2. Test to see if the GUI event loop is running. If it is, you should not
30 start it. If the event loop is not running you may start it.
30 start it. If the event loop is not running you may start it.
31
31
32 This module contains functions for each toolkit that perform these things
32 This module contains functions for each toolkit that perform these things
33 in a consistent manner. Because of how PyOS_InputHook runs the event loop
33 in a consistent manner. Because of how PyOS_InputHook runs the event loop
34 you cannot detect if the event loop is running using the traditional calls
34 you cannot detect if the event loop is running using the traditional calls
35 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
35 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
36 set These methods will return a false negative. That is, they will say the
36 set These methods will return a false negative. That is, they will say the
37 event loop is not running, when is actually is. To work around this limitation
37 event loop is not running, when is actually is. To work around this limitation
38 we proposed the following informal protocol:
38 we proposed the following informal protocol:
39
39
40 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
40 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
41 attribute of the main application object to ``True``. This should be done
41 attribute of the main application object to ``True``. This should be done
42 regardless of how the event loop is actually run.
42 regardless of how the event loop is actually run.
43 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
43 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
44 attribute of the main application object to ``False``.
44 attribute of the main application object to ``False``.
45 * If you want to see if the event loop is running, you *must* use ``hasattr``
45 * If you want to see if the event loop is running, you *must* use ``hasattr``
46 to see if ``_in_event_loop`` attribute has been set. If it is set, you
46 to see if ``_in_event_loop`` attribute has been set. If it is set, you
47 *must* use its value. If it has not been set, you can query the toolkit
47 *must* use its value. If it has not been set, you can query the toolkit
48 in the normal manner.
48 in the normal manner.
49 * If you want GUI support and no one else has created an application or
49 * If you want GUI support and no one else has created an application or
50 started the event loop you *must* do this. We don't want projects to
50 started the event loop you *must* do this. We don't want projects to
51 attempt to defer these things to someone else if they themselves need it.
51 attempt to defer these things to someone else if they themselves need it.
52
52
53 The functions below implement this logic for each GUI toolkit. If you need
53 The functions below implement this logic for each GUI toolkit. If you need
54 to create custom application subclasses, you will likely have to modify this
54 to create custom application subclasses, you will likely have to modify this
55 code for your own purposes. This code can be copied into your own project
55 code for your own purposes. This code can be copied into your own project
56 so you don't have to depend on IPython.
56 so you don't have to depend on IPython.
57
57
58 """
58 """
59
59
60 # Copyright (c) IPython Development Team.
60 # Copyright (c) IPython Development Team.
61 # Distributed under the terms of the Modified BSD License.
61 # Distributed under the terms of the Modified BSD License.
62
62
63 from IPython.core.getipython import get_ipython
63 from IPython.core.getipython import get_ipython
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # wx
66 # wx
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 def get_app_wx(*args, **kwargs):
69 def get_app_wx(*args, **kwargs):
70 """Create a new wx app or return an exiting one."""
70 """Create a new wx app or return an exiting one."""
71 import wx
71 import wx
72 app = wx.GetApp()
72 app = wx.GetApp()
73 if app is None:
73 if app is None:
74 if 'redirect' not in kwargs:
74 if 'redirect' not in kwargs:
75 kwargs['redirect'] = False
75 kwargs['redirect'] = False
76 app = wx.PySimpleApp(*args, **kwargs)
76 app = wx.PySimpleApp(*args, **kwargs)
77 return app
77 return app
78
78
79 def is_event_loop_running_wx(app=None):
79 def is_event_loop_running_wx(app=None):
80 """Is the wx event loop running."""
80 """Is the wx event loop running."""
81 # New way: check attribute on shell instance
81 # New way: check attribute on shell instance
82 ip = get_ipython()
82 ip = get_ipython()
83 if ip is not None:
83 if ip is not None:
84 if ip.active_eventloop and ip.active_eventloop == 'wx':
84 if ip.active_eventloop and ip.active_eventloop == 'wx':
85 return True
85 return True
86 # Fall through to checking the application, because Wx has a native way
86 # Fall through to checking the application, because Wx has a native way
87 # to check if the event loop is running, unlike Qt.
87 # to check if the event loop is running, unlike Qt.
88
88
89 # Old way: check Wx application
89 # Old way: check Wx application
90 if app is None:
90 if app is None:
91 app = get_app_wx()
91 app = get_app_wx()
92 if hasattr(app, '_in_event_loop'):
92 if hasattr(app, '_in_event_loop'):
93 return app._in_event_loop
93 return app._in_event_loop
94 else:
94 else:
95 return app.IsMainLoopRunning()
95 return app.IsMainLoopRunning()
96
96
97 def start_event_loop_wx(app=None):
97 def start_event_loop_wx(app=None):
98 """Start the wx event loop in a consistent manner."""
98 """Start the wx event loop in a consistent manner."""
99 if app is None:
99 if app is None:
100 app = get_app_wx()
100 app = get_app_wx()
101 if not is_event_loop_running_wx(app):
101 if not is_event_loop_running_wx(app):
102 app._in_event_loop = True
102 app._in_event_loop = True
103 app.MainLoop()
103 app.MainLoop()
104 app._in_event_loop = False
104 app._in_event_loop = False
105 else:
105 else:
106 app._in_event_loop = True
106 app._in_event_loop = True
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Qt
109 # Qt
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111
111
112 def get_app_qt4(*args, **kwargs):
112 def get_app_qt4(*args, **kwargs):
113 """Create a new Qt app or return an existing one."""
113 """Create a new Qt app or return an existing one."""
114 from IPython.external.qt_for_kernel import QtGui
114 from IPython.external.qt_for_kernel import QtGui
115 app = QtGui.QApplication.instance()
115 app = QtGui.QApplication.instance()
116 if app is None:
116 if app is None:
117 if not args:
117 if not args:
118 args = ([''],)
118 args = ([""],)
119 app = QtGui.QApplication(*args, **kwargs)
119 app = QtGui.QApplication(*args, **kwargs)
120 return app
120 return app
121
121
122 def is_event_loop_running_qt4(app=None):
122 def is_event_loop_running_qt4(app=None):
123 """Is the qt event loop running."""
123 """Is the qt event loop running."""
124 # New way: check attribute on shell instance
124 # New way: check attribute on shell instance
125 ip = get_ipython()
125 ip = get_ipython()
126 if ip is not None:
126 if ip is not None:
127 return ip.active_eventloop and ip.active_eventloop.startswith('qt')
127 return ip.active_eventloop and ip.active_eventloop.startswith('qt')
128
128
129 # Old way: check attribute on QApplication singleton
129 # Old way: check attribute on QApplication singleton
130 if app is None:
130 if app is None:
131 app = get_app_qt4([''])
131 app = get_app_qt4([""])
132 if hasattr(app, '_in_event_loop'):
132 if hasattr(app, '_in_event_loop'):
133 return app._in_event_loop
133 return app._in_event_loop
134 else:
134 else:
135 # Does qt provide a other way to detect this?
135 # Does qt provide a other way to detect this?
136 return False
136 return False
137
137
138 def start_event_loop_qt4(app=None):
138 def start_event_loop_qt4(app=None):
139 """Start the qt event loop in a consistent manner."""
139 """Start the qt event loop in a consistent manner."""
140 if app is None:
140 if app is None:
141 app = get_app_qt([''])
141 app = get_app_qt4([""])
142 if not is_event_loop_running_qt4(app):
142 if not is_event_loop_running_qt4(app):
143 app._in_event_loop = True
143 app._in_event_loop = True
144 app.exec_()
144 app.exec_()
145 app._in_event_loop = False
145 app._in_event_loop = False
146 else:
146 else:
147 app._in_event_loop = True
147 app._in_event_loop = True
148
148
149 #-----------------------------------------------------------------------------
149 #-----------------------------------------------------------------------------
150 # Tk
150 # Tk
151 #-----------------------------------------------------------------------------
151 #-----------------------------------------------------------------------------
152
152
153 #-----------------------------------------------------------------------------
153 #-----------------------------------------------------------------------------
154 # gtk
154 # gtk
155 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
General Comments 0
You need to be logged in to leave comments. Login now