1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/appbase.cpp
3 // Purpose:     implements wxAppConsole class
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     19.06.2003 (extracted from common/appcmn.cpp)
7 // RCS-ID:      $Id: appbase.cpp 52093 2008-02-25 13:43:07Z VZ $
8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License:     wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 #ifndef WX_PRECOMP
28     #ifdef __WXMSW__
29         #include  "wx/msw/wrapwin.h"  // includes windows.h for MessageBox()
30     #endif
31     #include "wx/list.h"
32     #include "wx/app.h"
33     #include "wx/intl.h"
34     #include "wx/log.h"
35     #include "wx/utils.h"
36 #endif //WX_PRECOMP
37 
38 #include "wx/apptrait.h"
39 #include "wx/cmdline.h"
40 #include "wx/confbase.h"
41 #include "wx/filename.h"
42 #include "wx/msgout.h"
43 #include "wx/tokenzr.h"
44 
45 #if !defined(__WXMSW__) || defined(__WXMICROWIN__)
46   #include  <signal.h>      // for SIGTRAP used by wxTrap()
47 #endif  //Win/Unix
48 
49 #if wxUSE_FONTMAP
50     #include "wx/fontmap.h"
51 #endif // wxUSE_FONTMAP
52 
53 #if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
54     // For MacTypes.h for Debugger function
55     #include <CoreFoundation/CFBase.h>
56 #endif
57 
58 #if defined(__WXMAC__)
59     #ifdef __DARWIN__
60         #include  <CoreServices/CoreServices.h>
61     #else
62         #include  "wx/mac/private.h"  // includes mac headers
63     #endif
64 #endif // __WXMAC__
65 
66 #ifdef __WXDEBUG__
67     #if wxUSE_STACKWALKER
68         #include "wx/stackwalk.h"
69         #ifdef __WXMSW__
70             #include "wx/msw/debughlp.h"
71         #endif
72     #endif // wxUSE_STACKWALKER
73 
74     #include "wx/recguard.h"
75 #endif // __WXDEBUG__
76 
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"
82 #endif
83 
84 // ----------------------------------------------------------------------------
85 // private functions prototypes
86 // ----------------------------------------------------------------------------
87 
88 #ifdef __WXDEBUG__
89     // really just show the assert dialog
90     static bool DoShowAssertDialog(const wxString& msg);
91 
92     // prepare for showing the assert dialog, use the given traits or
93     // DoShowAssertDialog() as last fallback to really show it
94     static
95     void ShowAssertDialog(const wxChar *szFile,
96                           int nLine,
97                           const wxChar *szFunc,
98                           const wxChar *szCond,
99                           const wxChar *szMsg,
100                           wxAppTraits *traits = NULL);
101 
102     // turn on the trace masks specified in the env variable WXTRACE
103     static void LINKAGEMODE SetTraceMasks();
104 #endif // __WXDEBUG__
105 
106 // ----------------------------------------------------------------------------
107 // global vars
108 // ----------------------------------------------------------------------------
109 
110 wxAppConsole *wxAppConsole::ms_appInstance = NULL;
111 
112 wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL;
113 
114 // ============================================================================
115 // wxAppConsole implementation
116 // ============================================================================
117 
118 // ----------------------------------------------------------------------------
119 // ctor/dtor
120 // ----------------------------------------------------------------------------
121 
wxAppConsole()122 wxAppConsole::wxAppConsole()
123 {
124     m_traits = NULL;
125 
126     ms_appInstance = this;
127 
128 #ifdef __WXDEBUG__
129     SetTraceMasks();
130 #if wxUSE_UNICODE
131     // In unicode mode the SetTraceMasks call can cause an apptraits to be
132     // created, but since we are still in the constructor the wrong kind will
133     // be created for GUI apps.  Destroy it so it can be created again later.
134     delete m_traits;
135     m_traits = NULL;
136 #endif
137 #endif
138 }
139 
~wxAppConsole()140 wxAppConsole::~wxAppConsole()
141 {
142     delete m_traits;
143 }
144 
145 // ----------------------------------------------------------------------------
146 // initilization/cleanup
147 // ----------------------------------------------------------------------------
148 
Initialize(int & argcOrig,wxChar ** argvOrig)149 bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig)
150 {
151     // remember the command line arguments
152     argc = argcOrig;
153     argv = argvOrig;
154 
155 #ifndef __WXPALMOS__
156     if ( m_appName.empty() && argv )
157     {
158         // the application name is, by default, the name of its executable file
159         wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL);
160     }
161 #endif
162 
163     return true;
164 }
165 
CleanUp()166 void wxAppConsole::CleanUp()
167 {
168 }
169 
170 // ----------------------------------------------------------------------------
171 // OnXXX() callbacks
172 // ----------------------------------------------------------------------------
173 
OnInit()174 bool wxAppConsole::OnInit()
175 {
176 #if wxUSE_CMDLINE_PARSER
177     wxCmdLineParser parser(argc, argv);
178 
179     OnInitCmdLine(parser);
180 
181     bool cont;
182     switch ( parser.Parse(false /* don't show usage */) )
183     {
184         case -1:
185             cont = OnCmdLineHelp(parser);
186             break;
187 
188         case 0:
189             cont = OnCmdLineParsed(parser);
190             break;
191 
192         default:
193             cont = OnCmdLineError(parser);
194             break;
195     }
196 
197     if ( !cont )
198         return false;
199 #endif // wxUSE_CMDLINE_PARSER
200 
201     return true;
202 }
203 
OnExit()204 int wxAppConsole::OnExit()
205 {
206 #if wxUSE_CONFIG
207     // delete the config object if any (don't use Get() here, but Set()
208     // because Get() could create a new config object)
209     delete wxConfigBase::Set((wxConfigBase *) NULL);
210 #endif // wxUSE_CONFIG
211 
212     return 0;
213 }
214 
Exit()215 void wxAppConsole::Exit()
216 {
217     exit(-1);
218 }
219 
220 // ----------------------------------------------------------------------------
221 // traits stuff
222 // ----------------------------------------------------------------------------
223 
CreateTraits()224 wxAppTraits *wxAppConsole::CreateTraits()
225 {
226     return new wxConsoleAppTraits;
227 }
228 
GetTraits()229 wxAppTraits *wxAppConsole::GetTraits()
230 {
231     // FIXME-MT: protect this with a CS?
232     if ( !m_traits )
233     {
234         m_traits = CreateTraits();
235 
236         wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") );
237     }
238 
239     return m_traits;
240 }
241 
242 // we must implement CreateXXX() in wxApp itself for backwards compatibility
243 #if WXWIN_COMPATIBILITY_2_4
244 
245 #if wxUSE_LOG
246 
CreateLogTarget()247 wxLog *wxAppConsole::CreateLogTarget()
248 {
249     wxAppTraits *traits = GetTraits();
250     return traits ? traits->CreateLogTarget() : NULL;
251 }
252 
253 #endif // wxUSE_LOG
254 
CreateMessageOutput()255 wxMessageOutput *wxAppConsole::CreateMessageOutput()
256 {
257     wxAppTraits *traits = GetTraits();
258     return traits ? traits->CreateMessageOutput() : NULL;
259 }
260 
261 #endif // WXWIN_COMPATIBILITY_2_4
262 
263 // ----------------------------------------------------------------------------
264 // event processing
265 // ----------------------------------------------------------------------------
266 
ProcessPendingEvents()267 void wxAppConsole::ProcessPendingEvents()
268 {
269 #if wxUSE_THREADS
270     if ( !wxPendingEventsLocker )
271         return;
272 #endif
273 
274     // ensure that we're the only thread to modify the pending events list
275     wxENTER_CRIT_SECT( *wxPendingEventsLocker );
276 
277     if ( !wxPendingEvents )
278     {
279         wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
280         return;
281     }
282 
283     // iterate until the list becomes empty
284     wxList::compatibility_iterator node = wxPendingEvents->GetFirst();
285     while (node)
286     {
287         wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
288         wxPendingEvents->Erase(node);
289 
290         // In ProcessPendingEvents(), new handlers might be add
291         // and we can safely leave the critical section here.
292         wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
293 
294         handler->ProcessPendingEvents();
295 
296         wxENTER_CRIT_SECT( *wxPendingEventsLocker );
297 
298         node = wxPendingEvents->GetFirst();
299     }
300 
301     wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
302 }
303 
FilterEvent(wxEvent & WXUNUSED (event))304 int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event))
305 {
306     // process the events normally by default
307     return -1;
308 }
309 
310 // ----------------------------------------------------------------------------
311 // exception handling
312 // ----------------------------------------------------------------------------
313 
314 #if wxUSE_EXCEPTIONS
315 
316 void
HandleEvent(wxEvtHandler * handler,wxEventFunction func,wxEvent & event) const317 wxAppConsole::HandleEvent(wxEvtHandler *handler,
318                           wxEventFunction func,
319                           wxEvent& event) const
320 {
321     // by default, simply call the handler
322     (handler->*func)(event);
323 }
324 
325 #endif // wxUSE_EXCEPTIONS
326 
327 // ----------------------------------------------------------------------------
328 // cmd line parsing
329 // ----------------------------------------------------------------------------
330 
331 #if wxUSE_CMDLINE_PARSER
332 
333 #define OPTION_VERBOSE _T("verbose")
334 
OnInitCmdLine(wxCmdLineParser & parser)335 void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser)
336 {
337     // the standard command line options
338     static const wxCmdLineEntryDesc cmdLineDesc[] =
339     {
340         {
341             wxCMD_LINE_SWITCH,
342             _T("h"),
343             _T("help"),
344             gettext_noop("show this help message"),
345             wxCMD_LINE_VAL_NONE,
346             wxCMD_LINE_OPTION_HELP
347         },
348 
349 #if wxUSE_LOG
350         {
351             wxCMD_LINE_SWITCH,
352             wxEmptyString,
353             OPTION_VERBOSE,
354             gettext_noop("generate verbose log messages"),
355             wxCMD_LINE_VAL_NONE,
356             0x0
357         },
358 #endif // wxUSE_LOG
359 
360         // terminator
361         {
362             wxCMD_LINE_NONE,
363             wxEmptyString,
364             wxEmptyString,
365             wxEmptyString,
366             wxCMD_LINE_VAL_NONE,
367             0x0
368         }
369     };
370 
371     parser.SetDesc(cmdLineDesc);
372 }
373 
OnCmdLineParsed(wxCmdLineParser & parser)374 bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser)
375 {
376 #if wxUSE_LOG
377     if ( parser.Found(OPTION_VERBOSE) )
378     {
379         wxLog::SetVerbose(true);
380     }
381 #else
382     wxUnusedVar(parser);
383 #endif // wxUSE_LOG
384 
385     return true;
386 }
387 
OnCmdLineHelp(wxCmdLineParser & parser)388 bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser)
389 {
390     parser.Usage();
391 
392     return false;
393 }
394 
OnCmdLineError(wxCmdLineParser & parser)395 bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser)
396 {
397     parser.Usage();
398 
399     return false;
400 }
401 
402 #endif // wxUSE_CMDLINE_PARSER
403 
404 // ----------------------------------------------------------------------------
405 // debugging support
406 // ----------------------------------------------------------------------------
407 
408 /* static */
CheckBuildOptions(const char * optionsSignature,const char * componentName)409 bool wxAppConsole::CheckBuildOptions(const char *optionsSignature,
410                                      const char *componentName)
411 {
412 #if 0 // can't use wxLogTrace, not up and running yet
413     printf("checking build options object '%s' (ptr %p) in '%s'\n",
414              optionsSignature, optionsSignature, componentName);
415 #endif
416 
417     if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
418     {
419         wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
420         wxString prog = wxString::FromAscii(optionsSignature);
421         wxString progName = wxString::FromAscii(componentName);
422         wxString msg;
423 
424         msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
425                    lib.c_str(), progName.c_str(), prog.c_str());
426 
427         wxLogFatalError(msg.c_str());
428 
429         // normally wxLogFatalError doesn't return
430         return false;
431     }
432 #undef wxCMP
433 
434     return true;
435 }
436 
437 #ifdef __WXDEBUG__
438 
OnAssertFailure(const wxChar * file,int line,const wxChar * func,const wxChar * cond,const wxChar * msg)439 void wxAppConsole::OnAssertFailure(const wxChar *file,
440                                    int line,
441                                    const wxChar *func,
442                                    const wxChar *cond,
443                                    const wxChar *msg)
444 {
445     ShowAssertDialog(file, line, func, cond, msg, GetTraits());
446 }
447 
OnAssert(const wxChar * file,int line,const wxChar * cond,const wxChar * msg)448 void wxAppConsole::OnAssert(const wxChar *file,
449                             int line,
450                             const wxChar *cond,
451                             const wxChar *msg)
452 {
453     OnAssertFailure(file, line, NULL, cond, msg);
454 }
455 
456 #endif // __WXDEBUG__
457 
458 #if WXWIN_COMPATIBILITY_2_4
459 
CheckBuildOptions(const wxBuildOptions & buildOptions)460 bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions)
461 {
462     return CheckBuildOptions(buildOptions.m_signature, "your program");
463 }
464 
465 #endif
466 
467 // ============================================================================
468 // other classes implementations
469 // ============================================================================
470 
471 // ----------------------------------------------------------------------------
472 // wxConsoleAppTraitsBase
473 // ----------------------------------------------------------------------------
474 
475 #if wxUSE_LOG
476 
CreateLogTarget()477 wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
478 {
479     return new wxLogStderr;
480 }
481 
482 #endif // wxUSE_LOG
483 
CreateMessageOutput()484 wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
485 {
486     return new wxMessageOutputStderr;
487 }
488 
489 #if wxUSE_FONTMAP
490 
CreateFontMapper()491 wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
492 {
493     return (wxFontMapper *)new wxFontMapperBase;
494 }
495 
496 #endif // wxUSE_FONTMAP
497 
CreateRenderer()498 wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
499 {
500     // console applications don't use renderers
501     return NULL;
502 }
503 
504 #ifdef __WXDEBUG__
ShowAssertDialog(const wxString & msg)505 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
506 {
507     return wxAppTraitsBase::ShowAssertDialog(msg);
508 }
509 #endif
510 
HasStderr()511 bool wxConsoleAppTraitsBase::HasStderr()
512 {
513     // console applications always have stderr, even under Mac/Windows
514     return true;
515 }
516 
ScheduleForDestroy(wxObject * object)517 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
518 {
519     delete object;
520 }
521 
RemoveFromPendingDelete(wxObject * WXUNUSED (object))522 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
523 {
524     // nothing to do
525 }
526 
527 #if wxUSE_SOCKETS
GetSocketGUIFunctionsTable()528 GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
529 {
530     return NULL;
531 }
532 #endif
533 
534 // ----------------------------------------------------------------------------
535 // wxAppTraits
536 // ----------------------------------------------------------------------------
537 
538 #ifdef __WXDEBUG__
539 
ShowAssertDialog(const wxString & msgOriginal)540 bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
541 {
542     wxString msg = msgOriginal;
543 
544 #if wxUSE_STACKWALKER
545 #if !defined(__WXMSW__)
546     // on Unix stack frame generation may take some time, depending on the
547     // size of the executable mainly... warn the user that we are working
548     wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait"));
549     fflush(stderr);
550 #endif
551 
552     const wxString stackTrace = GetAssertStackTrace();
553     if ( !stackTrace.empty() )
554         msg << _T("\n\nCall stack:\n") << stackTrace;
555 #endif // wxUSE_STACKWALKER
556 
557     return DoShowAssertDialog(msg);
558 }
559 
560 #if wxUSE_STACKWALKER
GetAssertStackTrace()561 wxString wxAppTraitsBase::GetAssertStackTrace()
562 {
563     wxString stackTrace;
564 
565     class StackDump : public wxStackWalker
566     {
567     public:
568         StackDump() { }
569 
570         const wxString& GetStackTrace() const { return m_stackTrace; }
571 
572     protected:
573         virtual void OnStackFrame(const wxStackFrame& frame)
574         {
575             m_stackTrace << wxString::Format
576                             (
577                               _T("[%02d] "),
578                               wx_truncate_cast(int, frame.GetLevel())
579                             );
580 
581             wxString name = frame.GetName();
582             if ( !name.empty() )
583             {
584                 m_stackTrace << wxString::Format(_T("%-40s"), name.c_str());
585             }
586             else
587             {
588                 m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress());
589             }
590 
591             if ( frame.HasSourceLocation() )
592             {
593                 m_stackTrace << _T('\t')
594                              << frame.GetFileName()
595                              << _T(':')
596                              << frame.GetLine();
597             }
598 
599             m_stackTrace << _T('\n');
600         }
601 
602     private:
603         wxString m_stackTrace;
604     };
605 
606     // don't show more than maxLines or we could get a dialog too tall to be
607     // shown on screen: 20 should be ok everywhere as even with 15 pixel high
608     // characters it is still only 300 pixels...
609     static const int maxLines = 20;
610 
611     StackDump dump;
612     dump.Walk(2, maxLines); // don't show OnAssert() call itself
613     stackTrace = dump.GetStackTrace();
614 
615     const int count = stackTrace.Freq(wxT('\n'));
616     for ( int i = 0; i < count - maxLines; i++ )
617         stackTrace = stackTrace.BeforeLast(wxT('\n'));
618 
619     return stackTrace;
620 }
621 #endif // wxUSE_STACKWALKER
622 
623 
624 #endif // __WXDEBUG__
625 
626 // ============================================================================
627 // global functions implementation
628 // ============================================================================
629 
wxExit()630 void wxExit()
631 {
632     if ( wxTheApp )
633     {
634         wxTheApp->Exit();
635     }
636     else
637     {
638         // what else can we do?
639         exit(-1);
640     }
641 }
642 
wxWakeUpIdle()643 void wxWakeUpIdle()
644 {
645     if ( wxTheApp )
646     {
647         wxTheApp->WakeUpIdle();
648     }
649     //else: do nothing, what can we do?
650 }
651 
652 #ifdef  __WXDEBUG__
653 
654 // wxASSERT() helper
wxAssertIsEqual(int x,int y)655 bool wxAssertIsEqual(int x, int y)
656 {
657     return x == y;
658 }
659 
660 // break into the debugger
wxTrap()661 void wxTrap()
662 {
663 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
664     DebugBreak();
665 #elif defined(__WXMAC__) && !defined(__DARWIN__)
666     #if __powerc
667         Debugger();
668     #else
669         SysBreak();
670     #endif
671 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
672     Debugger();
673 #elif defined(__UNIX__)
674     raise(SIGTRAP);
675 #else
676     // TODO
677 #endif // Win/Unix
678 }
679 
680 // this function is called when an assert fails
wxOnAssert(const wxChar * szFile,int nLine,const char * szFunc,const wxChar * szCond,const wxChar * szMsg)681 void wxOnAssert(const wxChar *szFile,
682                 int nLine,
683                 const char *szFunc,
684                 const wxChar *szCond,
685                 const wxChar *szMsg)
686 {
687     // FIXME MT-unsafe
688     static int s_bInAssert = 0;
689 
690     wxRecursionGuard guard(s_bInAssert);
691     if ( guard.IsInside() )
692     {
693         // can't use assert here to avoid infinite loops, so just trap
694         wxTrap();
695 
696         return;
697     }
698 
699     // __FUNCTION__ is always in ASCII, convert it to wide char if needed
700     const wxString strFunc = wxString::FromAscii(szFunc);
701 
702     if ( !wxTheApp )
703     {
704         // by default, show the assert dialog box -- we can't customize this
705         // behaviour
706         ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg);
707     }
708     else
709     {
710         // let the app process it as it wants
711         wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg);
712     }
713 }
714 
715 #endif // __WXDEBUG__
716 
717 // ============================================================================
718 // private functions implementation
719 // ============================================================================
720 
721 #ifdef __WXDEBUG__
722 
SetTraceMasks()723 static void LINKAGEMODE SetTraceMasks()
724 {
725 #if wxUSE_LOG
726     wxString mask;
727     if ( wxGetEnv(wxT("WXTRACE"), &mask) )
728     {
729         wxStringTokenizer tkn(mask, wxT(",;:"));
730         while ( tkn.HasMoreTokens() )
731             wxLog::AddTraceMask(tkn.GetNextToken());
732     }
733 #endif // wxUSE_LOG
734 }
735 
DoShowAssertDialog(const wxString & msg)736 bool DoShowAssertDialog(const wxString& msg)
737 {
738     // under MSW we can show the dialog even in the console mode
739 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
740     wxString msgDlg(msg);
741 
742     // this message is intentionally not translated -- it is for
743     // developpers only
744     msgDlg += wxT("\nDo you want to stop the program?\n")
745               wxT("You can also choose [Cancel] to suppress ")
746               wxT("further warnings.");
747 
748     switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"),
749                           MB_YESNOCANCEL | MB_ICONSTOP ) )
750     {
751         case IDYES:
752             wxTrap();
753             break;
754 
755         case IDCANCEL:
756             // stop the asserts
757             return true;
758 
759         //case IDNO: nothing to do
760     }
761 #else // !__WXMSW__
762     wxFprintf(stderr, wxT("%s\n"), msg.c_str());
763     fflush(stderr);
764 
765     // TODO: ask the user to enter "Y" or "N" on the console?
766     wxTrap();
767 #endif // __WXMSW__/!__WXMSW__
768 
769     // continue with the asserts
770     return false;
771 }
772 
773 // show the assert modal dialog
774 static
ShowAssertDialog(const wxChar * szFile,int nLine,const wxChar * szFunc,const wxChar * szCond,const wxChar * szMsg,wxAppTraits * traits)775 void ShowAssertDialog(const wxChar *szFile,
776                       int nLine,
777                       const wxChar *szFunc,
778                       const wxChar *szCond,
779                       const wxChar *szMsg,
780                       wxAppTraits *traits)
781 {
782     // this variable can be set to true to suppress "assert failure" messages
783     static bool s_bNoAsserts = false;
784 
785     wxString msg;
786     msg.reserve(2048);
787 
788     // make life easier for people using VC++ IDE by using this format: like
789     // this, clicking on the message will take us immediately to the place of
790     // the failed assert
791     msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond);
792 
793     // add the function name, if any
794     if ( szFunc && *szFunc )
795         msg << _T(" in ") << szFunc << _T("()");
796 
797     // and the message itself
798     if ( szMsg )
799     {
800         msg << _T(": ") << szMsg;
801     }
802     else // no message given
803     {
804         msg << _T('.');
805     }
806 
807 #if wxUSE_THREADS
808     // if we are not in the main thread, output the assert directly and trap
809     // since dialogs cannot be displayed
810     if ( !wxThread::IsMain() )
811     {
812         msg += wxT(" [in child thread]");
813 
814 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
815         msg << wxT("\r\n");
816         OutputDebugString(msg );
817 #else
818         // send to stderr
819         wxFprintf(stderr, wxT("%s\n"), msg.c_str());
820         fflush(stderr);
821 #endif
822         // He-e-e-e-elp!! we're asserting in a child thread
823         wxTrap();
824     }
825     else
826 #endif // wxUSE_THREADS
827 
828     if ( !s_bNoAsserts )
829     {
830         // send it to the normal log destination
831         wxLogDebug(_T("%s"), msg.c_str());
832 
833         if ( traits )
834         {
835             // delegate showing assert dialog (if possible) to that class
836             s_bNoAsserts = traits->ShowAssertDialog(msg);
837         }
838         else // no traits object
839         {
840             // fall back to the function of last resort
841             s_bNoAsserts = DoShowAssertDialog(msg);
842         }
843     }
844 }
845 
846 #endif // __WXDEBUG__
847