1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/appcmn.cpp 
   3 // Purpose:     wxAppBase methods common to all platforms 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) Vadim Zeitlin 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  23 #if defined(__BORLANDC__) 
  29     #include "wx/window.h" 
  30     #include "wx/bitmap.h" 
  32     #include "wx/msgdlg.h" 
  33     #include "wx/confbase.h" 
  35     #include "wx/wxcrtvararg.h" 
  38 #include "wx/apptrait.h" 
  39 #include "wx/cmdline.h" 
  40 #include "wx/msgout.h" 
  41 #include "wx/thread.h" 
  42 #include "wx/vidmode.h" 
  43 #include "wx/evtloop.h" 
  46     #include "wx/fontmap.h" 
  47 #endif // wxUSE_FONTMAP 
  49 // DLL options compatibility check: 
  51 WX_CHECK_BUILD_OPTIONS("wxCore") 
  53 // ============================================================================ 
  54 // wxAppBase implementation 
  55 // ============================================================================ 
  57 // ---------------------------------------------------------------------------- 
  59 // ---------------------------------------------------------------------------- 
  61 wxAppBase::wxAppBase() 
  65     m_useBestVisual 
= false; 
  66     m_forceTrueColour 
= false; 
  70     // We don't want to exit the app if the user code shows a dialog from its 
  71     // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete 
  72     // to Yes initially as this dialog would be the last top level window. 
  73     // OTOH, if we set it to No initially we'll have to overwrite it with Yes 
  74     // when we enter our OnRun() because we do want the default behaviour from 
  75     // then on. But this would be a problem if the user code calls 
  76     // SetExitOnFrameDelete(false) from OnInit(). 
  78     // So we use the special "Later" value which is such that 
  79     // GetExitOnFrameDelete() returns false for it but which we know we can 
  80     // safely (i.e. without losing the effect of the users SetExitOnFrameDelete 
  81     // call) overwrite in OnRun() 
  82     m_exitOnFrameDelete 
= Later
; 
  85 bool wxAppBase::Initialize(int& argcOrig
, wxChar 
**argvOrig
) 
  87     if ( !wxAppConsole::Initialize(argcOrig
, argvOrig
) ) 
  90     wxInitializeStockLists(); 
  92     wxBitmap::InitStandardHandlers(); 
  94     // for compatibility call the old initialization function too 
 101 // ---------------------------------------------------------------------------- 
 103 // ---------------------------------------------------------------------------- 
 105 wxAppBase::~wxAppBase() 
 107     // this destructor is required for Darwin 
 110 void wxAppBase::CleanUp() 
 112     // clean up all the pending objects 
 113     DeletePendingObjects(); 
 115     // and any remaining TLWs (they remove themselves from wxTopLevelWindows 
 116     // when destroyed, so iterate until none are left) 
 117     while ( !wxTopLevelWindows
.empty() ) 
 119         // do not use Destroy() here as it only puts the TLW in pending list 
 120         // but we want to delete them now 
 121         delete wxTopLevelWindows
.GetFirst()->GetData(); 
 124     // undo everything we did in Initialize() above 
 125     wxBitmap::CleanUpHandlers(); 
 127     wxStockGDI::DeleteAll(); 
 129     wxDeleteStockLists(); 
 131     delete wxTheColourDatabase
; 
 132     wxTheColourDatabase 
= NULL
; 
 134     wxAppConsole::CleanUp(); 
 137 // ---------------------------------------------------------------------------- 
 139 // ---------------------------------------------------------------------------- 
 141 wxWindow
* wxAppBase::GetTopWindow() const 
 143     wxWindow
* window 
= m_topWindow
; 
 144     if (window 
== NULL 
&& wxTopLevelWindows
.GetCount() > 0) 
 145         window 
= wxTopLevelWindows
.GetFirst()->GetData(); 
 149 wxVideoMode 
wxAppBase::GetDisplayMode() const 
 151     return wxVideoMode(); 
 154 wxLayoutDirection 
wxAppBase::GetLayoutDirection() const 
 157     const wxLocale 
*const locale 
= wxGetLocale(); 
 160         const wxLanguageInfo 
*const 
 161             info 
= wxLocale::GetLanguageInfo(locale
->GetLanguage()); 
 164             return info
->LayoutDirection
; 
 169     return wxLayout_Default
; 
 172 #if wxUSE_CMDLINE_PARSER 
 174 // ---------------------------------------------------------------------------- 
 175 // GUI-specific command line options handling 
 176 // ---------------------------------------------------------------------------- 
 178 #define OPTION_THEME   "theme" 
 179 #define OPTION_MODE    "mode" 
 181 void wxAppBase::OnInitCmdLine(wxCmdLineParser
& parser
) 
 183     // first add the standard non GUI options 
 184     wxAppConsole::OnInitCmdLine(parser
); 
 186     // the standard command line options 
 187     static const wxCmdLineEntryDesc cmdLineGUIDesc
