1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/appbase.cpp 
   3 // Purpose:     implements wxAppConsoleBase class 
   4 // Author:      Vadim Zeitlin 
   6 // Created:     19.06.2003 (extracted from common/appcmn.cpp) 
   8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // License:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // for compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29         #include  "wx/msw/wrapwin.h"  // includes windows.h for MessageBox() 
  36     #include "wx/wxcrtvararg.h" 
  39 #include "wx/apptrait.h" 
  40 #include "wx/cmdline.h" 
  41 #include "wx/confbase.h" 
  42 #include "wx/evtloop.h" 
  43 #include "wx/filename.h" 
  44 #include "wx/msgout.h" 
  45 #include "wx/scopedptr.h" 
  46 #include "wx/tokenzr.h" 
  47 #include "wx/thread.h" 
  49 #if wxUSE_EXCEPTIONS && wxUSE_STL 
  55 #if !defined(__WXMSW__) || defined(__WXMICROWIN__) 
  56   #include  <signal.h>      // for SIGTRAP used by wxTrap() 
  60 #endif // ! __WXPALMOS5__ 
  63     #include "wx/fontmap.h" 
  64 #endif // wxUSE_FONTMAP 
  68         #include "wx/stackwalk.h" 
  70             #include "wx/msw/debughlp.h" 
  72     #endif // wxUSE_STACKWALKER 
  74     #include "wx/recguard.h" 
  75 #endif // wxDEBUG_LEVEL 
  77 // wxABI_VERSION can be defined when compiling applications but it should be 
  78 // left undefined when compiling the library itself, it is then set to its 
  79 // default value in version.h 
  80 #if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 
  81 #error "wxABI_VERSION should not be defined when compiling the library" 
  84 // ---------------------------------------------------------------------------- 
  85 // private functions prototypes 
  86 // ---------------------------------------------------------------------------- 
  89     // really just show the assert dialog 
  90     static bool DoShowAssertDialog(const wxString
& msg
); 
  92     // prepare for showing the assert dialog, use the given traits or 
  93     // DoShowAssertDialog() as last fallback to really show it 
  95     void ShowAssertDialog(const wxString
& file
, 
 100                           wxAppTraits 
*traits 
= NULL
); 
 101 #endif // wxDEBUG_LEVEL 
 104     // turn on the trace masks specified in the env variable WXTRACE 
 105     static void LINKAGEMODE 
SetTraceMasks(); 
 106 #endif // __WXDEBUG__ 
 108 // ---------------------------------------------------------------------------- 
 110 // ---------------------------------------------------------------------------- 
 112 wxAppConsole 
*wxAppConsoleBase::ms_appInstance 
= NULL
; 
 114 wxAppInitializerFunction 
wxAppConsoleBase::ms_appInitFn 
= NULL
; 
 116 wxSocketManager 
*wxAppTraitsBase::ms_manager 
= NULL
; 
 118 // ---------------------------------------------------------------------------- 
 120 // ---------------------------------------------------------------------------- 
 122 // this defines wxEventLoopPtr 
 123 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopBase
) 
 125 // ============================================================================ 
 126 // wxAppConsoleBase implementation 
 127 // ============================================================================ 
 129 // ---------------------------------------------------------------------------- 
 131 // ---------------------------------------------------------------------------- 
 133 wxAppConsoleBase::wxAppConsoleBase() 
 137     m_bDoPendingEventProcessing 
= true; 
 139     ms_appInstance 
= static_cast<wxAppConsole 
*>(this); 
 144     // In unicode mode the SetTraceMasks call can cause an apptraits to be 
 145     // created, but since we are still in the constructor the wrong kind will 
 146     // be created for GUI apps.  Destroy it so it can be created again later. 
 153 wxAppConsoleBase::~wxAppConsoleBase() 
 158 // ---------------------------------------------------------------------------- 
 159 // initialization/cleanup 
 160 // ---------------------------------------------------------------------------- 
 162 bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc
), wxChar 
**argv
) 
 165     GetTraits()->SetLocale(); 
 169     if ( m_appName
.empty() && argv 
&& argv
[0] ) 
 171         // the application name is, by default, the name of its executable file 
 172         wxFileName::SplitPath(argv
[0], NULL
, &m_appName
, NULL
); 
 174 #endif // !__WXPALMOS__ 
 179 wxEventLoopBase 
