]> git.saurik.com Git - wxWidgets.git/blame - wxPython/src/_app_ex.py
Revert reentrancy patch (#1573619)
[wxWidgets.git] / wxPython / src / _app_ex.py
CommitLineData
d14a1e28
RD
1
2#----------------------------------------------------------------------
3
4class PyOnDemandOutputWindow:
6c3b4aae
RD
5 """
6 A class that can be used for redirecting Python's stdout and
7 stderr streams. It will do nothing until something is wrriten to
8 the stream at which point it will create a Frame with a text area
9 and write the text there.
10 """
d14a1e28
RD
11 def __init__(self, title = "wxPython: stdout/stderr"):
12 self.frame = None
13 self.title = title
488256e0
RD
14 self.pos = wx.DefaultPosition
15 self.size = (450, 300)
d14a1e28
RD
16 self.parent = None
17
18 def SetParent(self, parent):
6c3b4aae 19 """Set the window to be used as the popup Frame's parent."""
d14a1e28
RD
20 self.parent = parent
21
6c3b4aae
RD
22
23 def CreateOutputWindow(self, st):
488256e0
RD
24 self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size,
25 style=wx.DEFAULT_FRAME_STYLE)
64e8a1f0 26 self.text = wx.TextCtrl(self.frame, -1, "",
488256e0 27 style=wx.TE_MULTILINE|wx.TE_READONLY)
4a7ea057 28 self.text.AppendText(st)
6c3b4aae 29 self.frame.Show(True)
7e8142e9 30 self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
6c3b4aae 31
d14a1e28 32
330af869
RD
33 def OnCloseWindow(self, event):
34 if self.frame is not None:
35 self.frame.Destroy()
36 self.frame = None
37 self.text = None
38
39
d14a1e28 40 # These methods provide the file-like output behaviour.
6c3b4aae
RD
41 def write(self, text):
42 """
43 Create the output window if needed and write the string to it.
44 If not called in the context of the gui thread then uses
45 CallAfter to do the work there.
46 """
47 if self.frame is None:
48 if not wx.Thread_IsMain():
49 wx.CallAfter(self.CreateOutputWindow, text)
50 else:
51 self.CreateOutputWindow(text)
52 else:
53 if not wx.Thread_IsMain():
54 wx.CallAfter(self.text.AppendText, text)
55 else:
56 self.text.AppendText(text)
57
d14a1e28
RD
58
59 def close(self):
6c3b4aae
RD
60 if self.frame is not None:
61 wx.CallAfter(self.frame.Close)
d14a1e28
RD
62
63
f454e362
RD
64 def flush(self):
65 pass
66
67
6c3b4aae 68
d14a1e28 69#----------------------------------------------------------------------
d14a1e28
RD
70
71_defRedirect = (wx.Platform == '__WXMSW__' or wx.Platform == '__WXMAC__')
4d9de110 72
d14a1e28 73class App(wx.PyApp):
6c3b4aae 74 """
dce2bd22
RD
75 The ``wx.App`` class represents the application and is used to:
76
77 * bootstrap the wxPython system and initialize the underlying
78 gui toolkit
79 * set and get application-wide properties
80 * implement the windowing system main message or event loop,
81 and to dispatch events to window instances
82 * etc.
83
84 Every application must have a ``wx.App`` instance, and all
85 creation of UI objects should be delayed until after the
d7403ad2
RD
86 ``wx.App`` object has been created in order to ensure that the gui
87 platform and wxWidgets have been fully initialized.
dce2bd22
RD
88
89 Normally you would derive from this class and implement an
90 ``OnInit`` method that creates a frame and then calls
91 ``self.SetTopWindow(frame)``.
92
d7403ad2 93 :see: `wx.PySimpleApp` for a simpler app class that can be used
d07d2bc9 94 directly.
6c3b4aae 95 """
dce2bd22 96
d14a1e28
RD
97 outputWindowClass = PyOnDemandOutputWindow
98
d7403ad2
RD
99 def __init__(self, redirect=_defRedirect, filename=None,
100 useBestVisual=False, clearSigInt=True):
dce2bd22
RD
101 """
102 Construct a ``wx.App`` object.
103
d7403ad2
RD
104 :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be
105 redirected? Defaults to True on Windows and Mac, False
106 otherwise. If `filename` is None then output will be
107 redirected to a window that pops up as needed. (You can
108 control what kind of window is created for the output by
109 resetting the class variable ``outputWindowClass`` to a
110 class of your choosing.)
dce2bd22 111
d7403ad2
RD
112 :param filename: The name of a file to redirect output to, if
113 redirect is True.
dce2bd22
RD
114
115 :param useBestVisual: Should the app try to use the best
d7403ad2
RD
116 available visual provided by the system (only relevant on
117 systems that have more than one visual.) This parameter
118 must be used instead of calling `SetUseBestVisual` later
119 on because it must be set before the underlying GUI
120 toolkit is initialized.
121
122 :param clearSigInt: Should SIGINT be cleared? This allows the
123 app to terminate upon a Ctrl-C in the console like other
124 GUI apps will.
dce2bd22
RD
125
126 :note: You should override OnInit to do applicaition
127 initialization to ensure that the system, toolkit and
128 wxWidgets are fully initialized.
129 """
4d9de110 130
d14a1e28
RD
131 wx.PyApp.__init__(self)
132
4d9de110 133 # make sure we can create a GUI
a4314b7e 134 if not self.IsDisplayAvailable():
4d9de110
RD
135
136 if wx.Platform == "__WXMAC__":
137 msg = """This program needs access to the screen.
138Please run with 'pythonw', not 'python', and only when you are logged
139in on the main display of your Mac."""
140
141 elif wx.Platform == "__WXGTK__":
142 msg ="Unable to access the X Display, is $DISPLAY set properly?"
143
144 else:
145 msg = "Unable to create GUI"
146 # TODO: more description is needed for wxMSW...
d14a1e28 147
4d9de110
RD
148 raise SystemExit(msg)
149
d14a1e28
RD
150 # This has to be done before OnInit
151 self.SetUseBestVisual(useBestVisual)
152
153 # Set the default handler for SIGINT. This fixes a problem
154 # where if Ctrl-C is pressed in the console that started this
155 # app then it will not appear to do anything, (not even send
156 # KeyboardInterrupt???) but will later segfault on exit. By
157 # setting the default handler then the app will exit, as
158 # expected (depending on platform.)
d7403ad2
RD
159 if clearSigInt:
160 try:
161 import signal
162 signal.signal(signal.SIGINT, signal.SIG_DFL)
163 except:
164 pass
d14a1e28
RD
165
166 # Save and redirect the stdio to a window?
167 self.stdioWin = None
168 self.saveStdio = (_sys.stdout, _sys.stderr)
169 if redirect:
170 self.RedirectStdio(filename)
171
62038e59
RD
172 # Use Python's install prefix as the default
173 wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix)
174
d14a1e28
RD
175 # This finishes the initialization of wxWindows and then calls
176 # the OnInit that should be present in the derived class
177 self._BootstrapApp()
178
179
57ffa585
RD
180 def OnPreInit(self):
181 """
182 Things that must be done after _BootstrapApp has done its
183 thing, but would be nice if they were already done by the time
184 that OnInit is called.
185 """
186 wx.StockGDI._initStockObjects()
187
188
99269e6c
RD
189 def __del__(self, destroy=wx.PyApp.__del__):
190 self.RestoreStdio() # Just in case the MainLoop was overridden
191 destroy(self)
d14a1e28 192
69ac96fd 193 def Destroy(self):
4b5a79cf 194 self.this.own(False)
69ac96fd 195 wx.PyApp.Destroy(self)
d14a1e28
RD
196
197 def SetTopWindow(self, frame):
1e0c8722 198 """Set the \"main\" top level window"""
d14a1e28
RD
199 if self.stdioWin:
200 self.stdioWin.SetParent(frame)
201 wx.PyApp.SetTopWindow(self, frame)
202
203
204 def MainLoop(self):
1e0c8722 205 """Execute the main GUI event loop"""
d14a1e28
RD
206 wx.PyApp.MainLoop(self)
207 self.RestoreStdio()
208
209
330af869 210 def RedirectStdio(self, filename=None):
1e0c8722 211 """Redirect sys.stdout and sys.stderr to a file or a popup window."""
d14a1e28
RD
212 if filename:
213 _sys.stdout = _sys.stderr = open(filename, 'a')
214 else:
215 self.stdioWin = self.outputWindowClass()
216 _sys.stdout = _sys.stderr = self.stdioWin
217
218
219 def RestoreStdio(self):
99269e6c
RD
220 try:
221 _sys.stdout, _sys.stderr = self.saveStdio
222 except:
223 pass
d14a1e28
RD
224
225
488256e0
RD
226 def SetOutputWindowAttributes(self, title=None, pos=None, size=None):
227 """
228 Set the title, position and/or size of the output window if
d20c6820
RD
229 the stdio has been redirected. This should be called before
230 any output would cause the output window to be created.
488256e0
RD
231 """
232 if self.stdioWin:
233 if title is not None:
234 self.stdioWin.title = title
235 if pos is not None:
236 self.stdioWin.pos = pos
237 if size is not None:
238 self.stdioWin.size = size
239
240
241
d14a1e28 242
dce2bd22 243# change from wx.PyApp_XX to wx.App_XX
54f9ee45
RD
244App_GetMacSupportPCMenuShortcuts = _core_.PyApp_GetMacSupportPCMenuShortcuts
245App_GetMacAboutMenuItemId = _core_.PyApp_GetMacAboutMenuItemId
246App_GetMacPreferencesMenuItemId = _core_.PyApp_GetMacPreferencesMenuItemId
247App_GetMacExitMenuItemId = _core_.PyApp_GetMacExitMenuItemId
248App_GetMacHelpMenuTitleName = _core_.PyApp_GetMacHelpMenuTitleName
249App_SetMacSupportPCMenuShortcuts = _core_.PyApp_SetMacSupportPCMenuShortcuts
250App_SetMacAboutMenuItemId = _core_.PyApp_SetMacAboutMenuItemId
251App_SetMacPreferencesMenuItemId = _core_.PyApp_SetMacPreferencesMenuItemId
252App_SetMacExitMenuItemId = _core_.PyApp_SetMacExitMenuItemId
253App_SetMacHelpMenuTitleName = _core_.PyApp_SetMacHelpMenuTitleName
254App_GetComCtl32Version = _core_.PyApp_GetComCtl32Version
d14a1e28
RD
255
256#----------------------------------------------------------------------------
257
258class PySimpleApp(wx.App):
6c3b4aae
RD
259 """
260 A simple application class. You can just create one of these and
261 then then make your top level windows later, and not have to worry
dce2bd22
RD
262 about OnInit. For example::
263
264 app = wx.PySimpleApp()
265 frame = wx.Frame(None, title='Hello World')
266 frame.Show()
267 app.MainLoop()
268
269 :see: `wx.App`
270 """
6c3b4aae 271
d7403ad2
RD
272 def __init__(self, redirect=False, filename=None,
273 useBestVisual=False, clearSigInt=True):
dce2bd22
RD
274 """
275 :see: `wx.App.__init__`
276 """
d7403ad2 277 wx.App.__init__(self, redirect, filename, useBestVisual, clearSigInt)
6c3b4aae 278
d14a1e28 279 def OnInit(self):
d14a1e28
RD
280 return True
281
282
dce2bd22 283
6c3b4aae 284# Is anybody using this one?
d14a1e28
RD
285class PyWidgetTester(wx.App):
286 def __init__(self, size = (250, 100)):
287 self.size = size
288 wx.App.__init__(self, 0)
289
290 def OnInit(self):
64e8a1f0 291 self.frame = wx.Frame(None, -1, "Widget Tester", pos=(0,0), size=self.size)
d14a1e28
RD
292 self.SetTopWindow(self.frame)
293 return True
294
dce2bd22
RD
295 def SetWidget(self, widgetClass, *args, **kwargs):
296 w = widgetClass(self.frame, *args, **kwargs)
d14a1e28
RD
297 self.frame.Show(True)
298
299#----------------------------------------------------------------------------
300# DO NOT hold any other references to this object. This is how we
dce2bd22 301# know when to cleanup system resources that wxWidgets is holding. When
d14a1e28 302# the sys module is unloaded, the refcount on sys.__wxPythonCleanup
dce2bd22 303# goes to zero and it calls the wx.App_CleanUp function.
d14a1e28
RD
304
305class __wxPyCleanup:
306 def __init__(self):
54f9ee45 307 self.cleanup = _core_.App_CleanUp
d14a1e28
RD
308 def __del__(self):
309 self.cleanup()
310
311_sys.__wxPythonCleanup = __wxPyCleanup()
312
313## # another possible solution, but it gets called too early...
dce2bd22
RD
314## import atexit
315## atexit.register(_core_.wxApp_CleanUp)
d14a1e28
RD
316
317
318#----------------------------------------------------------------------------