Dispatch pending events without waiting for idle time (closes #10994).
[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 // synthesize an idle event and check if more of them are needed
337 wxIdleEvent event;
338 event.SetEventObject(this);
339 ProcessEvent(event);
340
341 return event.MoreRequested();
342 }
343
344 // ----------------------------------------------------------------------------
345 // events
346 // ----------------------------------------------------------------------------
347
348 /* static */
349 bool wxAppConsoleBase::IsMainLoopRunning()
350 {
351 const wxAppConsole * const app = GetInstance();
352
353 return app && app->m_mainLoop != NULL;
354 }
355
356 int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
357 {
358 // process the events normally by default
359 return -1;
360 }
361
362 void wxAppConsoleBase::DelayPendingEventHandler(wxEvtHandler* toDelay)
363 {
364 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
365
366 // move the handler from the list of handlers with processable pending events
367 // to the list of handlers with pending events which needs to be processed later
368 m_handlersWithPendingEvents.Remove(toDelay);
369
370 if (m_handlersWithPendingDelayedEvents.Index(toDelay) == wxNOT_FOUND)
371 m_handlersWithPendingDelayedEvents.Add(toDelay);
372
373 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
374 }
375
376 void wxAppConsoleBase::RemovePendingEventHandler(wxEvtHandler* toRemove)
377 {
378 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
379
380 if (m_handlersWithPendingEvents.Index(toRemove) != wxNOT_FOUND)
381 {
382 m_handlersWithPendingEvents.Remove(toRemove);
383
384 // check that the handler was present only once in the list
385 wxASSERT_MSG( m_handlersWithPendingEvents.Index(toRemove) == wxNOT_FOUND,
386 "Handler occurs twice in the m_handlersWithPendingEvents list!" );
387 }
388 //else: it wasn't in this list at all, it's ok
389
390 if (m_handlersWithPendingDelayedEvents.Index(toRemove) != wxNOT_FOUND)
391 {
392 m_handlersWithPendingDelayedEvents.Remove(toRemove);
393
394 // check that the handler was present only once in the list
395 wxASSERT_MSG( m_handlersWithPendingDelayedEvents.Index(toRemove) == wxNOT_FOUND,
396 "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" );
397 }
398 //else: it wasn't in this list at all, it's ok
399
400 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
401 }
402
403 void wxAppConsoleBase::AppendPendingEventHandler(wxEvtHandler* toAppend)
404 {
405 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
406
407 if ( m_handlersWithPendingEvents.Index(toAppend) == wxNOT_FOUND )
408 m_handlersWithPendingEvents.Add(toAppend);
409
410 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
411 }
412
413 bool wxAppConsoleBase::HasPendingEvents() const
414 {
415 wxENTER_CRIT_SECT(const_cast<wxAppConsoleBase*>(this)->m_handlersWithPendingEventsLocker);
416
417 bool has = !m_handlersWithPendingEvents.IsEmpty();
418
419 wxLEAVE_CRIT_SECT(const_cast<wxAppConsoleBase*>(this)->m_handlersWithPendingEventsLocker);
420
421 return has;
422 }
423
424 void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
425 {
426 m_bDoPendingEventProcessing = false;
427 }
428
429 void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
430 {
431 m_bDoPendingEventProcessing = true;
432 }
433
434 void wxAppConsoleBase::ProcessPendingEvents()
435 {
436 if (!m_bDoPendingEventProcessing)
437 return;
438
439 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
440
441 wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
442 "this helper list should be empty" );
443
444 // iterate until the list becomes empty: the handlers remove themselves
445 // from it when they don't have any more pending events
446 while (!m_handlersWithPendingEvents.IsEmpty())
447 {
448 // In ProcessPendingEvents(), new handlers might be added
449 // and we can safely leave the critical section here.
450 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
451
452 // NOTE: we always call ProcessPendingEvents() on the first event handler
453 // with pending events because handlers auto-remove themselves
454 // from this list (see RemovePendingEventHandler) if they have no
455 // more pending events.
456 m_handlersWithPendingEvents[0]->ProcessPendingEvents();
457
458 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
459 }
460
461 // now the wxHandlersWithPendingEvents is surely empty; however some event
462 // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
463 // because of a selective wxYield call in progress.
464 // Now we need to move them back to wxHandlersWithPendingEvents so the next
465 // call to this function has the chance of processing them:
466 if (!m_handlersWithPendingDelayedEvents.IsEmpty())
467 {
468 WX_APPEND_ARRAY(m_handlersWithPendingEvents, m_handlersWithPendingDelayedEvents);
469 m_handlersWithPendingDelayedEvents.Clear();
470 }
471
472 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
473 }
474
475 void wxAppConsoleBase::DeletePendingEvents()
476 {
477 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
478
479 wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
480 "this helper list should be empty" );
481
482 for (unsigned int i=0; i<m_handlersWithPendingEvents.GetCount(); i++)
483 m_handlersWithPendingEvents[i]->DeletePendingEvents();
484
485 m_handlersWithPendingEvents.Clear();
486
487 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
488 }
489
490 // ----------------------------------------------------------------------------
491 // exception handling
492 // ----------------------------------------------------------------------------
493
494 #if wxUSE_EXCEPTIONS
495
496 void
497 wxAppConsoleBase::HandleEvent(wxEvtHandler *handler,
498 wxEventFunction func,
499 wxEvent& event) const
500 {
501 // by default, simply call the handler
502 (handler->*func)(event);
503 }
504
505 void wxAppConsoleBase::CallEventHandler(wxEvtHandler *handler,
506 wxEventFunctor& functor,
507 wxEvent& event) const
508 {
509 // If the functor holds a method then, for backward compatibility, call
510 // HandleEvent():
511 wxEventFunction eventFunction = functor.GetEvtMethod();
512
513 if ( eventFunction )
514 HandleEvent(handler, eventFunction, event);
515 else
516 functor(handler, event);
517 }
518
519 void wxAppConsoleBase::OnUnhandledException()
520 {
521 #ifdef __WXDEBUG__
522 // we're called from an exception handler so we can re-throw the exception
523 // to recover its type
524 wxString what;
525 try
526 {
527 throw;
528 }
529 #if wxUSE_STL
530 catch ( std::exception& e )
531 {
532 what.Printf("std::exception of type \"%s\", what() = \"%s\"",
533 typeid(e).name(), e.what());
534 }
535 #endif // wxUSE_STL
536 catch ( ... )
537 {
538 what = "unknown exception";
539 }
540
541 wxMessageOutputBest().Printf(
542 "*** Caught unhandled %s; terminating\n", what
543 );
544 #endif // __WXDEBUG__
545 }
546
547 // ----------------------------------------------------------------------------
548 // exceptions support
549 // ----------------------------------------------------------------------------
550
551 bool wxAppConsoleBase::OnExceptionInMainLoop()
552 {
553 throw;
554
555 // some compilers are too stupid to know that we never return after throw
556 #if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200)
557 return false;
558 #endif
559 }
560
561 #endif // wxUSE_EXCEPTIONS
562
563 // ----------------------------------------------------------------------------
564 // cmd line parsing
565 // ----------------------------------------------------------------------------
566
567 #if wxUSE_CMDLINE_PARSER
568
569 #define OPTION_VERBOSE "verbose"
570
571 void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser)
572 {
573 // the standard command line options
574 static const wxCmdLineEntryDesc cmdLineDesc[] =
575 {
576 {
577 wxCMD_LINE_SWITCH,
578 "h",
579 "help",
580 gettext_noop("show this help message"),
581 wxCMD_LINE_VAL_NONE,
582 wxCMD_LINE_OPTION_HELP
583 },
584
585 #if wxUSE_LOG
586 {
587 wxCMD_LINE_SWITCH,
588 NULL,
589 OPTION_VERBOSE,
590 gettext_noop("generate verbose log messages"),
591 wxCMD_LINE_VAL_NONE,
592 0x0
593 },
594 #endif // wxUSE_LOG
595
596 // terminator
597 wxCMD_LINE_DESC_END
598 };
599
600 parser.SetDesc(cmdLineDesc);
601 }
602
603 bool wxAppConsoleBase::OnCmdLineParsed(wxCmdLineParser& parser)
604 {
605 #if wxUSE_LOG
606 if ( parser.Found(OPTION_VERBOSE) )
607 {
608 wxLog::SetVerbose(true);
609 }
610 #else
611 wxUnusedVar(parser);
612 #endif // wxUSE_LOG
613
614 return true;
615 }
616
617 bool wxAppConsoleBase::OnCmdLineHelp(wxCmdLineParser& parser)
618 {
619 parser.Usage();
620
621 return false;
622 }
623
624 bool wxAppConsoleBase::OnCmdLineError(wxCmdLineParser& parser)
625 {
626 parser.Usage();
627
628 return false;
629 }
630
631 #endif // wxUSE_CMDLINE_PARSER
632
633 // ----------------------------------------------------------------------------
634 // debugging support
635 // ----------------------------------------------------------------------------
636
637 /* static */
638 bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature,
639 const char *componentName)
640 {
641 #if 0 // can't use wxLogTrace, not up and running yet
642 printf("checking build options object '%s' (ptr %p) in '%s'\n",
643 optionsSignature, optionsSignature, componentName);
644 #endif
645
646 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
647 {
648 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
649 wxString prog = wxString::FromAscii(optionsSignature);
650 wxString progName = wxString::FromAscii(componentName);
651 wxString msg;
652
653 msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
654 lib.c_str(), progName.c_str(), prog.c_str());
655
656 wxLogFatalError(msg.c_str());
657
658 // normally wxLogFatalError doesn't return
659 return false;
660 }
661
662 return true;
663 }
664
665 void wxAppConsoleBase::OnAssertFailure(const wxChar *file,
666 int line,
667 const wxChar *func,
668 const wxChar *cond,
669 const wxChar *msg)
670 {
671 #if wxDEBUG_LEVEL
672 ShowAssertDialog(file, line, func, cond, msg, GetTraits());
673 #else
674 // this function is still present even in debug level 0 build for ABI
675 // compatibility reasons but is never called there and so can simply do
676 // nothing in it
677 wxUnusedVar(file);
678 wxUnusedVar(line);
679 wxUnusedVar(func);
680 wxUnusedVar(cond);
681 wxUnusedVar(msg);
682 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
683 }
684
685 void wxAppConsoleBase::OnAssert(const wxChar *file,
686 int line,
687 const wxChar *cond,
688 const wxChar *msg)
689 {
690 OnAssertFailure(file, line, NULL, cond, msg);
691 }
692
693 // ============================================================================
694 // other classes implementations
695 // ============================================================================
696
697 // ----------------------------------------------------------------------------
698 // wxConsoleAppTraitsBase
699 // ----------------------------------------------------------------------------
700
701 #if wxUSE_LOG
702
703 wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
704 {
705 return new wxLogStderr;
706 }
707
708 #endif // wxUSE_LOG
709
710 wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
711 {
712 return new wxMessageOutputStderr;
713 }
714
715 #if wxUSE_FONTMAP
716
717 wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
718 {
719 return (wxFontMapper *)new wxFontMapperBase;
720 }
721
722 #endif // wxUSE_FONTMAP
723
724 wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
725 {
726 // console applications don't use renderers
727 return NULL;
728 }
729
730 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
731 {
732 return wxAppTraitsBase::ShowAssertDialog(msg);
733 }
734
735 bool wxConsoleAppTraitsBase::HasStderr()
736 {
737 // console applications always have stderr, even under Mac/Windows
738 return true;
739 }
740
741 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
742 {
743 delete object;
744 }
745
746 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
747 {
748 // nothing to do
749 }
750
751 // ----------------------------------------------------------------------------
752 // wxAppTraits
753 // ----------------------------------------------------------------------------
754
755 #if wxUSE_INTL
756 void wxAppTraitsBase::SetLocale()
757 {
758 wxSetlocale(LC_ALL, "");
759 wxUpdateLocaleIsUtf8();
760 }
761 #endif
762
763 #if wxUSE_THREADS
764 void wxMutexGuiEnterImpl();
765 void wxMutexGuiLeaveImpl();
766
767 void wxAppTraitsBase::MutexGuiEnter()
768 {
769 wxMutexGuiEnterImpl();
770 }
771
772 void wxAppTraitsBase::MutexGuiLeave()
773 {
774 wxMutexGuiLeaveImpl();
775 }
776
777 void WXDLLIMPEXP_BASE wxMutexGuiEnter()
778 {
779 wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists();
780 if ( traits )
781 traits->MutexGuiEnter();
782 }
783
784 void WXDLLIMPEXP_BASE wxMutexGuiLeave()
785 {
786 wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists();
787 if ( traits )
788 traits->MutexGuiLeave();
789 }
790 #endif // wxUSE_THREADS
791
792 bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
793 {
794 #if wxDEBUG_LEVEL
795 wxString msg = msgOriginal;
796
797 #if wxUSE_STACKWALKER
798 #if !defined(__WXMSW__)
799 // on Unix stack frame generation may take some time, depending on the
800 // size of the executable mainly... warn the user that we are working
801 wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait"));
802 fflush(stderr);
803 #endif
804
805 const wxString stackTrace = GetAssertStackTrace();
806 if ( !stackTrace.empty() )
807 msg << _T("\n\nCall stack:\n") << stackTrace;
808 #endif // wxUSE_STACKWALKER
809
810 return DoShowAssertDialog(msg);
811 #else // !wxDEBUG_LEVEL
812 wxUnusedVar(msgOriginal);
813
814 return false;
815 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
816 }
817
818 #if wxUSE_STACKWALKER
819 wxString wxAppTraitsBase::GetAssertStackTrace()
820 {
821 #if wxDEBUG_LEVEL
822 wxString stackTrace;
823
824 class StackDump : public wxStackWalker
825 {
826 public:
827 StackDump() { }
828
829 const wxString& GetStackTrace() const { return m_stackTrace; }
830
831 protected:
832 virtual void OnStackFrame(const wxStackFrame& frame)
833 {
834 m_stackTrace << wxString::Format
835 (
836 _T("[%02d] "),
837 wx_truncate_cast(int, frame.GetLevel())
838 );
839
840 wxString name = frame.GetName();
841 if ( !name.empty() )
842 {
843 m_stackTrace << wxString::Format(_T("%-40s"), name.c_str());
844 }
845 else
846 {
847 m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress());
848 }
849
850 if ( frame.HasSourceLocation() )
851 {
852 m_stackTrace << _T('\t')
853 << frame.GetFileName()
854 << _T(':')
855 << frame.GetLine();
856 }
857
858 m_stackTrace << _T('\n');
859 }
860
861 private:
862 wxString m_stackTrace;
863 };
864
865 // don't show more than maxLines or we could get a dialog too tall to be
866 // shown on screen: 20 should be ok everywhere as even with 15 pixel high
867 // characters it is still only 300 pixels...
868 static const int maxLines = 20;
869
870 StackDump dump;
871 dump.Walk(2, maxLines); // don't show OnAssert() call itself
872 stackTrace = dump.GetStackTrace();
873
874 const int count = stackTrace.Freq(wxT('\n'));
875 for ( int i = 0; i < count - maxLines; i++ )
876 stackTrace = stackTrace.BeforeLast(wxT('\n'));
877
878 return stackTrace;
879 #else // !wxDEBUG_LEVEL
880 // this function is still present for ABI-compatibility even in debug level
881 // 0 build but is not used there and so can simply do nothing
882 return wxString();
883 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
884 }
885 #endif // wxUSE_STACKWALKER
886
887
888 // ============================================================================
889 // global functions implementation
890 // ============================================================================
891
892 void wxExit()
893 {
894 if ( wxTheApp )
895 {
896 wxTheApp->Exit();
897 }
898 else
899 {
900 // what else can we do?
901 exit(-1);
902 }
903 }
904
905 void wxWakeUpIdle()
906 {
907 if ( wxTheApp )
908 {
909 wxTheApp->WakeUpIdle();
910 }
911 //else: do nothing, what can we do?
912 }
913
914 // wxASSERT() helper
915 bool wxAssertIsEqual(int x, int y)
916 {
917 return x == y;
918 }
919
920 #if wxDEBUG_LEVEL
921
922 // break into the debugger
923 void wxTrap()
924 {
925 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
926 DebugBreak();
927 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
928 Debugger();
929 #elif defined(__UNIX__)
930 raise(SIGTRAP);
931 #else
932 // TODO
933 #endif // Win/Unix
934 }
935
936 // default assert handler
937 static void
938 wxDefaultAssertHandler(const wxString& file,
939 int line,
940 const wxString& func,
941 const wxString& cond,
942 const wxString& msg)
943 {
944 // FIXME MT-unsafe
945 static int s_bInAssert = 0;
946
947 wxRecursionGuard guard(s_bInAssert);
948 if ( guard.IsInside() )
949 {
950 // can't use assert here to avoid infinite loops, so just trap
951 wxTrap();
952
953 return;
954 }
955
956 if ( !wxTheApp )
957 {
958 // by default, show the assert dialog box -- we can't customize this
959 // behaviour
960 ShowAssertDialog(file, line, func, cond, msg);
961 }
962 else
963 {
964 // let the app process it as it wants
965 // FIXME-UTF8: use wc_str(), not c_str(), when ANSI build is removed
966 wxTheApp->OnAssertFailure(file.c_str(), line, func.c_str(),
967 cond.c_str(), msg.c_str());
968 }
969 }
970
971 wxAssertHandler_t wxTheAssertHandler = wxDefaultAssertHandler;
972
973 void wxOnAssert(const wxString& file,
974 int line,
975 const wxString& func,
976 const wxString& cond,
977 const wxString& msg)
978 {
979 wxTheAssertHandler(file, line, func, cond, msg);
980 }
981
982 void wxOnAssert(const wxString& file,
983 int line,
984 const wxString& func,
985 const wxString& cond)
986 {
987 wxTheAssertHandler(file, line, func, cond, wxString());
988 }
989
990 void wxOnAssert(const wxChar *file,
991 int line,
992 const char *func,
993 const wxChar *cond,
994 const wxChar *msg)
995 {
996 // this is the backwards-compatible version (unless we don't use Unicode)
997 // so it could be called directly from the user code and this might happen
998 // even when wxTheAssertHandler is NULL
999 #if wxUSE_UNICODE
1000 if ( wxTheAssertHandler )
1001 #endif // wxUSE_UNICODE
1002 wxTheAssertHandler(file, line, func, cond, msg);
1003 }
1004
1005 void wxOnAssert(const char *file,
1006 int line,
1007 const char *func,
1008 const char *cond,
1009 const wxString& msg)
1010 {
1011 wxTheAssertHandler(file, line, func, cond, msg);
1012 }
1013
1014 void wxOnAssert(const char *file,
1015 int line,
1016 const char *func,
1017 const char *cond,
1018 const wxCStrData& msg)
1019 {
1020 wxTheAssertHandler(file, line, func, cond, msg);
1021 }
1022
1023 #if wxUSE_UNICODE
1024 void wxOnAssert(const char *file,
1025 int line,
1026 const char *func,
1027 const char *cond)
1028 {
1029 wxTheAssertHandler(file, line, func, cond, wxString());
1030 }
1031
1032 void wxOnAssert(const char *file,
1033 int line,
1034 const char *func,
1035 const char *cond,
1036 const char *msg)
1037 {
1038 wxTheAssertHandler(file, line, func, cond, msg);
1039 }
1040
1041 void wxOnAssert(const char *file,
1042 int line,
1043 const char *func,
1044 const char *cond,
1045 const wxChar *msg)
1046 {
1047 wxTheAssertHandler(file, line, func, cond, msg);
1048 }
1049 #endif // wxUSE_UNICODE
1050
1051 #endif // wxDEBUG_LEVEL
1052
1053 // ============================================================================
1054 // private functions implementation
1055 // ============================================================================
1056
1057 #ifdef __WXDEBUG__
1058
1059 static void LINKAGEMODE SetTraceMasks()
1060 {
1061 #if wxUSE_LOG
1062 wxString mask;
1063 if ( wxGetEnv(wxT("WXTRACE"), &mask) )
1064 {
1065 wxStringTokenizer tkn(mask, wxT(",;:"));
1066 while ( tkn.HasMoreTokens() )
1067 wxLog::AddTraceMask(tkn.GetNextToken());
1068 }
1069 #endif // wxUSE_LOG
1070 }
1071
1072 #endif // __WXDEBUG__
1073
1074 #if wxDEBUG_LEVEL
1075
1076 static
1077 bool DoShowAssertDialog(const wxString& msg)
1078 {
1079 // under MSW we can show the dialog even in the console mode
1080 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1081 wxString msgDlg(msg);
1082
1083 // this message is intentionally not translated -- it is for developers
1084 // only -- and the less code we use here, less is the danger of recursively
1085 // asserting and dying
1086 msgDlg += wxT("\nDo you want to stop the program?\n")
1087 wxT("You can also choose [Cancel] to suppress ")
1088 wxT("further warnings.");
1089
1090 switch ( ::MessageBox(NULL, msgDlg.wx_str(), _T("wxWidgets Debug Alert"),
1091 MB_YESNOCANCEL | MB_ICONSTOP ) )
1092 {
1093 case IDYES:
1094 wxTrap();
1095 break;
1096
1097 case IDCANCEL:
1098 // stop the asserts
1099 return true;
1100
1101 //case IDNO: nothing to do
1102 }
1103 #else // !__WXMSW__
1104 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
1105 fflush(stderr);
1106
1107 // TODO: ask the user to enter "Y" or "N" on the console?
1108 wxTrap();
1109 #endif // __WXMSW__/!__WXMSW__
1110
1111 // continue with the asserts
1112 return false;
1113 }
1114
1115 // show the standard assert dialog
1116 static
1117 void ShowAssertDialog(const wxString& file,
1118 int line,
1119 const wxString& func,
1120 const wxString& cond,
1121 const wxString& msgUser,
1122 wxAppTraits *traits)
1123 {
1124 // this variable can be set to true to suppress "assert failure" messages
1125 static bool s_bNoAsserts = false;
1126
1127 wxString msg;
1128 msg.reserve(2048);
1129
1130 // make life easier for people using VC++ IDE by using this format: like
1131 // this, clicking on the message will take us immediately to the place of
1132 // the failed assert
1133 msg.Printf(wxT("%s(%d): assert \"%s\" failed"), file, line, cond);
1134
1135 // add the function name, if any
1136 if ( !func.empty() )
1137 msg << _T(" in ") << func << _T("()");
1138
1139 // and the message itself
1140 if ( !msgUser.empty() )
1141 {
1142 msg << _T(": ") << msgUser;
1143 }
1144 else // no message given
1145 {
1146 msg << _T('.');
1147 }
1148
1149 #if wxUSE_THREADS
1150 // if we are not in the main thread, output the assert directly and trap
1151 // since dialogs cannot be displayed
1152 if ( !wxThread::IsMain() )
1153 {
1154 msg += wxT(" [in child thread]");
1155
1156 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
1157 msg << wxT("\r\n");
1158 OutputDebugString(msg.wx_str());
1159 #else
1160 // send to stderr
1161 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
1162 fflush(stderr);
1163 #endif
1164 // He-e-e-e-elp!! we're asserting in a child thread
1165 wxTrap();
1166 }
1167 else
1168 #endif // wxUSE_THREADS
1169
1170 if ( !s_bNoAsserts )
1171 {
1172 // send it to the normal log destination
1173 wxLogDebug(_T("%s"), msg.c_str());
1174
1175 if ( traits )
1176 {
1177 // delegate showing assert dialog (if possible) to that class
1178 s_bNoAsserts = traits->ShowAssertDialog(msg);
1179 }
1180 else // no traits object
1181 {
1182 // fall back to the function of last resort
1183 s_bNoAsserts = DoShowAssertDialog(msg);
1184 }
1185 }
1186 }
1187
1188 #endif // wxDEBUG_LEVEL