*wxAppConsoleBase::CreateMainLoop() 
 181     return GetTraits()->CreateEventLoop(); 
 184 void wxAppConsoleBase::CleanUp() 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 bool wxAppConsoleBase::OnInit() 
 199 #if wxUSE_CMDLINE_PARSER 
 200     wxCmdLineParser 
parser(argc
, argv
); 
 202     OnInitCmdLine(parser
); 
 205     switch ( parser
.Parse(false /* don't show usage */) ) 
 208             cont 
= OnCmdLineHelp(parser
); 
 212             cont 
= OnCmdLineParsed(parser
); 
 216             cont 
= OnCmdLineError(parser
); 
 222 #endif // wxUSE_CMDLINE_PARSER 
 227 int wxAppConsoleBase::OnRun() 
 232 int wxAppConsoleBase::OnExit() 
 235     // delete the config object if any (don't use Get() here, but Set() 
 236     // because Get() could create a new config object) 
 237     delete wxConfigBase::Set(NULL
); 
 238 #endif // wxUSE_CONFIG 
 243 void wxAppConsoleBase::Exit() 
 245     if (m_mainLoop 
!= NULL
) 
 251 // ---------------------------------------------------------------------------- 
 253 // ---------------------------------------------------------------------------- 
 255 wxAppTraits 
*wxAppConsoleBase::CreateTraits() 
 257     return new wxConsoleAppTraits
; 
 260 wxAppTraits 
*wxAppConsoleBase::GetTraits() 
 262     // FIXME-MT: protect this with a CS? 
 265         m_traits 
= CreateTraits(); 
 267         wxASSERT_MSG( m_traits
, _T("wxApp::CreateTraits() failed?") ); 
 274 wxAppTraits 
*wxAppConsoleBase::GetTraitsIfExists() 
 276     wxAppConsole 
* const app 
= GetInstance(); 
 277     return app 
? app
->GetTraits() : NULL
; 
 280 // ---------------------------------------------------------------------------- 
 281 // wxEventLoop redirection 
 282 // ---------------------------------------------------------------------------- 
 284 int wxAppConsoleBase::MainLoop() 
 286     wxEventLoopBaseTiedPtr 
mainLoop(&m_mainLoop
, CreateMainLoop()); 
 288     return m_mainLoop 
? m_mainLoop
->Run() : -1; 
 291 void wxAppConsoleBase::ExitMainLoop() 
 293     // we should exit from the main event loop, not just any currently active 
 294     // (e.g. modal dialog) event loop 
 295     if ( m_mainLoop 
&& m_mainLoop
->IsRunning() ) 
 301 bool wxAppConsoleBase::Pending() 
 303     // use the currently active message loop here, not m_mainLoop, because if 
 304     // we're showing a modal dialog (with its own event loop) currently the 
 305     // main event loop is not running anyhow 
 306     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 308     return loop 
&& loop
->Pending(); 
 311 bool wxAppConsoleBase::Dispatch() 
 313     // see comment in Pending() 
 314     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 316     return loop 
&& loop
->Dispatch(); 
 319 bool wxAppConsoleBase::Yield(bool onlyIfNeeded
) 
 321     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 323     return loop 
&& loop
->Yield(onlyIfNeeded
); 
 326 void wxAppConsoleBase::WakeUpIdle() 
 328     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 334 bool wxAppConsoleBase::ProcessIdle() 
 336     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 338     return loop 
&& loop
->ProcessIdle(); 
 341 // ---------------------------------------------------------------------------- 
 343 // ---------------------------------------------------------------------------- 
 346 bool wxAppConsoleBase::IsMainLoopRunning() 
 348     const wxAppConsole 
* const app 
= GetInstance(); 
 350     return app 
