]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/appbase.cpp
remove unused static function (avoids a warning about it)
[wxWidgets.git] / src / common / appbase.cpp
... / ...
CommitLineData
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$
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 #include "wx/wxcrtvararg.h"
37#endif //WX_PRECOMP
38
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/ptr_scpd.h"
46#include "wx/tokenzr.h"
47
48#if !defined(__WXMSW__) || defined(__WXMICROWIN__)
49 #include <signal.h> // for SIGTRAP used by wxTrap()
50#endif //Win/Unix
51
52#include <locale.h>
53
54#if wxUSE_FONTMAP
55 #include "wx/fontmap.h"
56#endif // wxUSE_FONTMAP
57
58#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
59 // For MacTypes.h for Debugger function
60 #include <CoreFoundation/CFBase.h>
61#endif
62
63#if defined(__WXMAC__)
64 #ifdef __DARWIN__
65 #include <CoreServices/CoreServices.h>
66 #else
67 #include "wx/mac/private.h" // includes mac headers
68 #endif
69#endif // __WXMAC__
70
71#ifdef __WXDEBUG__
72 #if wxUSE_STACKWALKER
73 #include "wx/stackwalk.h"
74 #ifdef __WXMSW__
75 #include "wx/msw/debughlp.h"
76 #endif
77 #endif // wxUSE_STACKWALKER
78#endif // __WXDEBUG__
79
80// wxABI_VERSION can be defined when compiling applications but it should be
81// left undefined when compiling the library itself, it is then set to its
82// default value in version.h
83#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99
84#error "wxABI_VERSION should not be defined when compiling the library"
85#endif
86
87// ----------------------------------------------------------------------------
88// private functions prototypes
89// ----------------------------------------------------------------------------
90
91#ifdef __WXDEBUG__
92 // really just show the assert dialog
93 static bool DoShowAssertDialog(const wxString& msg);
94
95 // prepare for showing the assert dialog, use the given traits or
96 // DoShowAssertDialog() as last fallback to really show it
97 static
98 void ShowAssertDialog(const wxString& szFile,
99 int nLine,
100 const wxString& szFunc,
101 const wxString& szCond,
102 const wxString& szMsg,
103 wxAppTraits *traits = NULL);
104
105 // turn on the trace masks specified in the env variable WXTRACE
106 static void LINKAGEMODE SetTraceMasks();
107#endif // __WXDEBUG__
108
109// ----------------------------------------------------------------------------
110// global vars
111// ----------------------------------------------------------------------------
112
113wxAppConsole *wxAppConsole::ms_appInstance = NULL;
114
115wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL;
116
117// ----------------------------------------------------------------------------
118// wxEventLoopPtr
119// ----------------------------------------------------------------------------
120
121// this defines wxEventLoopPtr
122wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop)
123
124// ============================================================================
125// wxAppConsole implementation
126// ============================================================================
127
128// ----------------------------------------------------------------------------
129// ctor/dtor
130// ----------------------------------------------------------------------------
131
132wxAppConsole::wxAppConsole()
133{
134 m_traits = NULL;
135 m_mainLoop = NULL;
136
137 ms_appInstance = this;
138
139#ifdef __WXDEBUG__
140 SetTraceMasks();
141#if wxUSE_UNICODE
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.
145 delete m_traits;
146 m_traits = NULL;
147#endif
148#endif
149}
150
151wxAppConsole::~wxAppConsole()
152{
153 delete m_traits;
154}
155
156// ----------------------------------------------------------------------------
157// initilization/cleanup
158// ----------------------------------------------------------------------------
159
160bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig)
161{
162#if wxUSE_INTL
163 GetTraits()->SetLocale();
164#endif // wxUSE_INTL
165
166 // remember the command line arguments
167 argc = argcOrig;
168 argv = argvOrig;
169
170#if wxUSE_THREADS
171 wxPendingEventsLocker = new wxCriticalSection;
172#endif
173
174 // create port-specific main loop
175 m_mainLoop = CreateMainLoop();
176
177#ifndef __WXPALMOS__
178 if ( m_appName.empty() && argv )
179 {
180 // the application name is, by default, the name of its executable file
181 wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL);
182 }
183#endif // !__WXPALMOS__
184
185 return true;
186}
187
188wxEventLoop *wxAppConsole::CreateMainLoop()
189{
190 return GetTraits()->CreateEventLoop();
191}
192
193void wxAppConsole::CleanUp()
194{
195 delete m_mainLoop;
196 m_mainLoop = NULL;
197
198 delete wxPendingEvents;
199 wxPendingEvents = NULL;
200
201#if wxUSE_THREADS
202 delete wxPendingEventsLocker;
203 wxPendingEventsLocker = NULL;
204#endif // wxUSE_THREADS
205}
206
207// ----------------------------------------------------------------------------
208// OnXXX() callbacks
209// ----------------------------------------------------------------------------
210
211bool wxAppConsole::OnInit()
212{
213#if wxUSE_CMDLINE_PARSER
214 wxCmdLineParser parser(argc, argv);
215
216 OnInitCmdLine(parser);
217
218 bool cont;
219 switch ( parser.Parse(false /* don't show usage */) )
220 {
221 case -1:
222 cont = OnCmdLineHelp(parser);
223 break;
224
225 case 0:
226 cont = OnCmdLineParsed(parser);
227 break;
228
229 default:
230 cont = OnCmdLineError(parser);
231 break;
232 }
233
234 if ( !cont )
235 return false;
236#endif // wxUSE_CMDLINE_PARSER
237
238 return true;
239}
240
241int wxAppConsole::OnRun()
242{
243 return MainLoop();
244}
245
246int wxAppConsole::OnExit()
247{
248#if wxUSE_CONFIG
249 // delete the config object if any (don't use Get() here, but Set()
250 // because Get() could create a new config object)
251 delete wxConfigBase::Set((wxConfigBase *) NULL);
252#endif // wxUSE_CONFIG
253
254 return 0;
255}
256
257void wxAppConsole::Exit()
258{
259 if (m_mainLoop != NULL)
260 ExitMainLoop();
261 else
262 exit(-1);
263}
264
265// ----------------------------------------------------------------------------
266// traits stuff
267// ----------------------------------------------------------------------------
268
269wxAppTraits *wxAppConsole::CreateTraits()
270{
271 return new wxConsoleAppTraits;
272}
273
274wxAppTraits *wxAppConsole::GetTraits()
275{
276 // FIXME-MT: protect this with a CS?
277 if ( !m_traits )
278 {
279 m_traits = CreateTraits();
280
281 wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") );
282 }
283
284 return m_traits;
285}
286
287// ----------------------------------------------------------------------------
288// event processing
289// ----------------------------------------------------------------------------
290
291int wxAppConsole::MainLoop()
292{
293 wxEventLoopTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
294
295 return m_mainLoop ? m_mainLoop->Run() : -1;
296}
297
298void wxAppConsole::ExitMainLoop()
299{
300 // we should exit from the main event loop, not just any currently active
301 // (e.g. modal dialog) event loop
302 if ( m_mainLoop && m_mainLoop->IsRunning() )
303 {
304 m_mainLoop->Exit(0);
305 }
306}
307
308bool wxAppConsole::Pending()
309{
310 // use the currently active message loop here, not m_mainLoop, because if
311 // we're showing a modal dialog (with its own event loop) currently the
312 // main event loop is not running anyhow
313 wxEventLoop * const loop = wxEventLoopBase::GetActive();
314
315 return loop && loop->Pending();
316}
317
318bool wxAppConsole::Dispatch()
319{
320 // see comment in Pending()
321 wxEventLoop * const loop = wxEventLoopBase::GetActive();
322
323 return loop && loop->Dispatch();
324}
325
326bool wxAppConsole::HasPendingEvents() const
327{
328 // ensure that we're the only thread to modify the pending events list
329 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
330
331 if ( !wxPendingEvents )
332 {
333 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
334 return false;
335 }
336 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
337 return true;
338}
339
340void wxAppConsole::ProcessPendingEvents()
341{
342#if wxUSE_THREADS
343 if ( !wxPendingEventsLocker )
344 return;
345#endif
346
347 if ( !HasPendingEvents() )
348 return;
349
350 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
351
352 // iterate until the list becomes empty
353 wxList::compatibility_iterator node = wxPendingEvents->GetFirst();
354 while (node)
355 {
356 wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
357 wxPendingEvents->Erase(node);
358
359 // In ProcessPendingEvents(), new handlers might be add
360 // and we can safely leave the critical section here.
361 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
362
363 handler->ProcessPendingEvents();
364
365 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
366
367 node = wxPendingEvents->GetFirst();
368 }
369
370 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
371}
372
373void wxAppConsole::WakeUpIdle()
374{
375 if ( m_mainLoop )
376 m_mainLoop->WakeUp();
377}
378
379bool wxAppConsole::ProcessIdle()
380{
381 wxIdleEvent event;
382
383 event.SetEventObject(this);
384 ProcessEvent(event);
385 return event.MoreRequested();
386}
387
388int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event))
389{
390 // process the events normally by default
391 return -1;
392}
393
394// ----------------------------------------------------------------------------
395// exception handling
396// ----------------------------------------------------------------------------
397
398#if wxUSE_EXCEPTIONS
399
400void
401wxAppConsole::HandleEvent(wxEvtHandler *handler,
402 wxEventFunction func,
403 wxEvent& event) const
404{
405 // by default, simply call the handler
406 (handler->*func)(event);
407}
408
409// ----------------------------------------------------------------------------
410// exceptions support
411// ----------------------------------------------------------------------------
412
413#if wxUSE_EXCEPTIONS
414
415bool wxAppConsole::OnExceptionInMainLoop()
416{
417 throw;
418
419 // some compilers are too stupid to know that we never return after throw
420#if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200)
421 return false;
422#endif
423}
424
425#endif // wxUSE_EXCEPTIONS
426
427
428#endif // wxUSE_EXCEPTIONS
429
430// ----------------------------------------------------------------------------
431// cmd line parsing
432// ----------------------------------------------------------------------------
433
434#if wxUSE_CMDLINE_PARSER
435
436#define OPTION_VERBOSE _T("verbose")
437
438void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser)
439{
440 // the standard command line options
441 static const wxCmdLineEntryDesc cmdLineDesc[] =
442 {
443 {
444 wxCMD_LINE_SWITCH,
445 _T("h"),
446 _T("help"),
447 gettext_noop("show this help message"),
448 wxCMD_LINE_VAL_NONE,
449 wxCMD_LINE_OPTION_HELP
450 },
451
452#if wxUSE_LOG
453 {
454 wxCMD_LINE_SWITCH,
455 wxEmptyString,
456 OPTION_VERBOSE,
457 gettext_noop("generate verbose log messages"),
458 wxCMD_LINE_VAL_NONE,
459 0x0
460 },
461#endif // wxUSE_LOG
462
463 // terminator
464 {
465 wxCMD_LINE_NONE,
466 wxEmptyString,
467 wxEmptyString,
468 wxEmptyString,
469 wxCMD_LINE_VAL_NONE,
470 0x0
471 }
472 };
473
474 parser.SetDesc(cmdLineDesc);
475}
476
477bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser)
478{
479#if wxUSE_LOG
480 if ( parser.Found(OPTION_VERBOSE) )
481 {
482 wxLog::SetVerbose(true);
483 }
484#else
485 wxUnusedVar(parser);
486#endif // wxUSE_LOG
487
488 return true;
489}
490
491bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser)
492{
493 parser.Usage();
494
495 return false;
496}
497
498bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser)
499{
500 parser.Usage();
501
502 return false;
503}
504
505#endif // wxUSE_CMDLINE_PARSER
506
507// ----------------------------------------------------------------------------
508// debugging support
509// ----------------------------------------------------------------------------
510
511/* static */
512bool wxAppConsole::CheckBuildOptions(const char *optionsSignature,
513 const char *componentName)
514{
515#if 0 // can't use wxLogTrace, not up and running yet
516 printf("checking build options object '%s' (ptr %p) in '%s'\n",
517 optionsSignature, optionsSignature, componentName);
518#endif
519
520 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
521 {
522 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
523 wxString prog = wxString::FromAscii(optionsSignature);
524 wxString progName = wxString::FromAscii(componentName);
525 wxString msg;
526
527 msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
528 lib.c_str(), progName.c_str(), prog.c_str());
529
530 wxLogFatalError(msg.c_str());
531
532 // normally wxLogFatalError doesn't return
533 return false;
534 }
535#undef wxCMP
536
537 return true;
538}
539
540#ifdef __WXDEBUG__
541
542void wxAppConsole::OnAssertFailure(const wxChar *file,
543 int line,
544 const wxChar *func,
545 const wxChar *cond,
546 const wxChar *msg)
547{
548 ShowAssertDialog(file, line, func, cond, msg, GetTraits());
549}
550
551void wxAppConsole::OnAssert(const wxChar *file,
552 int line,
553 const wxChar *cond,
554 const wxChar *msg)
555{
556 OnAssertFailure(file, line, NULL, cond, msg);
557}
558
559#endif // __WXDEBUG__
560
561// ============================================================================
562// other classes implementations
563// ============================================================================
564
565// ----------------------------------------------------------------------------
566// wxConsoleAppTraitsBase
567// ----------------------------------------------------------------------------
568
569#if wxUSE_LOG
570
571wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
572{
573 return new wxLogStderr;
574}
575
576#endif // wxUSE_LOG
577
578wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
579{
580 return new wxMessageOutputStderr;
581}
582
583#if wxUSE_FONTMAP
584
585wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
586{
587 return (wxFontMapper *)new wxFontMapperBase;
588}
589
590#endif // wxUSE_FONTMAP
591
592wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
593{
594 // console applications don't use renderers
595 return NULL;
596}
597
598#ifdef __WXDEBUG__
599bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
600{
601 return wxAppTraitsBase::ShowAssertDialog(msg);
602}
603#endif
604
605bool wxConsoleAppTraitsBase::HasStderr()
606{
607 // console applications always have stderr, even under Mac/Windows
608 return true;
609}
610
611void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
612{
613 delete object;
614}
615
616void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
617{
618 // nothing to do
619}
620
621#if wxUSE_SOCKETS
622GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
623{
624 return NULL;
625}
626#endif
627
628// ----------------------------------------------------------------------------
629// wxAppTraits
630// ----------------------------------------------------------------------------
631
632#if wxUSE_INTL
633void wxAppTraitsBase::SetLocale()
634{
635 setlocale(LC_ALL, "");
636 wxUpdateLocaleIsUtf8();
637}
638#endif
639
640#ifdef __WXDEBUG__
641
642bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
643{
644 wxString msg = msgOriginal;
645
646#if wxUSE_STACKWALKER
647#if !defined(__WXMSW__)
648 // on Unix stack frame generation may take some time, depending on the
649 // size of the executable mainly... warn the user that we are working
650 wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait"));
651 fflush(stderr);
652#endif
653
654 const wxString stackTrace = GetAssertStackTrace();
655 if ( !stackTrace.empty() )
656 msg << _T("\n\nCall stack:\n") << stackTrace;
657#endif // wxUSE_STACKWALKER
658
659 return DoShowAssertDialog(msg);
660}
661
662#if wxUSE_STACKWALKER
663wxString wxAppTraitsBase::GetAssertStackTrace()
664{
665 wxString stackTrace;
666
667 class StackDump : public wxStackWalker
668 {
669 public:
670 StackDump() { }
671
672 const wxString& GetStackTrace() const { return m_stackTrace; }
673
674 protected:
675 virtual void OnStackFrame(const wxStackFrame& frame)
676 {
677 m_stackTrace << wxString::Format
678 (
679 _T("[%02d] "),
680 wx_truncate_cast(int, frame.GetLevel())
681 );
682
683 wxString name = frame.GetName();
684 if ( !name.empty() )
685 {
686 m_stackTrace << wxString::Format(_T("%-40s"), name.c_str());
687 }
688 else
689 {
690 m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress());
691 }
692
693 if ( frame.HasSourceLocation() )
694 {
695 m_stackTrace << _T('\t')
696 << frame.GetFileName()
697 << _T(':')
698 << frame.GetLine();
699 }
700
701 m_stackTrace << _T('\n');
702 }
703
704 private:
705 wxString m_stackTrace;
706 };
707
708 // don't show more than maxLines or we could get a dialog too tall to be
709 // shown on screen: 20 should be ok everywhere as even with 15 pixel high
710 // characters it is still only 300 pixels...
711 static const int maxLines = 20;
712
713 StackDump dump;
714 dump.Walk(2, maxLines); // don't show OnAssert() call itself
715 stackTrace = dump.GetStackTrace();
716
717 const int count = stackTrace.Freq(wxT('\n'));
718 for ( int i = 0; i < count - maxLines; i++ )
719 stackTrace = stackTrace.BeforeLast(wxT('\n'));
720
721 return stackTrace;
722}
723#endif // wxUSE_STACKWALKER
724
725
726#endif // __WXDEBUG__
727
728// ============================================================================
729// global functions implementation
730// ============================================================================
731
732void wxExit()
733{
734 if ( wxTheApp )
735 {
736 wxTheApp->Exit();
737 }
738 else
739 {
740 // what else can we do?
741 exit(-1);
742 }
743}
744
745void wxWakeUpIdle()
746{
747 if ( wxTheApp )
748 {
749 wxTheApp->WakeUpIdle();
750 }
751 //else: do nothing, what can we do?
752}
753
754#ifdef __WXDEBUG__
755
756// wxASSERT() helper
757bool wxAssertIsEqual(int x, int y)
758{
759 return x == y;
760}
761
762// break into the debugger
763void wxTrap()
764{
765#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
766 DebugBreak();
767#elif defined(__WXMAC__) && !defined(__DARWIN__)
768 #if __powerc
769 Debugger();
770 #else
771 SysBreak();
772 #endif
773#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
774 Debugger();
775#elif defined(__UNIX__)
776 raise(SIGTRAP);
777#else
778 // TODO
779#endif // Win/Unix
780}
781
782// this function is called when an assert fails
783static void wxDoOnAssert(const wxString& szFile,
784 int nLine,
785 const wxString& szFunc,
786 const wxString& szCond,
787 const wxString& szMsg = wxEmptyString)
788{
789 // FIXME MT-unsafe
790 static bool s_bInAssert = false;
791
792 if ( s_bInAssert )
793 {
794 // He-e-e-e-elp!! we're trapped in endless loop
795 wxTrap();
796
797 s_bInAssert = false;
798
799 return;
800 }
801
802 s_bInAssert = true;
803
804 if ( !wxTheApp )
805 {
806 // by default, show the assert dialog box -- we can't customize this
807 // behaviour
808 ShowAssertDialog(szFile, nLine, szFunc, szCond, szMsg);
809 }
810 else
811 {
812 // let the app process it as it wants
813 // FIXME-UTF8: use wc_str(), not c_str(), when ANSI build is removed
814 wxTheApp->OnAssertFailure(szFile.c_str(), nLine, szFunc.c_str(),
815 szCond.c_str(), szMsg.c_str());
816 }
817
818 s_bInAssert = false;
819}
820
821void wxOnAssert(const wxString& szFile,
822 int nLine,
823 const wxString& szFunc,
824 const wxString& szCond,
825 const wxString& szMsg)
826{
827 wxDoOnAssert(szFile, nLine, szFunc, szCond, szMsg);
828}
829
830void wxOnAssert(const wxString& szFile,
831 int nLine,
832 const wxString& szFunc,
833 const wxString& szCond)
834{
835 wxDoOnAssert(szFile, nLine, szFunc, szCond);
836}
837
838void wxOnAssert(const wxChar *szFile,
839 int nLine,
840 const char *szFunc,
841 const wxChar *szCond,
842 const wxChar *szMsg)
843{
844 wxDoOnAssert(szFile, nLine, szFunc, szCond, szMsg);
845}
846
847void wxOnAssert(const char *szFile,
848 int nLine,
849 const char *szFunc,
850 const char *szCond,
851 const wxString& szMsg)
852{
853 wxDoOnAssert(szFile, nLine, szFunc, szCond, szMsg);
854}
855
856void wxOnAssert(const char *szFile,
857 int nLine,
858 const char *szFunc,
859 const char *szCond,
860 const wxCStrData& msg)
861{
862 wxDoOnAssert(szFile, nLine, szFunc, szCond, msg);
863}
864
865#if wxUSE_UNICODE
866void wxOnAssert(const char *szFile,
867 int nLine,
868 const char *szFunc,
869 const char *szCond)
870{
871 wxDoOnAssert(szFile, nLine, szFunc, szCond);
872}
873
874void wxOnAssert(const char *szFile,
875 int nLine,
876 const char *szFunc,
877 const char *szCond,
878 const char *szMsg)
879{
880 wxDoOnAssert(szFile, nLine, szFunc, szCond, szMsg);
881}
882
883void wxOnAssert(const char *szFile,
884 int nLine,
885 const char *szFunc,
886 const char *szCond,
887 const wxChar *szMsg)
888{
889 wxDoOnAssert(szFile, nLine, szFunc, szCond, szMsg);
890}
891#endif // wxUSE_UNICODE
892
893#endif // __WXDEBUG__
894
895// ============================================================================
896// private functions implementation
897// ============================================================================
898
899#ifdef __WXDEBUG__
900
901static void LINKAGEMODE SetTraceMasks()
902{
903#if wxUSE_LOG
904 wxString mask;
905 if ( wxGetEnv(wxT("WXTRACE"), &mask) )
906 {
907 wxStringTokenizer tkn(mask, wxT(",;:"));
908 while ( tkn.HasMoreTokens() )
909 wxLog::AddTraceMask(tkn.GetNextToken());
910 }
911#endif // wxUSE_LOG
912}
913
914bool DoShowAssertDialog(const wxString& msg)
915{
916 // under MSW we can show the dialog even in the console mode
917#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
918 wxString msgDlg(msg);
919
920 // this message is intentionally not translated -- it is for
921 // developpers only
922 msgDlg += wxT("\nDo you want to stop the program?\n")
923 wxT("You can also choose [Cancel] to suppress ")
924 wxT("further warnings.");
925
926 switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"),
927 MB_YESNOCANCEL | MB_ICONSTOP ) )
928 {
929 case IDYES:
930 wxTrap();
931 break;
932
933 case IDCANCEL:
934 // stop the asserts
935 return true;
936
937 //case IDNO: nothing to do
938 }
939#else // !__WXMSW__
940 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
941 fflush(stderr);
942
943 // TODO: ask the user to enter "Y" or "N" on the console?
944 wxTrap();
945#endif // __WXMSW__/!__WXMSW__
946
947 // continue with the asserts
948 return false;
949}
950
951// show the assert modal dialog
952static
953void ShowAssertDialog(const wxString& szFile,
954 int nLine,
955 const wxString& szFunc,
956 const wxString& szCond,
957 const wxString& szMsg,
958 wxAppTraits *traits)
959{
960 // this variable can be set to true to suppress "assert failure" messages
961 static bool s_bNoAsserts = false;
962
963 wxString msg;
964 msg.reserve(2048);
965
966 // make life easier for people using VC++ IDE by using this format: like
967 // this, clicking on the message will take us immediately to the place of
968 // the failed assert
969 msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond);
970
971 // add the function name, if any
972 if ( !szFunc.empty() )
973 msg << _T(" in ") << szFunc << _T("()");
974
975 // and the message itself
976 if ( !szMsg.empty() )
977 {
978 msg << _T(": ") << szMsg;
979 }
980 else // no message given
981 {
982 msg << _T('.');
983 }
984
985#if wxUSE_THREADS
986 // if we are not in the main thread, output the assert directly and trap
987 // since dialogs cannot be displayed
988 if ( !wxThread::IsMain() )
989 {
990 msg += wxT(" [in child thread]");
991
992#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
993 msg << wxT("\r\n");
994 OutputDebugString(msg );
995#else
996 // send to stderr
997 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
998 fflush(stderr);
999#endif
1000 // He-e-e-e-elp!! we're asserting in a child thread
1001 wxTrap();
1002 }
1003 else
1004#endif // wxUSE_THREADS
1005
1006 if ( !s_bNoAsserts )
1007 {
1008 // send it to the normal log destination
1009 wxLogDebug(_T("%s"), msg.c_str());
1010
1011 if ( traits )
1012 {
1013 // delegate showing assert dialog (if possible) to that class
1014 s_bNoAsserts = traits->ShowAssertDialog(msg);
1015 }
1016 else // no traits object
1017 {
1018 // fall back to the function of last resort
1019 s_bNoAsserts = DoShowAssertDialog(msg);
1020 }
1021 }
1022}
1023
1024#endif // __WXDEBUG__