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