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