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