&& app
->m_mainLoop 
!= NULL
; 
 353 int wxAppConsoleBase::FilterEvent(wxEvent
& WXUNUSED(event
)) 
 355     // process the events normally by default 
 359 void wxAppConsoleBase::DelayPendingEventHandler(wxEvtHandler
* toDelay
) 
 361     wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 363     // move the handler from the list of handlers with processable pending events 
 364     // to the list of handlers with pending events which needs to be processed later 
 365     m_handlersWithPendingEvents
.Remove(toDelay
); 
 367     if (m_handlersWithPendingDelayedEvents
.Index(toDelay
) == wxNOT_FOUND
) 
 368         m_handlersWithPendingDelayedEvents
.Add(toDelay
); 
 370     wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 373 void wxAppConsoleBase::RemovePendingEventHandler(wxEvtHandler
* toRemove
) 
 375     wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 377     if (m_handlersWithPendingEvents
.Index(toRemove
) != wxNOT_FOUND
) 
 379         m_handlersWithPendingEvents
.Remove(toRemove
); 
 381         // check that the handler was present only once in the list 
 382         wxASSERT_MSG( m_handlersWithPendingEvents
.Index(toRemove
) == wxNOT_FOUND
, 
 383                         "Handler occurs twice in the m_handlersWithPendingEvents list!" ); 
 385     //else: it wasn't in this list at all, it's ok 
 387     if (m_handlersWithPendingDelayedEvents
.Index(toRemove
) != wxNOT_FOUND
) 
 389         m_handlersWithPendingDelayedEvents
.Remove(toRemove
); 
 391         // check that the handler was present only once in the list 
 392         wxASSERT_MSG( m_handlersWithPendingDelayedEvents
.Index(toRemove
) == wxNOT_FOUND
, 
 393                         "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" ); 
 395     //else: it wasn't in this list at all, it's ok 
 397     wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 400 void wxAppConsoleBase::AppendPendingEventHandler(wxEvtHandler
* toAppend
) 
 402     wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 404     if ( m_handlersWithPendingEvents
.Index(toAppend
) == wxNOT_FOUND 
) 
 405         m_handlersWithPendingEvents
.Add(toAppend
); 
 407     wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 410 bool wxAppConsoleBase::HasPendingEvents() const 
 412     wxENTER_CRIT_SECT(const_cast<wxAppConsoleBase
*>(this)->m_handlersWithPendingEventsLocker
); 
 414     bool has 
= !m_handlersWithPendingEvents
.IsEmpty(); 
 416     wxLEAVE_CRIT_SECT(const_cast<wxAppConsoleBase
*>(this)->m_handlersWithPendingEventsLocker
); 
 421 void wxAppConsoleBase::SuspendProcessingOfPendingEvents() 
 423     m_bDoPendingEventProcessing 
= false; 
 426 void wxAppConsoleBase::ResumeProcessingOfPendingEvents() 
 428     m_bDoPendingEventProcessing 
= true; 
 431 void wxAppConsoleBase::ProcessPendingEvents() 
 433     if (!m_bDoPendingEventProcessing
) 
 436     wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 438     wxCHECK_RET( m_handlersWithPendingDelayedEvents
.IsEmpty(), 
 439                  "this helper list should be empty" ); 
 441     // iterate until the list becomes empty: the handlers remove themselves 
 442     // from it when they don't have any more pending events 
 443     while (!m_handlersWithPendingEvents
.IsEmpty()) 
 445         // In ProcessPendingEvents(), new handlers might be added 
 446         // and we can safely leave the critical section here. 
 447         wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 449         // NOTE: we always call ProcessPendingEvents() on the first event handler 
 450         //       with pending events because handlers auto-remove themselves 
 451         //       from this list (see RemovePendingEventHandler) if they have no 
 452         //       more pending events. 
 453         m_handlersWithPendingEvents
[0]->ProcessPendingEvents(); 
 455         wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 458     // now the wxHandlersWithPendingEvents is surely empty; however some event 
 459     // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents 
 460     // because of a selective wxYield call in progress. 
 461     // Now we need to move them back to wxHandlersWithPendingEvents so the next 
 462     // call to this function has the chance of processing them: 
 463     if (!m_handlersWithPendingDelayedEvents
.IsEmpty()) 
 465         WX_APPEND_ARRAY(m_handlersWithPendingEvents
, m_handlersWithPendingDelayedEvents
); 
 466         m_handlersWithPendingDelayedEvents
