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