]> git.saurik.com Git - wxWidgets.git/blob - src/common/appbase.cpp
added wxAppTraits::SetLocale() and call it during wxApp initialization in all ports...
[wxWidgets.git] / src / common / appbase.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/appbase.cpp
3 // Purpose: implements wxAppConsole class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 19.06.2003 (extracted from common/appcmn.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #ifdef __WXMSW__
29 #include "wx/msw/wrapwin.h" // includes windows.h for MessageBox()
30 #endif
31 #include "wx/list.h"
32 #include "wx/app.h"
33 #include "wx/intl.h"
34 #include "wx/log.h"
35 #include "wx/utils.h"
36 #endif //WX_PRECOMP
37
38 #include "wx/apptrait.h"
39 #include "wx/cmdline.h"
40 #include "wx/confbase.h"
41 #include "wx/filename.h"
42 #include "wx/msgout.h"
43 #include "wx/tokenzr.h"
44
45 #if !defined(__WXMSW__) || defined(__WXMICROWIN__)
46 #include <signal.h> // for SIGTRAP used by wxTrap()
47 #endif //Win/Unix
48
49 #if wxUSE_FONTMAP
50 #include "wx/fontmap.h"
51 #endif // wxUSE_FONTMAP
52
53 #if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
54 // For MacTypes.h for Debugger function
55 #include <CoreFoundation/CFBase.h>
56 #endif
57
58 #if defined(__WXMAC__)
59 #ifdef __DARWIN__
60 #include <CoreServices/CoreServices.h>
61 #else
62 #include "wx/mac/private.h" // includes mac headers
63 #endif
64 #endif // __WXMAC__
65
66 #ifdef __WXDEBUG__
67 #if wxUSE_STACKWALKER
68 #include "wx/stackwalk.h"
69 #ifdef __WXMSW__
70 #include "wx/msw/debughlp.h"
71 #endif
72 #endif // wxUSE_STACKWALKER
73 #endif // __WXDEBUG__
74
75 // wxABI_VERSION can be defined when compiling applications but it should be
76 // left undefined when compiling the library itself, it is then set to its
77 // default value in version.h
78 #if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99
79 #error "wxABI_VERSION should not be defined when compiling the library"
80 #endif
81
82 // ----------------------------------------------------------------------------
83 // private functions prototypes
84 // ----------------------------------------------------------------------------
85
86 #ifdef __WXDEBUG__
87 // really just show the assert dialog
88 static bool DoShowAssertDialog(const wxString& msg);
89
90 // prepare for showing the assert dialog, use the given traits or
91 // DoShowAssertDialog() as last fallback to really show it
92 static
93 void ShowAssertDialog(const wxChar *szFile,
94 int nLine,
95 const wxChar *szFunc,
96 const wxChar *szCond,
97 const wxChar *szMsg,
98 wxAppTraits *traits = NULL);
99
100 // turn on the trace masks specified in the env variable WXTRACE
101 static void LINKAGEMODE SetTraceMasks();
102 #endif // __WXDEBUG__
103
104 // ----------------------------------------------------------------------------
105 // global vars
106 // ----------------------------------------------------------------------------
107
108 wxAppConsole *wxAppConsole::ms_appInstance = NULL;
109
110 wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL;
111
112 // ============================================================================
113 // wxAppConsole implementation
114 // ============================================================================
115
116 // ----------------------------------------------------------------------------
117 // ctor/dtor
118 // ----------------------------------------------------------------------------
119
120 wxAppConsole::wxAppConsole()
121 {
122 m_traits = NULL;
123
124 ms_appInstance = this;
125
126 #ifdef __WXDEBUG__
127 SetTraceMasks();
128 #if wxUSE_UNICODE
129 // In unicode mode the SetTraceMasks call can cause an apptraits to be
130 // created, but since we are still in the constructor the wrong kind will
131 // be created for GUI apps. Destroy it so it can be created again later.
132 delete m_traits;
133 m_traits = NULL;
134 #endif
135 #endif
136 }
137
138 wxAppConsole::~wxAppConsole()
139 {
140 delete m_traits;
141 }
142
143 // ----------------------------------------------------------------------------
144 // initilization/cleanup
145 // ----------------------------------------------------------------------------
146
147 bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig)
148 {
149 #if wxUSE_INTL
150 GetTraits()->SetLocale();
151 #endif // wxUSE_INTL
152
153 // remember the command line arguments
154 argc = argcOrig;
155 argv = argvOrig;
156
157 #ifndef __WXPALMOS__
158 if ( m_appName.empty() && argv )
159 {
160 // the application name is, by default, the name of its executable file
161 wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL);
162 }
163 #endif // !__WXPALMOS__
164
165 return true;
166 }
167
168 void wxAppConsole::CleanUp()
169 {
170 }
171
172 // ----------------------------------------------------------------------------
173 // OnXXX() callbacks
174 // ----------------------------------------------------------------------------
175
176 bool wxAppConsole::OnInit()
177 {
178 #if wxUSE_CMDLINE_PARSER
179 wxCmdLineParser parser(argc, argv);
180
181 OnInitCmdLine(parser);
182
183 bool cont;
184 switch ( parser.Parse(false /* don't show usage */) )
185 {
186 case -1:
187 cont = OnCmdLineHelp(parser);
188 break;
189
190 case 0:
191 cont = OnCmdLineParsed(parser);
192 break;
193
194 default:
195 cont = OnCmdLineError(parser);
196 break;
197 }
198
199 if ( !cont )
200 return false;
201 #endif // wxUSE_CMDLINE_PARSER
202
203 return true;
204 }
205
206 int wxAppConsole::OnExit()
207 {
208 #if wxUSE_CONFIG
209 // delete the config object if any (don't use Get() here, but Set()
210 // because Get() could create a new config object)
211 delete wxConfigBase::Set((wxConfigBase *) NULL);
212 #endif // wxUSE_CONFIG
213
214 return 0;
215 }
216
217 void wxAppConsole::Exit()
218 {
219 exit(-1);
220 }
221
222 // ----------------------------------------------------------------------------
223 // traits stuff
224 // ----------------------------------------------------------------------------
225
226 wxAppTraits *wxAppConsole::CreateTraits()
227 {
228 return new wxConsoleAppTraits;
229 }
230
231 wxAppTraits *wxAppConsole::GetTraits()
232 {
233 // FIXME-MT: protect this with a CS?
234 if ( !m_traits )
235 {
236 m_traits = CreateTraits();
237
238 wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") );
239 }
240
241 return m_traits;
242 }
243
244 // ----------------------------------------------------------------------------
245 // event processing
246 // ----------------------------------------------------------------------------
247
248 void wxAppConsole::ProcessPendingEvents()
249 {
250 #if wxUSE_THREADS
251 if ( !wxPendingEventsLocker )
252 return;
253 #endif
254
255 // ensure that we're the only thread to modify the pending events list
256 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
257
258 if ( !wxPendingEvents )
259 {
260 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
261 return;
262 }
263
264 // iterate until the list becomes empty
265 wxList::compatibility_iterator node = wxPendingEvents->GetFirst();
266 while (node)
267 {
268 wxEvtHandler *handler = (wxEvtHandler *)node->GetData();
269 wxPendingEvents->Erase(node);
270
271 // In ProcessPendingEvents(), new handlers might be add
272 // and we can safely leave the critical section here.
273 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
274
275 handler->ProcessPendingEvents();
276
277 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
278
279 node = wxPendingEvents->GetFirst();
280 }
281
282 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
283 }
284
285 int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event))
286 {
287 // process the events normally by default
288 return -1;
289 }
290
291 // ----------------------------------------------------------------------------
292 // exception handling
293 // ----------------------------------------------------------------------------
294
295 #if wxUSE_EXCEPTIONS
296
297 void
298 wxAppConsole::HandleEvent(wxEvtHandler *handler,
299 wxEventFunction func,
300 wxEvent& event) const
301 {
302 // by default, simply call the handler
303 (handler->*func)(event);
304 }
305
306 #endif // wxUSE_EXCEPTIONS
307
308 // ----------------------------------------------------------------------------
309 // cmd line parsing
310 // ----------------------------------------------------------------------------
311
312 #if wxUSE_CMDLINE_PARSER
313
314 #define OPTION_VERBOSE _T("verbose")
315
316 void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser)
317 {
318 // the standard command line options
319 static const wxCmdLineEntryDesc cmdLineDesc[] =
320 {
321 {
322 wxCMD_LINE_SWITCH,
323 _T("h"),
324 _T("help"),
325 gettext_noop("show this help message"),
326 wxCMD_LINE_VAL_NONE,
327 wxCMD_LINE_OPTION_HELP
328 },
329
330 #if wxUSE_LOG
331 {
332 wxCMD_LINE_SWITCH,
333 wxEmptyString,
334 OPTION_VERBOSE,
335 gettext_noop("generate verbose log messages"),
336 wxCMD_LINE_VAL_NONE,
337 0x0
338 },
339 #endif // wxUSE_LOG
340
341 // terminator
342 {
343 wxCMD_LINE_NONE,
344 wxEmptyString,
345 wxEmptyString,
346 wxEmptyString,
347 wxCMD_LINE_VAL_NONE,
348 0x0
349 }
350 };
351
352 parser.SetDesc(cmdLineDesc);
353 }
354
355 bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser)
356 {
357 #if wxUSE_LOG
358 if ( parser.Found(OPTION_VERBOSE) )
359 {
360 wxLog::SetVerbose(true);
361 }
362 #else
363 wxUnusedVar(parser);
364 #endif // wxUSE_LOG
365
366 return true;
367 }
368
369 bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser)
370 {
371 parser.Usage();
372
373 return false;
374 }
375
376 bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser)
377 {
378 parser.Usage();
379
380 return false;
381 }
382
383 #endif // wxUSE_CMDLINE_PARSER
384
385 // ----------------------------------------------------------------------------
386 // debugging support
387 // ----------------------------------------------------------------------------
388
389 /* static */
390 bool wxAppConsole::CheckBuildOptions(const char *optionsSignature,
391 const char *componentName)
392 {
393 #if 0 // can't use wxLogTrace, not up and running yet
394 printf("checking build options object '%s' (ptr %p) in '%s'\n",
395 optionsSignature, optionsSignature, componentName);
396 #endif
397
398 if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 )
399 {
400 wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE);
401 wxString prog = wxString::FromAscii(optionsSignature);
402 wxString progName = wxString::FromAscii(componentName);
403 wxString msg;
404
405 msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."),
406 lib.c_str(), progName.c_str(), prog.c_str());
407
408 wxLogFatalError(msg.c_str());
409
410 // normally wxLogFatalError doesn't return
411 return false;
412 }
413 #undef wxCMP
414
415 return true;
416 }
417
418 #ifdef __WXDEBUG__
419
420 void wxAppConsole::OnAssertFailure(const wxChar *file,
421 int line,
422 const wxChar *func,
423 const wxChar *cond,
424 const wxChar *msg)
425 {
426 ShowAssertDialog(file, line, func, cond, msg, GetTraits());
427 }
428
429 void wxAppConsole::OnAssert(const wxChar *file,
430 int line,
431 const wxChar *cond,
432 const wxChar *msg)
433 {
434 OnAssertFailure(file, line, NULL, cond, msg);
435 }
436
437 #endif // __WXDEBUG__
438
439 // ============================================================================
440 // other classes implementations
441 // ============================================================================
442
443 // ----------------------------------------------------------------------------
444 // wxConsoleAppTraitsBase
445 // ----------------------------------------------------------------------------
446
447 #if wxUSE_LOG
448
449 wxLog *wxConsoleAppTraitsBase::CreateLogTarget()
450 {
451 return new wxLogStderr;
452 }
453
454 #endif // wxUSE_LOG
455
456 wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput()
457 {
458 return new wxMessageOutputStderr;
459 }
460
461 #if wxUSE_FONTMAP
462
463 wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper()
464 {
465 return (wxFontMapper *)new wxFontMapperBase;
466 }
467
468 #endif // wxUSE_FONTMAP
469
470 wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer()
471 {
472 // console applications don't use renderers
473 return NULL;
474 }
475
476 #ifdef __WXDEBUG__
477 bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg)
478 {
479 return wxAppTraitsBase::ShowAssertDialog(msg);
480 }
481 #endif
482
483 bool wxConsoleAppTraitsBase::HasStderr()
484 {
485 // console applications always have stderr, even under Mac/Windows
486 return true;
487 }
488
489 void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object)
490 {
491 delete object;
492 }
493
494 void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object))
495 {
496 // nothing to do
497 }
498
499 #if wxUSE_SOCKETS
500 GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
501 {
502 return NULL;
503 }
504 #endif
505
506 // ----------------------------------------------------------------------------
507 // wxAppTraits
508 // ----------------------------------------------------------------------------
509
510 void wxAppTraitsBase::SetLocale()
511 {
512 setlocale(LC_ALL, "");
513 }
514
515 #ifdef __WXDEBUG__
516
517 bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal)
518 {
519 wxString msg = msgOriginal;
520
521 #if wxUSE_STACKWALKER
522 #if !defined(__WXMSW__)
523 // on Unix stack frame generation may take some time, depending on the
524 // size of the executable mainly... warn the user that we are working
525 wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait"));
526 fflush(stderr);
527 #endif
528
529 const wxString stackTrace = GetAssertStackTrace();
530 if ( !stackTrace.empty() )
531 msg << _T("\n\nCall stack:\n") << stackTrace;
532 #endif // wxUSE_STACKWALKER
533
534 return DoShowAssertDialog(msg);
535 }
536
537 #if wxUSE_STACKWALKER
538 wxString wxAppTraitsBase::GetAssertStackTrace()
539 {
540 wxString stackTrace;
541
542 class StackDump : public wxStackWalker
543 {
544 public:
545 StackDump() { }
546
547 const wxString& GetStackTrace() const { return m_stackTrace; }
548
549 protected:
550 virtual void OnStackFrame(const wxStackFrame& frame)
551 {
552 m_stackTrace << wxString::Format
553 (
554 _T("[%02d] "),
555 wx_truncate_cast(int, frame.GetLevel())
556 );
557
558 wxString name = frame.GetName();
559 if ( !name.empty() )
560 {
561 m_stackTrace << wxString::Format(_T("%-40s"), name.c_str());
562 }
563 else
564 {
565 m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress());
566 }
567
568 if ( frame.HasSourceLocation() )
569 {
570 m_stackTrace << _T('\t')
571 << frame.GetFileName()
572 << _T(':')
573 << frame.GetLine();
574 }
575
576 m_stackTrace << _T('\n');
577 }
578
579 private:
580 wxString m_stackTrace;
581 };
582
583 // don't show more than maxLines or we could get a dialog too tall to be
584 // shown on screen: 20 should be ok everywhere as even with 15 pixel high
585 // characters it is still only 300 pixels...
586 static const int maxLines = 20;
587
588 StackDump dump;
589 dump.Walk(2, maxLines); // don't show OnAssert() call itself
590 stackTrace = dump.GetStackTrace();
591
592 const int count = stackTrace.Freq(wxT('\n'));
593 for ( int i = 0; i < count - maxLines; i++ )
594 stackTrace = stackTrace.BeforeLast(wxT('\n'));
595
596 return stackTrace;
597 }
598 #endif // wxUSE_STACKWALKER
599
600
601 #endif // __WXDEBUG__
602
603 // ============================================================================
604 // global functions implementation
605 // ============================================================================
606
607 void wxExit()
608 {
609 if ( wxTheApp )
610 {
611 wxTheApp->Exit();
612 }
613 else
614 {
615 // what else can we do?
616 exit(-1);
617 }
618 }
619
620 void wxWakeUpIdle()
621 {
622 if ( wxTheApp )
623 {
624 wxTheApp->WakeUpIdle();
625 }
626 //else: do nothing, what can we do?
627 }
628
629 #ifdef __WXDEBUG__
630
631 // wxASSERT() helper
632 bool wxAssertIsEqual(int x, int y)
633 {
634 return x == y;
635 }
636
637 // break into the debugger
638 void wxTrap()
639 {
640 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
641 DebugBreak();
642 #elif defined(__WXMAC__) && !defined(__DARWIN__)
643 #if __powerc
644 Debugger();
645 #else
646 SysBreak();
647 #endif
648 #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
649 Debugger();
650 #elif defined(__UNIX__)
651 raise(SIGTRAP);
652 #else
653 // TODO
654 #endif // Win/Unix
655 }
656
657 // this function is called when an assert fails
658 void wxOnAssert(const wxChar *szFile,
659 int nLine,
660 const char *szFunc,
661 const wxChar *szCond,
662 const wxChar *szMsg)
663 {
664 // FIXME MT-unsafe
665 static bool s_bInAssert = false;
666
667 if ( s_bInAssert )
668 {
669 // He-e-e-e-elp!! we're trapped in endless loop
670 wxTrap();
671
672 s_bInAssert = false;
673
674 return;
675 }
676
677 s_bInAssert = true;
678
679 // __FUNCTION__ is always in ASCII, convert it to wide char if needed
680 const wxString strFunc = wxString::FromAscii(szFunc);
681
682 if ( !wxTheApp )
683 {
684 // by default, show the assert dialog box -- we can't customize this
685 // behaviour
686 ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg);
687 }
688 else
689 {
690 // let the app process it as it wants
691 wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg);
692 }
693
694 s_bInAssert = false;
695 }
696
697 #endif // __WXDEBUG__
698
699 // ============================================================================
700 // private functions implementation
701 // ============================================================================
702
703 #ifdef __WXDEBUG__
704
705 static void LINKAGEMODE SetTraceMasks()
706 {
707 #if wxUSE_LOG
708 wxString mask;
709 if ( wxGetEnv(wxT("WXTRACE"), &mask) )
710 {
711 wxStringTokenizer tkn(mask, wxT(",;:"));
712 while ( tkn.HasMoreTokens() )
713 wxLog::AddTraceMask(tkn.GetNextToken());
714 }
715 #endif // wxUSE_LOG
716 }
717
718 bool DoShowAssertDialog(const wxString& msg)
719 {
720 // under MSW we can show the dialog even in the console mode
721 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
722 wxString msgDlg(msg);
723
724 // this message is intentionally not translated -- it is for
725 // developpers only
726 msgDlg += wxT("\nDo you want to stop the program?\n")
727 wxT("You can also choose [Cancel] to suppress ")
728 wxT("further warnings.");
729
730 switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"),
731 MB_YESNOCANCEL | MB_ICONSTOP ) )
732 {
733 case IDYES:
734 wxTrap();
735 break;
736
737 case IDCANCEL:
738 // stop the asserts
739 return true;
740
741 //case IDNO: nothing to do
742 }
743 #else // !__WXMSW__
744 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
745 fflush(stderr);
746
747 // TODO: ask the user to enter "Y" or "N" on the console?
748 wxTrap();
749 #endif // __WXMSW__/!__WXMSW__
750
751 // continue with the asserts
752 return false;
753 }
754
755 // show the assert modal dialog
756 static
757 void ShowAssertDialog(const wxChar *szFile,
758 int nLine,
759 const wxChar *szFunc,
760 const wxChar *szCond,
761 const wxChar *szMsg,
762 wxAppTraits *traits)
763 {
764 // this variable can be set to true to suppress "assert failure" messages
765 static bool s_bNoAsserts = false;
766
767 wxString msg;
768 msg.reserve(2048);
769
770 // make life easier for people using VC++ IDE by using this format: like
771 // this, clicking on the message will take us immediately to the place of
772 // the failed assert
773 msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond);
774
775 // add the function name, if any
776 if ( szFunc && *szFunc )
777 msg << _T(" in ") << szFunc << _T("()");
778
779 // and the message itself
780 if ( szMsg )
781 {
782 msg << _T(": ") << szMsg;
783 }
784 else // no message given
785 {
786 msg << _T('.');
787 }
788
789 #if wxUSE_THREADS
790 // if we are not in the main thread, output the assert directly and trap
791 // since dialogs cannot be displayed
792 if ( !wxThread::IsMain() )
793 {
794 msg += wxT(" [in child thread]");
795
796 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
797 msg << wxT("\r\n");
798 OutputDebugString(msg );
799 #else
800 // send to stderr
801 wxFprintf(stderr, wxT("%s\n"), msg.c_str());
802 fflush(stderr);
803 #endif
804 // He-e-e-e-elp!! we're asserting in a child thread
805 wxTrap();
806 }
807 else
808 #endif // wxUSE_THREADS
809
810 if ( !s_bNoAsserts )
811 {
812 // send it to the normal log destination
813 wxLogDebug(_T("%s"), msg.c_str());
814
815 if ( traits )
816 {
817 // delegate showing assert dialog (if possible) to that class
818 s_bNoAsserts = traits->ShowAssertDialog(msg);
819 }
820 else // no traits object
821 {
822 // fall back to the function of last resort
823 s_bNoAsserts = DoShowAssertDialog(msg);
824 }
825 }
826 }
827
828 #endif // __WXDEBUG__