]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/appcmn.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / common / appcmn.cpp
... / ...
CommitLineData
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"
50WX_CHECK_BUILD_OPTIONS("wxCore")
51
52// ============================================================================
53// wxAppBase implementation
54// ============================================================================
55
56// ----------------------------------------------------------------------------
57// initialization
58// ----------------------------------------------------------------------------
59
60wxAppBase::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
84bool 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
125wxAppBase::~wxAppBase()
126{
127 // this destructor is required for Darwin
128}
129
130void 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
160wxWindow* 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
168wxVideoMode wxAppBase::GetDisplayMode() const
169{
170 return wxVideoMode();
171}
172
173wxLayoutDirection 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
200void 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
240bool 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
284bool wxAppBase::OnInitGui()
285{
286#ifdef __WXUNIVERSAL__
287 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
288 return false;
289#endif // __WXUNIVERSAL__
290
291 return true;
292}
293
294int 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
307int wxAppBase::OnExit()
308{
309#ifdef __WXUNIVERSAL__
310 delete wxTheme::Set(NULL);
311#endif // __WXUNIVERSAL__
312
313 return wxAppConsole::OnExit();
314}
315
316wxAppTraits *wxAppBase::CreateTraits()
317{
318 return new wxGUIAppTraits;
319}
320
321// ----------------------------------------------------------------------------
322// misc
323// ----------------------------------------------------------------------------
324
325void 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
338bool 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
347bool 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.
362bool 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
391wxLog *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
407wxMessageOutput *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
431wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper()
432{
433 return new wxFontMapper;
434}
435
436#endif // wxUSE_FONTMAP
437
438wxRendererNative *wxGUIAppTraitsBase::CreateRenderer()
439{
440 // use the default native renderer by default
441 return NULL;
442}
443
444bool 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
497bool 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