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