From: Vadim Zeitlin Date: Wed, 11 Jul 2001 15:19:32 +0000 (+0000) Subject: added and documented wxApp::OnAssert X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/a5f1fd3e33d25740ad47e4755868c74a58c0f9eb?ds=sidebyside added and documented wxApp::OnAssert git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10971 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/latex/wx/app.tex b/docs/latex/wx/app.tex index 4ccfd04f3b..f662fd4048 100644 --- a/docs/latex/wx/app.tex +++ b/docs/latex/wx/app.tex @@ -189,46 +189,71 @@ to provide your own (environment-dependent) main loop. Returns 0 under X, and the wParam of the WM\_QUIT message under Windows. -\membersection{wxApp::OnActivate}\label{wxapponactivate} - -\func{void}{OnActivate}{\param{wxActivateEvent\& }{event}} - -Provide this member function to know whether the application is being -activated or deactivated (Windows only). - -\wxheading{See also} - -\helpref{wxWindow::OnActivate}{wxwindowonactivate}, \helpref{wxActivateEvent}{wxactivateevent} - -\membersection{wxApp::OnExit}\label{wxapponexit} - -\func{int}{OnExit}{\void} +%% VZ: OnXXX() functions should *not* be documented +%% +%%\membersection{wxApp::OnActivate}\label{wxapponactivate} +%% +%%\func{void}{OnActivate}{\param{wxActivateEvent\& }{event}} +%% +%%Provide this member function to know whether the application is being +%%activated or deactivated (Windows only). +%% +%%\wxheading{See also} +%% +%%\helpref{wxWindow::OnActivate}{wxwindowonactivate}, \helpref{wxActivateEvent}{wxactivateevent} +%% +%%\membersection{wxApp::OnCharHook}\label{wxapponcharhook} +%% +%%\func{void}{OnCharHook}{\param{wxKeyEvent\&}{ event}} +%% +%%This event handler function is called (under Windows only) to allow the window to intercept keyboard events +%%before they are processed by child windows. +%% +%%\wxheading{Parameters} +%% +%%\docparam{event}{The keypress event.} +%% +%%\wxheading{Remarks} +%% +%%Use the wxEVT\_CHAR\_HOOK macro in your event table. +%% +%%If you use this member, you can selectively consume keypress events by calling\rtfsp +%%\helpref{wxEvent::Skip}{wxeventskip} for characters the application is not interested in. +%% +%%\wxheading{See also} +%% +%%\helpref{wxKeyEvent}{wxkeyevent}, \helpref{wxWindow::OnChar}{wxwindowonchar},\rtfsp +%%\helpref{wxWindow::OnCharHook}{wxwindowoncharhook}, \helpref{wxDialog::OnCharHook}{wxdialogoncharhook} -Provide this member function for any processing which needs to be done as -the application is about to exit. +\membersection{wxApp::OnAssert}\label{wxapponassert} -\membersection{wxApp::OnCharHook}\label{wxapponcharhook} +\func{void}{OnAssert}{\param{const wxChar }{*file}, \param{int }{line}, \param{const wxChar }{*msg}} -\func{void}{OnCharHook}{\param{wxKeyEvent\&}{ event}} +This function is called when an assert failure occurs, i.e. the condition +specified in \helpref{wxASSERT}{wxassert} macro evaluated to {\tt FALSE}. +It is only called in debug mode (when {\tt \_\_WXDEBUG\_\_| is defined) as +asserts are not left in the release code at all. -This event handler function is called (under Windows only) to allow the window to intercept keyboard events -before they are processed by child windows. +The base class version show the default assert failure dialog box proposing to +the user to stop the program, continue or ignore all subsequent asserts. \wxheading{Parameters} -\docparam{event}{The keypress event.} +\docparam{file}{the name of the source file where the assert occured} -\wxheading{Remarks} +\docparam{line}{the line number in this file where the assert occured} -Use the wxEVT\_CHAR\_HOOK macro in your event table. +\docparam{msg}{the message specified as argument to +\helpref{wxASSERT\_MSG}{wxassertmsg} or \helpref{wxFAIL\_MSG}{wxfailmsg}, will +be {\tt NULL} if just \helpref{wxASSERT}{wxassert} or \helpref{wxFAIL}{wxfail} +was used} -If you use this member, you can selectively consume keypress events by calling\rtfsp -\helpref{wxEvent::Skip}{wxeventskip} for characters the application is not interested in. +\membersection{wxApp::OnExit}\label{wxapponexit} -\wxheading{See also} +\func{int}{OnExit}{\void} -\helpref{wxKeyEvent}{wxkeyevent}, \helpref{wxWindow::OnChar}{wxwindowonchar},\rtfsp -\helpref{wxWindow::OnCharHook}{wxwindowoncharhook}, \helpref{wxDialog::OnCharHook}{wxdialogoncharhook} +Provide this member function for any processing which needs to be done as +the application is about to exit. \membersection{wxApp::OnCmdLineError}\label{wxapponcmdlineerror} diff --git a/include/wx/app.h b/include/wx/app.h index b6db5db471..e052dedb4c 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -263,6 +263,16 @@ public: virtual void SetActive(bool isActive, wxWindow *lastFocus); #endif // wxUSE_GUI + // debugging support + // ----------------- + + // this function is called when an assert failure occurs, the base class + // version does the normal processing (i.e. shows the usual assert failure + // dialog box) +#ifdef __WXDEBUG__ + virtual void OnAssert(const wxChar *file, int line, const wxChar *msg); +#endif // __WXDEBUG__ + // implementation only from now on // ------------------------------- diff --git a/include/wx/debug.h b/include/wx/debug.h index 82785eca9b..9010e74c63 100644 --- a/include/wx/debug.h +++ b/include/wx/debug.h @@ -41,6 +41,8 @@ WXDLLEXPORT_DATA(extern const bool) wxTrue; WXDLLEXPORT_DATA(extern const bool) wxFalse; // Macros which are completely disabled in 'release' mode +// +// NB: these functions are implemented in src/common/appcmn.cpp #ifdef __WXDEBUG__ /* this function may be redefined to do something non trivial and is called diff --git a/include/wx/gtk/app.h b/include/wx/gtk/app.h index 9f25e61545..6014589623 100644 --- a/include/wx/gtk/app.h +++ b/include/wx/gtk/app.h @@ -61,9 +61,11 @@ public: bool ProcessIdle(); void DeletePendingObjects(); - // This can be used to suppress the generation of Idle events. - void SuppressIdleEvents(bool arg = TRUE) { m_suppressIdleEvents = arg; } - bool GetSuppressIdleEvents() const { return m_suppressIdleEvents; } +#ifdef __WXDEBUG__ + virtual void OnAssert(const wxChar *file, int line, const wxChar *msg); + + bool IsInAssert() const { return m_isInAssert; } +#endif // __WXDEBUG__ bool m_initialized; @@ -74,10 +76,11 @@ public: unsigned char *m_colorCube; private: - // Set to TRUE while we are in wxYield(). - bool m_suppressIdleEvents; + // true if we're inside an assert modal dialog +#ifdef __WXDEBUG__ + bool m_isInAssert; +#endif // __WXDEBUG__ -private: DECLARE_DYNAMIC_CLASS(wxApp) DECLARE_EVENT_TABLE() }; diff --git a/include/wx/gtk1/app.h b/include/wx/gtk1/app.h index 9f25e61545..6014589623 100644 --- a/include/wx/gtk1/app.h +++ b/include/wx/gtk1/app.h @@ -61,9 +61,11 @@ public: bool ProcessIdle(); void DeletePendingObjects(); - // This can be used to suppress the generation of Idle events. - void SuppressIdleEvents(bool arg = TRUE) { m_suppressIdleEvents = arg; } - bool GetSuppressIdleEvents() const { return m_suppressIdleEvents; } +#ifdef __WXDEBUG__ + virtual void OnAssert(const wxChar *file, int line, const wxChar *msg); + + bool IsInAssert() const { return m_isInAssert; } +#endif // __WXDEBUG__ bool m_initialized; @@ -74,10 +76,11 @@ public: unsigned char *m_colorCube; private: - // Set to TRUE while we are in wxYield(). - bool m_suppressIdleEvents; + // true if we're inside an assert modal dialog +#ifdef __WXDEBUG__ + bool m_isInAssert; +#endif // __WXDEBUG__ -private: DECLARE_DYNAMIC_CLASS(wxApp) DECLARE_EVENT_TABLE() }; diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index 63cfeb9c77..3de3b7cd2b 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -32,12 +32,23 @@ #include "wx/app.h" #include "wx/intl.h" #include "wx/list.h" + #if wxUSE_GUI + #include "wx/msgdlg.h" + #endif // wxUSE_GUI #endif #include "wx/cmdline.h" #include "wx/thread.h" #include "wx/confbase.h" +#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 + // =========================================================================== // implementation // =========================================================================== @@ -258,3 +269,149 @@ bool wxAppBase::OnCmdLineError(wxCmdLineParser& parser) #endif // wxUSE_CMDLINE_PARSER +// ---------------------------------------------------------------------------- +// debugging support +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +// wxASSERT() helper +bool wxAssertIsEqual(int x, int y) +{ + return x == y; +} + +// break into the debugger +void wxTrap() +{ +#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 +} + +// show the assert modal dialog +static +void ShowAssertDialog(const wxChar *szFile, int nLine, const wxChar *szMsg) +{ + // this variable can be set to true to suppress "assert failure" messages + static bool s_bNoAsserts = FALSE; + static bool s_bInAssert = FALSE; // FIXME MT-unsafe + + if ( s_bInAssert ) + { + // He-e-e-e-elp!! we're trapped in endless loop + wxTrap(); + + s_bInAssert = FALSE; + + return; + } + + s_bInAssert = TRUE; + + 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 + { + wxStrcat(szBuf, wxT(".")); + } + + 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 + } + + s_bInAssert = FALSE; +} + +// this function is called when an assert fails +void wxOnAssert(const wxChar *szFile, int nLine, const wxChar *szMsg) +{ + 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); + } +} + +void wxAppBase::OnAssert(const wxChar *file, int line, const wxChar *msg) +{ + ShowAssertDialog(file, line, msg); +} + +#endif //WXDEBUG + diff --git a/src/common/log.cpp b/src/common/log.cpp index ebf14bf02c..1ec1077722 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -39,7 +39,6 @@ #ifdef __WXMSW__ #include "wx/msw/private.h" #endif - #include "wx/msgdlg.h" #endif #endif //WX_PRECOMP @@ -61,10 +60,6 @@ #include "wx/msw/private.h" // includes windows.h for OutputDebugString #endif -#if !defined(__WXMSW__) || defined(__WXMICROWIN__) - #include -#endif //Win/Unix - // ---------------------------------------------------------------------------- // non member functions // ---------------------------------------------------------------------------- @@ -748,122 +743,4 @@ const wxChar *wxSysErrorMsg(unsigned long nErrCode) #endif // Win/Unix } -// ---------------------------------------------------------------------------- -// debug helper -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -// wxASSERT() helper -bool wxAssertIsEqual(int x, int y) -{ - return x == y; -} - -// break into the debugger -void wxTrap() -{ -#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 -} - -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, int nLine, const wxChar *szMsg) -{ - // this variable can be set to true to suppress "assert failure" messages - static bool s_bNoAsserts = FALSE; - static bool s_bInAssert = FALSE; // FIXME MT-unsafe - - if ( s_bInAssert ) { - // He-e-e-e-elp!! we're trapped in endless loop - wxTrap(); - - s_bInAssert = FALSE; - - return; - } - - s_bInAssert = TRUE; - - wxChar szBuf[LOG_BUFFER_SIZE]; - - // 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 { - wxStrcat(szBuf, wxT(".")); - } - - 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 - } - - s_bInAssert = FALSE; -} - -#endif //WXDEBUG - #endif //wxUSE_LOG diff --git a/src/gtk/app.cpp b/src/gtk/app.cpp index e2bdb2f344..bb01f6b872 100644 --- a/src/gtk/app.cpp +++ b/src/gtk/app.cpp @@ -194,7 +194,18 @@ gint wxapp_pending_callback( gpointer WXUNUSED(data) ) gint wxapp_idle_callback( gpointer WXUNUSED(data) ) { - if (!wxTheApp) return TRUE; + if (!wxTheApp) + return TRUE; + +#ifdef __WXDEBUG__ + if ( wxTheApp->IsInAssert() ) + { + // don't generate the idle events while the assert modal dialog is + // shown, this completely confuses the apps which don't expect to be + // reentered from some safely-looking functions + return FALSE; + } +#endif // __WXDEBUG__ // when getting called from GDK's time-out handler // we are no longer within GDK's grab on the GUI @@ -309,6 +320,11 @@ END_EVENT_TABLE() wxApp::wxApp() { + m_initialized = FALSE; +#ifdef __WXDEBUG__ + m_isInAssert = FALSE; +#endif // __WXDEBUG__ + m_idleTag = 0; wxapp_install_idle_handler(); @@ -850,3 +866,17 @@ wxApp::GetStdIcon(int which) const return wxIcon(error_xpm); } } + +#ifdef __WXDEBUG__ + +void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg) +{ + m_isInAssert = TRUE; + + wxAppBase::OnAssert(file, line, msg); + + m_isInAssert = FALSE; +} + +#endif // __WXDEBUG__ + diff --git a/src/gtk1/app.cpp b/src/gtk1/app.cpp index e2bdb2f344..bb01f6b872 100644 --- a/src/gtk1/app.cpp +++ b/src/gtk1/app.cpp @@ -194,7 +194,18 @@ gint wxapp_pending_callback( gpointer WXUNUSED(data) ) gint wxapp_idle_callback( gpointer WXUNUSED(data) ) { - if (!wxTheApp) return TRUE; + if (!wxTheApp) + return TRUE; + +#ifdef __WXDEBUG__ + if ( wxTheApp->IsInAssert() ) + { + // don't generate the idle events while the assert modal dialog is + // shown, this completely confuses the apps which don't expect to be + // reentered from some safely-looking functions + return FALSE; + } +#endif // __WXDEBUG__ // when getting called from GDK's time-out handler // we are no longer within GDK's grab on the GUI @@ -309,6 +320,11 @@ END_EVENT_TABLE() wxApp::wxApp() { + m_initialized = FALSE; +#ifdef __WXDEBUG__ + m_isInAssert = FALSE; +#endif // __WXDEBUG__ + m_idleTag = 0; wxapp_install_idle_handler(); @@ -850,3 +866,17 @@ wxApp::GetStdIcon(int which) const return wxIcon(error_xpm); } } + +#ifdef __WXDEBUG__ + +void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg) +{ + m_isInAssert = TRUE; + + wxAppBase::OnAssert(file, line, msg); + + m_isInAssert = FALSE; +} + +#endif // __WXDEBUG__ +