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