removed extra semicolons added by last commit
[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 wxPendingEvents;
196 wxPendingEvents = NULL;
197
198 #if wxUSE_THREADS
199 delete wxPendingEventsLocker;
200 wxPendingEventsLocker = NULL;
201 #endif // wxUSE_THREADS
202 }
203
204 // ----------------------------------------------------------------------------
205 // OnXXX() callbacks
206 // ----------------------------------------------------------------------------
207
208 bool wxAppConsole::OnInit()
209 {
210 #if wxUSE_CMDLINE_PARSER
211 wxCmdLineParser parser(argc, argv);
212
213 OnInitCmdLine(parser);
214
215 bool cont;
216 switch ( parser.Parse(false /* don't show usage */) )
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 )
232 return false;
233 #endif // wxUSE_CMDLINE_PARSER
234
235 return true;
236 }
237
238 int wxAppConsole::OnRun()
239 {
240 return MainLoop();
241 }
242
243 int 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
251 return 0;
252 }
253
254 void wxAppConsole::Exit()
255 {
256 if (m_mainLoop != NULL)
257 ExitMainLoop();
258 else
259 exit(-1);
260 }
261
262 // ----------------------------------------------------------------------------
263 // traits stuff
264 // ----------------------------------------------------------------------------
265
266 wxAppTraits *wxAppConsole::CreateTraits()
267 {
268 return new wxConsoleAppTraits;
269 }
270
271 wxAppTraits *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
284 // ----------------------------------------------------------------------------
285 // event processing
286 // ----------------------------------------------------------------------------
287
288 int wxAppConsole::MainLoop()
289 {
290 wxEventLoopTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
291
292 return m_mainLoop ? m_mainLoop->Run() : -1;
293 }
294
295 void 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
305 bool 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
315 bool wxAppConsole::Dispatch()
316 {
317 // see comment in Pending()
318 wxEventLoop * const loop = wxEventLoopBase::GetActive();
319
320 return loop && loop->Dispatch();
321 }
322
323 bool wxAppConsole::HasPendingEvents() const
324 {
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 );
331 return false;
332 }
333 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
334 return true;
335 }
336
337 void wxAppConsole::ProcessPendingEvents()
338 {
339 #if wxUSE_THREADS
340 if ( !wxPendingEventsLocker )
341 return;
342 #endif
343
344 if ( !HasPendingEvents() )
345 return;
346
347 // iterate until the list becomes empty
348 wxList::compatibility_iterator node = wxPendingEvents->GetFirst();
349 while (node)
350 {
351 wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
352 wxPendingEvents->Erase(node);
353
354 // In ProcessPendingEvents(), new handlers might be add
355 // and we can safely leave the critical section here.
356 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
357
358 handler->ProcessPendingEvents();
359
360 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
361
362 node = wxPendingEvents->GetFirst();
363 }
364
365 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
366 }
367
368 void wxAppConsole::WakeUpIdle()
369 {
370 if ( m_mainLoop )
371 m_mainLoop->WakeUp();
372 }
373
374 bool wxAppConsole::ProcessIdle()
375 {
376 wxIdleEvent event;
377
378 event.SetEventObject(this);
379 ProcessEvent(event);
380 return event.MoreRequested();
381 }
382
383 int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event))
384 {
385 // process the events normally by default
386 return -1;
387 }
388
389 // ----------------------------------------------------------------------------
390 // exception handling
391 // ----------------------------------------------------------------------------
392
393 #if wxUSE_EXCEPTIONS
394
395 void
396 wxAppConsole::HandleEvent(wxEvtHandler *handler,
397 wxEventFunction func,
398 wxEvent& event) const
399 {
400 // by default, simply call the handler
401 (handler->*func)(event);
402 }
403
404 // ----------------------------------------------------------------------------
405 // exceptions support
406 // ----------------------------------------------------------------------------
407
408 #if wxUSE_EXCEPTIONS
409
410 bool 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
423 #endif // wxUSE_EXCEPTIONS
424
425 // ----------------------------------------------------------------------------
426 // cmd line parsing
427 // ----------------------------------------------------------------------------
428
429 #if wxUSE_CMDLINE_PARSER
430
431 #define OPTION_VERBOSE _T("verbose")
432
433 void 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,
450 wxEmptyString,
451 OPTION_VERBOSE,
452 gettext_noop("generate verbose log messages"),
453 wxCMD_LINE_VAL_NONE,
454 0x0
455 },
456 #endif // wxUSE_LOG
457
458 // terminator
459 {
460 wxCMD_LINE_NONE,
461 wxEmptyString,
462 wxEmptyString,
463 wxEmptyString,
464 wxCMD_LINE_VAL_NONE,
465 0x0
466 }
467 };
468
469 parser.SetDesc(cmdLineDesc);
470 }
471
472 bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser)
473 {
474 #if wxUSE_LOG
475 if ( parser.Found(OPTION_VERBOSE) )
476 {
477 wxLog::SetVerbose(true);
478 }
479 #else
480 wxUnusedVar(parser);
481 #endif // wxUSE_LOG
482
483 return true;
484 }
485
486 bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser)
487 {
488 parser.Usage();
489
490 return false;
491 }
492
493 bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser)
494 {
495 parser.Usage();
496
497 return false;
498 }
499
500 #endif // wxUSE_CMDLINE_PARSER
501
502 // ----------------------------------------------------------------------------
503 // debugging support
504 // ----------------------------------------------------------------------------
505
506 /* static */
507 bool wxAppConsole::CheckBuildOptions(const char *optionsSignature,
508 const char *componentName)
509 {
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);
513 #endif
514
515 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
516 {
517 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
518 wxString prog = wxString::FromAscii(optionsSignature);
519 wxString progName = wxString::FromAscii(componentName);
520 wxString msg;
521
522 msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
523 lib.c_str(), progName.c_str(), prog.c_str());
524
525 wxLogFatalError(msg.c_str());
526
527 // normally wxLogFatalError doesn't return
528 return false;
529 }
530 #undef wxCMP
531
532 return true;
533 }
534
535 #ifdef __WXDEBUG__
536
537 void 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
546 void wxAppConsole::OnAssert(const wxChar *file,
547 int line,
548 const wxChar *cond,
549 const wxChar *msg)
550 {
551 OnAssertFailure(file, line, NULL, cond, msg);
552 }
553
554 #endif // __WXDEBUG__
555
556 // ============================================================================
557 // other classes implementations
558 // ============================================================================
559
560 // ----------------------------------------------------------------------------
561 // wxConsoleAppTraitsBase
562 // ----------------------------------------------------------------------------
563
564 #if wxUSE_LOG
565
566 wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
567 {
568 return new wxLogStderr;
569 }
570
571 #endif // wxUSE_LOG
572
573 wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
574 {
575 return new wxMessageOutputStderr;
576 }
577
578 #if wxUSE_FONTMAP
579
580 wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
581 {
582 return (wxFontMapper *)new wxFontMapperBase;
583 }
584
585 #endif // wxUSE_FONTMAP
586
587 wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
588 {
589 // console applications don't use renderers
590 return NULL;
591 }
592
593 #ifdef __WXDEBUG__
594 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
595 {
596 return wxAppTraitsBase::ShowAssertDialog(msg);
597 }
598 #endif
599
600 bool wxConsoleAppTraitsBase::HasStderr()
601 {
602 // console applications always have stderr, even under Mac/Windows
603 return true;
604 }
605
606 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
607 {
608 delete object;
609 }
610
611 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
612 {
613 // nothing to do
614 }
615
616 #if wxUSE_SOCKETS
617 GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
618 {
619 return NULL;
620 }
621 #endif
622
623 // ----------------------------------------------------------------------------
624 // wxAppTraits
625 // ----------------------------------------------------------------------------
626
627 #if wxUSE_INTL
628 void wxAppTraitsBase::SetLocale()
629 {
630 setlocale(LC_ALL, "");
631 wxUpdateLocaleIsUtf8();
632 }
633 #endif
634
635 #ifdef __WXDEBUG__
636
637 bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
638 {
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
654 return DoShowAssertDialog(msg);
655 }
656
657 #if wxUSE_STACKWALKER
658 wxString 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
721 #endif // __WXDEBUG__
722
723 // ============================================================================
724 // global functions implementation
725 // ============================================================================
726
727 void 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
740 void 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
752 bool wxAssertIsEqual(int x, int y)
753 {
754 return x == y;
755 }
756
757 // break into the debugger
758 void 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
768 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
769 Debugger();
770 #elif defined(__UNIX__)
771 raise(SIGTRAP);
772 #else
773 // TODO
774 #endif // Win/Unix
775 }
776
777 // this function is called when an assert fails
778 void wxOnAssert(const wxChar *szFile,
779 int nLine,
780 const char *szFunc,
781 const wxChar *szCond,
782 const wxChar *szMsg)
783 {
784 // FIXME MT-unsafe
785 static bool s_bInAssert = false;
786
787 if ( s_bInAssert )
788 {
789 // He-e-e-e-elp!! we're trapped in endless loop
790 wxTrap();
791
792 s_bInAssert = false;
793
794 return;
795 }
796
797 s_bInAssert = true;
798
799 // __FUNCTION__ is always in ASCII, convert it to wide char if needed
800 const wxString strFunc = wxString::FromAscii(szFunc);
801
802 if ( !wxTheApp )
803 {
804 // by default, show the assert dialog box -- we can't customize this
805 // behaviour
806 ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg);
807 }
808 else
809 {
810 // let the app process it as it wants
811 wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg);
812 }
813
814 s_bInAssert = false;
815 }
816
817 #endif // __WXDEBUG__
818
819 // ============================================================================
820 // private functions implementation
821 // ============================================================================
822
823 #ifdef __WXDEBUG__
824
825 static 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
838 bool 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
850 switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"),
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
875 // show the assert modal dialog
876 static
877 void ShowAssertDialog(const wxChar *szFile,
878 int nLine,
879 const wxChar *szFunc,
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
895 // add the function name, if any
896 if ( szFunc && *szFunc )
897 msg << _T(" in ") << szFunc << _T("()");
898
899 // and the message itself
900 if ( szMsg )
901 {
902 msg << _T(": ") << szMsg;
903 }
904 else // no message given
905 {
906 msg << _T('.');
907 }
908
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 }
927 else
928 #endif // wxUSE_THREADS
929
930 if ( !s_bNoAsserts )
931 {
932 // send it to the normal log destination
933 wxLogDebug(_T("%s"), msg.c_str());
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__