[] = 
 189 #ifdef __WXUNIVERSAL__ 
 194             gettext_noop("specify the theme to use"), 
 195             wxCMD_LINE_VAL_STRING
, 
 198 #endif // __WXUNIVERSAL__ 
 200 #if defined(__WXMGL__) 
 201         // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports 
 202         //     should provide this option. That's why it is in common/appcmn.cpp 
 203         //     and not mgl/app.cpp 
 208             gettext_noop("specify display mode to use (e.g. 640x480-16)"), 
 209             wxCMD_LINE_VAL_STRING
, 
 218     parser
.SetDesc(cmdLineGUIDesc
); 
 221 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser
& parser
) 
 223 #ifdef __WXUNIVERSAL__ 
 225     if ( parser
.Found(OPTION_THEME
, &themeName
) ) 
 227         wxTheme 
*theme 
= wxTheme::Create(themeName
); 
 230             wxLogError(_("Unsupported theme '%s'."), themeName
.c_str()); 
 234         // Delete the defaultly created theme and set the new theme. 
 235         delete wxTheme::Get(); 
 238 #endif // __WXUNIVERSAL__ 
 240 #if defined(__WXMGL__) 
 242     if ( parser
.Found(OPTION_MODE
, &modeDesc
) ) 
 245         if ( wxSscanf(modeDesc
.c_str(), _T("%ux%u-%u"), &w
, &h
, &bpp
) != 3 ) 
 247             wxLogError(_("Invalid display mode specification '%s'."), modeDesc
.c_str()); 
 251         if ( !SetDisplayMode(wxVideoMode(w
, h
, bpp
)) ) 
 256     return wxAppConsole::OnCmdLineParsed(parser
); 
 259 #endif // wxUSE_CMDLINE_PARSER 
 261 // ---------------------------------------------------------------------------- 
 263 // ---------------------------------------------------------------------------- 
 265 bool wxAppBase::OnInitGui() 
 267 #ifdef __WXUNIVERSAL__ 
 268     if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) 
 270 #endif // __WXUNIVERSAL__ 
 275 int wxAppBase::OnRun() 
 277     // see the comment in ctor: if the initial value hasn't been changed, use 
 278     // the default Yes from now on 
 279     if ( m_exitOnFrameDelete 
== Later 
) 
 281         m_exitOnFrameDelete 
= Yes
; 
 283     //else: it has been changed, assume the user knows what he is doing 
 285     return wxAppConsole::OnRun(); 
 288 int wxAppBase::OnExit() 
 290 #ifdef __WXUNIVERSAL__ 
 291     delete wxTheme::Set(NULL
); 
 292 #endif // __WXUNIVERSAL__ 
 294     return wxAppConsole::OnExit(); 
 297 wxAppTraits 
*wxAppBase::CreateTraits() 
 299     return new wxGUIAppTraits
; 
 302 // ---------------------------------------------------------------------------- 
 304 // ---------------------------------------------------------------------------- 
 306 void wxAppBase::SetActive(bool active
, wxWindow 
* WXUNUSED(lastFocus
)) 
 308     if ( active 
== m_isActive 
) 
 313     wxActivateEvent 
event(wxEVT_ACTIVATE_APP
, active
); 
 314     event
.SetEventObject(this); 
 316     (void)ProcessEvent(event
); 
 319 bool wxAppBase::SafeYield(wxWindow 
*win
, bool onlyIfNeeded
) 
 321     wxWindowDisabler 
wd(win
); 
 323     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 325     return loop 
&& loop
->Yield(onlyIfNeeded
); 
 328 bool wxAppBase::SafeYieldFor(wxWindow 
*win
, long eventsToProcess
) 
 330     wxWindowDisabler 
wd(win
); 
 332     wxEventLoopBase 
* const loop 
= wxEventLoopBase::GetActive(); 
 334     return loop 
&& loop
->YieldFor(eventsToProcess
); 
 338 // ---------------------------------------------------------------------------- 
 340 // ---------------------------------------------------------------------------- 
 342 // Returns true if more time is needed. 
 343 bool wxAppBase::ProcessIdle() 
 345     // call the base class version first to send the idle event to wxTheApp 
 347     bool needMore 
= wxAppConsoleBase::ProcessIdle(); 
 349     wxWindowList::compatibility_iterator node 
= wxTopLevelWindows
.GetFirst(); 
 352         wxWindow
