X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/49e885f80715560a88d0f7eccbb497ec8c3c1641..8fdbcf4de8eeff67ccfaf3deec833d203f112629:/src/common/appcmn.cpp diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index af586d4f31..9a3ead6a33 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: common/appcmn.cpp +// Name: src/common/appcmn.cpp // Purpose: wxAppBase methods common to all platforms // Author: Vadim Zeitlin // Modified by: @@ -17,10 +17,6 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "appbase.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -30,232 +26,199 @@ #ifndef WX_PRECOMP #include "wx/app.h" - #include "wx/intl.h" - #include "wx/list.h" - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif // wxUSE_GUI + #include "wx/window.h" + #include "wx/bitmap.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/confbase.h" + #include "wx/utils.h" + #include "wx/wxcrtvararg.h" #endif +#include "wx/apptrait.h" #include "wx/cmdline.h" +#include "wx/msgout.h" #include "wx/thread.h" -#include "wx/confbase.h" +#include "wx/vidmode.h" +#include "wx/evtloop.h" -#if !defined(__WXMSW__) || defined(__WXMICROWIN__) - #include // for SIGTRAP used by wxTrap() -#endif //Win/Unix +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for MessageBox() -#endif +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxCore") -// =========================================================================== -// implementation -// =========================================================================== +// ============================================================================ +// wxAppBase implementation +// ============================================================================ // ---------------------------------------------------------------------------- -// initialization and termination +// initialization // ---------------------------------------------------------------------------- wxAppBase::wxAppBase() { - wxTheApp = (wxApp *)this; - - // VZ: what's this? is it obsolete? - m_wantDebugOutput = FALSE; - -#if wxUSE_GUI - m_topWindow = (wxWindow *)NULL; - m_useBestVisual = FALSE; - m_exitOnFrameDelete = TRUE; - m_isActive = TRUE; -#endif // wxUSE_GUI + m_topWindow = NULL; + + m_useBestVisual = false; + m_forceTrueColour = false; + + m_isActive = true; + + // We don't want to exit the app if the user code shows a dialog from its + // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete + // to Yes initially as this dialog would be the last top level window. + // OTOH, if we set it to No initially we'll have to overwrite it with Yes + // when we enter our OnRun() because we do want the default behaviour from + // then on. But this would be a problem if the user code calls + // SetExitOnFrameDelete(false) from OnInit(). + // + // So we use the special "Later" value which is such that + // GetExitOnFrameDelete() returns false for it but which we know we can + // safely (i.e. without losing the effect of the users SetExitOnFrameDelete + // call) overwrite in OnRun() + m_exitOnFrameDelete = Later; } -#if wxUSE_GUI -bool wxAppBase::OnInitGui() +bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig) { -#ifdef __WXUNIVERSAL__ - if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) - return FALSE; -#endif // __WXUNIVERSAL__ + if ( !wxAppConsole::Initialize(argcOrig, argvOrig) ) + return false; - return TRUE; -} -#endif // wxUSE_GUI + wxInitializeStockLists(); -int wxAppBase::OnExit() -{ -#if wxUSE_CONFIG - // delete the config object if any (don't use Get() here, but Set() - // because Get() could create a new config object) - delete wxConfigBase::Set((wxConfigBase *) NULL); -#endif // wxUSE_CONFIG + wxBitmap::InitStandardHandlers(); -#ifdef __WXUNIVERSAL__ - delete wxTheme::Set(NULL); -#endif // __WXUNIVERSAL__ + // for compatibility call the old initialization function too + if ( !OnInitGui() ) + return false; - return 0; + return true; } -// --------------------------------------------------------------------------- -// wxAppBase +// ---------------------------------------------------------------------------- +// cleanup // ---------------------------------------------------------------------------- -void wxAppBase::ProcessPendingEvents() +wxAppBase::~wxAppBase() { - // ensure that we're the only thread to modify the pending events list - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + // this destructor is required for Darwin +} - if ( !wxPendingEvents ) - { - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - return; - } +void wxAppBase::CleanUp() +{ + // clean up all the pending objects + DeletePendingObjects(); - // iterate until the list becomes empty - wxNode *node = wxPendingEvents->First(); - while (node) + // and any remaining TLWs (they remove themselves from wxTopLevelWindows + // when destroyed, so iterate until none are left) + while ( !wxTopLevelWindows.empty() ) { - wxEvtHandler *handler = (wxEvtHandler *)node->Data(); - delete node; - - // In ProcessPendingEvents(), new handlers might be add - // and we can safely leave the critical section here. - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - handler->ProcessPendingEvents(); - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - node = wxPendingEvents->First(); + // do not use Destroy() here as it only puts the TLW in pending list + // but we want to delete them now + delete wxTopLevelWindows.GetFirst()->GetData(); } - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -#if wxUSE_GUI + // undo everything we did in Initialize() above + wxBitmap::CleanUpHandlers(); -void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) -{ - if ( active == m_isActive ) - return; + wxStockGDI::DeleteAll(); - m_isActive = active; + wxDeleteStockLists(); - wxActivateEvent event(wxEVT_ACTIVATE_APP, active); - event.SetEventObject(this); + wxDELETE(wxTheColourDatabase); - (void)ProcessEvent(event); + wxAppConsole::CleanUp(); } -#endif // wxUSE_GUI - // ---------------------------------------------------------------------------- -// cmd line parsing +// various accessors // ---------------------------------------------------------------------------- -bool wxAppBase::OnInit() +wxWindow* wxAppBase::GetTopWindow() const { -#if wxUSE_CMDLINE_PARSER - wxCmdLineParser parser(argc, argv); + wxWindow* window = m_topWindow; + if (window == NULL && wxTopLevelWindows.GetCount() > 0) + window = wxTopLevelWindows.GetFirst()->GetData(); + return window; +} - OnInitCmdLine(parser); +wxVideoMode wxAppBase::GetDisplayMode() const +{ + return wxVideoMode(); +} - bool cont; - switch ( parser.Parse() ) +wxLayoutDirection wxAppBase::GetLayoutDirection() const +{ +#if wxUSE_INTL + const wxLocale *const locale = wxGetLocale(); + if ( locale ) { - case -1: - cont = OnCmdLineHelp(parser); - break; + const wxLanguageInfo *const + info = wxLocale::GetLanguageInfo(locale->GetLanguage()); - case 0: - cont = OnCmdLineParsed(parser); - break; - - default: - cont = OnCmdLineError(parser); - break; + if ( info ) + return info->LayoutDirection; } +#endif // wxUSE_INTL - if ( !cont ) - return FALSE; -#endif // wxUSE_CMDLINE_PARSER - - return TRUE; + // we don't know + return wxLayout_Default; } #if wxUSE_CMDLINE_PARSER -#define OPTION_VERBOSE _T("verbose") -#define OPTION_THEME _T("theme") -#define OPTION_MODE _T("mode") +// ---------------------------------------------------------------------------- +// GUI-specific command line options handling +// ---------------------------------------------------------------------------- + +#define OPTION_THEME "theme" +#define OPTION_MODE "mode" void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) { + // first add the standard non GUI options + wxAppConsole::OnInitCmdLine(parser); + // the standard command line options - static const wxCmdLineEntryDesc cmdLineDesc[] = + static const wxCmdLineEntryDesc cmdLineGUIDesc[] = { - { - wxCMD_LINE_SWITCH, - _T("h"), - _T("help"), - gettext_noop("show this help message"), - wxCMD_LINE_VAL_NONE, - wxCMD_LINE_OPTION_HELP - }, - -#if wxUSE_LOG - { - wxCMD_LINE_SWITCH, - _T(""), - OPTION_VERBOSE, - gettext_noop("generate verbose log messages") - }, -#endif // wxUSE_LOG - #ifdef __WXUNIVERSAL__ { wxCMD_LINE_OPTION, - _T(""), + NULL, OPTION_THEME, gettext_noop("specify the theme to use"), - wxCMD_LINE_VAL_STRING + wxCMD_LINE_VAL_STRING, + 0x0 }, #endif // __WXUNIVERSAL__ -#if defined(__WXMGL__) - // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports +#if defined(__WXDFB__) + // VS: this is not specific to wxDFB, all fullscreen (framebuffer) ports // should provide this option. That's why it is in common/appcmn.cpp - // and not mgl/app.cpp + // and not dfb/app.cpp { wxCMD_LINE_OPTION, - _T(""), + NULL, OPTION_MODE, gettext_noop("specify display mode to use (e.g. 640x480-16)"), - wxCMD_LINE_VAL_STRING + wxCMD_LINE_VAL_STRING, + 0x0 }, -#endif // __WXMGL__ +#endif // __WXDFB__ // terminator - { wxCMD_LINE_NONE } + wxCMD_LINE_DESC_END }; - parser.SetDesc(cmdLineDesc); + parser.SetDesc(cmdLineGUIDesc); } bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) { -#if wxUSE_LOG - if ( parser.Found(OPTION_VERBOSE) ) - { - wxLog::SetVerbose(TRUE); - } -#endif // wxUSE_LOG - #ifdef __WXUNIVERSAL__ wxString themeName; if ( parser.Found(OPTION_THEME, &themeName) ) @@ -264,195 +227,261 @@ bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) if ( !theme ) { wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); - - return FALSE; + return false; } + // Delete the defaultly created theme and set the new theme. + delete wxTheme::Get(); wxTheme::Set(theme); } #endif // __WXUNIVERSAL__ -#if defined(__WXMGL__) +#if defined(__WXDFB__) wxString modeDesc; if ( parser.Found(OPTION_MODE, &modeDesc) ) { unsigned w, h, bpp; - if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) + if ( wxSscanf(modeDesc.c_str(), wxT("%ux%u-%u"), &w, &h, &bpp) != 3 ) { wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); - - return FALSE; + return false; } - if ( !SetDisplayMode(wxDisplayModeInfo(wxSize(w, h), bpp)) ) - return FALSE; + if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) ) + return false; } -#endif +#endif // __WXDFB__ - return TRUE; + return wxAppConsole::OnCmdLineParsed(parser); } -bool wxAppBase::OnCmdLineHelp(wxCmdLineParser& parser) +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// OnXXX() hooks +// ---------------------------------------------------------------------------- + +bool wxAppBase::OnInitGui() { - parser.Usage(); +#ifdef __WXUNIVERSAL__ + if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) + return false; +#endif // __WXUNIVERSAL__ - return FALSE; + return true; } -bool wxAppBase::OnCmdLineError(wxCmdLineParser& parser) +int wxAppBase::OnRun() { - parser.Usage(); + // see the comment in ctor: if the initial value hasn't been changed, use + // the default Yes from now on + if ( m_exitOnFrameDelete == Later ) + { + m_exitOnFrameDelete = Yes; + } + //else: it has been changed, assume the user knows what he is doing - return FALSE; + return wxAppConsole::OnRun(); } -#endif // wxUSE_CMDLINE_PARSER +int wxAppBase::OnExit() +{ +#ifdef __WXUNIVERSAL__ + delete wxTheme::Set(NULL); +#endif // __WXUNIVERSAL__ + + return wxAppConsole::OnExit(); +} + +wxAppTraits *wxAppBase::CreateTraits() +{ + return new wxGUIAppTraits; +} // ---------------------------------------------------------------------------- -// debugging support +// misc // ---------------------------------------------------------------------------- -#ifdef __WXDEBUG__ +void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) +{ + if ( active == m_isActive ) + return; + + m_isActive = active; + + wxActivateEvent event(wxEVT_ACTIVATE_APP, active); + event.SetEventObject(this); -// wxASSERT() helper -bool wxAssertIsEqual(int x, int y) + (void)ProcessEvent(event); +} + +bool wxAppBase::SafeYield(wxWindow *win, bool onlyIfNeeded) { - return x == y; + wxWindowDisabler wd(win); + + wxEventLoopBase * const loop = wxEventLoopBase::GetActive(); + + return loop && loop->Yield(onlyIfNeeded); } -// break into the debugger -void wxTrap() +bool wxAppBase::SafeYieldFor(wxWindow *win, long eventsToProcess) { -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - DebugBreak(); -#elif defined(__WXMAC__) -#if __powerc - Debugger(); -#else - SysBreak(); -#endif -#elif defined(__UNIX__) - raise(SIGTRAP); -#else - // TODO -#endif // Win/Unix + wxWindowDisabler wd(win); + + wxEventLoopBase * const loop = wxEventLoopBase::GetActive(); + + return loop && loop->YieldFor(eventsToProcess); } -// show the assert modal dialog -static -void ShowAssertDialog(const wxChar *szFile, int nLine, const wxChar *szMsg) + +// ---------------------------------------------------------------------------- +// idle handling +// ---------------------------------------------------------------------------- + +// Returns true if more time is needed. +bool wxAppBase::ProcessIdle() { - // this variable can be set to true to suppress "assert failure" messages - static bool s_bNoAsserts = FALSE; - - wxChar szBuf[4096]; - - // make life easier for people using VC++ IDE: clicking on the message - // will take us immediately to the place of the failed assert - wxSnprintf(szBuf, WXSIZEOF(szBuf), -#ifdef __VISUALC__ - wxT("%s(%d): assert failed"), -#else // !VC++ - // make the error message more clear for all the others - wxT("Assert failed in file %s at line %d"), -#endif // VC/!VC - szFile, nLine); - - if ( szMsg != NULL ) - { - wxStrcat(szBuf, wxT(": ")); - wxStrcat(szBuf, szMsg); - } - else // no message given + // call the base class version first to send the idle event to wxTheApp + // itself + bool needMore = wxAppConsoleBase::ProcessIdle(); + wxIdleEvent event; + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + while (node) { - wxStrcat(szBuf, wxT(".")); + wxWindow* win = node->GetData(); + + // Don't send idle events to the windows that are about to be destroyed + // anyhow, this is wasteful and unexpected. + if ( !wxPendingDelete.Member(win) && win->SendIdleEvents(event) ) + needMore = true; + node = node->GetNext(); } - if ( !s_bNoAsserts ) - { - // send it to the normal log destination - wxLogDebug(szBuf); + wxUpdateUIEvent::ResetUpdateTime(); -#if (wxUSE_GUI && wxUSE_MSGDLG) || defined(__WXMSW__) - // this message is intentionally not translated - it is for - // developpers only - wxStrcat(szBuf, wxT("\nDo you want to stop the program?\nYou can also choose [Cancel] to suppress further warnings.")); + return needMore; +} - // use the native message box if available: this is more robust than - // using our own -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - switch ( ::MessageBox(NULL, szBuf, _T("Debug"), - MB_YESNOCANCEL | MB_ICONSTOP ) ) - { - case IDYES: - wxTrap(); - break; +// ---------------------------------------------------------------------------- +// wxGUIAppTraitsBase +// ---------------------------------------------------------------------------- - case IDCANCEL: - s_bNoAsserts = TRUE; - break; +#if wxUSE_LOG - //case IDNO: nothing to do - } -#else // !MSW - switch ( wxMessageBox(szBuf, wxT("Debug"), - wxYES_NO | wxCANCEL | wxICON_STOP ) ) - { - case wxYES: - wxTrap(); - break; +wxLog *wxGUIAppTraitsBase::CreateLogTarget() +{ +#if wxUSE_LOGGUI +#ifndef __WXOSX_IPHONE__ + return new wxLogGui; +#else + return new wxLogStderr; +#endif +#else + // we must have something! + return new wxLogStderr; +#endif +} - case wxCANCEL: - s_bNoAsserts = TRUE; - break; +#endif // wxUSE_LOG - //case wxNO: nothing to do - } -#endif // GUI or MSW +wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() +{ + // The standard way of printing help on command line arguments (app --help) + // is (according to common practice): + // - console apps: to stderr (on any platform) + // - GUI apps: stderr on Unix platforms (!) + // stderr if available and message box otherwise on others + // (currently stderr only Windows if app running from console) +#ifdef __UNIX__ + return new wxMessageOutputStderr; +#else // !__UNIX__ + // wxMessageOutputMessageBox doesn't work under Motif + #ifdef __WXMOTIF__ + return new wxMessageOutputLog; + #elif wxUSE_MSGDLG + return new wxMessageOutputBest(wxMSGOUT_PREFER_STDERR); + #else + return new wxMessageOutputStderr; + #endif +#endif // __UNIX__/!__UNIX__ +} -#else // !GUI - wxTrap(); -#endif // GUI/!GUI - } +#if wxUSE_FONTMAP + +wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() +{ + return new wxFontMapper; } -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, int nLine, const wxChar *szMsg) +#endif // wxUSE_FONTMAP + +wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() { - // FIXME MT-unsafe - static bool s_bInAssert = FALSE; + // use the default native renderer by default + return NULL; +} - if ( s_bInAssert ) +bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) +{ +#if wxDEBUG_LEVEL + // under MSW we prefer to use the base class version using ::MessageBox() + // even if wxMessageBox() is available because it has less chances to + // double fault our app than our wxMessageBox() + // + // under DFB the message dialog is not always functional right now + // + // and finally we can't use wxMessageBox() if it wasn't compiled in, of + // course +#if !defined(__WXMSW__) && !defined(__WXDFB__) && wxUSE_MSGDLG + + // we can't (safely) show the GUI dialog from another thread, only do it + // for the asserts in the main thread + if ( wxIsMainThread() ) { - // He-e-e-e-elp!! we're trapped in endless loop - wxTrap(); + wxString msgDlg = msg; - s_bInAssert = FALSE; +#if wxUSE_STACKWALKER + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msgDlg << wxT("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER - return; - } + // this message is intentionally not translated -- it is for + // developpers only + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); - s_bInAssert = TRUE; + switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), + wxYES_NO | wxCANCEL | wxICON_STOP ) ) + { + case wxYES: + wxTrap(); + break; - if ( !wxTheApp ) - { - // by default, show the assert dialog box - we can't customize this - // behaviour - ShowAssertDialog(szFile, nLine, szMsg); - } - else - { - // let the app process it as it wants - wxTheApp->OnAssert(szFile, nLine, szMsg); + case wxCANCEL: + // no more asserts + return true; + + //case wxNO: nothing to do + } + + return false; } +#endif // wxUSE_MSGDLG +#endif // wxDEBUG_LEVEL - s_bInAssert = FALSE; + return wxAppTraitsBase::ShowAssertDialog(msg); } -void wxAppBase::OnAssert(const wxChar *file, int line, const wxChar *msg) +bool wxGUIAppTraitsBase::HasStderr() { - ShowAssertDialog(file, line, msg); + // we consider that under Unix stderr always goes somewhere, even if the + // user doesn't always see it under GUI desktops +#ifdef __UNIX__ + return true; +#else + return false; +#endif } -#endif //WXDEBUG -