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