* win 
= node
->GetData(); 
 353         if (SendIdleEvents(win
, event
)) 
 355         node 
= node
->GetNext(); 
 359     // flush the logged messages if any 
 360     wxLog::FlushActive(); 
 363     wxUpdateUIEvent::ResetUpdateTime(); 
 368 // Send idle event to window and all subwindows 
 369 bool wxAppBase::SendIdleEvents(wxWindow
* win
, wxIdleEvent
& event
) 
 371     bool needMore 
= false; 
 373     win
->OnInternalIdle(); 
 375     // should we send idle event to this window? 
 376     if ( wxIdleEvent::GetMode() == wxIDLE_PROCESS_ALL 
|| 
 377             win
->HasExtraStyle(wxWS_EX_PROCESS_IDLE
) ) 
 379         event
.SetEventObject(win
); 
 380         win
->HandleWindowEvent(event
); 
 382         if (event
.MoreRequested()) 
 385     wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst(); 
 388         wxWindow 
*child 
= node
->GetData(); 
 389         if (SendIdleEvents(child
, event
)) 
 392         node 
= node
->GetNext(); 
 398 // ---------------------------------------------------------------------------- 
 399 // wxGUIAppTraitsBase 
 400 // ---------------------------------------------------------------------------- 
 404 wxLog 
*wxGUIAppTraitsBase::CreateLogTarget() 
 409     // we must have something! 
 410     return new wxLogStderr
; 
 416 wxMessageOutput 
*wxGUIAppTraitsBase::CreateMessageOutput() 
 418     // The standard way of printing help on command line arguments (app --help) 
 419     // is (according to common practice): 
 420     //     - console apps: to stderr (on any platform) 
 421     //     - GUI apps: stderr on Unix platforms (!) 
 422     //                 stderr if available and message box otherwise on others 
 423     //                 (currently stderr only Windows if app running from console) 
 425     return new wxMessageOutputStderr
; 
 427     // wxMessageOutputMessageBox doesn't work under Motif 
 429         return new wxMessageOutputLog
; 
 431         return new wxMessageOutputBest(wxMSGOUT_PREFER_STDERR
); 
 433         return new wxMessageOutputStderr
; 
 435 #endif // __UNIX__/!__UNIX__ 
 440 wxFontMapper 
*wxGUIAppTraitsBase::CreateFontMapper() 
 442     return new wxFontMapper
; 
 445 #endif // wxUSE_FONTMAP 
 447 wxRendererNative 
*wxGUIAppTraitsBase::CreateRenderer() 
 449     // use the default native renderer by default 
 453 bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString
& msg
) 
 455     // under MSW we prefer to use the base class version using ::MessageBox() 
 456     // even if wxMessageBox() is available because it has less chances to 
 457     // double fault our app than our wxMessageBox() 
 459     // under DFB the message dialog is not always functional right now 
 461     // and finally we can't use wxMessageBox() if it wasn't compiled in, of 
 463 #if defined(__WXMSW__) || defined(__WXDFB__) || !wxUSE_MSGDLG 
 464     return wxAppTraitsBase::ShowAssertDialog(msg
); 
 465 #else // wxUSE_MSGDLG 
 467     wxString msgDlg 
= msg
; 
 469 #if wxUSE_STACKWALKER 
 470     // on Unix stack frame generation may take some time, depending on the 
 471     // size of the executable mainly... warn the user that we are working 
 472     wxFprintf(stderr
, wxT("[Debug] Generating a stack trace... please wait")); 
 475     const wxString stackTrace 
= GetAssertStackTrace(); 
 476     if ( !stackTrace
.empty() ) 
 477         msgDlg 
<< _T("\n\nCall stack:\n") << stackTrace
; 
 478 #endif // wxUSE_STACKWALKER 
 480     // this message is intentionally not translated -- it is for 
 482     msgDlg 
+= wxT("\nDo you want to stop the program?\n") 
 483               wxT("You can also choose [Cancel] to suppress ") 
 484               wxT("further warnings."); 
 486     switch ( wxMessageBox(msgDlg
, wxT("wxWidgets Debug Alert"), 
 487                           wxYES_NO 
| wxCANCEL 
| wxICON_STOP 
) ) 
 497         //case wxNO: nothing to do 
 499 #else // !wxDEBUG_LEVEL 
 500     // this function always exists (for ABI compatibility) but is never called 
 501     // if debug level is 0 and so can simply do nothing then 
 503 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL 
 506 #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG 
 509 bool wxGUIAppTraitsBase::HasStderr() 
 511     // we consider that under Unix stderr always goes somewhere, even if the 
 512     // user doesn't always see it under GUI desktops