#include "wx/utils.h"
#include "wx/msgdlg.h"
#include "wx/icon.h"
+
+ #include "wx/thread.h"
#endif
// ----------------------------------------------------------------------------
// catch exceptions which occur in MyFrame methods here
virtual bool ProcessEvent(wxEvent& event);
- // show how an assert failure message box looks like
+ // provoke assert in main or worker thread
+ //
+ // this is used to show how an assert failure message box looks like
void OnShowAssert(wxCommandEvent& event);
+#if wxUSE_THREADS
+ void OnShowAssertInThread(wxCommandEvent& event);
+#endif // wxUSE_THREADS
private:
// any class wishing to process wxWidgets events must use this macro
Except_HandleCrash,
#endif // wxUSE_ON_FATAL_EXCEPTION
Except_ShowAssert,
+#if wxUSE_THREADS
+ Except_ShowAssertInThread,
+#endif // wxUSE_THREADS
Except_Dialog,
Except_Quit = wxID_EXIT,
EVT_MENU(Except_HandleCrash, MyFrame::OnHandleCrash)
#endif // wxUSE_ON_FATAL_EXCEPTION
EVT_MENU(Except_ShowAssert, MyFrame::OnShowAssert)
+#if wxUSE_THREADS
+ EVT_MENU(Except_ShowAssertInThread, MyFrame::OnShowAssertInThread)
+#endif // wxUSE_THREADS
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(MyDialog, wxDialog)
const wxChar *cond,
const wxChar *msg)
{
- if ( wxMessageBox
- (
- wxString::Format("An assert failed in %s().", func) +
- "\n"
- "Do you want to call the default assert handler?",
- "wxExcept Sample",
- wxYES_NO | wxICON_QUESTION
- ) == wxYES )
+ // take care to not show the message box from a worker thread, this doesn't
+ // work as it doesn't have any event loop
+ if ( !wxIsMainThread() ||
+ wxMessageBox
+ (
+ wxString::Format("An assert failed in %s().", func) +
+ "\n"
+ "Do you want to call the default assert handler?",
+ "wxExcept Sample",
+ wxYES_NO | wxICON_QUESTION
+ ) == wxYES )
{
wxApp::OnAssertFailure(file, line, func, cond, msg);
}
menuFile->AppendSeparator();
#endif // wxUSE_ON_FATAL_EXCEPTION
menuFile->Append(Except_ShowAssert, wxT("Provoke &assert failure\tCtrl-A"));
+#if wxUSE_THREADS
+ menuFile->Append(Except_ShowAssertInThread,
+ wxT("Assert failure in &thread\tShift-Ctrl-A"));
+#endif // wxUSE_THREADS
menuFile->AppendSeparator();
menuFile->Append(Except_Quit, wxT("E&xit\tCtrl-Q"), wxT("Quit this program"));
arr[0];
}
+#if wxUSE_THREADS
+
+void MyFrame::OnShowAssertInThread(wxCommandEvent& WXUNUSED(event))
+{
+ class AssertThread : public wxThread
+ {
+ public:
+ AssertThread()
+ : wxThread(wxTHREAD_JOINABLE)
+ {
+ }
+
+ protected:
+ virtual void *Entry()
+ {
+ wxFAIL_MSG("Test assert in another thread.");
+
+ return 0;
+ }
+ };
+
+ AssertThread thread;
+ thread.Create();
+ thread.Run();
+ thread.Wait();
+}
+
+#endif // wxUSE_THREADS
+
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
wxString msg;
//case IDNO: nothing to do
}
#else // !__WXMSW__
- wxFprintf(stderr, wxT("%s\n"), msg.c_str());
- fflush(stderr);
+ wxMessageOutputDebug().Output(msg);
- // TODO: ask the user to enter "Y" or "N" on the console?
- wxTrap();
+ // TODO: ask the user whether to trap on the console?
#endif // __WXMSW__/!__WXMSW__
// continue with the asserts
// since dialogs cannot be displayed
if ( !wxThread::IsMain() )
{
- msg += wxT(" [in child thread]");
-
-#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
- msg << wxT("\r\n");
- OutputDebugString(msg.wx_str());
-#else
- // send to stderr
- wxFprintf(stderr, wxT("%s\n"), msg.c_str());
- fflush(stderr);
-#endif
- // He-e-e-e-elp!! we're asserting in a child thread
- wxTrap();
+ msg += wxString::Format(" [in thread %lx]", wxThread::GetCurrentId());
}
- else
#endif // wxUSE_THREADS
+ // log the assert in any case
+ wxMessageOutputDebug().Output(msg);
+
if ( !s_bNoAsserts )
{
- // send it to the normal log destination
- wxLogDebug(wxT("%s"), msg.c_str());
-
if ( traits )
{
// delegate showing assert dialog (if possible) to that class
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()
//
// and finally we can't use wxMessageBox() if it wasn't compiled in, of
// course
-#if defined(__WXMSW__) || defined(__WXDFB__) || !wxUSE_MSGDLG
- return wxAppTraitsBase::ShowAssertDialog(msg);
-#else // wxUSE_MSGDLG
-#if wxDEBUG_LEVEL
- wxString msgDlg = msg;
+#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() )
+ {
+ 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 << wxT("\n\nCall stack:\n") << stackTrace;
+ // 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 << wxT("\n\nCall stack:\n") << stackTrace;
#endif // wxUSE_STACKWALKER
- // 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.");
+ // 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.");
- switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"),
- wxYES_NO | wxCANCEL | wxICON_STOP ) )
- {
- case wxYES:
- wxTrap();
- break;
+ switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"),
+ wxYES_NO | wxCANCEL | wxICON_STOP ) )
+ {
+ case wxYES:
+ wxTrap();
+ break;
+
+ case wxCANCEL:
+ // no more asserts
+ return true;
- case wxCANCEL:
- // no more asserts
- return true;
+ //case wxNO: nothing to do
+ }
- //case wxNO: nothing to do
+ return false;
}
-#else // !wxDEBUG_LEVEL
- // this function always exists (for ABI compatibility) but is never called
- // if debug level is 0 and so can simply do nothing then
- wxUnusedVar(msg);
-#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
+#endif // wxUSE_MSGDLG
+#endif // wxDEBUG_LEVEL
- return false;
-#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG
+ return wxAppTraitsBase::ShowAssertDialog(msg);
}
bool wxGUIAppTraitsBase::HasStderr()
bool wxGUIAppTraits::ShowAssertDialog(const wxString& msg)
{
#if wxDEBUG_LEVEL
- // under GTK2 we prefer to use a dialog widget written using directly in
- // GTK+ as use a dialog written using wxWidgets would need the wxWidgets
- // idle processing to work correctly which might not be the case when
- // assert happens
- GtkWidget *dialog = gtk_assert_dialog_new();
- gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog), msg.mb_str());
+ // we can't show the dialog from another thread
+ if ( wxIsMainThread() )
+ {
+ // under GTK2 we prefer to use a dialog widget written using directly
+ // in GTK+ as use a dialog written using wxWidgets would need the
+ // wxWidgets idle processing to work correctly which might not be the
+ // case when assert happens
+ 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( wxT("unexpected return code from GtkAssertDialog") );
+ // 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( wxT("unexpected return code from GtkAssertDialog") );
+ }
+
+ gtk_widget_destroy(dialog);
+ return returnCode;
}
+#endif // wxDEBUG_LEVEL
- gtk_widget_destroy(dialog);
- return returnCode;
-#else // !wxDEBUG_LEVEL
- // this function is never called in this case
- wxUnusedVar(msg);
- return false;
-#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
+ return wxAppTraitsBase::ShowAssertDialog(msg);
}
wxString wxGUIAppTraits::GetDesktopEnvironment() const