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