From a5f1fd3e33d25740ad47e4755868c74a58c0f9eb Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Wed, 11 Jul 2001 15:19:32 +0000
Subject: [PATCH] added and documented wxApp::OnAssert

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10971 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/app.tex |  81 ++++++++++++++--------
 include/wx/app.h      |  10 +++
 include/wx/debug.h    |   2 +
 include/wx/gtk/app.h  |  15 ++--
 include/wx/gtk1/app.h |  15 ++--
 src/common/appcmn.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++
 src/common/log.cpp    | 123 ---------------------------------
 src/gtk/app.cpp       |  32 ++++++++-
 src/gtk1/app.cpp      |  32 ++++++++-
 9 files changed, 302 insertions(+), 165 deletions(-)

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  <signal.h>      // 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  <signal.h>
-#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__
+
-- 
2.50.0