.Clear(); 
 469     wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 472 void wxAppConsoleBase::DeletePendingEvents() 
 474     wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 476     wxCHECK_RET( m_handlersWithPendingDelayedEvents
.IsEmpty(), 
 477                  "this helper list should be empty" ); 
 479     for (unsigned int i
=0; i
<m_handlersWithPendingEvents
.GetCount(); i
++) 
 480         m_handlersWithPendingEvents
[i
]->DeletePendingEvents(); 
 482     m_handlersWithPendingEvents
.Clear(); 
 484     wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
); 
 487 // ---------------------------------------------------------------------------- 
 488 // exception handling 
 489 // ---------------------------------------------------------------------------- 
 494 wxAppConsoleBase::HandleEvent(wxEvtHandler 
*handler
, 
 495                               wxEventFunction func
, 
 496                               wxEvent
& event
) const 
 498     // by default, simply call the handler 
 499     (handler
->*func
)(event
); 
 502 void wxAppConsoleBase::CallEventHandler(wxEvtHandler 
*handler
, 
 503                                         wxEventFunctor
& functor
, 
 504                                         wxEvent
& event
) const 
 506     // If the functor holds a method then, for backward compatibility, call 
 508     wxEventFunction eventFunction 
= functor
.GetEvtMethod(); 
 511         HandleEvent(handler
, eventFunction
, event
); 
 513         functor(handler
, event
); 
 516 void wxAppConsoleBase::OnUnhandledException() 
 519     // we're called from an exception handler so we can re-throw the exception 
 520     // to recover its type 
 527     catch ( std::exception
& e 
) 
 529         what
.Printf("std::exception of type \"%s\", what() = \"%s\"", 
 530                     typeid(e
).name(), e
.what()); 
 535         what 
= "unknown exception"; 
 538     wxMessageOutputBest().Printf( 
 539         "*** Caught unhandled %s; terminating\n", what
 
 541 #endif // __WXDEBUG__ 
 544 // ---------------------------------------------------------------------------- 
 545 // exceptions support 
 546 // ---------------------------------------------------------------------------- 
 548 bool wxAppConsoleBase::OnExceptionInMainLoop() 
 552     // some compilers are too stupid to know that we never return after throw 
 553 #if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) 
 558 #endif // wxUSE_EXCEPTIONS 
 560 // ---------------------------------------------------------------------------- 
 562 // ---------------------------------------------------------------------------- 
 564 #if wxUSE_CMDLINE_PARSER 
 566 #define OPTION_VERBOSE "verbose" 
 568 void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser
& parser
) 
 570     // the standard command line options 
 571     static const wxCmdLineEntryDesc cmdLineDesc
[] = 
 577             gettext_noop("show this help message"), 
 579             wxCMD_LINE_OPTION_HELP
 
 587             gettext_noop("generate verbose log messages"), 
 597     parser
.SetDesc(cmdLineDesc
); 
 600 bool wxAppConsoleBase::OnCmdLineParsed(wxCmdLineParser
& parser
) 
 603     if ( parser
.Found(OPTION_VERBOSE
) ) 
 605         wxLog::SetVerbose(true); 
 614 bool wxAppConsoleBase::OnCmdLineHelp(wxCmdLineParser
& parser
) 
 621 bool wxAppConsoleBase::OnCmdLineError(wxCmdLineParser
& parser
) 
 628 #endif // wxUSE_CMDLINE_PARSER 
 630 // ---------------------------------------------------------------------------- 
 632 // ---------------------------------------------------------------------------- 
 635 bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature
, 
 636                                          const char *componentName
) 
 638 #if 0 // can't use wxLogTrace, not up and running yet 
 639     printf("checking build options object '%s' (ptr %p) in '%s'\n", 
 640              optionsSignature
, optionsSignature
, componentName
); 
 643     if ( strcmp(optionsSignature
, WX_BUILD_OPTIONS_SIGNATURE
) != 0 ) 
 645         wxString lib 
= wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE
); 
 646         wxString prog 
