1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        common/base/appbase.cpp 
   3 // Purpose:     implements wxAppConsole 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" 
  35 #include "wx/apptrait.h" 
  36 #include "wx/cmdline.h" 
  37 #include "wx/confbase.h" 
  38 #include "wx/filename.h" 
  39 #include "wx/msgout.h" 
  40 #include "wx/tokenzr.h" 
  42 #if !defined(__WXMSW__) || defined(__WXMICROWIN__) 
  43   #include  <signal.h>      // for SIGTRAP used by wxTrap() 
  46 #if defined(__WXMSW__) 
  47   #include  "wx/msw/wrapwin.h"  // includes windows.h for MessageBox() 
  51     #include "wx/fontmap.h" 
  52 #endif // wxUSE_FONTMAP 
  54 #if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS 
  55     // For MacTypes.h for Debugger function 
  56     #include <CoreFoundation/CFBase.h> 
  59 #if defined(__WXMAC__) 
  60     // VZ: MacTypes.h is enough under Mac OS X (where I could test it) but 
  61     //     I don't know which headers are needed under earlier systems so 
  62     //     include everything when in doubt 
  66         #include  "wx/mac/private.h"  // includes mac headers 
  72         #include "wx/stackwalk.h" 
  74             #include "wx/msw/debughlp.h" 
  76     #endif // wxUSE_STACKWALKER 
  79 // ---------------------------------------------------------------------------- 
  80 // private functions prototypes 
  81 // ---------------------------------------------------------------------------- 
  84     // really just show the assert dialog 
  85     static bool DoShowAssertDialog(const wxString
& msg
); 
  87     // prepare for showing the assert dialog, use the given traits or 
  88     // DoShowAssertDialog() as last fallback to really show it 
  90     void ShowAssertDialog(const wxChar 
*szFile
, 
  94                           wxAppTraits 
*traits 
= NULL
); 
  96     // turn on the trace masks specified in the env variable WXTRACE 
  97     static void LINKAGEMODE 
SetTraceMasks(); 
 100 // ---------------------------------------------------------------------------- 
 102 // ---------------------------------------------------------------------------- 
 104 wxAppConsole 
*wxAppConsole::ms_appInstance 
= NULL
; 
 106 wxAppInitializerFunction 
wxAppConsole::ms_appInitFn 
= NULL
; 
 108 // ============================================================================ 
 109 // wxAppConsole implementation 
 110 // ============================================================================ 
 112 // ---------------------------------------------------------------------------- 
 114 // ---------------------------------------------------------------------------- 
 116 wxAppConsole::wxAppConsole() 
 120     ms_appInstance 
= this; 
 125     // In unicode mode the SetTraceMasks call can cause an apptraits to be 
 126     // created, but since we are still in the constructor the wrong kind will 
 127     // be created for GUI apps.  Destroy it so it can be created again later. 
 134 wxAppConsole::~wxAppConsole() 
 139 // ---------------------------------------------------------------------------- 
 140 // initilization/cleanup 
 141 // ---------------------------------------------------------------------------- 
 143 bool wxAppConsole::Initialize(int& argc
, wxChar 
**argv
) 
 145     // remember the command line arguments 
 150     if ( m_appName
.empty() && argv 
) 
 152         // the application name is, by default, the name of its executable file 
 153         wxFileName::SplitPath(argv
[0], NULL
, &m_appName
, NULL
); 
 160 void wxAppConsole::CleanUp() 
 164 // ---------------------------------------------------------------------------- 
 166 // ---------------------------------------------------------------------------- 
 168 bool wxAppConsole::OnInit() 
 170 #if wxUSE_CMDLINE_PARSER 
 171     wxCmdLineParser 
parser(argc
, argv
); 
 173     OnInitCmdLine(parser
); 
 176     switch ( parser
.Parse(false /* don't show usage */) ) 
 179             cont 
= OnCmdLineHelp(parser
); 
 183             cont 
= OnCmdLineParsed(parser
); 
 187             cont 
= OnCmdLineError(parser
); 
 193 #endif // wxUSE_CMDLINE_PARSER 
 198 int wxAppConsole::OnExit() 
 201     // delete the config object if any (don't use Get() here, but Set() 
 202     // because Get() could create a new config object) 
 203     delete wxConfigBase::Set((wxConfigBase 
*) NULL
); 
 204 #endif // wxUSE_CONFIG 
 206     // use Set(NULL) and not Get() to avoid creating a message output object on 
 207     // demand when we just want to delete it 
 208     delete wxMessageOutput::Set(NULL
); 
 213 void wxAppConsole::Exit() 
 218 // ---------------------------------------------------------------------------- 
 220 // ---------------------------------------------------------------------------- 
 222 wxAppTraits 
