1 |
/////////////////////////////////////////////////////////////////////////////// |
2 |
// Name: src/common/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: appbase.cpp 52093 2008-02-25 13:43:07Z VZ $ |
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 |
#ifdef __WXMSW__ |
29 |
#include "wx/msw/wrapwin.h" // includes windows.h for MessageBox() |
30 |
#endif |
31 |
#include "wx/list.h" |
32 |
#include "wx/app.h" |
33 |
#include "wx/intl.h" |
34 |
#include "wx/log.h" |
35 |
#include "wx/utils.h" |
36 |
#endif //WX_PRECOMP |
37 |
|
38 |
#include "wx/apptrait.h" |
39 |
#include "wx/cmdline.h" |
40 |
#include "wx/confbase.h" |
41 |
#include "wx/filename.h" |
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 wxUSE_FONTMAP |
50 |
#include "wx/fontmap.h" |
51 |
#endif // wxUSE_FONTMAP |
52 |
|
53 |
#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS |
54 |
// For MacTypes.h for Debugger function |
55 |
#include <CoreFoundation/CFBase.h> |
56 |
#endif |
57 |
|
58 |
#if defined(__WXMAC__) |
59 |
#ifdef __DARWIN__ |
60 |
#include <CoreServices/CoreServices.h> |
61 |
#else |
62 |
#include "wx/mac/private.h" // includes mac headers |
63 |
#endif |
64 |
#endif // __WXMAC__ |
65 |
|
66 |
#ifdef __WXDEBUG__ |
67 |
#if wxUSE_STACKWALKER |
68 |
#include "wx/stackwalk.h" |
69 |
#ifdef __WXMSW__ |
70 |
#include "wx/msw/debughlp.h" |
71 |
#endif |
72 |
#endif // wxUSE_STACKWALKER |
73 |
|
74 |
#include "wx/recguard.h" |
75 |
#endif // __WXDEBUG__ |
76 |
|
77 |
// wxABI_VERSION can be defined when compiling applications but it should be |
78 |
// left undefined when compiling the library itself, it is then set to its |
79 |
// default value in version.h |
80 |
#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 |
81 |
#error "wxABI_VERSION should not be defined when compiling the library" |
82 |
#endif |
83 |
|
84 |
// ---------------------------------------------------------------------------- |
85 |
// private functions prototypes |
86 |
// ---------------------------------------------------------------------------- |
87 |
|
88 |
#ifdef __WXDEBUG__ |
89 |
// really just show the assert dialog |
90 |
static bool DoShowAssertDialog(const wxString& msg); |
91 |
|
92 |
// prepare for showing the assert dialog, use the given traits or |
93 |
// DoShowAssertDialog() as last fallback to really show it |
94 |
static |
95 |
void ShowAssertDialog(const wxChar *szFile, |
96 |
int nLine, |
97 |
const wxChar *szFunc, |
98 |
const wxChar *szCond, |
99 |
const wxChar *szMsg, |
100 |
wxAppTraits *traits = NULL); |
101 |
|
102 |
// turn on the trace masks specified in the env variable WXTRACE |
103 |
static void LINKAGEMODE SetTraceMasks(); |
104 |
#endif // __WXDEBUG__ |
105 |
|
106 |
// ---------------------------------------------------------------------------- |
107 |
// global vars |
108 |
// ---------------------------------------------------------------------------- |
109 |
|
110 |
wxAppConsole *wxAppConsole::ms_appInstance = NULL; |
111 |
|
112 |
wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL; |
113 |
|
114 |
// ============================================================================ |
115 |
// wxAppConsole implementation |
116 |
// ============================================================================ |
117 |
|
118 |
// ---------------------------------------------------------------------------- |
119 |
// ctor/dtor |
120 |
// ---------------------------------------------------------------------------- |
121 |
|
122 |
wxAppConsole::wxAppConsole() |
123 |
{ |
124 |
m_traits = NULL; |
125 |
|
126 |
ms_appInstance = this; |
127 |
|
128 |
#ifdef __WXDEBUG__ |
129 |
SetTraceMasks(); |
130 |
#if wxUSE_UNICODE |
131 |
// In unicode mode the SetTraceMasks call can cause an apptraits to be |
132 |
// created, but since we are still in the constructor the wrong kind will |
133 |
// be created for GUI apps. Destroy it so it can be created again later. |
134 |
delete m_traits; |
135 |
m_traits = NULL; |
136 |
#endif |
137 |
#endif |
138 |
} |
139 |
|
140 |
wxAppConsole::~wxAppConsole() |
141 |
{ |
142 |
delete m_traits; |
143 |
} |
144 |
|
145 |
// ---------------------------------------------------------------------------- |
146 |
// initilization/cleanup |
147 |
// ---------------------------------------------------------------------------- |
148 |
|
149 |
bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig) |
150 |
{ |
151 |
// remember the command line arguments |
152 |
argc = argcOrig; |
153 |
argv = argvOrig; |
154 |
|
155 |
#ifndef __WXPALMOS__ |
156 |
if ( m_appName.empty() && argv ) |
157 |
{ |
158 |
// the application name is, by default, the name of its executable file |
159 |
wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); |
160 |
} |
161 |
#endif |
162 |
|
163 |
return true; |
164 |
} |
165 |
|
166 |
void wxAppConsole::CleanUp() |
167 |
{ |
168 |
} |
169 |
|
170 |
// ---------------------------------------------------------------------------- |
171 |
// OnXXX() callbacks |
172 |
// ---------------------------------------------------------------------------- |
173 |
|
174 |
bool wxAppConsole::OnInit() |
175 |
{ |
176 |
#if wxUSE_CMDLINE_PARSER |
177 |
wxCmdLineParser parser(argc, argv); |
178 |
|
179 |
OnInitCmdLine(parser); |
180 |
|
181 |
bool cont; |
182 |
switch ( parser.Parse(false /* don't show usage */) ) |
183 |
{ |
184 |
case -1: |
185 |
cont = OnCmdLineHelp(parser); |
186 |
break; |
187 |
|
188 |
case 0: |
189 |
cont = OnCmdLineParsed(parser); |
190 |
break; |
191 |
|
192 |
default: |
193 |
cont = OnCmdLineError(parser); |
194 |
break; |
195 |
} |
196 |
|
197 |
if ( !cont ) |
198 |
return false; |
199 |
#endif // wxUSE_CMDLINE_PARSER |
200 |
|
201 |
return true; |
202 |
} |
203 |
|
204 |
int wxAppConsole::OnExit() |
205 |
{ |
206 |
#if wxUSE_CONFIG |
207 |
// delete the config object if any (don't use Get() here, but Set() |
208 |
// because Get() could create a new config object) |
209 |
delete wxConfigBase::Set((wxConfigBase *) NULL); |
210 |
#endif // wxUSE_CONFIG |
211 |
|
212 |
return 0; |
213 |
} |
214 |
|
215 |
void wxAppConsole::Exit() |
216 |
{ |
217 |
exit(-1); |
218 |
} |
219 |
|
220 |
// ---------------------------------------------------------------------------- |
221 |
// traits stuff |
222 |
// ---------------------------------------------------------------------------- |
223 |
|
224 |
wxAppTraits *wxAppConsole::CreateTraits() |
225 |
{ |
226 |
return new wxConsoleAppTraits; |
227 |
} |
228 |
|
229 |
wxAppTraits *wxAppConsole::GetTraits() |
230 |
{ |
231 |
// FIXME-MT: protect this with a CS? |
232 |
if ( !m_traits ) |
233 |
{ |
234 |
m_traits = CreateTraits(); |
235 |
|
236 |
wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") ); |
237 |
} |
238 |
|
239 |
return m_traits; |
240 |
} |
241 |
|
242 |
// we must implement CreateXXX() in wxApp itself for backwards compatibility |
243 |
#if WXWIN_COMPATIBILITY_2_4 |
244 |
|
245 |
#if wxUSE_LOG |
246 |
|
247 |
wxLog *wxAppConsole::CreateLogTarget() |
248 |
{ |
249 |
wxAppTraits *traits = GetTraits(); |
250 |
return traits ? traits->CreateLogTarget() : NULL; |
251 |
} |
252 |
|
253 |
#endif // wxUSE_LOG |
254 |
|
255 |
wxMessageOutput *wxAppConsole::CreateMessageOutput() |
256 |
{ |
257 |
wxAppTraits *traits = GetTraits(); |
258 |
return traits ? traits->CreateMessageOutput() : NULL; |
259 |
} |
260 |
|
261 |
#endif // WXWIN_COMPATIBILITY_2_4 |
262 |
|
263 |
// ---------------------------------------------------------------------------- |
264 |
// event processing |
265 |
// ---------------------------------------------------------------------------- |
266 |
|
267 |
void wxAppConsole::ProcessPendingEvents() |
268 |
{ |
269 |
#if wxUSE_THREADS |
270 |
if ( !wxPendingEventsLocker ) |
271 |
return; |
272 |
#endif |
273 |
|
274 |
// ensure that we're the only thread to modify the pending events list |
275 |
wxENTER_CRIT_SECT( *wxPendingEventsLocker ); |
276 |
|
277 |
if ( !wxPendingEvents ) |
278 |
{ |
279 |
wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); |
280 |
return; |
281 |
} |
282 |
|
283 |
// iterate until the list becomes empty |
284 |
wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); |
285 |
while (node) |
286 |
{ |
287 |
wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); |
288 |
wxPendingEvents->Erase(node); |
289 |
|
290 |
// In ProcessPendingEvents(), new handlers might be add |
291 |
// and we can safely leave the critical section here. |
292 |
wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); |
293 |
|
294 |
handler->ProcessPendingEvents(); |
295 |
|
296 |
wxENTER_CRIT_SECT( *wxPendingEventsLocker ); |
297 |
|
298 |
node = wxPendingEvents->GetFirst(); |
299 |
} |
300 |
|
301 |
wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); |
302 |
} |
303 |
|
304 |
int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event)) |
305 |
{ |
306 |
// process the events normally by default |
307 |
return -1; |
308 |
} |
309 |
|
310 |
// ---------------------------------------------------------------------------- |
311 |
// exception handling |
312 |
// ---------------------------------------------------------------------------- |
313 |
|
314 |
#if wxUSE_EXCEPTIONS |
315 |
|
316 |
void |
317 |
wxAppConsole::HandleEvent(wxEvtHandler *handler, |
318 |
wxEventFunction func, |
319 |
wxEvent& event) const |
320 |
{ |
321 |
// by default, simply call the handler |
322 |
(handler->*func)(event); |
323 |
} |
324 |
|
325 |
#endif // wxUSE_EXCEPTIONS |
326 |
|
327 |
// ---------------------------------------------------------------------------- |
328 |
// cmd line parsing |
329 |
// ---------------------------------------------------------------------------- |
330 |
|
331 |
#if wxUSE_CMDLINE_PARSER |
332 |
|
333 |
#define OPTION_VERBOSE _T("verbose") |
334 |
|
335 |
void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser) |
336 |
{ |
337 |
// the standard command line options |
338 |
static const wxCmdLineEntryDesc cmdLineDesc[] = |
339 |
{ |
340 |
{ |
341 |
wxCMD_LINE_SWITCH, |
342 |
_T("h"), |
343 |
_T("help"), |
344 |
gettext_noop("show this help message"), |
345 |
wxCMD_LINE_VAL_NONE, |
346 |
wxCMD_LINE_OPTION_HELP |
347 |
}, |
348 |
|
349 |
#if wxUSE_LOG |
350 |
{ |
351 |
wxCMD_LINE_SWITCH, |
352 |
wxEmptyString, |
353 |
OPTION_VERBOSE, |
354 |
gettext_noop("generate verbose log messages"), |
355 |
wxCMD_LINE_VAL_NONE, |
356 |
0x0 |
357 |
}, |
358 |
#endif // wxUSE_LOG |
359 |
|
360 |
// terminator |
361 |
{ |
362 |
wxCMD_LINE_NONE, |
363 |
wxEmptyString, |
364 |
wxEmptyString, |
365 |
wxEmptyString, |
366 |
wxCMD_LINE_VAL_NONE, |
367 |
0x0 |
368 |
} |
369 |
}; |
370 |
|
371 |
parser.SetDesc(cmdLineDesc); |
372 |
} |
373 |
|
374 |
bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser) |
375 |
{ |
376 |
#if wxUSE_LOG |
377 |
if ( parser.Found(OPTION_VERBOSE) ) |
378 |
{ |
379 |
wxLog::SetVerbose(true); |
380 |
} |
381 |
#else |
382 |
wxUnusedVar(parser); |
383 |
#endif // wxUSE_LOG |
384 |
|
385 |
return true; |
386 |
} |
387 |
|
388 |
bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser) |
389 |
{ |
390 |
parser.Usage(); |
391 |
|
392 |
return false; |
393 |
} |
394 |
|
395 |
bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser) |
396 |
{ |
397 |
parser.Usage(); |
398 |
|
399 |
return false; |
400 |
} |
401 |
|
402 |
#endif // wxUSE_CMDLINE_PARSER |
403 |
|
404 |
// ---------------------------------------------------------------------------- |
405 |
// debugging support |
406 |
// ---------------------------------------------------------------------------- |
407 |
|
408 |
/* static */ |
409 |
bool wxAppConsole::CheckBuildOptions(const char *optionsSignature, |
410 |
const char *componentName) |
411 |
{ |
412 |
#if 0 // can't use wxLogTrace, not up and running yet |
413 |
printf("checking build options object '%s' (ptr %p) in '%s'\n", |
414 |
optionsSignature, optionsSignature, componentName); |
415 |
#endif |
416 |
|
417 |
if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 ) |
418 |
{ |
419 |
wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE); |
420 |
wxString prog = wxString::FromAscii(optionsSignature); |
421 |
wxString progName = wxString::FromAscii(componentName); |
422 |
wxString msg; |
423 |
|
424 |
msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), |
425 |
lib.c_str(), progName.c_str(), prog.c_str()); |
426 |
|
427 |
wxLogFatalError(msg.c_str()); |
428 |
|
429 |
// normally wxLogFatalError doesn't return |
430 |
return false; |
431 |
} |
432 |
#undef wxCMP |
433 |
|
434 |
return true; |
435 |
} |
436 |
|
437 |
#ifdef __WXDEBUG__ |
438 |
|
439 |
void wxAppConsole::OnAssertFailure(const wxChar *file, |
440 |
int line, |
441 |
const wxChar *func, |
442 |
const wxChar *cond, |
443 |
const wxChar *msg) |
444 |
{ |
445 |
ShowAssertDialog(file, line, func, cond, msg, GetTraits()); |
446 |
} |
447 |
|
448 |
void wxAppConsole::OnAssert(const wxChar *file, |
449 |
int line, |
450 |
const wxChar *cond, |
451 |
const wxChar *msg) |
452 |
{ |
453 |
OnAssertFailure(file, line, NULL, cond, msg); |
454 |
} |
455 |
|
456 |
#endif // __WXDEBUG__ |
457 |
|
458 |
#if WXWIN_COMPATIBILITY_2_4 |
459 |
|
460 |
bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions) |
461 |
{ |
462 |
return CheckBuildOptions(buildOptions.m_signature, "your program"); |
463 |
} |
464 |
|
465 |
#endif |
466 |
|
467 |
// ============================================================================ |
468 |
// other classes implementations |
469 |
// ============================================================================ |
470 |
|
471 |
// ---------------------------------------------------------------------------- |
472 |
// wxConsoleAppTraitsBase |
473 |
// ---------------------------------------------------------------------------- |
474 |
|
475 |
#if wxUSE_LOG |
476 |
|
477 |
wxLog *wxConsoleAppTraitsBase::CreateLogTarget() |
478 |
{ |
479 |
return new wxLogStderr; |
480 |
} |
481 |
|
482 |
#endif // wxUSE_LOG |
483 |
|
484 |
wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput() |
485 |
{ |
486 |
return new wxMessageOutputStderr; |
487 |
} |
488 |
|
489 |
#if wxUSE_FONTMAP |
490 |
|
491 |
wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper() |
492 |
{ |
493 |
return (wxFontMapper *)new wxFontMapperBase; |
494 |
} |
495 |
|
496 |
#endif // wxUSE_FONTMAP |
497 |
|
498 |
wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer() |
499 |
{ |
500 |
// console applications don't use renderers |
501 |
return NULL; |
502 |
} |
503 |
|
504 |
#ifdef __WXDEBUG__ |
505 |
bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg) |
506 |
{ |
507 |
return wxAppTraitsBase::ShowAssertDialog(msg); |
508 |
} |
509 |
#endif |
510 |
|
511 |
bool wxConsoleAppTraitsBase::HasStderr() |
512 |
{ |
513 |
// console applications always have stderr, even under Mac/Windows |
514 |
return true; |
515 |
} |
516 |
|
517 |
void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object) |
518 |
{ |
519 |
delete object; |
520 |
} |
521 |
|
522 |
void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object)) |
523 |
{ |
524 |
// nothing to do |
525 |
} |
526 |
|
527 |
#if wxUSE_SOCKETS |
528 |
GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() |
529 |
{ |
530 |
return NULL; |
531 |
} |
532 |
#endif |
533 |
|
534 |
// ---------------------------------------------------------------------------- |
535 |
// wxAppTraits |
536 |
// ---------------------------------------------------------------------------- |
537 |
|
538 |
#ifdef __WXDEBUG__ |
539 |
|
540 |
bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) |
541 |
{ |
542 |
wxString msg = msgOriginal; |
543 |
|
544 |
#if wxUSE_STACKWALKER |
545 |
#if !defined(__WXMSW__) |
546 |
// on Unix stack frame generation may take some time, depending on the |
547 |
// size of the executable mainly... warn the user that we are working |
548 |
wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); |
549 |
fflush(stderr); |
550 |
#endif |
551 |
|
552 |
const wxString stackTrace = GetAssertStackTrace(); |
553 |
if ( !stackTrace.empty() ) |
554 |
msg << _T("\n\nCall stack:\n") << stackTrace; |
555 |
#endif // wxUSE_STACKWALKER |
556 |
|
557 |
return DoShowAssertDialog(msg); |
558 |
} |
559 |
|
560 |
#if wxUSE_STACKWALKER |
561 |
wxString wxAppTraitsBase::GetAssertStackTrace() |
562 |
{ |
563 |
wxString stackTrace; |
564 |
|
565 |
class StackDump : public wxStackWalker |
566 |
{ |
567 |
public: |
568 |
StackDump() { } |
569 |
|
570 |
const wxString& GetStackTrace() const { return m_stackTrace; } |
571 |
|
572 |
protected: |
573 |
virtual void OnStackFrame(const wxStackFrame& frame) |
574 |
{ |
575 |
m_stackTrace << wxString::Format |
576 |
( |
577 |
_T("[%02d] "), |
578 |
wx_truncate_cast(int, frame.GetLevel()) |
579 |
); |
580 |
|
581 |
wxString name = frame.GetName(); |
582 |
if ( !name.empty() ) |
583 |
{ |
584 |
m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); |
585 |
} |
586 |
else |
587 |
{ |
588 |
m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); |
589 |
} |
590 |
|
591 |
if ( frame.HasSourceLocation() ) |
592 |
{ |
593 |
m_stackTrace << _T('\t') |
594 |
<< frame.GetFileName() |
595 |
<< _T(':') |
596 |
<< frame.GetLine(); |
597 |
} |
598 |
|
599 |
m_stackTrace << _T('\n'); |
600 |
} |
601 |
|
602 |
private: |
603 |
wxString m_stackTrace; |
604 |
}; |
605 |
|
606 |
// don't show more than maxLines or we could get a dialog too tall to be |
607 |
// shown on screen: 20 should be ok everywhere as even with 15 pixel high |
608 |
// characters it is still only 300 pixels... |
609 |
static const int maxLines = 20; |
610 |
|
611 |
StackDump dump; |
612 |
dump.Walk(2, maxLines); // don't show OnAssert() call itself |
613 |
stackTrace = dump.GetStackTrace(); |
614 |
|
615 |
const int count = stackTrace.Freq(wxT('\n')); |
616 |
for ( int i = 0; i < count - maxLines; i++ ) |
617 |
stackTrace = stackTrace.BeforeLast(wxT('\n')); |
618 |
|
619 |
return stackTrace; |
620 |
} |
621 |
#endif // wxUSE_STACKWALKER |
622 |
|
623 |
|
624 |
#endif // __WXDEBUG__ |
625 |
|
626 |
// ============================================================================ |
627 |
// global functions implementation |
628 |
// ============================================================================ |
629 |
|
630 |
void wxExit() |
631 |
{ |
632 |
if ( wxTheApp ) |
633 |
{ |
634 |
wxTheApp->Exit(); |
635 |
} |
636 |
else |
637 |
{ |
638 |
// what else can we do? |
639 |
exit(-1); |
640 |
} |
641 |
} |
642 |
|
643 |
void wxWakeUpIdle() |
644 |
{ |
645 |
if ( wxTheApp ) |
646 |
{ |
647 |
wxTheApp->WakeUpIdle(); |
648 |
} |
649 |
//else: do nothing, what can we do? |
650 |
} |
651 |
|
652 |
#ifdef __WXDEBUG__ |
653 |
|
654 |
// wxASSERT() helper |
655 |
bool wxAssertIsEqual(int x, int y) |
656 |
{ |
657 |
return x == y; |
658 |
} |
659 |
|
660 |
// break into the debugger |
661 |
void wxTrap() |
662 |
{ |
663 |
#if defined(__WXMSW__) && !defined(__WXMICROWIN__) |
664 |
DebugBreak(); |
665 |
#elif defined(__WXMAC__) && !defined(__DARWIN__) |
666 |
#if __powerc |
667 |
Debugger(); |
668 |
#else |
669 |
SysBreak(); |
670 |
#endif |
671 |
#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS |
672 |
Debugger(); |
673 |
#elif defined(__UNIX__) |
674 |
raise(SIGTRAP); |
675 |
#else |
676 |
// TODO |
677 |
#endif // Win/Unix |
678 |
} |
679 |
|
680 |
// this function is called when an assert fails |
681 |
void wxOnAssert(const wxChar *szFile, |
682 |
int nLine, |
683 |
const char *szFunc, |
684 |
const wxChar *szCond, |
685 |
const wxChar *szMsg) |
686 |
{ |
687 |
// FIXME MT-unsafe |
688 |
static int s_bInAssert = 0; |
689 |
|
690 |
wxRecursionGuard guard(s_bInAssert); |
691 |
if ( guard.IsInside() ) |
692 |
{ |
693 |
// can't use assert here to avoid infinite loops, so just trap |
694 |
wxTrap(); |
695 |
|
696 |
return; |
697 |
} |
698 |
|
699 |
// __FUNCTION__ is always in ASCII, convert it to wide char if needed |
700 |
const wxString strFunc = wxString::FromAscii(szFunc); |
701 |
|
702 |
if ( !wxTheApp ) |
703 |
{ |
704 |
// by default, show the assert dialog box -- we can't customize this |
705 |
// behaviour |
706 |
ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg); |
707 |
} |
708 |
else |
709 |
{ |
710 |
// let the app process it as it wants |
711 |
wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg); |
712 |
} |
713 |
} |
714 |
|
715 |
#endif // __WXDEBUG__ |
716 |
|
717 |
// ============================================================================ |
718 |
// private functions implementation |
719 |
// ============================================================================ |
720 |
|
721 |
#ifdef __WXDEBUG__ |
722 |
|
723 |
static void LINKAGEMODE SetTraceMasks() |
724 |
{ |
725 |
#if wxUSE_LOG |
726 |
wxString mask; |
727 |
if ( wxGetEnv(wxT("WXTRACE"), &mask) ) |
728 |
{ |
729 |
wxStringTokenizer tkn(mask, wxT(",;:")); |
730 |
while ( tkn.HasMoreTokens() ) |
731 |
wxLog::AddTraceMask(tkn.GetNextToken()); |
732 |
} |
733 |
#endif // wxUSE_LOG |
734 |
} |
735 |
|
736 |
bool DoShowAssertDialog(const wxString& msg) |
737 |
{ |
738 |
// under MSW we can show the dialog even in the console mode |
739 |
#if defined(__WXMSW__) && !defined(__WXMICROWIN__) |
740 |
wxString msgDlg(msg); |
741 |
|
742 |
// this message is intentionally not translated -- it is for |
743 |
// developpers only |
744 |
msgDlg += wxT("\nDo you want to stop the program?\n") |
745 |
wxT("You can also choose [Cancel] to suppress ") |
746 |
wxT("further warnings."); |
747 |
|
748 |
switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), |
749 |
MB_YESNOCANCEL | MB_ICONSTOP ) ) |
750 |
{ |
751 |
case IDYES: |
752 |
wxTrap(); |
753 |
break; |
754 |
|
755 |
case IDCANCEL: |
756 |
// stop the asserts |
757 |
return true; |
758 |
|
759 |
//case IDNO: nothing to do |
760 |
} |
761 |
#else // !__WXMSW__ |
762 |
wxFprintf(stderr, wxT("%s\n"), msg.c_str()); |
763 |
fflush(stderr); |
764 |
|
765 |
// TODO: ask the user to enter "Y" or "N" on the console? |
766 |
wxTrap(); |
767 |
#endif // __WXMSW__/!__WXMSW__ |
768 |
|
769 |
// continue with the asserts |
770 |
return false; |
771 |
} |
772 |
|
773 |
// show the assert modal dialog |
774 |
static |
775 |
void ShowAssertDialog(const wxChar *szFile, |
776 |
int nLine, |
777 |
const wxChar *szFunc, |
778 |
const wxChar *szCond, |
779 |
const wxChar *szMsg, |
780 |
wxAppTraits *traits) |
781 |
{ |
782 |
// this variable can be set to true to suppress "assert failure" messages |
783 |
static bool s_bNoAsserts = false; |
784 |
|
785 |
wxString msg; |
786 |
msg.reserve(2048); |
787 |
|
788 |
// make life easier for people using VC++ IDE by using this format: like |
789 |
// this, clicking on the message will take us immediately to the place of |
790 |
// the failed assert |
791 |
msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); |
792 |
|
793 |
// add the function name, if any |
794 |
if ( szFunc && *szFunc ) |
795 |
msg << _T(" in ") << szFunc << _T("()"); |
796 |
|
797 |
// and the message itself |
798 |
if ( szMsg ) |
799 |
{ |
800 |
msg << _T(": ") << szMsg; |
801 |
} |
802 |
else // no message given |
803 |
{ |
804 |
msg << _T('.'); |
805 |
} |
806 |
|
807 |
#if wxUSE_THREADS |
808 |
// if we are not in the main thread, output the assert directly and trap |
809 |
// since dialogs cannot be displayed |
810 |
if ( !wxThread::IsMain() ) |
811 |
{ |
812 |
msg += wxT(" [in child thread]"); |
813 |
|
814 |
#if defined(__WXMSW__) && !defined(__WXMICROWIN__) |
815 |
msg << wxT("\r\n"); |
816 |
OutputDebugString(msg ); |
817 |
#else |
818 |
// send to stderr |
819 |
wxFprintf(stderr, wxT("%s\n"), msg.c_str()); |
820 |
fflush(stderr); |
821 |
#endif |
822 |
// He-e-e-e-elp!! we're asserting in a child thread |
823 |
wxTrap(); |
824 |
} |
825 |
else |
826 |
#endif // wxUSE_THREADS |
827 |
|
828 |
if ( !s_bNoAsserts ) |
829 |
{ |
830 |
// send it to the normal log destination |
831 |
wxLogDebug(_T("%s"), msg.c_str()); |
832 |
|
833 |
if ( traits ) |
834 |
{ |
835 |
// delegate showing assert dialog (if possible) to that class |
836 |
s_bNoAsserts = traits->ShowAssertDialog(msg); |
837 |
} |
838 |
else // no traits object |
839 |
{ |
840 |
// fall back to the function of last resort |
841 |
s_bNoAsserts = DoShowAssertDialog(msg); |
842 |
} |
843 |
} |
844 |
} |
845 |
|
846 |
#endif // __WXDEBUG__ |