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