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"
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
& szFile
,
97 const wxString
& szFunc
,
98 const wxString
& szCond
,
99 const wxString
& szMsg
,
100 wxAppTraits
*traits
= NULL
);
102 // turn on the trace masks specified in the env variable WXTRACE
103 static void LINKAGEMODE
SetTraceMasks();
104 #endif // __WXDEBUG__
106 // ----------------------------------------------------------------------------
108 // ----------------------------------------------------------------------------
110 wxAppConsole
*wxAppConsoleBase::ms_appInstance
= NULL
;
112 wxAppInitializerFunction
wxAppConsoleBase::ms_appInitFn
= NULL
;
114 wxSocketManager
*wxAppTraitsBase::ms_manager
= NULL
;
116 // ----------------------------------------------------------------------------
118 // ----------------------------------------------------------------------------
120 // this defines wxEventLoopPtr
121 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopBase
)
123 // ============================================================================
124 // wxAppConsoleBase implementation
125 // ============================================================================
127 // ----------------------------------------------------------------------------
129 // ----------------------------------------------------------------------------
131 wxAppConsoleBase::wxAppConsoleBase()
135 m_bDoPendingEventProcessing
= true;
137 ms_appInstance
= static_cast<wxAppConsole
*>(this);
142 // In unicode mode the SetTraceMasks call can cause an apptraits to be
143 // created, but since we are still in the constructor the wrong kind will
144 // be created for GUI apps. Destroy it so it can be created again later.
151 wxAppConsoleBase::~wxAppConsoleBase()
156 // ----------------------------------------------------------------------------
157 // initialization/cleanup
158 // ----------------------------------------------------------------------------
160 bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc
), wxChar
**argv
)
163 GetTraits()->SetLocale();
167 if ( m_appName
.empty() && argv
&& argv
[0] )
169 // the application name is, by default, the name of its executable file
170 wxFileName::SplitPath(argv
[0], NULL
, &m_appName
, NULL
);
172 #endif // !__WXPALMOS__
177 wxEventLoopBase
*wxAppConsoleBase::CreateMainLoop()
179 return GetTraits()->CreateEventLoop();
182 void wxAppConsoleBase::CleanUp()
191 // ----------------------------------------------------------------------------
193 // ----------------------------------------------------------------------------
195 bool wxAppConsoleBase::OnInit()
197 #if wxUSE_CMDLINE_PARSER
198 wxCmdLineParser
parser(argc
, argv
);
200 OnInitCmdLine(parser
);
203 switch ( parser
.Parse(false /* don't show usage */) )
206 cont
= OnCmdLineHelp(parser
);
210 cont
= OnCmdLineParsed(parser
);
214 cont
= OnCmdLineError(parser
);
220 #endif // wxUSE_CMDLINE_PARSER
225 int wxAppConsoleBase::OnRun()
230 int wxAppConsoleBase::OnExit()
233 // delete the config object if any (don't use Get() here, but Set()
234 // because Get() could create a new config object)
235 delete wxConfigBase::Set(NULL
);
236 #endif // wxUSE_CONFIG
241 void wxAppConsoleBase::Exit()
243 if (m_mainLoop
!= NULL
)
249 // ----------------------------------------------------------------------------
251 // ----------------------------------------------------------------------------
253 wxAppTraits
*wxAppConsoleBase::CreateTraits()
255 return new wxConsoleAppTraits
;
258 wxAppTraits
*wxAppConsoleBase::GetTraits()
260 // FIXME-MT: protect this with a CS?
263 m_traits
= CreateTraits();
265 wxASSERT_MSG( m_traits
, _T("wxApp::CreateTraits() failed?") );
272 wxAppTraits
*wxAppConsoleBase::GetTraitsIfExists()
274 wxAppConsole
* const app
= GetInstance();
275 return app
? app
->GetTraits() : NULL
;
278 // ----------------------------------------------------------------------------
279 // wxEventLoop redirection
280 // ----------------------------------------------------------------------------
282 int wxAppConsoleBase::MainLoop()
284 wxEventLoopBaseTiedPtr
mainLoop(&m_mainLoop
, CreateMainLoop());
286 return m_mainLoop
? m_mainLoop
->Run() : -1;
289 void wxAppConsoleBase::ExitMainLoop()
291 // we should exit from the main event loop, not just any currently active
292 // (e.g. modal dialog) event loop
293 if ( m_mainLoop
&& m_mainLoop
->IsRunning() )
299 bool wxAppConsoleBase::Pending()
301 // use the currently active message loop here, not m_mainLoop, because if
302 // we're showing a modal dialog (with its own event loop) currently the
303 // main event loop is not running anyhow
304 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
306 return loop
&& loop
->Pending();
309 bool wxAppConsoleBase::Dispatch()
311 // see comment in Pending()
312 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
314 return loop
&& loop
->Dispatch();
317 bool wxAppConsoleBase::Yield(bool onlyIfNeeded
)
319 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
321 return loop
&& loop
->Yield(onlyIfNeeded
);
324 void wxAppConsoleBase::WakeUpIdle()
327 m_mainLoop
->WakeUp();
330 bool wxAppConsoleBase::ProcessIdle()
332 wxEventLoopBase
* const loop
= wxEventLoopBase::GetActive();
334 return loop
&& loop
->ProcessIdle();
337 // ----------------------------------------------------------------------------
339 // ----------------------------------------------------------------------------
342 bool wxAppConsoleBase::IsMainLoopRunning()
344 const wxAppConsole
* const app
= GetInstance();
346 return app
&& app
->m_mainLoop
!= NULL
;
349 int wxAppConsoleBase::FilterEvent(wxEvent
& WXUNUSED(event
))
351 // process the events normally by default
355 void wxAppConsoleBase::DelayPendingEventHandler(wxEvtHandler
* toDelay
)
357 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
359 // move the handler from the list of handlers with processable pending events
360 // to the list of handlers with pending events which needs to be processed later
361 m_handlersWithPendingEvents
.Remove(toDelay
);
363 if (m_handlersWithPendingDelayedEvents
.Index(toDelay
) == wxNOT_FOUND
)
364 m_handlersWithPendingDelayedEvents
.Add(toDelay
);
366 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
369 void wxAppConsoleBase::RemovePendingEventHandler(wxEvtHandler
* toRemove
)
371 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
373 if (m_handlersWithPendingEvents
.Index(toRemove
) != wxNOT_FOUND
)
375 m_handlersWithPendingEvents
.Remove(toRemove
);
377 // check that the handler was present only once in the list
378 wxASSERT_MSG( m_handlersWithPendingEvents
.Index(toRemove
) == wxNOT_FOUND
,
379 "Handler occurs twice in the m_handlersWithPendingEvents list!" );
381 //else: it wasn't in this list at all, it's ok
383 if (m_handlersWithPendingDelayedEvents
.Index(toRemove
) != wxNOT_FOUND
)
385 m_handlersWithPendingDelayedEvents
.Remove(toRemove
);
387 // check that the handler was present only once in the list
388 wxASSERT_MSG( m_handlersWithPendingDelayedEvents
.Index(toRemove
) == wxNOT_FOUND
,
389 "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" );
391 //else: it wasn't in this list at all, it's ok
393 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
396 void wxAppConsoleBase::AppendPendingEventHandler(wxEvtHandler
* toAppend
)
398 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
400 if ( m_handlersWithPendingEvents
.Index(toAppend
) == wxNOT_FOUND
)
401 m_handlersWithPendingEvents
.Add(toAppend
);
403 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
406 bool wxAppConsoleBase::HasPendingEvents() const
408 wxENTER_CRIT_SECT(const_cast<wxAppConsoleBase
*>(this)->m_handlersWithPendingEventsLocker
);
410 bool has
= !m_handlersWithPendingEvents
.IsEmpty();
412 wxLEAVE_CRIT_SECT(const_cast<wxAppConsoleBase
*>(this)->m_handlersWithPendingEventsLocker
);
417 void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
419 m_bDoPendingEventProcessing
= false;
422 void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
424 m_bDoPendingEventProcessing
= true;
427 void wxAppConsoleBase::ProcessPendingEvents()
429 if (!m_bDoPendingEventProcessing
)
432 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
434 wxCHECK_RET( m_handlersWithPendingDelayedEvents
.IsEmpty(),
435 "this helper list should be empty" );
437 // iterate until the list becomes empty: the handlers remove themselves
438 // from it when they don't have any more pending events
439 while (!m_handlersWithPendingEvents
.IsEmpty())
441 // In ProcessPendingEvents(), new handlers might be added
442 // and we can safely leave the critical section here.
443 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
445 // NOTE: we always call ProcessPendingEvents() on the first event handler
446 // with pending events because handlers auto-remove themselves
447 // from this list (see RemovePendingEventHandler) if they have no
448 // more pending events.
449 m_handlersWithPendingEvents
[0]->ProcessPendingEvents();
451 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
454 // now the wxHandlersWithPendingEvents is surely empty; however some event
455 // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
456 // because of a selective wxYield call in progress.
457 // Now we need to move them back to wxHandlersWithPendingEvents so the next
458 // call to this function has the chance of processing them:
459 if (!m_handlersWithPendingDelayedEvents
.IsEmpty())
461 WX_APPEND_ARRAY(m_handlersWithPendingEvents
, m_handlersWithPendingDelayedEvents
);
462 m_handlersWithPendingDelayedEvents
.Clear();
465 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
468 void wxAppConsoleBase::DeletePendingEvents()
470 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker
);
472 wxCHECK_RET( m_handlersWithPendingDelayedEvents
.IsEmpty(),
473 "this helper list should be empty" );
475 for (unsigned int i
=0; i
<m_handlersWithPendingEvents
.GetCount(); i
++)
476 m_handlersWithPendingEvents
[i
]->DeletePendingEvents();
478 m_handlersWithPendingEvents
.Clear();
480 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker
);
483 // ----------------------------------------------------------------------------
484 // exception handling
485 // ----------------------------------------------------------------------------
490 wxAppConsoleBase::HandleEvent(wxEvtHandler
*handler
,
491 wxEventFunction func
,
492 wxEvent
& event
) const
494 // by default, simply call the handler
495 (handler
->*func
)(event
);
498 void wxAppConsoleBase::CallEventHandler(wxEvtHandler
*handler
,
499 wxEventFunctor
& functor
,
500 wxEvent
& event
) const
502 // If the functor holds a method then, for backward compatibility, call
504 wxEventFunction eventFunction
= functor
.GetMethod();
507 HandleEvent(handler
, eventFunction
, event
);
509 functor(handler
, event
);
512 void wxAppConsoleBase::OnUnhandledException()
515 // we're called from an exception handler so we can re-throw the exception
516 // to recover its type
523 catch ( std::exception
& e
)
525 what
.Printf("std::exception of type \"%s\", what() = \"%s\"",
526 typeid(e
).name(), e
.what());
531 what
= "unknown exception";
534 wxMessageOutputBest().Printf(
535 "*** Caught unhandled %s; terminating\n", what
537 #endif // __WXDEBUG__
540 // ----------------------------------------------------------------------------
541 // exceptions support
542 // ----------------------------------------------------------------------------
544 bool wxAppConsoleBase::OnExceptionInMainLoop()
548 // some compilers are too stupid to know that we never return after throw
549 #if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200)
554 #endif // wxUSE_EXCEPTIONS
556 // ----------------------------------------------------------------------------
558 // ----------------------------------------------------------------------------
560 #if wxUSE_CMDLINE_PARSER
562 #define OPTION_VERBOSE "verbose"
564 void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser
& parser
)
566 // the standard command line options
567 static const wxCmdLineEntryDesc cmdLineDesc
[] =
573 gettext_noop("show this help message"),
575 wxCMD_LINE_OPTION_HELP
583 gettext_noop("generate verbose log messages"),
593 parser
.SetDesc(cmdLineDesc
);
596 bool wxAppConsoleBase::OnCmdLineParsed(wxCmdLineParser
& parser
)
599 if ( parser
.Found(OPTION_VERBOSE
) )
601 wxLog::SetVerbose(true);
610 bool wxAppConsoleBase::OnCmdLineHelp(wxCmdLineParser
& parser
)
617 bool wxAppConsoleBase::OnCmdLineError(wxCmdLineParser
& parser
)
624 #endif // wxUSE_CMDLINE_PARSER
626 // ----------------------------------------------------------------------------
628 // ----------------------------------------------------------------------------
631 bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature
,
632 const char *componentName
)
634 #if 0 // can't use wxLogTrace, not up and running yet
635 printf("checking build options object '%s' (ptr %p) in '%s'\n",
636 optionsSignature
, optionsSignature
, componentName
);
639 if ( strcmp(optionsSignature
, WX_BUILD_OPTIONS_SIGNATURE
) != 0 )
641 wxString lib
= wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE
);
642 wxString prog
= wxString::FromAscii(optionsSignature
);
643 wxString progName
= wxString::FromAscii(componentName
);
646 msg
.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
647 lib
.c_str(), progName
.c_str(), prog
.c_str());
649 wxLogFatalError(msg
.c_str());
651 // normally wxLogFatalError doesn't return
660 void wxAppConsoleBase::OnAssertFailure(const wxChar
*file
,
666 ShowAssertDialog(file
, line
, func
, cond
, msg
, GetTraits());
669 void wxAppConsoleBase::OnAssert(const wxChar
*file
,
674 OnAssertFailure(file
, line
, NULL
, cond
, msg
);
677 #endif // __WXDEBUG__
679 // ============================================================================
680 // other classes implementations
681 // ============================================================================
683 // ----------------------------------------------------------------------------
684 // wxConsoleAppTraitsBase
685 // ----------------------------------------------------------------------------
689 wxLog
*wxConsoleAppTraitsBase::CreateLogTarget()
691 return new wxLogStderr
;
696 wxMessageOutput
*wxConsoleAppTraitsBase::CreateMessageOutput()
698 return new wxMessageOutputStderr
;
703 wxFontMapper
*wxConsoleAppTraitsBase::CreateFontMapper()
705 return (wxFontMapper
*)new wxFontMapperBase
;
708 #endif // wxUSE_FONTMAP
710 wxRendererNative
*wxConsoleAppTraitsBase::CreateRenderer()
712 // console applications don't use renderers
717 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString
& msg
)
719 return wxAppTraitsBase::ShowAssertDialog(msg
);
723 bool wxConsoleAppTraitsBase::HasStderr()
725 // console applications always have stderr, even under Mac/Windows
729 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject
*object
)
734 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject
* WXUNUSED(object
))
739 // ----------------------------------------------------------------------------
741 // ----------------------------------------------------------------------------
744 void wxAppTraitsBase::SetLocale()
746 wxSetlocale(LC_ALL
, "");
747 wxUpdateLocaleIsUtf8();
752 void wxMutexGuiEnterImpl();
753 void wxMutexGuiLeaveImpl();
755 void wxAppTraitsBase::MutexGuiEnter()
757 wxMutexGuiEnterImpl();
760 void wxAppTraitsBase::MutexGuiLeave()
762 wxMutexGuiLeaveImpl();
765 void WXDLLIMPEXP_BASE
wxMutexGuiEnter()
767 wxAppTraits
* const traits
= wxAppConsoleBase::GetTraitsIfExists();
769 traits
->MutexGuiEnter();
772 void WXDLLIMPEXP_BASE
wxMutexGuiLeave()
774 wxAppTraits
* const traits
= wxAppConsoleBase::GetTraitsIfExists();
776 traits
->MutexGuiLeave();
778 #endif // wxUSE_THREADS
782 bool wxAppTraitsBase::ShowAssertDialog(const wxString
& msgOriginal
)
784 wxString msg
= msgOriginal
;
786 #if wxUSE_STACKWALKER
787 #if !defined(__WXMSW__)
788 // on Unix stack frame generation may take some time, depending on the
789 // size of the executable mainly... warn the user that we are working
790 wxFprintf(stderr
, wxT("[Debug] Generating a stack trace... please wait"));
794 const wxString stackTrace
= GetAssertStackTrace();
795 if ( !stackTrace
.empty() )
796 msg
<< _T("\n\nCall stack:\n") << stackTrace
;
797 #endif // wxUSE_STACKWALKER
799 return DoShowAssertDialog(msg
);
802 #if wxUSE_STACKWALKER
803 wxString
wxAppTraitsBase::GetAssertStackTrace()
807 class StackDump
: public wxStackWalker
812 const wxString
& GetStackTrace() const { return m_stackTrace
; }
815 virtual void OnStackFrame(const wxStackFrame
& frame
)
817 m_stackTrace
<< wxString::Format
820 wx_truncate_cast(int, frame
.GetLevel())
823 wxString name
= frame
.GetName();
826 m_stackTrace
<< wxString::Format(_T("%-40s"), name
.c_str());
830 m_stackTrace
<< wxString::Format(_T("%p"), frame
.GetAddress());
833 if ( frame
.HasSourceLocation() )
835 m_stackTrace
<< _T('\t')
836 << frame
.GetFileName()
841 m_stackTrace
<< _T('\n');
845 wxString m_stackTrace
;
848 // don't show more than maxLines or we could get a dialog too tall to be
849 // shown on screen: 20 should be ok everywhere as even with 15 pixel high
850 // characters it is still only 300 pixels...
851 static const int maxLines
= 20;
854 dump
.Walk(2, maxLines
); // don't show OnAssert() call itself
855 stackTrace
= dump
.GetStackTrace();
857 const int count
= stackTrace
.Freq(wxT('\n'));
858 for ( int i
= 0; i
< count
- maxLines
; i
++ )
859 stackTrace
= stackTrace
.BeforeLast(wxT('\n'));
863 #endif // wxUSE_STACKWALKER
866 #endif // __WXDEBUG__
868 // ============================================================================
869 // global functions implementation
870 // ============================================================================
880 // what else can we do?
889 wxTheApp
->WakeUpIdle();
891 //else: do nothing, what can we do?
897 bool wxAssertIsEqual(int x
, int y
)
902 // break into the debugger
905 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
907 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
909 #elif defined(__UNIX__)
916 // this function is called when an assert fails
917 static void wxDoOnAssert(const wxString
& szFile
,
919 const wxString
& szFunc
,
920 const wxString
& szCond
,
921 const wxString
& szMsg
= wxEmptyString
)
924 static int s_bInAssert
= 0;
926 wxRecursionGuard
guard(s_bInAssert
);
927 if ( guard
.IsInside() )
929 // can't use assert here to avoid infinite loops, so just trap
937 // by default, show the assert dialog box -- we can't customize this
939 ShowAssertDialog(szFile
, nLine
, szFunc
, szCond
, szMsg
);
943 // let the app process it as it wants
944 // FIXME-UTF8: use wc_str(), not c_str(), when ANSI build is removed
945 wxTheApp
->OnAssertFailure(szFile
.c_str(), nLine
, szFunc
.c_str(),
946 szCond
.c_str(), szMsg
.c_str());
950 void wxOnAssert(const wxString
& szFile
,
952 const wxString
& szFunc
,
953 const wxString
& szCond
,
954 const wxString
& szMsg
)
956 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, szMsg
);
959 void wxOnAssert(const wxString
& szFile
,
961 const wxString
& szFunc
,
962 const wxString
& szCond
)
964 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
);
967 void wxOnAssert(const wxChar
*szFile
,
970 const wxChar
*szCond
,
973 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, szMsg
);
976 void wxOnAssert(const char *szFile
,
980 const wxString
& szMsg
)
982 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, szMsg
);
985 void wxOnAssert(const char *szFile
,
989 const wxCStrData
& msg
)
991 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, msg
);
995 void wxOnAssert(const char *szFile
,
1000 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
);
1003 void wxOnAssert(const char *szFile
,
1009 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, szMsg
);
1012 void wxOnAssert(const char *szFile
,
1016 const wxChar
*szMsg
)
1018 wxDoOnAssert(szFile
, nLine
, szFunc
, szCond
, szMsg
);
1020 #endif // wxUSE_UNICODE
1022 #endif // __WXDEBUG__
1024 // ============================================================================
1025 // private functions implementation
1026 // ============================================================================
1030 static void LINKAGEMODE
SetTraceMasks()
1034 if ( wxGetEnv(wxT("WXTRACE"), &mask
) )
1036 wxStringTokenizer
tkn(mask
, wxT(",;:"));
1037 while ( tkn
.HasMoreTokens() )
1038 wxLog::AddTraceMask(tkn
.GetNextToken());
1044 bool DoShowAssertDialog(const wxString
& msg
)
1046 // under MSW we can show the dialog even in the console mode
1047 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1048 wxString
msgDlg(msg
);
1050 // this message is intentionally not translated -- it is for
1052 msgDlg
+= wxT("\nDo you want to stop the program?\n")
1053 wxT("You can also choose [Cancel] to suppress ")
1054 wxT("further warnings.");
1056 switch ( ::MessageBox(NULL
, msgDlg
.wx_str(), _T("wxWidgets Debug Alert"),
1057 MB_YESNOCANCEL
| MB_ICONSTOP
) )
1067 //case IDNO: nothing to do
1070 wxFprintf(stderr
, wxT("%s\n"), msg
.c_str());
1073 // TODO: ask the user to enter "Y" or "N" on the console?
1075 #endif // __WXMSW__/!__WXMSW__
1077 // continue with the asserts
1081 // show the assert modal dialog
1083 void ShowAssertDialog(const wxString
& szFile
,
1085 const wxString
& szFunc
,
1086 const wxString
& szCond
,
1087 const wxString
& szMsg
,
1088 wxAppTraits
*traits
)
1090 // this variable can be set to true to suppress "assert failure" messages
1091 static bool s_bNoAsserts
= false;
1096 // make life easier for people using VC++ IDE by using this format: like
1097 // this, clicking on the message will take us immediately to the place of
1098 // the failed assert
1099 msg
.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile
, nLine
, szCond
);
1101 // add the function name, if any
1102 if ( !szFunc
.empty() )
1103 msg
<< _T(" in ") << szFunc
<< _T("()");
1105 // and the message itself
1106 if ( !szMsg
.empty() )
1108 msg
<< _T(": ") << szMsg
;
1110 else // no message given
1116 // if we are not in the main thread, output the assert directly and trap
1117 // since dialogs cannot be displayed
1118 if ( !wxThread::IsMain() )
1120 msg
+= wxT(" [in child thread]");
1122 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1124 OutputDebugString(msg
.wx_str());
1127 wxFprintf(stderr
, wxT("%s\n"), msg
.c_str());
1130 // He-e-e-e-elp!! we're asserting in a child thread
1134 #endif // wxUSE_THREADS
1136 if ( !s_bNoAsserts
)
1138 // send it to the normal log destination
1139 wxLogDebug(_T("%s"), msg
.c_str());
1143 // delegate showing assert dialog (if possible) to that class
1144 s_bNoAsserts
= traits
->ShowAssertDialog(msg
);
1146 else // no traits object
1148 // fall back to the function of last resort
1149 s_bNoAsserts
= DoShowAssertDialog(msg
);
1154 #endif // __WXDEBUG__