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