]> git.saurik.com Git - wxWidgets.git/blob - src/common/appcmn.cpp
Applied patch [ 596061 ] Adds more navigation buttons to preview
[wxWidgets.git] / src / common / appcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/appcmn.cpp
3 // Purpose: wxAppBase methods common to all platforms
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 18.10.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "appbase.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/app.h"
33 #include "wx/intl.h"
34 #include "wx/list.h"
35 #if wxUSE_GUI
36 #include "wx/msgdlg.h"
37 #endif // wxUSE_GUI
38 #endif
39
40 #include "wx/cmdline.h"
41 #include "wx/thread.h"
42 #include "wx/confbase.h"
43 #include "wx/tokenzr.h"
44 #include "wx/utils.h"
45 #include "wx/msgout.h"
46
47 #if wxUSE_GUI
48 #include "wx/artprov.h"
49 #endif // wxUSE_GUI
50
51 #if !defined(__WXMSW__) || defined(__WXMICROWIN__)
52 #include <signal.h> // for SIGTRAP used by wxTrap()
53 #endif //Win/Unix
54
55 #if defined(__WXMSW__)
56 #include "wx/msw/private.h" // includes windows.h for MessageBox()
57 #endif
58
59 #if defined(__WXMAC__)
60 #include "wx/mac/private.h" // includes mac headers
61 #endif
62
63 // private functions prototypes
64 #ifdef __WXDEBUG__
65 static void LINKAGEMODE SetTraceMasks();
66 #endif // __WXDEBUG__
67
68 // ===========================================================================
69 // implementation
70 // ===========================================================================
71
72 // ----------------------------------------------------------------------------
73 // initialization and termination
74 // ----------------------------------------------------------------------------
75
76 wxAppBase::wxAppBase()
77 {
78 wxTheApp = (wxApp *)this;
79
80 #if WXWIN_COMPATIBILITY_2_2
81 m_wantDebugOutput = FALSE;
82 #endif // WXWIN_COMPATIBILITY_2_2
83
84 #if wxUSE_GUI
85 m_topWindow = (wxWindow *)NULL;
86 m_useBestVisual = FALSE;
87 m_isActive = TRUE;
88
89 // We don't want to exit the app if the user code shows a dialog from its
90 // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
91 // to Yes initially as this dialog would be the last top level window.
92 // OTOH, if we set it to No initially we'll have to overwrite it with Yes
93 // when we enter our OnRun() because we do want the default behaviour from
94 // then on. But this would be a problem if the user code calls
95 // SetExitOnFrameDelete(FALSE) from OnInit().
96 //
97 // So we use the special "Later" value which is such that
98 // GetExitOnFrameDelete() returns FALSE for it but which we know we can
99 // safely (i.e. without losing the effect of the users SetExitOnFrameDelete
100 // call) overwrite in OnRun()
101 m_exitOnFrameDelete = Later;
102 #endif // wxUSE_GUI
103
104 #ifdef __WXDEBUG__
105 SetTraceMasks();
106 #endif
107 }
108
109 wxAppBase::~wxAppBase()
110 {
111 // this destructor is required for Darwin
112 }
113
114 #if wxUSE_GUI
115 bool wxAppBase::OnInitGui()
116 {
117 #ifdef __WXUNIVERSAL__
118 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
119 return FALSE;
120 wxArtProvider *art = wxTheme::Get()->GetArtProvider();
121 if ( art )
122 wxArtProvider::PushProvider(art);
123 #endif // __WXUNIVERSAL__
124
125 return TRUE;
126 }
127 #endif // wxUSE_GUI
128
129 int wxAppBase::OnRun()
130 {
131 // see the comment in ctor: if the initial value hasn't been changed, use
132 // the default Yes from now on
133 if ( m_exitOnFrameDelete == Later )
134 {
135 m_exitOnFrameDelete = Yes;
136 }
137 //else: it has been changed, assume the user knows what he is doing
138
139 return MainLoop();
140 }
141
142 int wxAppBase::OnExit()
143 {
144 #if wxUSE_CONFIG
145 // delete the config object if any (don't use Get() here, but Set()
146 // because Get() could create a new config object)
147 delete wxConfigBase::Set((wxConfigBase *) NULL);
148 #endif // wxUSE_CONFIG
149
150 #ifdef __WXUNIVERSAL__
151 delete wxTheme::Set(NULL);
152 #endif // __WXUNIVERSAL__
153
154 return 0;
155 }
156
157 // ---------------------------------------------------------------------------
158 // wxAppBase
159 // ----------------------------------------------------------------------------
160
161 void wxAppBase::ProcessPendingEvents()
162 {
163 // ensure that we're the only thread to modify the pending events list
164 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
165
166 if ( !wxPendingEvents )
167 {
168 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
169 return;
170 }
171
172 // iterate until the list becomes empty
173 wxNode *node = wxPendingEvents->First();
174 while (node)
175 {
176 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
177 delete node;
178
179 // In ProcessPendingEvents(), new handlers might be add
180 // and we can safely leave the critical section here.
181 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
182 handler->ProcessPendingEvents();
183 wxENTER_CRIT_SECT( *wxPendingEventsLocker );
184
185 node = wxPendingEvents->First();
186 }
187
188 wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
189 }
190
191 // ----------------------------------------------------------------------------
192 // misc
193 // ----------------------------------------------------------------------------
194
195 #if wxUSE_GUI
196
197 void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
198 {
199 if ( active == m_isActive )
200 return;
201
202 m_isActive = active;
203
204 wxActivateEvent event(wxEVT_ACTIVATE_APP, active);
205 event.SetEventObject(this);
206
207 (void)ProcessEvent(event);
208 }
209
210 #endif // wxUSE_GUI
211
212 int wxAppBase::FilterEvent(wxEvent& WXUNUSED(event))
213 {
214 // process the events normally by default
215 return -1;
216 }
217
218 void wxAppBase::DoInit()
219 {
220 if (wxMessageOutput::Get())
221 return;
222
223 // NB: The standard way of printing help on command line arguments (app --help)
224 // is (according to common practice):
225 // - console apps: to stderr (on any platform)
226 // - GUI apps: stderr on Unix platforms (!)
227 // message box under Windows and others
228 #if wxUSE_GUI && !defined(__UNIX__)
229 #ifdef __WXMOTIF__
230 wxMessageOutput::Set(new wxMessageOutputLog);
231 #else
232 wxMessageOutput::Set(new wxMessageOutputMessageBox);
233 #endif
234 #else
235 wxMessageOutput::Set(new wxMessageOutputStderr);
236 #endif
237 }
238
239 // ----------------------------------------------------------------------------
240 // cmd line parsing
241 // ----------------------------------------------------------------------------
242
243 bool wxAppBase::OnInit()
244 {
245 DoInit();
246 #if wxUSE_CMDLINE_PARSER
247 wxCmdLineParser parser(argc, argv);
248
249 OnInitCmdLine(parser);
250
251 bool cont;
252 switch ( parser.Parse(FALSE /* don't show usage */) )
253 {
254 case -1:
255 cont = OnCmdLineHelp(parser);
256 break;
257
258 case 0:
259 cont = OnCmdLineParsed(parser);
260 break;
261
262 default:
263 cont = OnCmdLineError(parser);
264 break;
265 }
266
267 if ( !cont )
268 return FALSE;
269 #endif // wxUSE_CMDLINE_PARSER
270
271 return TRUE;
272 }
273
274 #if wxUSE_CMDLINE_PARSER
275
276 #define OPTION_VERBOSE _T("verbose")
277 #define OPTION_THEME _T("theme")
278 #define OPTION_MODE _T("mode")
279
280 void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser)
281 {
282 // the standard command line options
283 static const wxCmdLineEntryDesc cmdLineDesc[] =
284 {
285 {
286 wxCMD_LINE_SWITCH,
287 _T("h"),
288 _T("help"),
289 gettext_noop("show this help message"),
290 wxCMD_LINE_VAL_NONE,
291 wxCMD_LINE_OPTION_HELP
292 },
293
294 #if wxUSE_LOG
295 {
296 wxCMD_LINE_SWITCH,
297 _T(""),
298 OPTION_VERBOSE,
299 gettext_noop("generate verbose log messages"),
300 wxCMD_LINE_VAL_NONE,
301 0x0
302 },
303 #endif // wxUSE_LOG
304
305 #ifdef __WXUNIVERSAL__
306 {
307 wxCMD_LINE_OPTION,
308 _T(""),
309 OPTION_THEME,
310 gettext_noop("specify the theme to use"),
311 wxCMD_LINE_VAL_STRING,
312 0x0
313 },
314 #endif // __WXUNIVERSAL__
315
316 #if defined(__WXMGL__)
317 // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports
318 // should provide this option. That's why it is in common/appcmn.cpp
319 // and not mgl/app.cpp
320 {
321 wxCMD_LINE_OPTION,
322 _T(""),
323 OPTION_MODE,
324 gettext_noop("specify display mode to use (e.g. 640x480-16)"),
325 wxCMD_LINE_VAL_STRING,
326 0x0
327 },
328 #endif // __WXMGL__
329
330 // terminator
331 {
332 wxCMD_LINE_NONE,
333 _T(""),
334 _T(""),
335 _T(""),
336 wxCMD_LINE_VAL_NONE,
337 0x0
338 }
339 };
340
341 parser.SetDesc(cmdLineDesc);
342 }
343
344 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
345 {
346 #if wxUSE_LOG
347 if ( parser.Found(OPTION_VERBOSE) )
348 {
349 wxLog::SetVerbose(TRUE);
350 }
351 #endif // wxUSE_LOG
352
353 #ifdef __WXUNIVERSAL__
354 wxString themeName;
355 if ( parser.Found(OPTION_THEME, &themeName) )
356 {
357 wxTheme *theme = wxTheme::Create(themeName);
358 if ( !theme )
359 {
360 wxLogError(_("Unsupported theme '%s'."), themeName.c_str());
361
362 return FALSE;
363 }
364
365 wxTheme::Set(theme);
366 }
367 #endif // __WXUNIVERSAL__
368
369 #if defined(__WXMGL__)
370 wxString modeDesc;
371 if ( parser.Found(OPTION_MODE, &modeDesc) )
372 {
373 unsigned w, h, bpp;
374 if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 )
375 {
376 wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str());
377
378 return FALSE;
379 }
380
381 if ( !SetDisplayMode(wxDisplayModeInfo(w, h, bpp)) )
382 return FALSE;
383 }
384 #endif // __WXMGL__
385
386 return TRUE;
387 }
388
389 bool wxAppBase::OnCmdLineHelp(wxCmdLineParser& parser)
390 {
391 parser.Usage();
392
393 return FALSE;
394 }
395
396 bool wxAppBase::OnCmdLineError(wxCmdLineParser& parser)
397 {
398 parser.Usage();
399
400 return FALSE;
401 }
402
403 #endif // wxUSE_CMDLINE_PARSER
404
405 // ----------------------------------------------------------------------------
406 // debugging support
407 // ----------------------------------------------------------------------------
408
409 /* static */
410 bool wxAppBase::CheckBuildOptions(const wxBuildOptions& opts)
411 {
412 #define wxCMP(what) (what == opts.m_ ## what)
413
414 bool
415 #ifdef __WXDEBUG__
416 isDebug = TRUE;
417 #else
418 isDebug = FALSE;
419 #endif
420
421 int verMaj = wxMAJOR_VERSION,
422 verMin = wxMINOR_VERSION;
423
424 if ( !(wxCMP(isDebug) && wxCMP(verMaj) && wxCMP(verMin)) )
425 {
426 wxLogFatalError(_T("Mismatch between the program and library build ")
427 _T("versions detected."));
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 static void LINKAGEMODE SetTraceMasks()
440 {
441 wxString mask;
442 if ( wxGetEnv(wxT("WXTRACE"), &mask) )
443 {
444 wxStringTokenizer tkn(mask, wxT(","));
445 while ( tkn.HasMoreTokens() )
446 wxLog::AddTraceMask(tkn.GetNextToken());
447 }
448 }
449
450 // wxASSERT() helper
451 bool wxAssertIsEqual(int x, int y)
452 {
453 return x == y;
454 }
455
456 // break into the debugger
457 void wxTrap()
458 {
459 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
460 DebugBreak();
461 #elif defined(__WXMAC__) && !defined(__DARWIN__)
462 #if __powerc
463 Debugger();
464 #else
465 SysBreak();
466 #endif
467 #elif defined(__UNIX__)
468 raise(SIGTRAP);
469 #else
470 // TODO
471 #endif // Win/Unix
472 }
473
474 // show the assert modal dialog
475 static
476 void ShowAssertDialog(const wxChar *szFile,
477 int nLine,
478 const wxChar *szCond,
479 const wxChar *szMsg)
480 {
481 // this variable can be set to true to suppress "assert failure" messages
482 static bool s_bNoAsserts = FALSE;
483
484 wxChar szBuf[4096];
485
486 // make life easier for people using VC++ IDE by using this format: like
487 // this, clicking on the message will take us immediately to the place of
488 // the failed assert
489 wxSnprintf(szBuf, WXSIZEOF(szBuf),
490 wxT("%s(%d): assert \"%s\" failed"),
491 szFile, nLine, szCond);
492
493 if ( szMsg != NULL )
494 {
495 wxStrcat(szBuf, wxT(": "));
496 wxStrcat(szBuf, szMsg);
497 }
498 else // no message given
499 {
500 wxStrcat(szBuf, wxT("."));
501 }
502
503 if ( !s_bNoAsserts )
504 {
505 // send it to the normal log destination
506 wxLogDebug(szBuf);
507
508 #if (wxUSE_GUI && wxUSE_MSGDLG) || defined(__WXMSW__)
509 // this message is intentionally not translated - it is for
510 // developpers only
511 wxStrcat(szBuf, wxT("\nDo you want to stop the program?\nYou can also choose [Cancel] to suppress further warnings."));
512
513 // use the native message box if available: this is more robust than
514 // using our own
515 #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
516 switch ( ::MessageBox(NULL, szBuf, _T("Debug"),
517 MB_YESNOCANCEL | MB_ICONSTOP ) )
518 {
519 case IDYES:
520 wxTrap();
521 break;
522
523 case IDCANCEL:
524 s_bNoAsserts = TRUE;
525 break;
526
527 //case IDNO: nothing to do
528 }
529 #else // !MSW
530 switch ( wxMessageBox(szBuf, wxT("Debug"),
531 wxYES_NO | wxCANCEL | wxICON_STOP ) )
532 {
533 case wxYES:
534 wxTrap();
535 break;
536
537 case wxCANCEL:
538 s_bNoAsserts = TRUE;
539 break;
540
541 //case wxNO: nothing to do
542 }
543 #endif // GUI or MSW
544
545 #else // !GUI
546 wxTrap();
547 #endif // GUI/!GUI
548 }
549 }
550
551 // this function is called when an assert fails
552 void wxOnAssert(const wxChar *szFile,
553 int nLine,
554 const wxChar *szCond,
555 const wxChar *szMsg)
556 {
557 // FIXME MT-unsafe
558 static bool s_bInAssert = FALSE;
559
560 if ( s_bInAssert )
561 {
562 // He-e-e-e-elp!! we're trapped in endless loop
563 wxTrap();
564
565 s_bInAssert = FALSE;
566
567 return;
568 }
569
570 s_bInAssert = TRUE;
571
572 if ( !wxTheApp )
573 {
574 // by default, show the assert dialog box - we can't customize this
575 // behaviour
576 ShowAssertDialog(szFile, nLine, szCond, szMsg);
577 }
578 else
579 {
580 // let the app process it as it wants
581 wxTheApp->OnAssert(szFile, nLine, szCond, szMsg);
582 }
583
584 s_bInAssert = FALSE;
585 }
586
587 void wxAppBase::OnAssert(const wxChar *file,
588 int line,
589 const wxChar *cond,
590 const wxChar *msg)
591 {
592 ShowAssertDialog(file, line, cond, msg);
593 }
594
595 #endif //WXDEBUG
596