]> git.saurik.com Git - wxWidgets.git/blob - src/common/appcmn.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / common / appcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/appcmn.cpp
3 // Purpose: wxAppBase methods common to all platforms
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 18.10.99
7 // Copyright: (c) Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #if defined(__BORLANDC__)
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/app.h"
28 #include "wx/window.h"
29 #include "wx/bitmap.h"
30 #include "wx/log.h"
31 #include "wx/msgdlg.h"
32 #include "wx/confbase.h"
33 #include "wx/utils.h"
34 #include "wx/wxcrtvararg.h"
35 #endif
36
37 #include "wx/apptrait.h"
38 #include "wx/cmdline.h"
39 #include "wx/msgout.h"
40 #include "wx/thread.h"
41 #include "wx/vidmode.h"
42 #include "wx/evtloop.h"
43
44 #if wxUSE_FONTMAP
45 #include "wx/fontmap.h"
46 #endif // wxUSE_FONTMAP
47
48 // DLL options compatibility check:
49 #include "wx/build.h"
50 WX_CHECK_BUILD_OPTIONS("wxCore")
51
52 // ============================================================================
53 // wxAppBase implementation
54 // ============================================================================
55
56 // ----------------------------------------------------------------------------
57 // initialization
58 // ----------------------------------------------------------------------------
59
60 wxAppBase::wxAppBase()
61 {
62 m_topWindow = NULL;
63
64 m_useBestVisual = false;
65 m_forceTrueColour = false;
66
67 m_isActive = true;
68
69 // We don't want to exit the app if the user code shows a dialog from its
70 // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
71 // to Yes initially as this dialog would be the last top level window.
72 // OTOH, if we set it to No initially we'll have to overwrite it with Yes
73 // when we enter our OnRun() because we do want the default behaviour from
74 // then on. But this would be a problem if the user code calls
75 // SetExitOnFrameDelete(false) from OnInit().
76 //
77 // So we use the special "Later" value which is such that
78 // GetExitOnFrameDelete() returns false for it but which we know we can
79 // safely (i.e. without losing the effect of the users SetExitOnFrameDelete
80 // call) overwrite in OnRun()
81 m_exitOnFrameDelete = Later;
82 }
83
84 bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig)
85 {
86 #ifdef __WXOSX__
87 // Mac OS X passes a process serial number command line argument when
88 // the application is launched from the Finder. This argument must be
89 // removed from the command line arguments before being handled by the
90 // application (otherwise applications would need to handle it)
91 //
92 // Notice that this has to be done for all ports that can be used under OS
93 // X (e.g. wxGTK) and not just wxOSX itself, hence this code is here and
94 // not in a port-specific file.
95 if ( argcOrig > 1 )
96 {
97 static const wxChar *ARG_PSN = wxT("-psn_");
98 if ( wxStrncmp(argvOrig[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
99 {
100 // remove this argument
101 --argcOrig;
102 memmove(argvOrig + 1, argvOrig + 2, argcOrig * sizeof(wxChar*));
103 }
104 }
105 #endif // __WXOSX__
106
107 if ( !wxAppConsole::Initialize(argcOrig, argvOrig) )
108 return false;
109
110 wxInitializeStockLists();
111
112 wxBitmap::InitStandardHandlers();
113
114 // for compatibility call the old initialization function too
115 if ( !OnInitGui() )
116 return false;
117
118 return true;
119 }
120
121 // ----------------------------------------------------------------------------
122 // cleanup
123 // ----------------------------------------------------------------------------
124
125 wxAppBase::~wxAppBase()
126 {
127 // this destructor is required for Darwin
128 }
129
130 void wxAppBase::CleanUp()
131 {
132 // clean up all the pending objects
133 DeletePendingObjects();
134
135 // and any remaining TLWs (they remove themselves from wxTopLevelWindows
136 // when destroyed, so iterate until none are left)
137 while ( !wxTopLevelWindows.empty() )
138 {
139 // do not use Destroy() here as it only puts the TLW in pending list
140 // but we want to delete them now
141 delete wxTopLevelWindows.GetFirst()->GetData();
142 }
143
144 // undo everything we did in Initialize() above
145 wxBitmap::CleanUpHandlers();
146
147 wxStockGDI::DeleteAll();
148
149 wxDeleteStockLists();
150
151 wxDELETE(wxTheColourDatabase);
152
153 wxAppConsole::CleanUp();
154 }
155
156 // ----------------------------------------------------------------------------
157 // various accessors
158 // ----------------------------------------------------------------------------
159
160 wxWindow* wxAppBase::GetTopWindow() const
161 {
162 wxWindow* window = m_topWindow;
163 if (window == NULL && wxTopLevelWindows.GetCount() > 0)
164 window = wxTopLevelWindows.GetFirst()->GetData();
165 return window;
166 }
167
168 wxVideoMode wxAppBase::GetDisplayMode() const
169 {
170 return wxVideoMode();
171 }
172
173 wxLayoutDirection wxAppBase::GetLayoutDirection() const
174 {
175 #if wxUSE_INTL
176 const wxLocale *const locale = wxGetLocale();
177 if ( locale )
178 {
179 const wxLanguageInfo *const
180 info = wxLocale::GetLanguageInfo(locale->GetLanguage());
181
182 if ( info )
183 return info->LayoutDirection;
184 }
185 #endif // wxUSE_INTL
186
187 // we don't know
188 return wxLayout_Default;
189 }
190
191 #if wxUSE_CMDLINE_PARSER
192
193 // ----------------------------------------------------------------------------
194 // GUI-specific command line options handling
195 // ----------------------------------------------------------------------------
196
197 #define OPTION_THEME "theme"
198 #define OPTION_MODE "mode"
199
200 void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser)
201 {
202 // first add the standard non GUI options
203 wxAppConsole::OnInitCmdLine(parser);
204
205 // the standard command line options
206 static const wxCmdLineEntryDesc cmdLineGUIDesc[] =
207 {
208 #ifdef __WXUNIVERSAL__
209 {
210 wxCMD_LINE_OPTION,
211 NULL,
212 OPTION_THEME,
213 gettext_noop("specify the theme to use"),
214 wxCMD_LINE_VAL_STRING,
215 0x0
216 },
217 #endif // __WXUNIVERSAL__
218
219 #if defined(__WXDFB__)
220 // VS: this is not specific to wxDFB, all fullscreen (framebuffer) ports
221 // should provide this option. That's why it is in common/appcmn.cpp
222 // and not dfb/app.cpp
223 {
224 wxCMD_LINE_OPTION,
225 NULL,
226 OPTION_MODE,
227 gettext_noop("specify display mode to use (e.g. 640x480-16)"),
228 wxCMD_LINE_VAL_STRING,
229 0x0
230 },
231 #endif // __WXDFB__
232
233 // terminator
234 wxCMD_LINE_DESC_END
235 };
236
237 parser.SetDesc(cmdLineGUIDesc);
238 }
239
240 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
241 {
242 #ifdef __WXUNIVERSAL__
243 wxString themeName;
244 if ( parser.Found(OPTION_THEME, &themeName) )
245 {
246 wxTheme *theme = wxTheme::Create(themeName);
247 if ( !theme )
248 {
249 wxLogError(_("Unsupported theme '%s'."), themeName.c_str());
250 return false;
251 }
252
253 // Delete the defaultly created theme and set the new theme.
254 delete wxTheme::Get();
255 wxTheme::Set(theme);
256 }
257 #endif // __WXUNIVERSAL__
258
259 #if defined(__WXDFB__)
260 wxString modeDesc;
261 if ( parser.Found(OPTION_MODE, &modeDesc) )
262 {
263 unsigned w, h, bpp;
264 if ( wxSscanf(modeDesc.c_str(), wxT("%ux%u-%u"), &w, &h, &bpp) != 3 )
265 {
266 wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str());
267 return false;
268 }
269
270 if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) )
271 return false;
272 }
273 #endif // __WXDFB__
274
275 return wxAppConsole::OnCmdLineParsed(parser);
276 }
277
278 #endif // wxUSE_CMDLINE_PARSER
279
280 // ----------------------------------------------------------------------------
281 // OnXXX() hooks
282 // ----------------------------------------------------------------------------
283
284 bool wxAppBase::OnInitGui()
285 {
286 #ifdef __WXUNIVERSAL__
287 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
288 return false;
289 #endif // __WXUNIVERSAL__
290
291 return true;
292 }
293
294 int wxAppBase::OnRun()
295 {
296 // see the comment in ctor: if the initial value hasn't been changed, use
297 // the default Yes from now on
298 if ( m_exitOnFrameDelete == Later )
299 {
300 m_exitOnFrameDelete = Yes;
301 }
302 //else: it has been changed, assume the user knows what he is doing
303
304 return wxAppConsole::OnRun();
305 }
306
307 int wxAppBase::OnExit()
308 {
309 #ifdef __WXUNIVERSAL__
310 delete wxTheme::Set(NULL);
311 #endif // __WXUNIVERSAL__
312
313 return wxAppConsole::OnExit();
314 }
315
316 wxAppTraits *wxAppBase::CreateTraits()
317 {
318 return new wxGUIAppTraits;
319 }
320
321 // ----------------------------------------------------------------------------
322 // misc
323 // ----------------------------------------------------------------------------
324
325 void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
326 {
327 if ( active == m_isActive )
328 return;
329
330 m_isActive = active;
331
332 wxActivateEvent event(wxEVT_ACTIVATE_APP, active);
333 event.SetEventObject(this);
334
335 (void)ProcessEvent(event);
336 }
337
338 bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
339 {
340 wxWindowDisabler wd(win);
341
342 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
343
344 return loop && loop->Yield(onlyIfNeeded);
345 }
346
347 bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
348 {
349 wxWindowDisabler wd(win);
350
351 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
352
353 return loop && loop->YieldFor(eventsToProcess);
354 }
355
356
357 // ----------------------------------------------------------------------------
358 // idle handling
359 // ----------------------------------------------------------------------------
360
361 // Returns true if more time is needed.
362 bool wxAppBase::ProcessIdle()
363 {
364 // call the base class version first to send the idle event to wxTheApp
365 // itself
366 bool needMore = wxAppConsoleBase::ProcessIdle();
367 wxIdleEvent event;
368 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
369 while (node)
370 {
371 wxWindow* win = node->GetData();
372
373 // Don't send idle events to the windows that are about to be destroyed
374 // anyhow, this is wasteful and unexpected.
375 if ( !wxPendingDelete.Member(win) && win->SendIdleEvents(event) )
376 needMore = true;
377 node = node->GetNext();
378 }
379
380 wxUpdateUIEvent::ResetUpdateTime();
381
382 return needMore;
383 }
384
385 // ----------------------------------------------------------------------------
386 // wxGUIAppTraitsBase
387 // ----------------------------------------------------------------------------
388
389 #if wxUSE_LOG
390
391 wxLog *wxGUIAppTraitsBase::CreateLogTarget()
392 {
393 #if wxUSE_LOGGUI
394 #ifndef __WXOSX_IPHONE__
395 return new wxLogGui;
396 #else
397 return new wxLogStderr;
398 #endif
399 #else
400 // we must have something!
401 return new wxLogStderr;
402 #endif
403 }
404
405 #endif // wxUSE_LOG
406
407 wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput()
408 {
409 // The standard way of printing help on command line arguments (app --help)
410 // is (according to common practice):
411 // - console apps: to stderr (on any platform)
412 // - GUI apps: stderr on Unix platforms (!)
413 // stderr if available and message box otherwise on others
414 // (currently stderr only Windows if app running from console)
415 #ifdef __UNIX__
416 return new wxMessageOutputStderr;
417 #else // !__UNIX__
418 // wxMessageOutputMessageBox doesn't work under Motif
419 #ifdef __WXMOTIF__
420 return new wxMessageOutputLog;
421 #elif wxUSE_MSGDLG
422 return new wxMessageOutputBest(wxMSGOUT_PREFER_STDERR);
423 #else
424 return new wxMessageOutputStderr;
425 #endif
426 #endif // __UNIX__/!__UNIX__
427 }
428
429 #if wxUSE_FONTMAP
430
431 wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper()
432 {
433 return new wxFontMapper;
434 }
435
436 #endif // wxUSE_FONTMAP
437
438 wxRendererNative *wxGUIAppTraitsBase::CreateRenderer()
439 {
440 // use the default native renderer by default
441 return NULL;
442 }
443
444 bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg)
445 {
446 #if wxDEBUG_LEVEL
447 // under MSW we prefer to use the base class version using ::MessageBox()
448 // even if wxMessageBox() is available because it has less chances to
449 // double fault our app than our wxMessageBox()
450 //
451 // under DFB the message dialog is not always functional right now
452 //
453 // and finally we can't use wxMessageBox() if it wasn't compiled in, of
454 // course
455 #if !defined(__WXMSW__) && !defined(__WXDFB__) && wxUSE_MSGDLG
456
457 // we can't (safely) show the GUI dialog from another thread, only do it
458 // for the asserts in the main thread
459 if ( wxIsMainThread() )
460 {
461 wxString msgDlg = msg;
462
463 #if wxUSE_STACKWALKER
464 const wxString stackTrace = GetAssertStackTrace();
465 if ( !stackTrace.empty() )
466 msgDlg << wxT("\n\nCall stack:\n") << stackTrace;
467 #endif // wxUSE_STACKWALKER
468
469 // this message is intentionally not translated -- it is for
470 // developpers only
471 msgDlg += wxT("\nDo you want to stop the program?\n")
472 wxT("You can also choose [Cancel] to suppress ")
473 wxT("further warnings.");
474
475 switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"),
476 wxYES_NO | wxCANCEL | wxICON_STOP ) )
477 {
478 case wxYES:
479 wxTrap();
480 break;
481
482 case wxCANCEL:
483 // no more asserts
484 return true;
485
486 //case wxNO: nothing to do
487 }
488
489 return false;
490 }
491 #endif // wxUSE_MSGDLG
492 #endif // wxDEBUG_LEVEL
493
494 return wxAppTraitsBase::ShowAssertDialog(msg);
495 }
496
497 bool wxGUIAppTraitsBase::HasStderr()
498 {
499 // we consider that under Unix stderr always goes somewhere, even if the
500 // user doesn't always see it under GUI desktops
501 #ifdef __UNIX__
502 return true;
503 #else
504 return false;
505 #endif
506 }
507