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