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