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