]> git.saurik.com Git - wxWidgets.git/blame - src/common/appbase.cpp
adding principal class for command line builds (High Resolution Support), changing...
[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>
526954c5 9// Licence: wxWindows licence
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
d98a58c5 28 #ifdef __WINDOWS__
57bd4c60
WS
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"
4d1ea475 46#include "wx/sysopt.h"
e2478fde 47#include "wx/tokenzr.h"
204abcd4 48#include "wx/thread.h"
e2478fde 49
fe24e4e9
VZ
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
1663c655 59
d98a58c5 60#if !defined(__WINDOWS__) || defined(__WXMICROWIN__)
e2478fde
VZ
61 #include <signal.h> // for SIGTRAP used by wxTrap()
62#endif //Win/Unix
63
0e5ab030
VZ
64#include <locale.h>
65
1c193821
JS
66#if wxUSE_FONTMAP
67 #include "wx/fontmap.h"
68#endif // wxUSE_FONTMAP
69
657a8a35 70#if wxDEBUG_LEVEL
7b1c3469 71 #if wxUSE_STACKWALKER
6c8f8d92 72 #include "wx/stackwalk.h"
d98a58c5 73 #ifdef __WINDOWS__
4a92d4bc
VZ
74 #include "wx/msw/debughlp.h"
75 #endif
6c8f8d92 76 #endif // wxUSE_STACKWALKER
000eea7a
VZ
77
78 #include "wx/recguard.h"
657a8a35 79#endif // wxDEBUG_LEVEL
6c8f8d92 80
121aea46
MW
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
e2478fde
VZ
88// ----------------------------------------------------------------------------
89// private functions prototypes
90// ----------------------------------------------------------------------------
91
657a8a35 92#if wxDEBUG_LEVEL
e2478fde
VZ
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
657a8a35
VZ
99 void ShowAssertDialog(const wxString& file,
100 int line,
101 const wxString& func,
102 const wxString& cond,
103 const wxString& msg,
e2478fde 104 wxAppTraits *traits = NULL);
657a8a35 105#endif // wxDEBUG_LEVEL
e2478fde 106
657a8a35 107#ifdef __WXDEBUG__
e2478fde
VZ
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
e0954e72 116wxAppConsole *wxAppConsoleBase::ms_appInstance = NULL;
e2478fde 117
e0954e72 118wxAppInitializerFunction wxAppConsoleBase::ms_appInitFn = NULL;
e2478fde 119
51fe4b60
VZ
120wxSocketManager *wxAppTraitsBase::ms_manager = NULL;
121
3185abc2
VZ
122WXDLLIMPEXP_DATA_BASE(wxList) wxPendingDelete;
123
b46b1d59
VZ
124// ----------------------------------------------------------------------------
125// wxEventLoopPtr
126// ----------------------------------------------------------------------------
127
128// this defines wxEventLoopPtr
2ddff00c 129wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopBase)
b46b1d59 130
e2478fde 131// ============================================================================
e0954e72 132// wxAppConsoleBase implementation
e2478fde
VZ
133// ============================================================================
134
135// ----------------------------------------------------------------------------
136// ctor/dtor
137// ----------------------------------------------------------------------------
138
e0954e72 139wxAppConsoleBase::wxAppConsoleBase()
e2478fde
VZ
140{
141 m_traits = NULL;
b46b1d59 142 m_mainLoop = NULL;
cae9e7b1 143 m_bDoPendingEventProcessing = true;
e2478fde 144
5c33522f 145 ms_appInstance = static_cast<wxAppConsole *>(this);
e2478fde
VZ
146
147#ifdef __WXDEBUG__
148 SetTraceMasks();
bc334f39
RD
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.
5276b0a5 153 wxDELETE(m_traits);
bc334f39 154#endif
e2478fde 155#endif
58cc1587
VZ
156
157 wxEvtHandler::AddFilter(this);
e2478fde
VZ
158}
159
e0954e72 160wxAppConsoleBase::~wxAppConsoleBase()
e2478fde 161{
58cc1587
VZ
162 wxEvtHandler::RemoveFilter(this);
163
89fb9e52
VZ
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
e2478fde
VZ
168 delete m_traits;
169}
170
94826170 171// ----------------------------------------------------------------------------
8b93348e 172// initialization/cleanup
94826170
VZ
173// ----------------------------------------------------------------------------
174
f432e677 175bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **WXUNUSED(argv))
94826170 176{
d774f916
VZ
177#if wxUSE_INTL
178 GetTraits()->SetLocale();
179#endif // wxUSE_INTL
180
f432e677
VZ
181 return true;
182}
183
184wxString wxAppConsoleBase::GetAppName() const
185{
186 wxString name = m_appName;
f432e677 187 if ( name.empty() )
94826170 188 {
f432e677
VZ
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 }
94826170 194 }
f432e677
VZ
195 return name;
196}
94826170 197
f432e677
VZ
198wxString 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();
94826170
VZ
212}
213
e0954e72 214wxEventLoopBase *wxAppConsoleBase::CreateMainLoop()
b46b1d59
VZ
215{
216 return GetTraits()->CreateEventLoop();
217}
218
e0954e72 219void wxAppConsoleBase::CleanUp()
94826170 220{
5276b0a5 221 wxDELETE(m_mainLoop);
94826170
VZ
222}
223
e2478fde
VZ
224// ----------------------------------------------------------------------------
225// OnXXX() callbacks
226// ----------------------------------------------------------------------------
227
e0954e72 228bool wxAppConsoleBase::OnInit()
e2478fde
VZ
229{
230#if wxUSE_CMDLINE_PARSER
231 wxCmdLineParser parser(argc, argv);
232
233 OnInitCmdLine(parser);
234
235 bool cont;
4629016d 236 switch ( parser.Parse(false /* don't show usage */) )
e2478fde
VZ
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 )
4629016d 252 return false;
e2478fde
VZ
253#endif // wxUSE_CMDLINE_PARSER
254
4629016d 255 return true;
e2478fde
VZ
256}
257
e0954e72 258int wxAppConsoleBase::OnRun()
b46b1d59
VZ
259{
260 return MainLoop();
8ac09e52 261}
b46b1d59 262
e0954e72 263int wxAppConsoleBase::OnExit()
e2478fde
VZ
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)
d3b9f782 268 delete wxConfigBase::Set(NULL);
e2478fde
VZ
269#endif // wxUSE_CONFIG
270
e2478fde
VZ
271 return 0;
272}
273
e0954e72 274void wxAppConsoleBase::Exit()
e2478fde 275{
b46b1d59
VZ
276 if (m_mainLoop != NULL)
277 ExitMainLoop();
278 else
279 exit(-1);
e2478fde
VZ
280}
281
282// ----------------------------------------------------------------------------
283// traits stuff
284// ----------------------------------------------------------------------------
285
e0954e72 286wxAppTraits *wxAppConsoleBase::CreateTraits()
e2478fde 287{
7843d11b 288 return new wxConsoleAppTraits;
e2478fde
VZ
289}
290
e0954e72 291wxAppTraits *wxAppConsoleBase::GetTraits()
e2478fde
VZ
292{
293 // FIXME-MT: protect this with a CS?
294 if ( !m_traits )
295 {
296 m_traits = CreateTraits();
297
9a83f860 298 wxASSERT_MSG( m_traits, wxT("wxApp::CreateTraits() failed?") );
e2478fde
VZ
299 }
300
301 return m_traits;
302}
303
96b2cbe8
VZ
304/* static */
305wxAppTraits *wxAppConsoleBase::GetTraitsIfExists()
306{
307 wxAppConsole * const app = GetInstance();
308 return app ? app->GetTraits() : NULL;
309}
310
e2478fde 311// ----------------------------------------------------------------------------
dde19c21 312// wxEventLoop redirection
e2478fde
VZ
313// ----------------------------------------------------------------------------
314
e0954e72 315int wxAppConsoleBase::MainLoop()
e2478fde 316{
2ddff00c 317 wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
b46b1d59
VZ
318
319 return m_mainLoop ? m_mainLoop->Run() : -1;
320}
321
e0954e72 322void wxAppConsoleBase::ExitMainLoop()
b46b1d59
VZ
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
e0954e72 332bool wxAppConsoleBase::Pending()
b46b1d59
VZ
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
2ddff00c 337 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
b46b1d59
VZ
338
339 return loop && loop->Pending();
340}
341
e0954e72 342bool wxAppConsoleBase::Dispatch()
b46b1d59
VZ
343{
344 // see comment in Pending()
2ddff00c 345 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
b46b1d59
VZ
346
347 return loop && loop->Dispatch();
348}
8ecff181 349
dde19c21
FM
350bool wxAppConsoleBase::Yield(bool onlyIfNeeded)
351{
352 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
6aacfc73
VZ
353 if ( loop )
354 return loop->Yield(onlyIfNeeded);
d48b06bd 355
6aacfc73
VZ
356 wxScopedPtr<wxEventLoopBase> tmpLoop(CreateMainLoop());
357 return tmpLoop->Yield(onlyIfNeeded);
e2478fde
VZ
358}
359
e0954e72 360void wxAppConsoleBase::WakeUpIdle()
b46b1d59 361{
53cda845
VZ
362 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
363
364 if ( loop )
365 loop->WakeUp();
b46b1d59
VZ
366}
367
e0954e72 368bool wxAppConsoleBase::ProcessIdle()
b46b1d59 369{
a758f601
VZ
370 // synthesize an idle event and check if more of them are needed
371 wxIdleEvent event;
372 event.SetEventObject(this);
373 ProcessEvent(event);
dde19c21 374
0055cc0e
VZ
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
e819ca3a
VZ
381 // Garbage collect all objects previously scheduled for destruction.
382 DeletePendingObjects();
383
a758f601 384 return event.MoreRequested();
dde19c21 385}
14eb37a0 386
3185abc2
VZ
387bool 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
dde19c21
FM
394// ----------------------------------------------------------------------------
395// events
396// ----------------------------------------------------------------------------
b46b1d59 397
dde19c21
FM
398/* static */
399bool wxAppConsoleBase::IsMainLoopRunning()
400{
401 const wxAppConsole * const app = GetInstance();
402
403 return app && app->m_mainLoop != NULL;
b46b1d59
VZ
404}
405
e0954e72 406int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event))
e2478fde
VZ
407{
408 // process the events normally by default
58cc1587 409 return Event_Skip;
e2478fde
VZ
410}
411
8e40ed85
FM
412void 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
426void 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
453void 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
463bool 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
474void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
475{
cae9e7b1 476 m_bDoPendingEventProcessing = false;
8e40ed85
FM
477}
478
479void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
480{
cae9e7b1 481 m_bDoPendingEventProcessing = true;
8e40ed85
FM
482}
483
484void wxAppConsoleBase::ProcessPendingEvents()
485{
3185abc2 486 if ( m_bDoPendingEventProcessing )
8e40ed85 487 {
3185abc2 488 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
8e40ed85 489
3185abc2
VZ
490 wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
491 "this helper list should be empty" );
8e40ed85 492
3185abc2
VZ
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 }
8e40ed85 520
3185abc2 521 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
8e40ed85 522 }
8e40ed85
FM
523}
524
cae9e7b1
FM
525void 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
3185abc2
VZ
540// ----------------------------------------------------------------------------
541// delayed objects destruction
542// ----------------------------------------------------------------------------
543
544bool wxAppConsoleBase::IsScheduledForDestruction(wxObject *object) const
545{
0f08aa44 546 return wxPendingDelete.Member(object);
3185abc2
VZ
547}
548
549void 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
563void 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
78361a0e
VZ
584// ----------------------------------------------------------------------------
585// exception handling
586// ----------------------------------------------------------------------------
587
6f054ac5
VZ
588#if wxUSE_EXCEPTIONS
589
590void
e0954e72
VZ
591wxAppConsoleBase::HandleEvent(wxEvtHandler *handler,
592 wxEventFunction func,
593 wxEvent& event) const
6f054ac5 594{
96d38c7e
VS
595 // by default, simply call the handler
596 (handler->*func)(event);
6f054ac5
VZ
597}
598
3c778901
VZ
599void 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():
890d70eb 605 wxEventFunction eventFunction = functor.GetEvtMethod();
3c778901
VZ
606
607 if ( eventFunction )
608 HandleEvent(handler, eventFunction, event);
609 else
610 functor(handler, event);
611}
612
1663c655
VZ
613void 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
b46b1d59
VZ
641// ----------------------------------------------------------------------------
642// exceptions support
643// ----------------------------------------------------------------------------
644
e0954e72 645bool wxAppConsoleBase::OnExceptionInMainLoop()
b46b1d59
VZ
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
6f054ac5
VZ
655#endif // wxUSE_EXCEPTIONS
656
e2478fde
VZ
657// ----------------------------------------------------------------------------
658// cmd line parsing
659// ----------------------------------------------------------------------------
660
661#if wxUSE_CMDLINE_PARSER
662
e6d4038a 663#define OPTION_VERBOSE "verbose"
e2478fde 664
e0954e72 665void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser)
e2478fde
VZ
666{
667 // the standard command line options
668 static const wxCmdLineEntryDesc cmdLineDesc[] =
669 {
670 {
671 wxCMD_LINE_SWITCH,
e6d4038a
VZ
672 "h",
673 "help",
e2478fde
VZ
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,
0d5ab92f 682 NULL,
e2478fde
VZ
683 OPTION_VERBOSE,
684 gettext_noop("generate verbose log messages"),
685 wxCMD_LINE_VAL_NONE,
686 0x0
687 },
688#endif // wxUSE_LOG
689
e2478fde 690 // terminator
0d5ab92f 691 wxCMD_LINE_DESC_END
e2478fde
VZ
692 };
693
694 parser.SetDesc(cmdLineDesc);
695}
696
e0954e72 697bool wxAppConsoleBase::OnCmdLineParsed(wxCmdLineParser& parser)
e2478fde
VZ
698{
699#if wxUSE_LOG
700 if ( parser.Found(OPTION_VERBOSE) )
701 {
fa0d3447 702 wxLog::SetVerbose(true);
e2478fde 703 }
fa0d3447
WS
704#else
705 wxUnusedVar(parser);
e2478fde
VZ
706#endif // wxUSE_LOG
707
fa0d3447 708 return true;
e2478fde
VZ
709}
710
e0954e72 711bool wxAppConsoleBase::OnCmdLineHelp(wxCmdLineParser& parser)
e2478fde
VZ
712{
713 parser.Usage();
714
4629016d 715 return false;
e2478fde
VZ
716}
717
e0954e72 718bool wxAppConsoleBase::OnCmdLineError(wxCmdLineParser& parser)
e2478fde
VZ
719{
720 parser.Usage();
721
4629016d 722 return false;
e2478fde
VZ
723}
724
725#endif // wxUSE_CMDLINE_PARSER
726
727// ----------------------------------------------------------------------------
728// debugging support
729// ----------------------------------------------------------------------------
730
731/* static */
e0954e72
VZ
732bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature,
733 const char *componentName)
e2478fde 734{
2a7c7605
VS
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);
e2478fde
VZ
738#endif
739
2a7c7605 740 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
e2478fde 741 {
2a7c7605
VS
742 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
743 wxString prog = wxString::FromAscii(optionsSignature);
744 wxString progName = wxString::FromAscii(componentName);
e2478fde 745 wxString msg;
2dbc444a 746
9a83f860 747 msg.Printf(wxT("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
2a7c7605 748 lib.c_str(), progName.c_str(), prog.c_str());
2dbc444a 749
095d49f2 750 wxLogFatalError(msg.c_str());
e2478fde
VZ
751
752 // normally wxLogFatalError doesn't return
4629016d 753 return false;
e2478fde 754 }
e2478fde 755
4629016d 756 return true;
e2478fde
VZ
757}
758
e0954e72
VZ
759void wxAppConsoleBase::OnAssertFailure(const wxChar *file,
760 int line,
761 const wxChar *func,
762 const wxChar *cond,
763 const wxChar *msg)
dfa0b52f 764{
657a8a35 765#if wxDEBUG_LEVEL
dfa0b52f 766 ShowAssertDialog(file, line, func, cond, msg, GetTraits());
657a8a35
VZ
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
dfa0b52f
VZ
777}
778
e0954e72
VZ
779void wxAppConsoleBase::OnAssert(const wxChar *file,
780 int line,
781 const wxChar *cond,
782 const wxChar *msg)
e2478fde 783{
acc476c5 784 OnAssertFailure(file, line, NULL, cond, msg);
e2478fde
VZ
785}
786
e2478fde
VZ
787// ============================================================================
788// other classes implementations
789// ============================================================================
790
791// ----------------------------------------------------------------------------
792// wxConsoleAppTraitsBase
793// ----------------------------------------------------------------------------
794
795#if wxUSE_LOG
796
797wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
798{
799 return new wxLogStderr;
800}
801
802#endif // wxUSE_LOG
803
804wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
805{
806 return new wxMessageOutputStderr;
807}
808
809#if wxUSE_FONTMAP
810
811wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
812{
813 return (wxFontMapper *)new wxFontMapperBase;
814}
815
816#endif // wxUSE_FONTMAP
817
f0244295
VZ
818wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
819{
820 // console applications don't use renderers
821 return NULL;
822}
823
e2478fde
VZ
824bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
825{
826 return wxAppTraitsBase::ShowAssertDialog(msg);
827}
828
829bool wxConsoleAppTraitsBase::HasStderr()
830{
831 // console applications always have stderr, even under Mac/Windows
832 return true;
833}
834
e2478fde
VZ
835// ----------------------------------------------------------------------------
836// wxAppTraits
837// ----------------------------------------------------------------------------
838
6c4f5ea5 839#if wxUSE_INTL
d774f916
VZ
840void wxAppTraitsBase::SetLocale()
841{
fe24e4e9
VZ
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).
d6f2a891 845 wxSetlocale(LC_ALL, "");
fe24e4e9
VZ
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
cb352236 855 wxUpdateLocaleIsUtf8();
d774f916 856}
6c4f5ea5 857#endif
d774f916 858
d254213e
PC
859#if wxUSE_THREADS
860void wxMutexGuiEnterImpl();
861void wxMutexGuiLeaveImpl();
862
863void wxAppTraitsBase::MutexGuiEnter()
864{
865 wxMutexGuiEnterImpl();
866}
867
868void wxAppTraitsBase::MutexGuiLeave()
869{
870 wxMutexGuiLeaveImpl();
871}
872
873void WXDLLIMPEXP_BASE wxMutexGuiEnter()
874{
96b2cbe8
VZ
875 wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists();
876 if ( traits )
877 traits->MutexGuiEnter();
d254213e
PC
878}
879
880void WXDLLIMPEXP_BASE wxMutexGuiLeave()
881{
96b2cbe8
VZ
882 wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists();
883 if ( traits )
884 traits->MutexGuiLeave();
d254213e
PC
885}
886#endif // wxUSE_THREADS
887
db9febdf 888bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
e2478fde 889{
657a8a35 890#if wxDEBUG_LEVEL
021efd65 891 wxString msg;
db9febdf
RR
892
893#if wxUSE_STACKWALKER
db9febdf
RR
894 const wxString stackTrace = GetAssertStackTrace();
895 if ( !stackTrace.empty() )
021efd65 896 {
9a83f860 897 msg << wxT("\n\nCall stack:\n") << stackTrace;
021efd65
VZ
898
899 wxMessageOutputDebug().Output(msg);
900 }
db9febdf
RR
901#endif // wxUSE_STACKWALKER
902
021efd65 903 return DoShowAssertDialog(msgOriginal + msg);
657a8a35
VZ
904#else // !wxDEBUG_LEVEL
905 wxUnusedVar(msgOriginal);
906
907 return false;
908#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
e2478fde
VZ
909}
910
db9febdf
RR
911#if wxUSE_STACKWALKER
912wxString wxAppTraitsBase::GetAssertStackTrace()
913{
657a8a35 914#if wxDEBUG_LEVEL
021efd65 915
d98a58c5 916#if !defined(__WINDOWS__)
021efd65
VZ
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);
d98a58c5 921#endif // !__WINDOWS__
021efd65
VZ
922
923
db9febdf
RR
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 (
9a83f860 938 wxT("[%02d] "),
db9febdf
RR
939 wx_truncate_cast(int, frame.GetLevel())
940 );
941
942 wxString name = frame.GetName();
943 if ( !name.empty() )
944 {
9a83f860 945 m_stackTrace << wxString::Format(wxT("%-40s"), name.c_str());
db9febdf
RR
946 }
947 else
948 {
9a83f860 949 m_stackTrace << wxString::Format(wxT("%p"), frame.GetAddress());
db9febdf
RR
950 }
951
952 if ( frame.HasSourceLocation() )
953 {
9a83f860 954 m_stackTrace << wxT('\t')
db9febdf 955 << frame.GetFileName()
9a83f860 956 << wxT(':')
db9febdf
RR
957 << frame.GetLine();
958 }
959
9a83f860 960 m_stackTrace << wxT('\n');
db9febdf
RR
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;
1114902a 973 dump.Walk(8, maxLines); // 8 is chosen to hide all OnAssert() calls
db9febdf
RR
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;
657a8a35
VZ
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
db9febdf
RR
986}
987#endif // wxUSE_STACKWALKER
988
989
e2478fde
VZ
990// ============================================================================
991// global functions implementation
992// ============================================================================
993
994void 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
1007void wxWakeUpIdle()
1008{
1009 if ( wxTheApp )
1010 {
1011 wxTheApp->WakeUpIdle();
1012 }
1013 //else: do nothing, what can we do?
1014}
1015
e2478fde
VZ
1016// wxASSERT() helper
1017bool wxAssertIsEqual(int x, int y)
1018{
1019 return x == y;
1020}
1021
975dc691
VZ
1022void wxAbort()
1023{
1024#ifdef __WXWINCE__
1025 ExitThread(3);
1026#else
1027 abort();
1028#endif
1029}
1030
657a8a35
VZ
1031#if wxDEBUG_LEVEL
1032
e2478fde
VZ
1033// break into the debugger
1034void wxTrap()
1035{
d98a58c5 1036#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
e2478fde 1037 DebugBreak();
f0756afe
DE
1038#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
1039 Debugger();
e2478fde
VZ
1040#elif defined(__UNIX__)
1041 raise(SIGTRAP);
1042#else
1043 // TODO
1044#endif // Win/Unix
1045}
1046
657a8a35
VZ
1047// default assert handler
1048static void
1049wxDefaultAssertHandler(const wxString& file,
1050 int line,
1051 const wxString& func,
1052 const wxString& cond,
1053 const wxString& msg)
e2478fde 1054{
4d1ea475
VZ
1055 // If this option is set, we should abort immediately when assert happens.
1056 if ( wxSystemOptions::GetOptionInt("exit-on-assert") )
d58c7af8 1057 wxAbort();
4d1ea475 1058
e2478fde 1059 // FIXME MT-unsafe
000eea7a 1060 static int s_bInAssert = 0;
e2478fde 1061
000eea7a
VZ
1062 wxRecursionGuard guard(s_bInAssert);
1063 if ( guard.IsInside() )
e2478fde 1064 {
000eea7a 1065 // can't use assert here to avoid infinite loops, so just trap
e2478fde
VZ
1066 wxTrap();
1067
e2478fde
VZ
1068 return;
1069 }
1070
e2478fde
VZ
1071 if ( !wxTheApp )
1072 {
1073 // by default, show the assert dialog box -- we can't customize this
1074 // behaviour
657a8a35 1075 ShowAssertDialog(file, line, func, cond, msg);
e2478fde
VZ
1076 }
1077 else
1078 {
1079 // let the app process it as it wants
0accd1cf 1080 // FIXME-UTF8: use wc_str(), not c_str(), when ANSI build is removed
657a8a35
VZ
1081 wxTheApp->OnAssertFailure(file.c_str(), line, func.c_str(),
1082 cond.c_str(), msg.c_str());
e2478fde 1083 }
e2478fde
VZ
1084}
1085
657a8a35
VZ
1086wxAssertHandler_t wxTheAssertHandler = wxDefaultAssertHandler;
1087
7d9550df
VZ
1088void wxSetDefaultAssertHandler()
1089{
1090 wxTheAssertHandler = wxDefaultAssertHandler;
1091}
1092
657a8a35
VZ
1093void wxOnAssert(const wxString& file,
1094 int line,
1095 const wxString& func,
1096 const wxString& cond,
1097 const wxString& msg)
0accd1cf 1098{
657a8a35 1099 wxTheAssertHandler(file, line, func, cond, msg);
0accd1cf
VS
1100}
1101
657a8a35
VZ
1102void wxOnAssert(const wxString& file,
1103 int line,
1104 const wxString& func,
1105 const wxString& cond)
0accd1cf 1106{
657a8a35 1107 wxTheAssertHandler(file, line, func, cond, wxString());
0accd1cf
VS
1108}
1109
657a8a35
VZ
1110void wxOnAssert(const wxChar *file,
1111 int line,
1112 const char *func,
1113 const wxChar *cond,
1114 const wxChar *msg)
0accd1cf 1115{
657a8a35
VZ
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);
0accd1cf
VS
1123}
1124
657a8a35
VZ
1125void wxOnAssert(const char *file,
1126 int line,
1127 const char *func,
1128 const char *cond,
1129 const wxString& msg)
fbaf7d45 1130{
657a8a35 1131 wxTheAssertHandler(file, line, func, cond, msg);
fbaf7d45
VS
1132}
1133
657a8a35
VZ
1134void wxOnAssert(const char *file,
1135 int line,
1136 const char *func,
1137 const char *cond,
2b232d20
VZ
1138 const wxCStrData& msg)
1139{
657a8a35 1140 wxTheAssertHandler(file, line, func, cond, msg);
2b232d20
VZ
1141}
1142
0accd1cf 1143#if wxUSE_UNICODE
657a8a35
VZ
1144void wxOnAssert(const char *file,
1145 int line,
1146 const char *func,
1147 const char *cond)
0accd1cf 1148{
657a8a35 1149 wxTheAssertHandler(file, line, func, cond, wxString());
0accd1cf
VS
1150}
1151
657a8a35
VZ
1152void wxOnAssert(const char *file,
1153 int line,
1154 const char *func,
1155 const char *cond,
1156 const char *msg)
0accd1cf 1157{
657a8a35 1158 wxTheAssertHandler(file, line, func, cond, msg);
0accd1cf
VS
1159}
1160
657a8a35
VZ
1161void wxOnAssert(const char *file,
1162 int line,
1163 const char *func,
1164 const char *cond,
1165 const wxChar *msg)
0accd1cf 1166{
657a8a35 1167 wxTheAssertHandler(file, line, func, cond, msg);
0accd1cf
VS
1168}
1169#endif // wxUSE_UNICODE
1170
657a8a35 1171#endif // wxDEBUG_LEVEL
e2478fde
VZ
1172
1173// ============================================================================
1174// private functions implementation
1175// ============================================================================
1176
1177#ifdef __WXDEBUG__
1178
1179static 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
657a8a35
VZ
1192#endif // __WXDEBUG__
1193
1194#if wxDEBUG_LEVEL
1195
6ef1b2a1 1196static
e2478fde
VZ
1197bool DoShowAssertDialog(const wxString& msg)
1198{
d98a58c5
VZ
1199 // under Windows we can show the dialog even in the console mode
1200#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
e2478fde
VZ
1201 wxString msgDlg(msg);
1202
657a8a35
VZ
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
e2478fde
VZ
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
b2b6da49 1210 switch ( ::MessageBox(NULL, msgDlg.t_str(), wxT("wxWidgets Debug Alert"),
e2478fde
VZ
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 }
d98a58c5 1223#else // !__WINDOWS__
021efd65 1224 wxUnusedVar(msg);
d98a58c5 1225#endif // __WINDOWS__/!__WINDOWS__
e2478fde 1226
021efd65 1227 // continue with the asserts by default
e2478fde
VZ
1228 return false;
1229}
1230
657a8a35 1231// show the standard assert dialog
4a92d4bc 1232static
657a8a35
VZ
1233void ShowAssertDialog(const wxString& file,
1234 int line,
1235 const wxString& func,
1236 const wxString& cond,
1237 const wxString& msgUser,
4a92d4bc
VZ
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
657a8a35 1249 msg.Printf(wxT("%s(%d): assert \"%s\" failed"), file, line, cond);
4a92d4bc 1250
dfa0b52f 1251 // add the function name, if any
657a8a35 1252 if ( !func.empty() )
9a83f860 1253 msg << wxT(" in ") << func << wxT("()");
dfa0b52f
VZ
1254
1255 // and the message itself
657a8a35 1256 if ( !msgUser.empty() )
2c9b3131 1257 {
9a83f860 1258 msg << wxT(": ") << msgUser;
2c9b3131 1259 }
4a92d4bc
VZ
1260 else // no message given
1261 {
9a83f860 1262 msg << wxT('.');
4a92d4bc
VZ
1263 }
1264
e2478fde
VZ
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 {
2d8e0096 1270 msg += wxString::Format(" [in thread %lx]", wxThread::GetCurrentId());
e2478fde
VZ
1271 }
1272#endif // wxUSE_THREADS
1273
2d8e0096
VZ
1274 // log the assert in any case
1275 wxMessageOutputDebug().Output(msg);
1276
e2478fde
VZ
1277 if ( !s_bNoAsserts )
1278 {
e2478fde
VZ
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
657a8a35 1292#endif // wxDEBUG_LEVEL