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