*wxAppConsole::CreateTraits() 
 224     return new wxConsoleAppTraits
; 
 227 wxAppTraits 
*wxAppConsole::GetTraits() 
 229     // FIXME-MT: protect this with a CS? 
 232         m_traits 
= CreateTraits(); 
 234         wxASSERT_MSG( m_traits
, _T("wxApp::CreateTraits() failed?") ); 
 240 // we must implement CreateXXX() in wxApp itself for backwards compatibility 
 241 #if WXWIN_COMPATIBILITY_2_4 
 245 wxLog 
*wxAppConsole::CreateLogTarget() 
 247     wxAppTraits 
*traits 
= GetTraits(); 
 248     return traits 
? traits
->CreateLogTarget() : NULL
; 
 253 wxMessageOutput 
*wxAppConsole::CreateMessageOutput() 
 255     wxAppTraits 
*traits 
= GetTraits(); 
 256     return traits 
? traits
->CreateMessageOutput() : NULL
; 
 259 #endif // WXWIN_COMPATIBILITY_2_4 
 261 // ---------------------------------------------------------------------------- 
 263 // ---------------------------------------------------------------------------- 
 265 void wxAppConsole::ProcessPendingEvents() 
 268     if ( !wxPendingEventsLocker 
) 
 272     // ensure that we're the only thread to modify the pending events list 
 273     wxENTER_CRIT_SECT( *wxPendingEventsLocker 
); 
 275     if ( !wxPendingEvents 
) 
 277         wxLEAVE_CRIT_SECT( *wxPendingEventsLocker 
); 
 281     // iterate until the list becomes empty 
 282     wxList::compatibility_iterator node 
= wxPendingEvents
->GetFirst(); 
 285         wxEvtHandler 
*handler 
= (wxEvtHandler 
*)node
->GetData(); 
 286         wxPendingEvents
->Erase(node
); 
 288         // In ProcessPendingEvents(), new handlers might be add 
 289         // and we can safely leave the critical section here. 
 290         wxLEAVE_CRIT_SECT( *wxPendingEventsLocker 
); 
 292         handler
->ProcessPendingEvents(); 
 294         wxENTER_CRIT_SECT( *wxPendingEventsLocker 
); 
 296         node 
= wxPendingEvents
->GetFirst(); 
 299     wxLEAVE_CRIT_SECT( *wxPendingEventsLocker 
); 
 302 int wxAppConsole::FilterEvent(wxEvent
& WXUNUSED(event
)) 
 304     // process the events normally by default 
 308 // ---------------------------------------------------------------------------- 
 309 // exception handling 
 310 // ---------------------------------------------------------------------------- 
 315 wxAppConsole::HandleEvent(wxEvtHandler 
*handler
, 
 316                           wxEventFunction func
, 
 317                           wxEvent
& event
) const 
 319     // by default, simply call the handler 
 320     (handler
->*func
)(event
); 
 324 wxAppConsole::OnExceptionInMainLoop() 
 328     // some compilers are too stupid to know that we never return after throw 
 329 #if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) 
 334 #endif // wxUSE_EXCEPTIONS 
 336 // ---------------------------------------------------------------------------- 
 338 // ---------------------------------------------------------------------------- 
 340 #if wxUSE_CMDLINE_PARSER 
 342 #define OPTION_VERBOSE _T("verbose") 
 344 void wxAppConsole::OnInitCmdLine(wxCmdLineParser
& parser
) 
 346     // the standard command line options 
 347     static const wxCmdLineEntryDesc cmdLineDesc
[] = 
 353             gettext_noop("show this help message"), 
 355             wxCMD_LINE_OPTION_HELP
 
 363             gettext_noop("generate verbose log messages"), 
 380     parser
.SetDesc(cmdLineDesc
); 
 383 bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser
& parser
) 
 386     if ( parser
.Found(OPTION_VERBOSE
) ) 
 388         wxLog::SetVerbose(true); 
 397 bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser
& parser
) 
 404 bool wxAppConsole::OnCmdLineError(wxCmdLineParser
& parser
) 
 411 #endif // wxUSE_CMDLINE_PARSER 
 413 // ---------------------------------------------------------------------------- 
 415 // ---------------------------------------------------------------------------- 
 418 bool wxAppConsole::CheckBuildOptions(const char *optionsSignature
, 
 419                                      const char *componentName
) 
 421 #if 0 // can't use wxLogTrace, not up and running yet 
 422     printf("checking build options object '%s' (ptr %p) in '%s'\n", 
 423              optionsSignature
, optionsSignature
, componentName
); 
 426     if ( strcmp(optionsSignature
, WX_BUILD_OPTIONS_SIGNATURE
) != 0 ) 
 428         wxString lib 
= wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE
); 
 429         wxString prog 
= wxString::FromAscii(optionsSignature
); 
 430         wxString progName 
= wxString::FromAscii(componentName
); 
 433         msg
.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), 
 434                    lib
.c_str(), progName
.c_str(), prog
.c_str()); 
 436         wxLogFatalError(msg
.c_str()); 
 438         // normally wxLogFatalError doesn't return 
 448 void wxAppConsole::OnAssert(const wxChar 
*file
, 
 453     ShowAssertDialog(file
, line
, cond
, msg
, GetTraits()); 
 456 #endif // __WXDEBUG__ 
 458 #if WXWIN_COMPATIBILITY_2_4 
 460 bool wxAppConsole::CheckBuildOptions(const wxBuildOptions
& buildOptions
) 
 462     return CheckBuildOptions(buildOptions
.m_signature
, "your program"); 
 467 // ============================================================================ 
 468 // other classes implementations 
 469 // ============================================================================ 
 471 // ---------------------------------------------------------------------------- 
 472 // wxConsoleAppTraitsBase 
 473 // ---------------------------------------------------------------------------- 
 477 wxLog 
*wxConsoleAppTraitsBase::CreateLogTarget() 
 479     return new wxLogStderr
; 
 484 wxMessageOutput 
*wxConsoleAppTraitsBase::CreateMessageOutput() 
 486     return new wxMessageOutputStderr
; 
 491 wxFontMapper 
*wxConsoleAppTraitsBase::CreateFontMapper() 
 493     return (wxFontMapper 
*)new wxFontMapperBase
; 
 496 #endif // wxUSE_FONTMAP 
 498 wxRendererNative 
*wxConsoleAppTraitsBase::CreateRenderer() 
 500     // console applications don't use renderers 
 505 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString
& msg
) 
 507     return wxAppTraitsBase::ShowAssertDialog(msg
); 
 511 bool wxConsoleAppTraitsBase::HasStderr() 
 513     // console applications always have stderr, even under Mac/Windows 
 517 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject 
*object
) 
 522 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject 
* WXUNUSED(object
)) 
 528 GSocketGUIFunctionsTable
* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() 
 534 // ---------------------------------------------------------------------------- 
 536 // ---------------------------------------------------------------------------- 
 540 bool wxAppTraitsBase::ShowAssertDialog(const wxString
& msg
) 
 542     return DoShowAssertDialog(msg
); 
 545 #endif // __WXDEBUG__ 
 547 // ============================================================================ 
 548 // global functions implementation 
 549 // ============================================================================ 
 559         // what else can we do? 
 568         wxTheApp
