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