From db9febdf4171fdb57434e080f77dca8a02be1cca Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Fri, 24 Nov 2006 10:55:26 +0000 Subject: [PATCH] Actually use new GTK+ native assert dialog. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@43628 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/apptrait.h | 10 ++- include/wx/unix/apptrait.h | 5 +- src/common/appbase.cpp | 151 ++++++++++++++++++++----------------- src/common/appcmn.cpp | 22 +++++- src/gtk/utilsgtk.cpp | 113 +++++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 76 deletions(-) diff --git a/include/wx/apptrait.h b/include/wx/apptrait.h index 3595571c28..1513596cc7 100644 --- a/include/wx/apptrait.h +++ b/include/wx/apptrait.h @@ -118,10 +118,16 @@ public: // return true if the port is using wxUniversal for the GUI, false if not virtual bool IsUsingUniversalWidgets() const = 0; - - // return the name of the Desktop Environment such as + + // return the name of the Desktop Environment such as // "KDE" or "GNOME". May return an empty string. virtual wxString GetDesktopEnvironment() const { return wxEmptyString; } + +protected: +#if wxUSE_STACKWALKER && defined( __WXDEBUG__ ) + // utility function: returns the stack frame as a plain wxString + virtual wxString GetAssertStackTrace(); +#endif }; // ---------------------------------------------------------------------------- diff --git a/include/wx/unix/apptrait.h b/include/wx/unix/apptrait.h index d84e63e67c..b3166e62c3 100644 --- a/include/wx/unix/apptrait.h +++ b/include/wx/unix/apptrait.h @@ -39,9 +39,12 @@ public: virtual wxStandardPathsBase& GetStandardPaths(); #endif virtual wxPortId GetToolkitVersion(int *majVer, int *minVer) const; - + #ifdef __WXGTK__ virtual wxString GetDesktopEnvironment() const; +#ifdef __WXDEBUG__ + virtual bool ShowAssertDialog(const wxString& msg); +#endif #endif }; diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 6f2bbbe5a4..86f141ce63 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -535,11 +535,90 @@ GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() #ifdef __WXDEBUG__ -bool wxAppTraitsBase::ShowAssertDialog(const wxString& msg) +bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) { + wxString msg = msgOriginal; + +#if wxUSE_STACKWALKER +#if !defined(__WXMSW__) + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); +#endif + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + return DoShowAssertDialog(msg); } +#if wxUSE_STACKWALKER +wxString wxAppTraitsBase::GetAssertStackTrace() +{ + wxString stackTrace; + + class StackDump : public wxStackWalker + { + public: + StackDump() { } + + const wxString& GetStackTrace() const { return m_stackTrace; } + + protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + m_stackTrace << wxString::Format + ( + _T("[%02d] "), + wx_truncate_cast(int, frame.GetLevel()) + ); + + wxString name = frame.GetName(); + if ( !name.empty() ) + { + m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); + } + else + { + m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); + } + + if ( frame.HasSourceLocation() ) + { + m_stackTrace << _T('\t') + << frame.GetFileName() + << _T(':') + << frame.GetLine(); + } + + m_stackTrace << _T('\n'); + } + + private: + wxString m_stackTrace; + }; + + // don't show more than maxLines or we could get a dialog too tall to be + // shown on screen: 20 should be ok everywhere as even with 15 pixel high + // characters it is still only 300 pixels... + static const int maxLines = 20; + + StackDump dump; + dump.Walk(2, maxLines); // don't show OnAssert() call itself + stackTrace = dump.GetStackTrace(); + + const int count = stackTrace.Freq(wxT('\n')); + for ( int i = 0; i < count - maxLines; i++ ) + stackTrace = stackTrace.BeforeLast(wxT('\n')); + + return stackTrace; +} +#endif // wxUSE_STACKWALKER + + #endif // __WXDEBUG__ // ============================================================================ @@ -694,68 +773,6 @@ bool DoShowAssertDialog(const wxString& msg) return false; } -#if wxUSE_STACKWALKER -static wxString GetAssertStackTrace() -{ - wxString stackTrace; - - class StackDump : public wxStackWalker - { - public: - StackDump() { } - - const wxString& GetStackTrace() const { return m_stackTrace; } - - protected: - virtual void OnStackFrame(const wxStackFrame& frame) - { - m_stackTrace << wxString::Format - ( - _T("[%02d] "), - wx_truncate_cast(int, frame.GetLevel()) - ); - - wxString name = frame.GetName(); - if ( !name.empty() ) - { - m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); - } - else - { - m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); - } - - if ( frame.HasSourceLocation() ) - { - m_stackTrace << _T('\t') - << frame.GetFileName() - << _T(':') - << frame.GetLine(); - } - - m_stackTrace << _T('\n'); - } - - private: - wxString m_stackTrace; - }; - - StackDump dump; - dump.Walk(2); // don't show OnAssert() call itself - stackTrace = dump.GetStackTrace(); - - // don't show more than maxLines or we could get a dialog too tall to be - // shown on screen: 20 should be ok everywhere as even with 15 pixel high - // characters it is still only 300 pixels... - static const int maxLines = 20; - const int count = stackTrace.Freq(wxT('\n')); - for ( int i = 0; i < count - maxLines; i++ ) - stackTrace = stackTrace.BeforeLast(wxT('\n')); - - return stackTrace; -} -#endif // wxUSE_STACKWALKER - // show the assert modal dialog static void ShowAssertDialog(const wxChar *szFile, @@ -790,14 +807,6 @@ void ShowAssertDialog(const wxChar *szFile, msg << _T('.'); } -#if wxUSE_STACKWALKER - const wxString stackTrace = GetAssertStackTrace(); - if ( !stackTrace.empty() ) - { - msg << _T("\n\nCall stack:\n") << stackTrace; - } -#endif // wxUSE_STACKWALKER - #if wxUSE_THREADS // if we are not in the main thread, output the assert directly and trap // since dialogs cannot be displayed diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index ad67fbd657..e6a72a3d27 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -42,6 +42,12 @@ #include "wx/vidmode.h" #include "wx/ptr_scpd.h" +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/stackwalk.h" + #endif // wxUSE_STACKWALKER +#endif // __WXDEBUG__ + #if defined(__WXMSW__) #include "wx/msw/private.h" // includes windows.h for LOGFONT #endif @@ -565,15 +571,27 @@ wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { +#if defined(__WXMSW__) || !wxUSE_MSGDLG // 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 + wxString msgDlg = msg; + +#if wxUSE_STACKWALKER + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msgDlg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + // 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."); diff --git a/src/gtk/utilsgtk.cpp b/src/gtk/utilsgtk.cpp index 1144d39c3a..8dedb3d263 100644 --- a/src/gtk/utilsgtk.cpp +++ b/src/gtk/utilsgtk.cpp @@ -24,6 +24,13 @@ #include "wx/unix/execute.h" +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/gtk/assertdlg_gtk.h" + #include "wx/stackwalk.h" + #endif // wxUSE_STACKWALKER +#endif // __WXDEBUG__ + #include #include #include @@ -328,6 +335,112 @@ static wxString GetSM() } #endif // wxUSE_DETECT_SM + +//----------------------------------------------------------------------------- +// wxGUIAppTraits +//----------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +#if wxUSE_STACKWALKER + +// private helper class +class StackDump : public wxStackWalker +{ +public: + StackDump(GtkAssertDialog *dlg) { m_dlg=dlg; } + +protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + wxString fncname = frame.GetName(); + wxString fncargs = fncname; + + size_t n = fncname.find(wxT('(')); + if (n != wxString::npos) + { + // remove arguments from function name + fncname.erase(n); + + // remove function name and brackets from arguments + fncargs = fncargs.substr(n+1, fncargs.length()-n-2); + } + else + fncargs = wxEmptyString; + + // append this stack frame's info in the dialog + if (!frame.GetFileName().empty() || !fncname.empty()) + gtk_assert_dialog_append_stack_frame(m_dlg, + fncname.mb_str(), + fncargs.mb_str(), + frame.GetFileName().mb_str(), + frame.GetLine()); + } + +private: + GtkAssertDialog *m_dlg; +}; + +// the callback functions must be extern "C" to comply with GTK+ declarations +extern "C" +{ + void get_stackframe_callback(StackDump *dump) + { + dump->ProcessFrames(2); // don't show ShowAssertDialog() call itself + } +} + +#endif // wxUSE_STACKWALKER + +bool wxGUIAppTraits::ShowAssertDialog(const wxString& msg) +{ + // under GTK2 we prefer to use a dialog widget written using directly GTK+; + // in fact we cannot use a dialog written using wxWidgets: it would need + // the wxWidgets idle processing to work correctly! + GtkWidget *dialog = gtk_assert_dialog_new(); + gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog), msg.mb_str()); + +#if wxUSE_STACKWALKER + // don't show more than maxLines or we could get a dialog too tall to be + // shown on screen: 20 should be ok everywhere as even with 15 pixel high + // characters it is still only 300 pixels... + static const int maxLines = 20; + + // save current stack frame... + StackDump dump(GTK_ASSERT_DIALOG(dialog)); + dump.SaveStack(maxLines); + + // ...but process it only if the user needs it + gtk_assert_dialog_set_backtrace_callback(GTK_ASSERT_DIALOG(dialog), + (GtkAssertDialogStackFrameCallback)get_stackframe_callback, + &dump); +#endif // wxUSE_STACKWALKER + + gint result = gtk_dialog_run(GTK_DIALOG (dialog)); + bool returnCode = false; + switch (result) + { + case GTK_ASSERT_DIALOG_STOP: + wxTrap(); + break; + case GTK_ASSERT_DIALOG_CONTINUE: + // nothing to do + break; + case GTK_ASSERT_DIALOG_CONTINUE_SUPPRESSING: + // no more asserts + returnCode = true; + break; + + default: + wxFAIL_MSG( _T("unexpected return code from GtkAssertDialog") ); + } + + gtk_widget_destroy(dialog); + return returnCode; +} + +#endif // __WXDEBUG__ + wxString wxGUIAppTraits::GetDesktopEnvironment() const { #if wxUSE_DETECT_SM -- 2.45.2