= wxString::FromAscii(optionsSignature
); 
 647         wxString progName 
= wxString::FromAscii(componentName
); 
 650         msg
.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), 
 651                    lib
.c_str(), progName
.c_str(), prog
.c_str()); 
 653         wxLogFatalError(msg
.c_str()); 
 655         // normally wxLogFatalError doesn't return 
 662 void wxAppConsoleBase::OnAssertFailure(const wxChar 
*file
, 
 669     ShowAssertDialog(file
, line
, func
, cond
, msg
, GetTraits()); 
 671     // this function is still present even in debug level 0 build for ABI 
 672     // compatibility reasons but is never called there and so can simply do 
 679 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL 
 682 void wxAppConsoleBase::OnAssert(const wxChar 
*file
, 
 687     OnAssertFailure(file
, line
, NULL
, cond
, msg
); 
 690 // ============================================================================ 
 691 // other classes implementations 
 692 // ============================================================================ 
 694 // ---------------------------------------------------------------------------- 
 695 // wxConsoleAppTraitsBase 
 696 // ---------------------------------------------------------------------------- 
 700 wxLog 
*wxConsoleAppTraitsBase::CreateLogTarget() 
 702     return new wxLogStderr
; 
 707 wxMessageOutput 
*wxConsoleAppTraitsBase::CreateMessageOutput() 
 709     return new wxMessageOutputStderr
; 
 714 wxFontMapper 
*wxConsoleAppTraitsBase::CreateFontMapper() 
 716     return (wxFontMapper 
*)new wxFontMapperBase
; 
 719 #endif // wxUSE_FONTMAP 
 721 wxRendererNative 
*wxConsoleAppTraitsBase::CreateRenderer() 
 723     // console applications don't use renderers 
 727 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString
& msg
) 
 729     return wxAppTraitsBase::ShowAssertDialog(msg
); 
 732 bool wxConsoleAppTraitsBase::HasStderr() 
 734     // console applications always have stderr, even under Mac/Windows 
 738 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject 
*object
) 
 743 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject 
* WXUNUSED(object
)) 
 748 // ---------------------------------------------------------------------------- 
 750 // ---------------------------------------------------------------------------- 
 753 void wxAppTraitsBase::SetLocale() 
 755     wxSetlocale(LC_ALL
, ""); 
 756     wxUpdateLocaleIsUtf8(); 
 761 void wxMutexGuiEnterImpl(); 
 762 void wxMutexGuiLeaveImpl(); 
 764 void wxAppTraitsBase::MutexGuiEnter() 
 766     wxMutexGuiEnterImpl(); 
 769 void wxAppTraitsBase::MutexGuiLeave() 
 771     wxMutexGuiLeaveImpl(); 
 774 void WXDLLIMPEXP_BASE 
wxMutexGuiEnter() 
 776     wxAppTraits 
* const traits 
= wxAppConsoleBase::GetTraitsIfExists(); 
 778         traits
->MutexGuiEnter(); 
 781 void WXDLLIMPEXP_BASE 
wxMutexGuiLeave() 
 783     wxAppTraits 
* const traits 
= wxAppConsoleBase::GetTraitsIfExists(); 
 785         traits
->MutexGuiLeave(); 
 787 #endif // wxUSE_THREADS 
 789 bool wxAppTraitsBase::ShowAssertDialog(const wxString
& msgOriginal
) 
 792     wxString msg 
= msgOriginal
; 
 794 #if wxUSE_STACKWALKER 
 795 #if !defined(__WXMSW__) 
 796     // on Unix stack frame generation may take some time, depending on the 
 797     // size of the executable mainly... warn the user that we are working 
 798     wxFprintf(stderr
, wxT("[Debug] Generating a stack trace... please wait")); 
 802     const wxString stackTrace 
= GetAssertStackTrace(); 
 803     if ( !stackTrace
.empty() ) 
 804         msg 
<< _T("\n\nCall stack:\n") << stackTrace
; 
 805 #endif // wxUSE_STACKWALKER 
 807     return DoShowAssertDialog(msg
); 
 808 #else // !wxDEBUG_LEVEL 
 809     wxUnusedVar(msgOriginal
); 
 812 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL 
 815 #if wxUSE_STACKWALKER 
 816 wxString 