->WakeUpIdle(); 
 570     //else: do nothing, what can we do? 
 576 bool wxAssertIsEqual(int x
, int y
) 
 581 // break into the debugger 
 584 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 586 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
 592 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS 
 594 #elif defined(__UNIX__) 
 601 void wxAssert(int cond
, 
 602               const wxChar 
*szFile
, 
 604               const wxChar 
*szCond
, 
 608         wxOnAssert(szFile
, nLine
, szCond
, szMsg
); 
 611 // this function is called when an assert fails 
 612 void wxOnAssert(const wxChar 
*szFile
, 
 614                 const wxChar 
*szCond
, 
 618     static bool s_bInAssert 
= false; 
 622         // He-e-e-e-elp!! we're trapped in endless loop 
 634         // by default, show the assert dialog box -- we can't customize this 
 636         ShowAssertDialog(szFile
, nLine
, szCond
, szMsg
); 
 640         // let the app process it as it wants 
 641         wxTheApp
->OnAssert(szFile
, nLine
, szCond
, szMsg
); 
 647 #endif // __WXDEBUG__ 
 649 // ============================================================================ 
 650 // private functions implementation 
 651 // ============================================================================ 
 655 static void LINKAGEMODE 
SetTraceMasks() 
 659     if ( wxGetEnv(wxT("WXTRACE"), &mask
) ) 
 661         wxStringTokenizer 
tkn(mask
, wxT(",;:")); 
 662         while ( tkn
.HasMoreTokens() ) 
 663             wxLog::AddTraceMask(tkn
.GetNextToken()); 
 668 bool DoShowAssertDialog(const wxString
& msg
) 
 670     // under MSW we can show the dialog even in the console mode 
 671 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 672     wxString 
msgDlg(msg
); 
 674     // this message is intentionally not translated -- it is for 
 676     msgDlg 
+= wxT("\nDo you want to stop the program?\n") 
 677               wxT("You can also choose [Cancel] to suppress ") 
 678               wxT("further warnings."); 
 680     switch ( ::MessageBox(NULL
, msgDlg
, _T("wxWidgets Debug Alert"), 
 681                           MB_YESNOCANCEL 
| MB_ICONSTOP 
) ) 
 691         //case IDNO: nothing to do 
 694     wxFprintf(stderr
, wxT("%s\n"), msg
.c_str()); 
 697     // TODO: ask the user to enter "Y" or "N" on the console? 
 699 #endif // __WXMSW__/!__WXMSW__ 
 701     // continue with the asserts 
 705 #if wxUSE_STACKWALKER 
 706 static wxString 
GetAssertStackTrace() 
 711     // check that we can get the stack trace before trying to do it 
 712     if ( !wxDbgHelpDLL::Init() ) 
 716     class StackDump 
: public wxStackWalker
 
 721         const wxString
& GetStackTrace() const { return m_stackTrace
; } 
 724         virtual void OnStackFrame(const wxStackFrame
& frame
) 
 726             m_stackTrace 
<< wxString::Format(_T("[%02d] "), frame
.GetLevel()); 
 728             wxString name 
= frame
.GetName(); 
 731                 m_stackTrace 
<< wxString::Format(_T("%-40s"), name
.c_str()); 
 735                 m_stackTrace 
<< wxString::Format
 
 738                                     (unsigned long)frame
.GetAddress() 
 742             if ( frame
.HasSourceLocation() ) 
 744                 m_stackTrace 
<< _T('\t') 
 745                              << frame
.GetFileName() 
 750             m_stackTrace 
<< _T('\n'); 
 754         wxString m_stackTrace
; 
 758     dump
.Walk(5); // don't show OnAssert() call itself 
 759     stackTrace 
= dump
.GetStackTrace(); 
 761     // don't show more than maxLines or we could get a dialog too tall to be 
 762     // shown on screen: 20 should be ok everywhere as even with 15 pixel high 
 763     // characters it is still only 300 pixels... 
 764     static const int maxLines 
= 20; 
 765     const int count 
= stackTrace
.Freq(wxT('\n')); 
 766     for ( int i 
= 0; i 
< count 
- maxLines
; i
++ ) 
 767         stackTrace 
= stackTrace
.BeforeLast(wxT('\n')); 
 771 #endif // wxUSE_STACKWALKER 
 773 // show the assert modal dialog 
 775 void ShowAssertDialog(const wxChar 
*szFile
, 
 777                       const wxChar 
*szCond
, 
 781     // this variable can be set to true to suppress "assert failure" messages 
 782     static bool s_bNoAsserts 
= false; 
 787     // make life easier for people using VC++ IDE by using this format: like 
 788     // this, clicking on the message will take us immediately to the place of 
 790     msg
.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile
, nLine
, szCond
); 
 794         msg 
<< _T(": ") << szMsg
; 
 796     else // no message given 
 801 #if wxUSE_STACKWALKER 
 802     const wxString stackTrace 
= GetAssertStackTrace(); 
 803     if ( !stackTrace
.empty() ) 
 805         msg 
<< _T("\n\nCall stack:\n") << stackTrace
; 
 807 #endif // wxUSE_STACKWALKER 
 810     // if we are not in the main thread, output the assert directly and trap 
 811     // since dialogs cannot be displayed 
 812     if ( !wxThread::IsMain() ) 
 814         msg 
+= wxT(" [in child thread]"); 
 816 #if defined(__WXMSW__) && !defined(__WXMICROWIN__) 
 818         OutputDebugString(msg 
); 
 821         wxFprintf(stderr
, wxT("%s\n"), msg
.c_str()); 
 824         // He-e-e-e-elp!! we're asserting in a child thread 
 828 #endif // wxUSE_THREADS 
 832         // send it to the normal log destination 
 833         wxLogDebug(_T("%s"), msg
.c_str()); 
 837             // delegate showing assert dialog (if possible) to that class 
 838             s_bNoAsserts 
= traits
->ShowAssertDialog(msg
); 
 840         else // no traits object 
 842             // fall back to the function of last resort 
 843             s_bNoAsserts 
= DoShowAssertDialog(msg
); 
 848 #endif // __WXDEBUG__