#include "wx/msw/private.h"
+// For MB_TASKMODAL
+#ifdef __WXWINCE__
+#include "wx/msw/wince/missing.h"
+#endif
+
#if wxUSE_THREADS
#include "wx/thread.h"
{
public:
// ctor
- wxEventLoopImpl() { SetExitCode(0); }
+ wxEventLoopImpl() { m_exitcode = 0; m_shouldExit = false; }
// process a message
void ProcessMessage(MSG *msg);
bool SendIdleMessage();
// set/get the exit code
- void SetExitCode(int exitcode) { m_exitcode = exitcode; }
+ void Exit(int exitcode) { m_exitcode = exitcode; m_shouldExit = true; }
int GetExitCode() const { return m_exitcode; }
+ bool ShouldExit() const { return m_shouldExit; }
+
+ enum wxCatchAllResponse {
+ catch_continue,
+ catch_exit,
+ catch_rethrow
+ };
+ wxCatchAllResponse OnCatchAll();
private:
// preprocess a message, return TRUE if processed (i.e. no further
// the exit code of the event loop
int m_exitcode;
+
+ // true if we were asked to terminate
+ bool m_shouldExit;
};
// ----------------------------------------------------------------------------
return wxTheApp->ProcessIdle();
}
+// ----------------------------------------------------------------------------
+// wxEventLoopImpl exception handling
+// ----------------------------------------------------------------------------
+
+wxEventLoopImpl::wxCatchAllResponse wxEventLoopImpl::OnCatchAll()
+{
+ switch (::MessageBox(NULL,
+ _T("An unhandled exception occurred. 'Abort' will terminate the program,\r\n\
+'Retry' will close the current dialog, 'Ignore' will try to continue."),
+ _T("Unhandled exception"),
+ MB_ABORTRETRYIGNORE|MB_ICONERROR|MB_TASKMODAL))
+ {
+ case IDABORT: return catch_rethrow;
+ case IDRETRY: return catch_exit;
+ case IDIGNORE: return catch_continue;
+ }
+ return catch_rethrow;
+}
+
// ============================================================================
// wxEventLoop implementation
// ============================================================================
wxEventLoopActivator activate(&ms_activeLoop, this);
wxEventLoopImplTiedPtr impl(&m_impl, new wxEventLoopImpl);
- class CallEventLoopMethod
- {
- public:
- typedef void (wxEventLoop::*FuncType)();
-
- CallEventLoopMethod(wxEventLoop *evtLoop, FuncType fn)
- : m_evtLoop(evtLoop), m_fn(fn) { }
- ~CallEventLoopMethod() { (m_evtLoop->*m_fn)(); }
-
- private:
- wxEventLoop *m_evtLoop;
- FuncType m_fn;
- } callOnExit(this, wxEventLoop::OnExit);
-
- for ( ;; )
+ // we must ensure that OnExit() is called even if an exception is thrown
+ // from inside Dispatch() but we must call it from Exit() in normal
+ // situations because it is supposed to be called synchronously,
+ // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or
+ // something similar here)
+#if wxUSE_EXCEPTIONS
+ bool retryAfterException = false;
+ do {
+ retryAfterException=false;
+#endif
+ wxTRY
{
-#if wxUSE_THREADS
- wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
+ for ( ;; )
+ {
+ #if wxUSE_THREADS
+ wxMutexGuiLeaveOrEnter();
+ #endif // wxUSE_THREADS
+
+ // generate and process idle events for as long as we don't have
+ // anything else to do
+ while ( !Pending() && m_impl->SendIdleMessage() )
+ ;
+
+ // if the "should exit" flag is set, the loop should terminate but
+ // not before processing any remaining messages so while Pending()
+ // returns true, do process them
+ if ( m_impl->ShouldExit() )
+ {
+ while ( Pending() )
+ Dispatch();
- // generate and process idle events for as long as we don't have
- // anything else to do
- while ( !Pending() && m_impl->SendIdleMessage() )
- ;
+ break;
+ }
- // a message came or no more idle processing to do, sit in
- // Dispatch() waiting for the next message
- if ( !Dispatch() )
- {
- // we got WM_QUIT
- break;
+ // a message came or no more idle processing to do, sit in
+ // Dispatch() waiting for the next message
+ if ( !Dispatch() )
+ {
+ // we got WM_QUIT
+ break;
+ }
}
+ }
+ wxCATCH_ALL(
+ switch (m_impl->OnCatchAll()) {
+ case wxEventLoopImpl::catch_continue:
+ retryAfterException=true;
+ break;
+ case wxEventLoopImpl::catch_exit:
+ OnExit();
+ break;
+ case wxEventLoopImpl::catch_rethrow:
+ OnExit();
+ // should be replaced with wx macro, but
+ // there is none yet. OTOH, wxCATCH_ALL isn't
+ // expanded unless wxUSE_EXCEPTIONS, so its
+ // safe to use throw here.
+ throw;
+ break;
}
+ )
+#if wxUSE_EXCEPTIONS
+ } while (retryAfterException);
+#endif
return m_impl->GetExitCode();
}
{
wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
- m_impl->SetExitCode(rc);
+ m_impl->Exit(rc);
+
+ OnExit();
- ::PostQuitMessage(rc);
+ // all we have to do to exit from the loop is to (maybe) wake it up so that
+ // it can notice that Exit() had been called
+ //
+ // in particular, we do *not* use PostQuitMessage() here because we're not
+ // sure that WM_QUIT is going to be processed by the correct event loop: it
+ // is possible that another one is started before this one has a chance to
+ // process WM_QUIT
+ ::PostMessage(NULL, WM_NULL, 0, 0);
}
// ----------------------------------------------------------------------------