1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/appcmn.cpp
3 // Purpose: wxAppBase methods common to all platforms
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 18.10.99
7 // Copyright: (c) Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22
23 #ifndef WX_PRECOMP
24 #include "wx/app.h"
25 #include "wx/window.h"
26 #include "wx/bitmap.h"
27 #include "wx/log.h"
28 #include "wx/module.h"
29 #include "wx/msgdlg.h"
30 #include "wx/confbase.h"
31 #include "wx/utils.h"
32 #include "wx/wxcrtvararg.h"
33 #endif
34
35 #include "wx/apptrait.h"
36 #include "wx/cmdline.h"
37 #include "wx/msgout.h"
38 #include "wx/richmsgdlg.h"
39 #include "wx/thread.h"
40 #include "wx/vidmode.h"
41 #include "wx/evtloop.h"
42
43 #if wxUSE_FONTMAP
44 #include "wx/fontmap.h"
45 #endif // wxUSE_FONTMAP
46
47 // DLL options compatibility check:
48 #include "wx/build.h"
49 WX_CHECK_BUILD_OPTIONS("wxCore")
50
51 // ============================================================================
52 // wxAppBase implementation
53 // ============================================================================
54
55 // ----------------------------------------------------------------------------
56 // initialization
57 // ----------------------------------------------------------------------------
58
wxAppBase()59 wxAppBase::wxAppBase()
60 {
61 m_topWindow = NULL;
62
63 m_useBestVisual = false;
64 m_forceTrueColour = false;
65
66 m_isActive = true;
67
68 // We don't want to exit the app if the user code shows a dialog from its
69 // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
70 // to Yes initially as this dialog would be the last top level window.
71 // OTOH, if we set it to No initially we'll have to overwrite it with Yes
72 // when we enter our OnRun() because we do want the default behaviour from
73 // then on. But this would be a problem if the user code calls
74 // SetExitOnFrameDelete(false) from OnInit().
75 //
76 // So we use the special "Later" value which is such that
77 // GetExitOnFrameDelete() returns false for it but which we know we can
78 // safely (i.e. without losing the effect of the users SetExitOnFrameDelete
79 // call) overwrite in OnRun()
80 m_exitOnFrameDelete = Later;
81 }
82
Initialize(int & argcOrig,wxChar ** argvOrig)83 bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig)
84 {
85 #ifdef __DARWIN__
86 // Mac OS X passes a process serial number command line argument when
87 // the application is launched from the Finder. This argument must be
88 // removed from the command line arguments before being handled by the
89 // application (otherwise applications would need to handle it)
90 //
91 // Notice that this has to be done for all ports that can be used under OS
92 // X (e.g. wxGTK) and not just wxOSX itself, hence this code is here and
93 // not in a port-specific file.
94 if ( argcOrig > 1 )
95 {
96 static const wxChar *ARG_PSN = wxT("-psn_");
97 if ( wxStrncmp(argvOrig[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
98 {
99 // remove this argument
100 --argcOrig;
101 memmove(argvOrig + 1, argvOrig + 2, argcOrig * sizeof(wxChar*));
102 }
103 }
104 #endif // __DARWIN__
105
106 if ( !wxAppConsole::Initialize(argcOrig, argvOrig) )
107 return false;
108
109 wxInitializeStockLists();
110
111 wxBitmap::InitStandardHandlers();
112
113 // for compatibility call the old initialization function too
114 if ( !OnInitGui() )
115 return false;
116
117 return true;
118 }
119
120 // ----------------------------------------------------------------------------
121 // cleanup
122 // ----------------------------------------------------------------------------
123
~wxAppBase()124 wxAppBase::~wxAppBase()
125 {
126 // this destructor is required for Darwin
127 }
128
DeleteAllTLWs()129 void wxAppBase::DeleteAllTLWs()
130 {
131 // TLWs remove themselves from wxTopLevelWindows when destroyed, so iterate
132 // until none are left.
133 while ( !wxTopLevelWindows.empty() )
134 {
135 // do not use Destroy() here as it only puts the TLW in pending list
136 // but we want to delete them now
137 delete wxTopLevelWindows.GetFirst()->GetData();
138 }
139 }
140
CleanUp()141 void wxAppBase::CleanUp()
142 {
143 // Clean up any still pending objects. Normally there shouldn't any as we
144 // already do this in OnExit(), but this could happen if the user code has
145 // somehow managed to create more of them since then or just forgot to call
146 // the base class OnExit().
147 DeletePendingObjects();
148
149 // and any remaining TLWs
150 DeleteAllTLWs();
151
152 // undo everything we did in Initialize() above
153 wxBitmap::CleanUpHandlers();
154
155 wxStockGDI::DeleteAll();
156
157 wxDeleteStockLists();
158
159 wxDELETE(wxTheColourDatabase);
160
161 wxAppConsole::CleanUp();
162 }
163
164 // ----------------------------------------------------------------------------
165 // various accessors
166 // ----------------------------------------------------------------------------
167
GetTopWindow() const168 wxWindow* wxAppBase::GetTopWindow() const
169 {
170 wxWindow* window = m_topWindow;
171
172 // If there is no top window or it is about to be destroyed,
173 // we need to search for the first TLW which is not pending delete
174 if ( !window || wxPendingDelete.Member(window) )
175 {
176 window = NULL;
177 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
178 while ( node )
179 {
180 wxWindow* win = node->GetData();
181 if ( !wxPendingDelete.Member(win) )
182 {
183 window = win;
184 break;
185 }
186 node = node->GetNext();
187 }
188 }
189
190 return window;
191 }
192
193 /* static */
GetMainTopWindow()194 wxWindow* wxAppBase::GetMainTopWindow()
195 {
196 const wxAppBase* const app = static_cast<wxAppBase*>(GetInstance());
197
198 return app ? app->GetTopWindow() : NULL;
199 }
200
GetDisplayMode() const201 wxVideoMode wxAppBase::GetDisplayMode() const
202 {
203 return wxVideoMode();
204 }
205
GetLayoutDirection() const206 wxLayoutDirection wxAppBase::GetLayoutDirection() const
207 {
208 #if wxUSE_INTL
209 const wxLocale *const locale = wxGetLocale();
210 if ( locale )
211 {
212 const wxLanguageInfo *const
213 info = wxLocale::GetLanguageInfo(locale->GetLanguage());
214
215 if ( info )
216 return info->LayoutDirection;
217 }
218 #endif // wxUSE_INTL
219
220 // we don't know
221 return wxLayout_Default;
222 }
223
224 #if wxUSE_CMDLINE_PARSER
225
226 // ----------------------------------------------------------------------------
227 // GUI-specific command line options handling
228 // ----------------------------------------------------------------------------
229
230 #ifdef __WXUNIVERSAL__
231 #define OPTION_THEME "theme"
232 #endif
233 #if defined(__WXDFB__)
234 #define OPTION_MODE "mode"
235 #endif
236
OnInitCmdLine(wxCmdLineParser & parser)237 void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser)
238 {
239 // first add the standard non GUI options
240 wxAppConsole::OnInitCmdLine(parser);
241
242 // the standard command line options
243 static const wxCmdLineEntryDesc cmdLineGUIDesc[] =
244 {
245 #ifdef __WXUNIVERSAL__
246 {
247 wxCMD_LINE_OPTION,
248 NULL,
249 OPTION_THEME,
250 gettext_noop("specify the theme to use"),
251 wxCMD_LINE_VAL_STRING,
252 0x0
253 },
254 #endif // __WXUNIVERSAL__
255
256 #if defined(__WXDFB__)
257 // VS: this is not specific to wxDFB, all fullscreen (framebuffer) ports
258 // should provide this option. That's why it is in common/appcmn.cpp
259 // and not dfb/app.cpp
260 {
261 wxCMD_LINE_OPTION,
262 NULL,
263 OPTION_MODE,
264 gettext_noop("specify display mode to use (e.g. 640x480-16)"),
265 wxCMD_LINE_VAL_STRING,
266 0x0
267 },
268 #endif // __WXDFB__
269
270 // terminator
271 wxCMD_LINE_DESC_END
272 };
273
274 parser.SetDesc(cmdLineGUIDesc);
275 }
276
OnCmdLineParsed(wxCmdLineParser & parser)277 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
278 {
279 #ifdef __WXUNIVERSAL__
280 wxString themeName;
281 if ( parser.Found(OPTION_THEME, &themeName) )
282 {
283 wxTheme *theme = wxTheme::Create(themeName);
284 if ( !theme )
285 {
286 wxLogError(_("Unsupported theme '%s'."), themeName.c_str());
287 return false;
288 }
289
290 // Delete the defaultly created theme and set the new theme.
291 delete wxTheme::Get();
292 wxTheme::Set(theme);
293 }
294 #endif // __WXUNIVERSAL__
295
296 #if defined(__WXDFB__)
297 wxString modeDesc;
298 if ( parser.Found(OPTION_MODE, &modeDesc) )
299 {
300 unsigned w, h, bpp;
301 if ( wxSscanf(modeDesc.c_str(), wxT("%ux%u-%u"), &w, &h, &bpp) != 3 )
302 {
303 wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str());
304 return false;
305 }
306
307 if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) )
308 return false;
309 }
310 #endif // __WXDFB__
311
312 return wxAppConsole::OnCmdLineParsed(parser);
313 }
314
315 #endif // wxUSE_CMDLINE_PARSER
316
317 // ----------------------------------------------------------------------------
318 // OnXXX() hooks
319 // ----------------------------------------------------------------------------
320
OnInitGui()321 bool wxAppBase::OnInitGui()
322 {
323 #ifdef __WXUNIVERSAL__
324 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
325 return false;
326 #endif // __WXUNIVERSAL__
327
328 return true;
329 }
330
OnRun()331 int wxAppBase::OnRun()
332 {
333 // see the comment in ctor: if the initial value hasn't been changed, use
334 // the default Yes from now on
335 if ( m_exitOnFrameDelete == Later )
336 {
337 m_exitOnFrameDelete = Yes;
338 }
339 //else: it has been changed, assume the user knows what he is doing
340
341 return wxAppConsole::OnRun();
342 }
343
OnExit()344 int wxAppBase::OnExit()
345 {
346 #ifdef __WXUNIVERSAL__
347 delete wxTheme::Set(NULL);
348 #endif // __WXUNIVERSAL__
349
350 return wxAppConsole::OnExit();
351 }
352
CreateTraits()353 wxAppTraits *wxAppBase::CreateTraits()
354 {
355 return new wxGUIAppTraits;
356 }
357
358 // ----------------------------------------------------------------------------
359 // misc
360 // ----------------------------------------------------------------------------
361
SetActive(bool active,wxWindow * WXUNUSED (lastFocus))362 void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
363 {
364 if ( active == m_isActive )
365 return;
366
367 m_isActive = active;
368
369 wxActivateEvent event(wxEVT_ACTIVATE_APP, active);
370 event.SetEventObject(this);
371
372 (void)ProcessEvent(event);
373 }
374
SafeYield(wxWindow * win,bool onlyIfNeeded)375 bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded)
376 {
377 wxWindowDisabler wd(win);
378
379 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
380
381 return loop && loop->Yield(onlyIfNeeded);
382 }
383
SafeYieldFor(wxWindow * win,long eventsToProcess)384 bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess)
385 {
386 wxWindowDisabler wd(win);
387
388 wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
389
390 return loop && loop->YieldFor(eventsToProcess);
391 }
392
393
394 // ----------------------------------------------------------------------------
395 // idle handling
396 // ----------------------------------------------------------------------------
397
398 // Returns true if more time is needed.
ProcessIdle()399 bool wxAppBase::ProcessIdle()
400 {
401 // call the base class version first to send the idle event to wxTheApp
402 // itself
403 bool needMore = wxAppConsoleBase::ProcessIdle();
404 wxIdleEvent event;
405 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
406 while (node)
407 {
408 wxWindow* win = node->GetData();
409
410 // Don't send idle events to the windows that are about to be destroyed
411 // anyhow, this is wasteful and unexpected.
412 if ( !wxPendingDelete.Member(win) && win->SendIdleEvents(event) )
413 needMore = true;
414 node = node->GetNext();
415 }
416
417 wxUpdateUIEvent::ResetUpdateTime();
418
419 return needMore;
420 }
421
422 // ----------------------------------------------------------------------------
423 // wxGUIAppTraitsBase
424 // ----------------------------------------------------------------------------
425
426 #if wxUSE_LOG
427
CreateLogTarget()428 wxLog *wxGUIAppTraitsBase::CreateLogTarget()
429 {
430 #if wxUSE_LOGGUI
431 #ifndef __WXOSX_IPHONE__
432 return new wxLogGui;
433 #else
434 return new wxLogStderr;
435 #endif
436 #else
437 // we must have something!
438 return new wxLogStderr;
439 #endif
440 }
441
442 #endif // wxUSE_LOG
443
CreateMessageOutput()444 wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput()
445 {
446 // The standard way of printing help on command line arguments (app --help)
447 // is (according to common practice):
448 // - console apps: to stderr (on any platform)
449 // - GUI apps: stderr on Unix platforms (!)
450 // stderr if available and message box otherwise on others
451 // (currently stderr only Windows if app running from console)
452 #ifdef __UNIX__
453 return new wxMessageOutputStderr;
454 #else // !__UNIX__
455 // wxMessageOutputMessageBox doesn't work under Motif
456 #ifdef __WXMOTIF__
457 return new wxMessageOutputLog;
458 #elif wxUSE_MSGDLG
459 return new wxMessageOutputBest(wxMSGOUT_PREFER_STDERR);
460 #else
461 return new wxMessageOutputStderr;
462 #endif
463 #endif // __UNIX__/!__UNIX__
464 }
465
466 #if wxUSE_FONTMAP
467
CreateFontMapper()468 wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper()
469 {
470 return new wxFontMapper;
471 }
472
473 #endif // wxUSE_FONTMAP
474
CreateRenderer()475 wxRendererNative *wxGUIAppTraitsBase::CreateRenderer()
476 {
477 // use the default native renderer by default
478 return NULL;
479 }
480
ShowAssertDialog(const wxString & msg)481 bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg)
482 {
483 #if wxDEBUG_LEVEL
484 // If possible, show the assert using a dialog allowing to hide the stack
485 // trace by default to avoid frightening people unnecessarily.
486 //
487 // Otherwise, show the assert using a basic message box, but under MSW
488 // we prefer to use the base class version using ::MessageBox() even if
489 // wxMessageBox() is available because it has less chances to double
490 // fault our app than our wxMessageBox()
491 //
492 // Notice that under DFB the message dialog is not always functional right
493 // now and, finally, we can't use wxMessageBox() if it wasn't compiled in.
494 #if wxUSE_RICHMSGDLG || \
495 (wxUSE_MSGDLG && !defined(__WXMSW__) && !defined(__WXDFB__))
496
497 // we can't (safely) show the GUI dialog from another thread, only do it
498 // for the asserts in the main thread
499 if ( wxIsMainThread() )
500 {
501 // Note that this and the other messages here are intentionally not
502 // translated -- they are for developpers only.
503 static const wxStringCharType* caption = wxS("wxWidgets Debug Alert");
504
505 wxString msgDlg = wxS("A debugging check in this application ")
506 wxS("has failed.\n\n") + msg;
507
508 // "No" button means to continue execution, so it should be the default
509 // action as leaving the "Yes" button the default one would mean that
510 // accidentally pressing Space or Enter would trap and kill the program.
511 const int flags = wxYES_NO | wxNO_DEFAULT | wxICON_STOP;
512
513 #if wxUSE_STACKWALKER
514 const wxString stackTrace = GetAssertStackTrace();
515 #endif // wxUSE_STACKWALKER
516
517 #if wxUSE_RICHMSGDLG
518 wxRichMessageDialog dlg(NULL, msgDlg, caption, flags);
519
520 dlg.SetYesNoLabels("Stop", "Continue");
521
522 dlg.ShowCheckBox("Don't show this dialog again");
523
524 #if wxUSE_STACKWALKER
525 if ( !stackTrace.empty() )
526 dlg.ShowDetailedText(stackTrace);
527 #endif // wxUSE_STACKWALKER
528 #else // !wxUSE_RICHMSGDLG
529 #if wxUSE_STACKWALKER
530 if ( !stackTrace.empty() )
531 msgDlg << wxT("\n\nCall stack:\n") << stackTrace;
532 #endif // wxUSE_STACKWALKER
533
534 msgDlg += wxT("\nDo you want to stop the program?\n")
535 wxT("You can also choose [Cancel] to suppress ")
536 wxT("further warnings.");
537
538 wxMessageDialog dlg(NULL, msg, caption, flags);
539 #endif // wxUSE_RICHMSGDLG/!wxUSE_RICHMSGDLG
540
541 switch ( dlg.ShowModal() )
542 {
543 case wxID_YES:
544 // See the comment about using the same variable in
545 // DoShowAssertDialog().
546 wxTrapInAssert = true;
547 break;
548
549 case wxID_CANCEL:
550 // This button is used with the plain message dialog only to
551 // indicate that no more assert dialogs should be shown, as
552 // there is no other way to do it with it.
553 return true;
554
555 case wxID_NO:
556 #if wxUSE_RICHMSGDLG
557 if ( dlg.IsCheckBoxChecked() )
558 {
559 // With this dialog, the checkbox is used to indicate that
560 // the subsequent asserts should be skipped.
561 return true;
562 }
563 #endif // wxUSE_RICHMSGDLG
564
565 // Nothing to do otherwise.
566 break;
567 }
568
569 return false;
570 }
571 #endif // wxUSE_RICHMSGDLG || wxUSE_MSGDLG
572 #endif // wxDEBUG_LEVEL
573
574 return wxAppTraitsBase::ShowAssertDialog(msg);
575 }
576
HasStderr()577 bool wxGUIAppTraitsBase::HasStderr()
578 {
579 // we consider that under Unix stderr always goes somewhere, even if the
580 // user doesn't always see it under GUI desktops
581 #ifdef __UNIX__
582 return true;
583 #else
584 return false;
585 #endif
586 }
587
588 #ifndef __WIN32__
589
SafeMessageBox(const wxString & text,const wxString & title)590 bool wxGUIAppTraitsBase::SafeMessageBox(const wxString& text,
591 const wxString& title)
592 {
593 // The modules are initialized only after a successful call to
594 // wxApp::Initialize() in wxEntryStart, so it can be used as a proxy for
595 // GUI availability (note that the mere existence of wxTheApp is not enough
596 // for this).
597 if ( !wxModule::AreInitialized() )
598 return false;
599
600 wxMessageBox(text, title, wxOK | wxICON_ERROR);
601
602 return true;
603 }
604
605 #endif // !__WIN32__
606