rename old wxAppConsole to wxAppConsoleBase and wxAppConsoleUnix to wxAppConsole...
[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 !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 wxString& szFile,
99 int nLine,
100 const wxString& szFunc,
101 const wxString& szCond,
102 const wxString& 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 *wxAppConsoleBase::ms_appInstance = NULL;
114
115 wxAppInitializerFunction wxAppConsoleBase::ms_appInitFn = NULL;
116
117 // ----------------------------------------------------------------------------
118 // wxEventLoopPtr
119 // ----------------------------------------------------------------------------
120
121 // this defines wxEventLoopPtr
122 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopBase)
123
124 // ============================================================================
125 // wxAppConsoleBase implementation
126 // ============================================================================
127
128 // ----------------------------------------------------------------------------
129 // ctor/dtor
130 // ----------------------------------------------------------------------------
131
132 wxAppConsoleBase::wxAppConsoleBase()
133 {
134 m_traits = NULL;
135 m_mainLoop = NULL;
136
137 ms_appInstance = wx_static_cast(wxAppConsole *, 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 wxAppConsoleBase::~wxAppConsoleBase()
152 {
153 delete m_traits;
154 }
155
156 // ----------------------------------------------------------------------------
157 // initilization/cleanup
158 // ----------------------------------------------------------------------------
159
160 bool wxAppConsoleBase::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 #ifndef __WXPALMOS__
175 if ( m_appName.empty() && argv )
176 {
177 // the application name is, by default, the name of its executable file
178 wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL);
179 }
180 #endif // !__WXPALMOS__
181
182 return true;
183 }
184
185 wxEventLoopBase *wxAppConsoleBase::CreateMainLoop()
186 {
187 return GetTraits()->CreateEventLoop();
188 }
189
190 void wxAppConsoleBase::CleanUp()
191 {
192 if ( m_mainLoop )
193 {
194 delete m_mainLoop;
195 m_mainLoop = NULL;
196 }
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 wxAppConsoleBase::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 wxAppConsoleBase::OnRun()
242 {
243 return MainLoop();
244 }
245
246 int wxAppConsoleBase::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 wxAppConsoleBase::Exit()
258 {
259 if (m_mainLoop != NULL)
260 ExitMainLoop();
261 else
262 exit(-1);
263 }
264
265 // ----------------------------------------------------------------------------
266 // traits stuff
267 // ----------------------------------------------------------------------------
268
269 wxAppTraits *wxAppConsoleBase::CreateTraits()
270 {
271 return new wxConsoleAppTraits;
272 }
273
274 wxAppTraits *wxAppConsoleBase::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 wxAppConsoleBase::MainLoop()
292 {
293 wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
294
295 return m_mainLoop ? m_mainLoop->Run() : -1;
296 }
297
298 void wxAppConsoleBase::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 wxAppConsoleBase::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 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
314
315 return loop && loop->Pending();
316 }
317
318 bool wxAppConsoleBase::Dispatch()
319 {
320 // see comment in Pending()
321 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
322
323 return loop && loop->Dispatch();
324 }
325
326 bool wxAppConsoleBase::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 /* static */
341 bool wxAppConsoleBase::IsMainLoopRunning()
342 {
343 const wxAppConsole * const app = GetInstance();
344
345 return app && app->m_mainLoop != NULL;
346 }
347
348 void wxAppConsoleBase::ProcessPendingEvents()
349 {
350 #if wxUSE_THREADS
351 if ( !wxPendingEventsLocker )
352 return;
353 #endif
354
355 if ( !HasPendingEvents() )
356 return;
357
358 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
359
360 // iterate until the list becomes empty
361 wxList::compatibility_iterator node = wxPendingEvents->GetFirst();
362 while (node)
363 {
364 wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
365 wxPendingEvents->Erase(node);
366
367 // In ProcessPendingEvents(), new handlers might be add
368 // and we can safely leave the critical section here.
369 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
370
371 handler->ProcessPendingEvents();
372
373 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
374
375 node = wxPendingEvents->GetFirst();
376 }
377
378 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
379 }
380
381 void wxAppConsoleBase::WakeUpIdle()
382 {
383 if ( m_mainLoop )
384 m_mainLoop->WakeUp();
385 }
386
387 bool wxAppConsoleBase::ProcessIdle()
388 {
389 wxIdleEvent event;
390
391 event.SetEventObject(this);
392 ProcessEvent(event);
393 return event.MoreRequested();
394 }
395
396 int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
397 {
398 // process the events normally by default
399 return -1;
400 }
401
402 // ----------------------------------------------------------------------------
403 // exception handling
404 // ----------------------------------------------------------------------------
405
406 #if wxUSE_EXCEPTIONS
407
408 void
409 wxAppConsoleBase::HandleEvent(wxEvtHandler *handler,
410 wxEventFunction func,
411 wxEvent& event) const
412 {
413 // by default, simply call the handler
414 (handler->*func)(event);
415 }
416
417 // ----------------------------------------------------------------------------
418 // exceptions support
419 // ----------------------------------------------------------------------------
420
421 #if wxUSE_EXCEPTIONS
422
423 bool wxAppConsoleBase::OnExceptionInMainLoop()
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
436 #endif // wxUSE_EXCEPTIONS
437
438 // ----------------------------------------------------------------------------
439 // cmd line parsing
440 // ----------------------------------------------------------------------------
441
442 #if wxUSE_CMDLINE_PARSER
443
444 #define OPTION_VERBOSE _T("verbose")
445
446 void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser)
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,
463 wxEmptyString,
464 OPTION_VERBOSE,
465 gettext_noop("generate verbose log messages"),
466 wxCMD_LINE_VAL_NONE,
467 0x0
468 },
469 #endif // wxUSE_LOG
470
471 // terminator
472 {
473 wxCMD_LINE_NONE,
474 wxEmptyString,
475 wxEmptyString,
476 wxEmptyString,
477 wxCMD_LINE_VAL_NONE,
478 0x0
479 }
480 };
481
482 parser.SetDesc(cmdLineDesc);
483 }
484
485 bool wxAppConsoleBase::OnCmdLineParsed(wxCmdLineParser& parser)
486 {
487 #if wxUSE_LOG
488 if ( parser.Found(OPTION_VERBOSE) )
489 {
490 wxLog::SetVerbose(true);
491 }
492 #else
493 wxUnusedVar(parser);
494 #endif // wxUSE_LOG
495
496 return true;
497 }
498
499 bool wxAppConsoleBase::OnCmdLineHelp(wxCmdLineParser& parser)
500 {
501 parser.Usage();
502
503 return false;
504 }
505
506 bool wxAppConsoleBase::OnCmdLineError(wxCmdLineParser& parser)
507 {
508 parser.Usage();
509
510 return false;
511 }
512
513 #endif // wxUSE_CMDLINE_PARSER
514
515 // ----------------------------------------------------------------------------
516 // debugging support
517 // ----------------------------------------------------------------------------
518
519 /* static */
520 bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature,
521 const char *componentName)
522 {
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);
526 #endif
527
528 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
529 {
530 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
531 wxString prog = wxString::FromAscii(optionsSignature);
532 wxString progName = wxString::FromAscii(componentName);
533 wxString msg;
534
535 msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
536 lib.c_str(), progName.c_str(), prog.c_str());
537
538 wxLogFatalError(msg.c_str());
539
540 // normally wxLogFatalError doesn't return
541 return false;
542 }
543 #undef wxCMP
544
545 return true;
546 }
547
548 #ifdef __WXDEBUG__
549
550 void wxAppConsoleBase::OnAssertFailure(const wxChar *file,
551 int line,
552 const wxChar *func,
553 const wxChar *cond,
554 const wxChar *msg)
555 {
556 ShowAssertDialog(file, line, func, cond, msg, GetTraits());
557 }
558
559 void wxAppConsoleBase::OnAssert(const wxChar *file,
560 int line,
561 const wxChar *cond,
562 const wxChar *msg)
563 {
564 OnAssertFailure(file, line, NULL, cond, msg);
565 }
566
567 #endif // __WXDEBUG__
568
569 // ============================================================================
570 // other classes implementations
571 // ============================================================================
572
573 // ----------------------------------------------------------------------------
574 // wxConsoleAppTraitsBase
575 // ----------------------------------------------------------------------------
576
577 #if wxUSE_LOG
578
579 wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
580 {
581 return new wxLogStderr;
582 }
583
584 #endif // wxUSE_LOG
585
586 wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
587 {
588 return new wxMessageOutputStderr;
589 }
590
591 #if wxUSE_FONTMAP
592
593 wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
594 {
595 return (wxFontMapper *)new wxFontMapperBase;
596 }
597
598 #endif // wxUSE_FONTMAP
599
600 wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
601 {
602 // console applications don't use renderers
603 return NULL;
604 }
605
606 #ifdef __WXDEBUG__
607 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
608 {
609 return wxAppTraitsBase::ShowAssertDialog(msg);
610 }
611 #endif
612
613 bool wxConsoleAppTraitsBase::HasStderr()
614 {
615 // console applications always have stderr, even under Mac/Windows
616 return true;
617 }
618
619 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
620 {
621 delete object;
622 }
623
624 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
625 {
626 // nothing to do
627 }
628
629 #if wxUSE_SOCKETS
630 GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
631 {
632 return NULL;
633 }
634 #endif
635
636 // ----------------------------------------------------------------------------
637 // wxAppTraits
638 // ----------------------------------------------------------------------------
639
640 #if wxUSE_INTL
641 void wxAppTraitsBase::SetLocale()
642 {
643 setlocale(LC_ALL, "");
644 wxUpdateLocaleIsUtf8();
645 }
646 #endif
647
648 #ifdef __WXDEBUG__
649
650 bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
651 {
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
667 return DoShowAssertDialog(msg);
668 }
669
670 #if wxUSE_STACKWALKER
671 wxString 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
734 #endif // __WXDEBUG__
735
736 // ============================================================================
737 // global functions implementation
738 // ============================================================================
739
740 void 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
753 void 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
765 bool wxAssertIsEqual(int x, int y)
766 {
767 return x == y;
768 }
769
770 // break into the debugger
771 void 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
781 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
782 Debugger();
783 #elif defined(__UNIX__)
784 raise(SIGTRAP);
785 #else
786 // TODO
787 #endif // Win/Unix
788 }
789
790 // this function is called when an assert fails
791 static void wxDoOnAssert(const wxString& szFile,
792 int nLine,
793 const wxString& szFunc,
794 const wxString& szCond,
795 const wxString& szMsg = wxEmptyString)
796 {
797 // FIXME MT-unsafe
798 static bool s_bInAssert = false;
799
800 if ( s_bInAssert )
801 {
802 // He-e-e-e-elp!! we're trapped in endless loop
803 wxTrap();
804
805 s_bInAssert = false;
806
807 return;
808 }
809
810 s_bInAssert = true;
811
812 if ( !wxTheApp )
813 {
814 // by default, show the assert dialog box -- we can't customize this
815 // behaviour
816 ShowAssertDialog(szFile, nLine, szFunc, szCond, szMsg);
817 }
818 else
819 {
820 // let the app process it as it wants
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());
824 }
825
826 s_bInAssert = false;
827 }
828
829 void 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
838 void wxOnAssert(const wxString& szFile,
839 int nLine,
840 const wxString& szFunc,
841 const wxString& szCond)
842 {
843 wxDoOnAssert(szFile, nLine, szFunc, szCond);
844 }
845
846 void 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
855 void 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
864 void 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
873 #if wxUSE_UNICODE
874 void wxOnAssert(const char *szFile,
875 int nLine,
876 const char *szFunc,
877 const char *szCond)
878 {
879 wxDoOnAssert(szFile, nLine, szFunc, szCond);
880 }
881
882 void 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
891 void 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
901 #endif // __WXDEBUG__
902
903 // ============================================================================
904 // private functions implementation
905 // ============================================================================
906
907 #ifdef __WXDEBUG__
908
909 static 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
922 bool 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
934 switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"),
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
959 // show the assert modal dialog
960 static
961 void ShowAssertDialog(const wxString& szFile,
962 int nLine,
963 const wxString& szFunc,
964 const wxString& szCond,
965 const wxString& szMsg,
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
979 // add the function name, if any
980 if ( !szFunc.empty() )
981 msg << _T(" in ") << szFunc << _T("()");
982
983 // and the message itself
984 if ( !szMsg.empty() )
985 {
986 msg << _T(": ") << szMsg;
987 }
988 else // no message given
989 {
990 msg << _T('.');
991 }
992
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 }
1011 else
1012 #endif // wxUSE_THREADS
1013
1014 if ( !s_bNoAsserts )
1015 {
1016 // send it to the normal log destination
1017 wxLogDebug(_T("%s"), msg.c_str());
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__