wxAppTraitsBase::GetAssertStackTrace() 
 821     class StackDump 
: public wxStackWalker
 
 826         const wxString
& GetStackTrace() const { return m_stackTrace
; } 
 829         virtual void OnStackFrame(const wxStackFrame
& frame
) 
 831             m_stackTrace 
<< wxString::Format
 
 834                               wx_truncate_cast(int, frame
.GetLevel()) 
 837             wxString name 
= frame
.GetName(); 
 840                 m_stackTrace 
<< wxString::Format(_T("%-40s"), name
.c_str()); 
 844                 m_stackTrace 
<< wxString::Format(_T("%p"), frame
.GetAddress()); 
 847             if ( frame
.HasSourceLocation() ) 
 849                 m_stackTrace 
<< _T('\t') 
 850                              << frame
.GetFileName() 
 855             m_stackTrace 
<< _T('\n'); 
 859         wxString m_stackTrace
; 
 862     // don't show more than maxLines or we could get a dialog too tall to be 
 863     // shown on screen: 20 should be ok everywhere as even with 15 pixel high 
 864     // characters it is still only 300 pixels... 
 865     static const int maxLines 
= 20; 
 868     dump
.Walk(2, maxLines
); // don't show OnAssert() call itself 
 869     stackTrace 
= dump
.GetStackTrace(); 
 871     const int count 
= stackTrace
.Freq(wxT('\n')); 
 872     for ( int i 
= 0; i 
< count 
- maxLines
; i
++ ) 
 873         stackTrace 
= stackTrace
.BeforeLast(wxT('\n')); 
 876 #else // !wxDEBUG_LEVEL 
 877     // this function is still present for ABI-compatibility even in debug level 
 878     // 0 build but is not used there and so can simply do nothing 
 880 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL 
 882 #endif // wxUSE_STACKWALKER 
 885 // ============================================================================ 
 886 // global functions implementation 
 887 // ============================================================================ 
 897         // what else can we do? 
 906         wxTheApp
