Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/wx/evtloop.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
int m_exitcode;

private:
void Loop();

// process all already pending events and dispatch a new one (blocking
// until it appears in the event queue if necessary)
//
Expand Down
9 changes: 9 additions & 0 deletions interface/wx/sysopt.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
this option allows changing it without modifying the program code and
also applies to asserts which may happen before the wxApp object
creation or after its destruction.
@flag{catch-unhandled-exceptions}
If set to zero, wxWidgets will not catch unhandled exceptions, but
rather lets the default behavior of aborting the program take place.
Not catching unhandled exceptions makes debugging easier, as the
backtrace is more likely to show what actually happened, and where.
The same applies to any crash dumps generated due to unhandled exceptions.
By default unhandled exceptions are eventually caught by wxWidgets.
This flag should be set very early during program startup, within
the constructor of the wxApp derivative.
@endFlagTable

@section sysopt_win Windows
Expand Down
5 changes: 5 additions & 0 deletions src/common/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "wx/event.h"
#include "wx/eventfilter.h"
#include "wx/evtloop.h"
#include "wx/sysopt.h"

#ifndef WX_PRECOMP
#include "wx/list.h"
Expand Down Expand Up @@ -1666,6 +1667,10 @@ bool wxEvtHandler::TryHereOnly(wxEvent& event)

bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
{
if ( wxSystemOptions::IsFalse("catch-unhandled-exceptions") )
{
return ProcessEvent(event);
}
#if wxUSE_EXCEPTIONS
try
{
Expand Down
183 changes: 97 additions & 86 deletions src/common/evtloopcmn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "wx/scopeguard.h"
#include "wx/apptrait.h"
#include "wx/sysopt.h"
#include "wx/private/eventloopsourcesmanager.h"

// Counts currently existing event loops.
Expand Down Expand Up @@ -243,6 +244,96 @@ bool wxEventLoopManual::ProcessEvents()
return res;
}

void wxEventLoopManual::Loop()
{
// this is the event loop itself
for ( ;; )
{
// give them the possibility to do whatever they want
OnNextIteration();

// generate and process idle events for as long as we don't
// have anything else to do, but stop doing this if Exit() is
// called by one of the idle handlers
//
// note that Pending() only checks for pending events from the
// underlying toolkit, but not our own pending events added by
// QueueEvent(), so we need to call HasPendingEvents() to check
// for them too
while (!m_shouldExit
&& !Pending()
&& !(wxTheApp && wxTheApp->HasPendingEvents())
&& ProcessIdle())
;

// if Exit() was called, don't dispatch any more events here
if ( m_shouldExit )
break;

// a message came or no more idle processing to do, dispatch
// all the pending events and call Dispatch() to wait for the
// next message
if ( !ProcessEvents() || m_shouldExit )
break;
}

// Process any still pending events.
for ( ;; )
{
bool hasMoreEvents = false;

// We always dispatch events pending at wx level: it may be
// important to do it before the loop exits and e.g. the modal
// dialog possibly referenced by these events handlers is
// destroyed. It also shouldn't result in the problems
// described below for the native events and while there is
// still a risk of never existing the loop due to an endless
// stream of events generated from the user-defined event
// handlers, we consider that well-behaved programs shouldn't
// do this -- and if they do, it's better to keep running the
// loop than crashing after leaving it.
if ( wxTheApp && wxTheApp->HasPendingEvents() )
{
wxTheApp->ProcessPendingEvents();
hasMoreEvents = true;
}

// For the underlying toolkit events, we only handle them when
// exiting the outermost event loop but not when exiting nested
// loops. This is required at least under MSW where, in case of
// a nested modal event loop, the modality has already been
// undone as Exit() had been already called, so all UI elements
// are re-enabled and if we dispatched events from them here,
// we could end up reentering the same event handler that had
// shown the modal dialog in the first place and showing the
// dialog second time before its first instance was destroyed,
// resulting in a lot of fun.
//
// Also, unlike wx events above, it should be fine to dispatch
// the native events from the outer event loop, as any events
// generated from outside the dialog itself (necessarily, as
// the dialog is already hidden and about to be destroyed)
// shouldn't reference the dialog. Which is one of the reasons
// we still dispatch them in the outermost event loop, to
// ensure they're still processed. Another reason is that if we
// do have an endless stream of native events, e.g. because we
// have a timer with a too short interval, it's arguably better
// to keep handling them instead of exiting.
if ( gs_eventLoopCount == 1 )
{
if ( Pending() )
{
Dispatch();
hasMoreEvents = true;
}
}

if ( !hasMoreEvents )
break;
}

}

int wxEventLoopManual::DoRun()
{

Expand All @@ -252,97 +343,17 @@ int wxEventLoopManual::DoRun()
// wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or
// something similar here)
#if wxUSE_EXCEPTIONS
if ( wxSystemOptions::IsFalse("catch-unhandled-exceptions") )
{
Loop();
return m_exitcode;
}
for ( ;; )
{
try
{
#endif // wxUSE_EXCEPTIONS

// this is the event loop itself
for ( ;; )
{
// give them the possibility to do whatever they want
OnNextIteration();

// generate and process idle events for as long as we don't
// have anything else to do, but stop doing this if Exit() is
// called by one of the idle handlers
//
// note that Pending() only checks for pending events from the
// underlying toolkit, but not our own pending events added by
// QueueEvent(), so we need to call HasPendingEvents() to check
// for them too
while ( !m_shouldExit
&& !Pending()
&& !(wxTheApp && wxTheApp->HasPendingEvents())
&& ProcessIdle() )
;

// if Exit() was called, don't dispatch any more events here
if ( m_shouldExit )
break;

// a message came or no more idle processing to do, dispatch
// all the pending events and call Dispatch() to wait for the
// next message
if ( !ProcessEvents() || m_shouldExit )
break;
}

// Process any still pending events.
for ( ;; )
{
bool hasMoreEvents = false;

// We always dispatch events pending at wx level: it may be
// important to do it before the loop exits and e.g. the modal
// dialog possibly referenced by these events handlers is
// destroyed. It also shouldn't result in the problems
// described below for the native events and while there is
// still a risk of never existing the loop due to an endless
// stream of events generated from the user-defined event
// handlers, we consider that well-behaved programs shouldn't
// do this -- and if they do, it's better to keep running the
// loop than crashing after leaving it.
if ( wxTheApp && wxTheApp->HasPendingEvents() )
{
wxTheApp->ProcessPendingEvents();
hasMoreEvents = true;
}

// For the underlying toolkit events, we only handle them when
// exiting the outermost event loop but not when exiting nested
// loops. This is required at least under MSW where, in case of
// a nested modal event loop, the modality has already been
// undone as Exit() had been already called, so all UI elements
// are re-enabled and if we dispatched events from them here,
// we could end up reentering the same event handler that had
// shown the modal dialog in the first place and showing the
// dialog second time before its first instance was destroyed,
// resulting in a lot of fun.
//
// Also, unlike wx events above, it should be fine to dispatch
// the native events from the outer event loop, as any events
// generated from outside the dialog itself (necessarily, as
// the dialog is already hidden and about to be destroyed)
// shouldn't reference the dialog. Which is one of the reasons
// we still dispatch them in the outermost event loop, to
// ensure they're still processed. Another reason is that if we
// do have an endless stream of native events, e.g. because we
// have a timer with a too short interval, it's arguably better
// to keep handling them instead of exiting.
if ( gs_eventLoopCount == 1 )
{
if ( Pending() )
{
Dispatch();
hasMoreEvents = true;
}
}

if ( !hasMoreEvents )
break;
}
Loop();
#if wxUSE_EXCEPTIONS
// exit the outer loop as well
break;
Expand Down
46 changes: 28 additions & 18 deletions src/common/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "wx/atomic.h"

#include "wx/except.h"
#include "wx/sysopt.h"

#if defined(__WINDOWS__)
#include "wx/msw/private.h"
Expand Down Expand Up @@ -528,6 +529,28 @@ void wxAddEntryHook(wxEntryHook hook)
#define wxEntryReal wxEntry
#endif // !__WINDOWS__

static int DoEntryReal()
{
// app initialization
if ( !wxTheApp->CallOnInit() )
{
// don't call OnExit() if OnInit() failed
return wxTheApp->GetErrorExitCode();
}

// ensure that OnExit() is called if OnInit() had succeeded
class CallOnExit
{
public:
~CallOnExit() { wxTheApp->OnExit(); }
} callOnExit;

WX_SUPPRESS_UNUSED_WARN(callOnExit);

// app execution
return wxTheApp->OnRun();
}

int wxEntryReal(int& argc, wxChar **argv)
{
// Do this before trying the hooks as they may use command line arguments.
Expand All @@ -553,26 +576,13 @@ int wxEntryReal(int& argc, wxChar **argv)
return wxApp::GetFatalErrorExitCode();
}

if ( wxSystemOptions::IsFalse("catch-unhandled-exceptions") )
{
return DoEntryReal();
}
wxTRY
{
// app initialization
if ( !wxTheApp->CallOnInit() )
{
// don't call OnExit() if OnInit() failed
return wxTheApp->GetErrorExitCode();
}

// ensure that OnExit() is called if OnInit() had succeeded
class CallOnExit
{
public:
~CallOnExit() { wxTheApp->OnExit(); }
} callOnExit;

WX_SUPPRESS_UNUSED_WARN(callOnExit);

// app execution
return wxTheApp->OnRun();
return DoEntryReal();
}
wxCATCH_ALL(
wxTheApp->OnUnhandledException();
Expand Down
Loading
Loading