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