->WakeUpIdle(); 
 908     //else: do nothing, what can we do? 
 912 bool wxAssertIsEqual(int x
, int y
) 
 919 // break into the debugger 
 922 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 924 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS 
 926 #elif defined(__UNIX__) 
 933 // default assert handler 
 935 wxDefaultAssertHandler(const wxString
& file
, 
 937                        const wxString
& func
, 
 938                        const wxString
& cond
, 
 942     static int s_bInAssert 
= 0; 
 944     wxRecursionGuard 
guard(s_bInAssert
); 
 945     if ( guard
.IsInside() ) 
 947         // can't use assert here to avoid infinite loops, so just trap 
 955         // by default, show the assert dialog box -- we can't customize this 
 957         ShowAssertDialog(file
, line
, func
, cond
, msg
); 
 961         // let the app process it as it wants 
 962         // FIXME-UTF8: use wc_str(), not c_str(), when ANSI build is removed 
 963         wxTheApp
->OnAssertFailure(file
.c_str(), line
, func
.c_str(), 
 964                                   cond
.c_str(), msg
.c_str()); 
 968 wxAssertHandler_t wxTheAssertHandler 
= wxDefaultAssertHandler
; 
 970 void wxOnAssert(const wxString
& file
, 
 972                 const wxString
& func
, 
 973                 const wxString
& cond
, 
 976     wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
 979 void wxOnAssert(const wxString
& file
, 
 981                 const wxString
& func
, 
 982                 const wxString
& cond
) 
 984     wxTheAssertHandler(file
, line
, func
, cond
, wxString()); 
 987 void wxOnAssert(const wxChar 
*file
, 
 993     // this is the backwards-compatible version (unless we don't use Unicode) 
 994     // so it could be called directly from the user code and this might happen 
 995     // even when wxTheAssertHandler is NULL 
 997     if ( wxTheAssertHandler 
) 
 998 #endif // wxUSE_UNICODE 
 999         wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
1002 void wxOnAssert(const char *file
, 
1006                 const wxString
& msg
) 
1008     wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
1011 void wxOnAssert(const char *file
, 
1015                 const wxCStrData
& msg
) 
1017     wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
1021 void wxOnAssert(const char *file
, 
1026     wxTheAssertHandler(file
, line
, func
, cond
, wxString()); 
1029 void wxOnAssert(const char *file
, 
1035     wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
1038 void wxOnAssert(const char *file
, 
1044     wxTheAssertHandler(file
, line
, func
, cond
, msg
); 
1046 #endif // wxUSE_UNICODE 
1048 #endif // wxDEBUG_LEVEL 
1050 // ============================================================================ 
1051 // private functions implementation 
1052 // ============================================================================ 
1056 static void LINKAGEMODE 
SetTraceMasks() 
1060     if ( wxGetEnv(wxT("WXTRACE"), &mask
) ) 
1062         wxStringTokenizer 
tkn(mask
, wxT(",;:")); 
1063         while ( tkn
.HasMoreTokens() ) 
1064             wxLog::AddTraceMask(tkn
.GetNextToken()); 
1069 #endif // __WXDEBUG__ 
1074 bool DoShowAssertDialog(const wxString
& msg
) 
1076     // under MSW we can show the dialog even in the console mode 
1077 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
1078     wxString 
msgDlg(msg
); 
1080     // this message is intentionally not translated -- it is for developers 
1081     // only -- and the less code we use here, less is the danger of recursively 
1082     // asserting and dying 
1083     msgDlg 
+= wxT("\nDo you want to stop the program?\n") 
1084               wxT("You can also choose [Cancel] to suppress ") 
1085               wxT("further warnings."); 
1087     switch ( ::MessageBox(NULL
, msgDlg
.wx_str(), _T("wxWidgets Debug Alert"), 
1088                           MB_YESNOCANCEL 
| MB_ICONSTOP 
) ) 
1098         //case IDNO: nothing to do 
1101     wxFprintf(stderr
, wxT("%s\n"), msg
.c_str()); 
1104     // TODO: ask the user to enter "Y" or "N" on the console? 
1106 #endif // __WXMSW__/!__WXMSW__ 
1108     // continue with the asserts 
1112 // show the standard assert dialog 
1114 void ShowAssertDialog(const wxString
& file
, 
1116                       const wxString
& func
, 
1117                       const wxString
& cond
, 
1118                       const wxString
& msgUser
, 
1119                       wxAppTraits 
*traits
) 
1121     // this variable can be set to true to suppress "assert failure" messages 
1122     static bool s_bNoAsserts 
= false; 
1127     // make life easier for people using VC++ IDE by using this format: like 
1128     // this, clicking on the message will take us immediately to the place of 
1129     // the failed assert 
1130     msg
.Printf(wxT("%s(%d): assert \"%s\" failed"), file
, line
, cond
); 
1132     // add the function name, if any 
1133     if ( !func
.empty() ) 
1134         msg 
<< _T(" in ") << func 
<< _T("()"); 
1136     // and the message itself 
1137     if ( !msgUser
.empty() ) 
1139         msg 
<< _T(": ") << msgUser
; 
1141     else // no message given 
1147     // if we are not in the main thread, output the assert directly and trap 
1148     // since dialogs cannot be displayed 
1149     if ( !wxThread::IsMain() ) 
1151         msg 
+= wxT(" [in child thread]"); 
1153 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
1155         OutputDebugString(msg
.wx_str()); 
1158         wxFprintf(stderr
, wxT("%s\n"), msg
.c_str()); 
1161         // He-e-e-e-elp!! we're asserting in a child thread 
1165 #endif // wxUSE_THREADS 
1167     if ( !s_bNoAsserts 
) 
1169         // send it to the normal log destination 
1170         wxLogDebug(_T("%s"), msg
.c_str()); 
1174             // delegate showing assert dialog (if possible) to that class 
1175             s_bNoAsserts 
= traits
->ShowAssertDialog(msg
); 
1177         else // no traits object 
1179             // fall back to the function of last resort 
1180             s_bNoAsserts 
= DoShowAssertDialog(msg
); 
1185 #endif // wxDEBUG_LEVEL