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