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