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