X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/19bb2f5bbe6104d00b81b084693c8071626e68b7..f9133b32002a600cb48dd05fbcce1ab3ed684dba:/src/common/appcmn.cpp diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index 25bda2572b..9424db3196 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: common/appcmn.cpp -// Purpose: wxAppBase methods common to all platforms +// Purpose: wxAppConsole and wxAppBase methods common to all platforms // Author: Vadim Zeitlin // Modified by: // Created: 18.10.99 @@ -30,61 +30,33 @@ #ifndef WX_PRECOMP #include "wx/app.h" + #include "wx/bitmap.h" #include "wx/intl.h" #include "wx/list.h" - #if wxUSE_LOG - #include "wx/log.h" - #endif // wxUSE_LOG - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif // wxUSE_GUI + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/bitmap.h" + #include "wx/confbase.h" #endif -#include "wx/cmdline.h" +#include "wx/apptrait.h" +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP +#include "wx/msgout.h" #include "wx/thread.h" -#include "wx/confbase.h" -#include "wx/tokenzr.h" #include "wx/utils.h" -#include "wx/msgout.h" - -#if wxUSE_GUI - #include "wx/artprov.h" -#endif // wxUSE_GUI - -#if !defined(__WXMSW__) || defined(__WXMICROWIN__) - #include // for SIGTRAP used by wxTrap() -#endif //Win/Unix -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for MessageBox() -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -// private functions prototypes -#ifdef __WXDEBUG__ - static void LINKAGEMODE SetTraceMasks(); -#endif // __WXDEBUG__ - -// =========================================================================== -// implementation -// =========================================================================== +// ============================================================================ +// wxAppBase implementation +// ============================================================================ // ---------------------------------------------------------------------------- -// initialization and termination +// initialization // ---------------------------------------------------------------------------- wxAppBase::wxAppBase() { - wxTheApp = (wxApp *)this; - -#if WXWIN_COMPATIBILITY_2_2 - m_wantDebugOutput = FALSE; -#endif // WXWIN_COMPATIBILITY_2_2 - -#if wxUSE_GUI m_topWindow = (wxWindow *)NULL; m_useBestVisual = FALSE; m_isActive = TRUE; @@ -102,19 +74,68 @@ wxAppBase::wxAppBase() // safely (i.e. without losing the effect of the users SetExitOnFrameDelete // call) overwrite in OnRun() m_exitOnFrameDelete = Later; -#endif // wxUSE_GUI +} -#ifdef __WXDEBUG__ - SetTraceMasks(); +bool wxAppBase::Initialize(int& argc, wxChar **argv) +{ + if ( !wxAppConsole::Initialize(argc, argv) ) + return false; + +#if wxUSE_THREADS + wxPendingEventsLocker = new wxCriticalSection; #endif + + wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING); + wxTheColourDatabase->Initialize(); + + wxInitializeStockLists(); + wxInitializeStockObjects(); + + wxBitmap::InitStandardHandlers(); + + return true; } +// ---------------------------------------------------------------------------- +// cleanup +// ---------------------------------------------------------------------------- + wxAppBase::~wxAppBase() { // this destructor is required for Darwin } -#if wxUSE_GUI +void wxAppBase::CleanUp() +{ + // one last chance for pending objects to be cleaned up + DeletePendingObjects(); + + wxBitmap::CleanUpHandlers(); + + wxDeleteStockObjects(); + + wxDeleteStockLists(); + + delete wxTheColourDatabase; + wxTheColourDatabase = NULL; + +#if wxUSE_THREADS + delete wxPendingEvents; + wxPendingEvents = NULL; + + delete wxPendingEventsLocker; + wxPendingEventsLocker = NULL; + +#if wxUSE_VALIDATORS + // If we don't do the following, we get an apparent memory leak. + ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); +#endif // wxUSE_VALIDATORS +#endif // wxUSE_THREADS +} + +// ---------------------------------------------------------------------------- +// OnXXX() hooks +// ---------------------------------------------------------------------------- bool wxAppBase::OnInitGui() { @@ -139,103 +160,20 @@ int wxAppBase::OnRun() return MainLoop(); } -#endif // wxUSE_GUI - -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 - -#ifdef __WXUNIVERSAL__ - delete wxTheme::Set(NULL); -#endif // __WXUNIVERSAL__ - - // use Set(NULL) and not Get() to avoid creating a message output object on - // demand when we just want to delete it - delete wxMessageOutput::Set(NULL); - - return 0; -} - -// ---------------------------------------------------------------------------- -// customization hooks -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG - -wxLog *wxAppBase::CreateLogTarget() -{ -#if wxUSE_GUI && wxUSE_LOGGUI && !defined(__WXMICROWIN__) - return new wxLogGui; -#else // !GUI - return new wxLogStderr; -#endif // wxUSE_GUI -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxAppBase::CreateMessageOutput() +void wxAppBase::Exit() { - // 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 (!) - // message box under Windows and others -#if wxUSE_GUI && !defined(__UNIX__) - // wxMessageOutputMessageBox doesn't work under Motif - #ifdef __WXMOTIF__ - return new wxMessageOutputLog; - #else - return new wxMessageOutputMessageBox; - #endif -#else // !wxUSE_GUI || __UNIX__ - return new wxMessageOutputStderr; -#endif + ExitMainLoop(); } -// --------------------------------------------------------------------------- -// wxAppBase -// ---------------------------------------------------------------------------- - -void wxAppBase::ProcessPendingEvents() +wxAppTraits *wxAppBase::CreateTraits() { - // ensure that we're the only thread to modify the pending events list - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - if ( !wxPendingEvents ) - { - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - return; - } - - // iterate until the list becomes empty - wxNode *node = wxPendingEvents->GetFirst(); - while (node) - { - wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); - 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->GetFirst(); - } - - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + return new wxGUIAppTraits; } // ---------------------------------------------------------------------------- // misc // ---------------------------------------------------------------------------- -#if wxUSE_GUI - void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) { if ( active == m_isActive ) @@ -249,414 +187,187 @@ void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) (void)ProcessEvent(event); } -#endif // wxUSE_GUI - -int wxAppBase::FilterEvent(wxEvent& WXUNUSED(event)) +void wxAppBase::DeletePendingObjects() { - // process the events normally by default - return -1; -} - -// ---------------------------------------------------------------------------- -// cmd line parsing -// ---------------------------------------------------------------------------- - -bool wxAppBase::OnInit() -{ -#if wxUSE_CMDLINE_PARSER - wxCmdLineParser parser(argc, argv); - - OnInitCmdLine(parser); - - bool cont; - switch ( parser.Parse(FALSE /* don't show usage */) ) + wxNode *node = wxPendingDelete.GetFirst(); + while (node) { - case -1: - cont = OnCmdLineHelp(parser); - break; - - case 0: - cont = OnCmdLineParsed(parser); - break; + wxObject *obj = node->GetData(); - default: - cont = OnCmdLineError(parser); - break; - } + delete obj; - if ( !cont ) - return FALSE; -#endif // wxUSE_CMDLINE_PARSER + if (wxPendingDelete.Member(obj)) + delete node; - return TRUE; + // Deleting one object may have deleted other pending + // objects, so start from beginning of list again. + node = wxPendingDelete.GetFirst(); + } } -#if wxUSE_CMDLINE_PARSER - -#define OPTION_VERBOSE _T("verbose") -#define OPTION_THEME _T("theme") -#define OPTION_MODE _T("mode") - -void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) +// Returns TRUE if more time is needed. +bool wxAppBase::ProcessIdle() { - // the standard command line options - static const wxCmdLineEntryDesc cmdLineDesc[] = + wxWindowList::Node* node = wxTopLevelWindows.GetFirst(); + node = wxTopLevelWindows.GetFirst(); + while (node) { - { - 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"), - wxCMD_LINE_VAL_NONE, - 0x0 - }, -#endif // wxUSE_LOG + wxWindow* win = node->GetData(); + win->ProcessInternalIdle(); + node = node->GetNext(); + } -#ifdef __WXUNIVERSAL__ - { - wxCMD_LINE_OPTION, - _T(""), - OPTION_THEME, - gettext_noop("specify the theme to use"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXUNIVERSAL__ + wxIdleEvent event; + event.SetEventObject(this); + bool processed = ProcessEvent(event); -#if defined(__WXMGL__) - // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports - // should provide this option. That's why it is in common/appcmn.cpp - // and not mgl/app.cpp - { - wxCMD_LINE_OPTION, - _T(""), - OPTION_MODE, - gettext_noop("specify display mode to use (e.g. 640x480-16)"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXMGL__ - - // terminator - { - wxCMD_LINE_NONE, - _T(""), - _T(""), - _T(""), - wxCMD_LINE_VAL_NONE, - 0x0 - } - }; - - parser.SetDesc(cmdLineDesc); + wxUpdateUIEvent::ResetUpdateTime(); + + return processed && event.MoreRequested(); } -bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) +// Send idle event to all top-level windows +bool wxAppBase::SendIdleEvents() { -#if wxUSE_LOG - if ( parser.Found(OPTION_VERBOSE) ) - { - wxLog::SetVerbose(TRUE); - } -#endif // wxUSE_LOG + bool needMore = FALSE; -#ifdef __WXUNIVERSAL__ - wxString themeName; - if ( parser.Found(OPTION_THEME, &themeName) ) - { - wxTheme *theme = wxTheme::Create(themeName); - if ( !theme ) - { - wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); - return FALSE; - } - - // Delete the defaultly created theme and set the new theme. - delete wxTheme::Get(); - wxTheme::Set(theme); - } -#endif // __WXUNIVERSAL__ - -#if defined(__WXMGL__) - wxString modeDesc; - if ( parser.Found(OPTION_MODE, &modeDesc) ) + wxWindowList::Node* node = wxTopLevelWindows.GetFirst(); + while (node) { - unsigned w, h, bpp; - if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) - { - wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); - return FALSE; - } - - if ( !SetDisplayMode(wxDisplayModeInfo(w, h, bpp)) ) - return FALSE; + wxWindow* win = node->GetData(); + if (SendIdleEvents(win)) + needMore = TRUE; + node = node->GetNext(); } -#endif // __WXMGL__ - return TRUE; + return needMore; } -bool wxAppBase::OnCmdLineHelp(wxCmdLineParser& parser) +// Send idle event to window and all subwindows +bool wxAppBase::SendIdleEvents(wxWindow* win) { - parser.Usage(); + bool needMore = FALSE; + + if (wxIdleEvent::CanSend(win)) + { + wxIdleEvent event; + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event); - return FALSE; -} + needMore = event.MoreRequested(); + } -bool wxAppBase::OnCmdLineError(wxCmdLineParser& parser) -{ - parser.Usage(); + wxWindowList::Node *node = win->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *win = node->GetData(); + if (SendIdleEvents(win)) + needMore = TRUE; + + node = node->GetNext(); + } - return FALSE; + return needMore; } -#endif // wxUSE_CMDLINE_PARSER // ---------------------------------------------------------------------------- -// debugging support +// wxGUIAppTraitsBase // ---------------------------------------------------------------------------- -/* static */ -bool wxAppBase::CheckBuildOptions(const wxBuildOptions& opts) -{ -#define wxCMP(what) (what == opts.m_ ## what) - - bool -#ifdef __WXDEBUG__ - isDebug = TRUE; -#else - isDebug = FALSE; -#endif - - int verMaj = wxMAJOR_VERSION, - verMin = wxMINOR_VERSION; - - if ( !(wxCMP(isDebug) && wxCMP(verMaj) && wxCMP(verMin)) ) - { - wxString msg; - wxString libDebug, progDebug; - - if (isDebug) - libDebug = wxT("debug"); - else - libDebug = wxT("no debug"); - - if (opts.m_isDebug) - progDebug = wxT("debug"); - else - progDebug = wxT("no debug"); - - msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %d.%d (%s), and your program used %d.%d (%s)."), - verMaj, verMin, libDebug.c_str(), opts.m_verMaj, opts.m_verMin, progDebug.c_str()); - - wxLogFatalError(msg); - - // normally wxLogFatalError doesn't return - return FALSE; - } -#undef wxCMP - - return TRUE; -} - -#ifdef __WXDEBUG__ - -static void LINKAGEMODE SetTraceMasks() -{ #if wxUSE_LOG - wxString mask; - if ( wxGetEnv(wxT("WXTRACE"), &mask) ) - { - wxStringTokenizer tkn(mask, wxT(",")); - while ( tkn.HasMoreTokens() ) - wxLog::AddTraceMask(tkn.GetNextToken()); - } -#endif // wxUSE_LOG -} -// wxASSERT() helper -bool wxAssertIsEqual(int x, int y) +wxLog *wxGUIAppTraitsBase::CreateLogTarget() { - return x == y; + return new wxLogGui; } -// break into the debugger -void wxTrap() +#endif // wxUSE_LOG + +wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() { -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - DebugBreak(); -#elif defined(__WXMAC__) && !defined(__DARWIN__) -#if __powerc - Debugger(); -#else - SysBreak(); -#endif -#elif defined(__UNIX__) - raise(SIGTRAP); -#else - // TODO -#endif // Win/Unix + // 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 (!) + // message box under Windows and others +#ifdef __UNIX__ + return new wxMessageOutputStderr; +#else // !__UNIX__ + // wxMessageOutputMessageBox doesn't work under Motif + #ifdef __WXMOTIF__ + return new wxMessageOutputLog; + #else + return new wxMessageOutputMessageBox; + #endif +#endif // __UNIX__/!__UNIX__ } +#if wxUSE_FONTMAP -void wxAssert(int cond, - const wxChar *szFile, - int nLine, - const wxChar *szCond, - const wxChar *szMsg) +wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() { - if ( !cond ) - wxOnAssert(szFile, nLine, szCond, szMsg); + return new wxFontMapper; } - -// show the assert modal dialog -static -void ShowAssertDialog(const wxChar *szFile, - int nLine, - const wxChar *szCond, - const wxChar *szMsg) -{ - // 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 by using this format: like - // this, clicking on the message will take us immediately to the place of - // the failed assert - wxSnprintf(szBuf, WXSIZEOF(szBuf), - wxT("%s(%d): assert \"%s\" failed"), - szFile, nLine, szCond); +#endif // wxUSE_FONTMAP - if ( szMsg != NULL ) - { - wxStrcat(szBuf, wxT(": ")); - wxStrcat(szBuf, szMsg); - } - else // no message given - { - wxStrcat(szBuf, wxT(".")); - } - -#if wxUSE_THREADS - // if we are not in the main thread, - // output the assert directly and trap since dialogs cannot be displayed - if (!wxThread::IsMain()) { - wxStrcat(szBuf, wxT(" [in child thread]")); -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - wxStrcat(szBuf, wxT("\r\n")); - OutputDebugString(szBuf); -#else - // send to stderr - wxFprintf(stderr, wxT("%s\n"), szBuf); - fflush(stderr); -#endif - // He-e-e-e-elp!! we're asserting in a child thread - wxTrap(); - } -#endif // wxUSE_THREADS - - if ( !s_bNoAsserts ) - { - // send it to the normal log destination - wxLogDebug(szBuf); - -#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.")); - - // 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; - - case IDCANCEL: - s_bNoAsserts = TRUE; - break; - - //case IDNO: nothing to do - } -#else // !MSW - switch ( wxMessageBox(szBuf, wxT("Debug"), - wxYES_NO | wxCANCEL | wxICON_STOP ) ) - { - case wxYES: - wxTrap(); - break; - - case wxCANCEL: - s_bNoAsserts = TRUE; - break; - - //case wxNO: nothing to do - } -#endif // GUI or MSW - -#else // !GUI - wxTrap(); -#endif // GUI/!GUI - } -} +#ifdef __WXDEBUG__ -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, - int nLine, - const wxChar *szCond, - const wxChar *szMsg) +bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { - // FIXME MT-unsafe - static bool s_bInAssert = FALSE; - - if ( s_bInAssert ) + // 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() +#if defined(__WXMSW__) || !wxUSE_MSGDLG + return wxAppTraitsBase::ShowAssertDialog(msg); +#else // wxUSE_MSGDLG + // this message is intentionally not translated -- it is for + // developpers only + wxString msgDlg(msg); + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); + + switch ( wxMessageBox(msgDlg, wxT("wxWindows Debug Alert"), + wxYES_NO | wxCANCEL | wxICON_STOP ) ) { - // He-e-e-e-elp!! we're trapped in endless loop - wxTrap(); + case wxYES: + wxTrap(); + break; - s_bInAssert = FALSE; + case wxCANCEL: + // no more asserts + return true; - return; + //case wxNO: nothing to do } - s_bInAssert = TRUE; + return false; +#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG +} - if ( !wxTheApp ) - { - // by default, show the assert dialog box - we can't customize this - // behaviour - ShowAssertDialog(szFile, nLine, szCond, szMsg); - } - else - { - // let the app process it as it wants - wxTheApp->OnAssert(szFile, nLine, szCond, szMsg); - } +#endif // __WXDEBUG__ - s_bInAssert = FALSE; +bool wxGUIAppTraitsBase::HasStderr() +{ + // 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 } -void wxAppBase::OnAssert(const wxChar *file, - int line, - const wxChar *cond, - const wxChar *msg) +void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object) { - ShowAssertDialog(file, line, cond, msg); + if ( !wxPendingDelete.Member(object) ) + wxPendingDelete.Append(object); } -#endif //WXDEBUG +void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object) +{ + wxPendingDelete.DeleteObject(object); +}