From 924b84ab9461c95cf5c5386d1091ae0f7a8e7ce7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Mon, 20 Jun 2005 08:20:50 +0000 Subject: [PATCH] changed exceptions handling to work under wxGTK git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34717 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 2 + docs/latex/wx/app.tex | 26 ++++++----- docs/latex/wx/evthand.tex | 14 ++++++ include/wx/app.h | 6 +++ include/wx/event.h | 13 +++++- include/wx/object.h | 8 +++- src/common/appbase.cpp | 11 ++++- src/common/appcmn.cpp | 30 +++++++++++++ src/common/event.cpp | 8 ++++ src/gtk/dialog.cpp | 5 ++- src/gtk/toplevel.cpp | 3 +- src/gtk1/dialog.cpp | 5 ++- src/gtk1/toplevel.cpp | 3 +- src/msw/evtloop.cpp | 92 ++++++++++++++------------------------- 14 files changed, 146 insertions(+), 80 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index a03e675209..8042cee430 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -9,6 +9,8 @@ All: - Fixed wxScopeGuard to work with VC++, documented it. - Fixed proxy handling in wxURL. +- Changed exceptions handling to work under wxGTK, added + virtual wxEvtHandler::DoHandleEvent() wxMSW: diff --git a/docs/latex/wx/app.tex b/docs/latex/wx/app.tex index 461dcc6f10..fc1fa101d6 100644 --- a/docs/latex/wx/app.tex +++ b/docs/latex/wx/app.tex @@ -197,6 +197,20 @@ different visuals, false otherwise. Returns the application's vendor name. +\membersection{wxApp::HandleEvent}\label{wxapphandleevent} + +\constfunc{virtual void}{HandleEvent}{\param{wxEvtHandler}{ *handler}, \param{wxEventFunction}{ func}, \param{wxEvent\& }{event}} + +This function simply invokes the +\helpref{DoHandleEvent}{wxevthandlerdohandleevent} method of event handler +\arg{handler}, passing \arg{func} and \arg{event} as parameters. If an +exception occurs, \helpref{OnExceptionInMainLoop}{wxapponexceptioninmainloop} +is called by this function. You can override it to customize exceptions +handling. + +If you want to modify this behaviour, override this function. + + \membersection{wxApp::IsActive}\label{wxappisactive} \constfunc{bool}{IsActive}{\void} @@ -665,18 +679,6 @@ This function currently only has effect under GTK. \docparam{flag}{If true, the app will use the best visual.} - -\membersection{wxApp::HandleEvent}\label{wxapphandleevent} - -\constfunc{virtual void}{HandleEvent}{\param{wxEvtHandler}{ *handler}, \param{wxEventFunction}{ func}, \param{wxEvent\& }{event}} - -This function simply invokes the given method \arg{func} of the specified -event handler \arg{handler} with the \arg{event} as parameter. It exists solely -to allow to catch the C++ exceptions which could be thrown by all event -handlers in the application in one place: if you want to do this, override this -function in your wxApp-derived class and add try/catch clause(s) to it. - - \membersection{wxApp::Yield}\label{wxappyield} \func{bool}{Yield}{\param{bool}{ onlyIfNeeded = false}} diff --git a/docs/latex/wx/evthand.tex b/docs/latex/wx/evthand.tex index 98fed35695..8c3e91fc83 100644 --- a/docs/latex/wx/evthand.tex +++ b/docs/latex/wx/evthand.tex @@ -155,6 +155,20 @@ to disconnect functions connected using the (static) event tables. \perlnote{In wxPerl this function takes 3 arguments: \texttt{id, lastid, type}.} +\membersection{wxEvtHandler::DoHandleEvent}\label{wxevthandlerdohandleevent} + +\func{virtual void}{DoHandleEvent}{\param{wxEventFunction}{ func}, \param{wxEvent\& }{event}} + +This function simply invokes the given method \arg{func} of this +event handler with the \arg{event} as parameter. It exists solely +to allow to catch the C++ exceptions which could be thrown by this event +handlers in one place: if you want to do this, override this +function in your wxEvtHandler-derived class and add try/catch clause(s) to it. + +Exceptions not caught at this level propagate to +\helpref{wxApp::HandleEvent}{wxapphandleevent} which in turn calls +\helpref{wxApp::OnExceptionInMainLoop}{wxapponexceptioninmainloop}. + \membersection{wxEvtHandler::GetClientData}\label{wxevthandlergetclientdata} \func{void* }{GetClientData}{\void} diff --git a/include/wx/app.h b/include/wx/app.h index 02c5aee54d..334c4d7c20 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -433,6 +433,12 @@ public: // Perform standard OnIdle behaviour: call from port's OnIdle void OnIdle(wxIdleEvent& event); +#if wxUSE_EXCEPTIONS + virtual void HandleEvent(wxEvtHandler *handler, + wxEventFunction func, + wxEvent& event) const; +#endif // wxUSE_EXCEPTIONS + // top level window functions // -------------------------- diff --git a/include/wx/event.h b/include/wx/event.h index 2e083e46b5..c8dda1ec36 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -2295,6 +2295,8 @@ protected: // wxEvtHandler: the base class for all objects handling wxWidgets events // ---------------------------------------------------------------------------- +typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&); + class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject { public: @@ -2322,6 +2324,15 @@ public: bool ProcessThreadEvent(wxEvent& event); #endif +#if wxUSE_EXCEPTIONS + // call the specified handler with the given event + // + // this method only exists to allow catching the exceptions thrown by any + // event handler, it would lead to an extra (useless) virtual function call + // if the exceptions were not used, so it doesn't even exist in that case + virtual void DoHandleEvent(wxEventFunction func, wxEvent& event); +#endif // wxUSE_EXCEPTIONS + // Dynamic association of a member function handler with the event handler, // winid and event type void Connect(int winid, @@ -2482,8 +2493,6 @@ inline void wxPostEvent(wxEvtHandler *dest, wxEvent& event) dest->AddPendingEvent(event); } -typedef void (wxEvtHandler::*wxEventFunction)(wxEvent&); - #define wxEventHandler(func) \ (wxObjectEventFunction)wxStaticCastEvent(wxEventFunction, &func) diff --git a/include/wx/object.h b/include/wx/object.h index 8f949c0979..b88a0d850a 100644 --- a/include/wx/object.h +++ b/include/wx/object.h @@ -26,6 +26,10 @@ class WXDLLIMPEXP_BASE wxObject; +// FIXME: remove in wx-2.7: +class WXDLLIMPEXP_BASE wxEvent; +class WXDLLIMPEXP_BASE wxEvtHandler; + #ifndef wxUSE_EXTENDED_RTTI #define wxUSE_EXTENDED_RTTI 0 #endif @@ -478,7 +482,9 @@ public: virtual void ReservedObjectFunc6() {} virtual void ReservedObjectFunc7() {} virtual void ReservedObjectFunc8() {} - virtual void ReservedObjectFunc9() {} + // FIXME: turn back into ReservedObjectFunc9() in wx-2.7 (see also FIXME + // near the top of this file) + virtual void DoHandleEvent(void (wxEvtHandler::*)(wxEvent&), wxEvent&) {} protected: // ensure that our data is not shared with anybody else: if we have no diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 0892aab62d..d9f65368b6 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -316,8 +316,15 @@ wxAppConsole::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const { - // by default, simply call the handler - (handler->*func)(event); + // by default, call wxApp::OnExceptionInMainLoop if an exception occurs + try + { + handler->DoHandleEvent(func, event); + } + catch ( ... ) + { + wxConstCast(this, wxAppConsole)->OnExceptionInMainLoop(); + } } bool diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index dddd390ab5..e5d27ef093 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -46,6 +46,7 @@ #include "wx/thread.h" #include "wx/utils.h" #include "wx/ptr_scpd.h" +#include "wx/evtloop.h" #if defined(__WXMSW__) #include "wx/msw/private.h" // includes windows.h for LOGFONT @@ -467,6 +468,35 @@ void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event)) } +// ---------------------------------------------------------------------------- +// exception handling +// ---------------------------------------------------------------------------- + +#if wxUSE_EXCEPTIONS + +void wxAppBase::HandleEvent(wxEvtHandler *handler, + wxEventFunction func, + wxEvent& event) const +{ + // by default, call wxApp::OnExceptionInMainLoop if an exception occurs + try + { + handler->DoHandleEvent(func, event); + } + catch ( ... ) + { + if ( !wxConstCast(this, wxAppBase)->OnExceptionInMainLoop() ) + { + wxEventLoop *loop = wxEventLoop::GetActive(); + if ( loop ) + loop->Exit(-1); + } + //else: continue running the event loop + } +} + +#endif // wxUSE_EXCEPTIONS + // ---------------------------------------------------------------------------- // wxGUIAppTraitsBase // ---------------------------------------------------------------------------- diff --git a/src/common/event.cpp b/src/common/event.cpp index ae6acd1979..648c80e2b7 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -1081,6 +1081,14 @@ void wxEvtHandler::ClearEventLocker() #endif // wxUSE_THREADS +#if wxUSE_EXCEPTIONS +void wxEvtHandler::DoHandleEvent(wxEventFunction func, wxEvent& event) +{ + // by default, just call then handler + (this->*func)(event); +} +#endif // wxUSE_EXCEPTIONS + void wxEvtHandler::AddPendingEvent(wxEvent& event) { // 1) Add event to list of pending events of this event handler diff --git a/src/gtk/dialog.cpp b/src/gtk/dialog.cpp index 115965adc4..17df0e50d0 100644 --- a/src/gtk/dialog.cpp +++ b/src/gtk/dialog.cpp @@ -18,6 +18,7 @@ #include "wx/frame.h" #include "wx/app.h" #include "wx/cursor.h" +#include "wx/evtloop.h" #include #include @@ -212,7 +213,9 @@ int wxDialog::ShowModal() g_openDialogs++; gtk_grab_add( m_widget ); - gtk_main(); + + wxEventLoop().Run(); + gtk_grab_remove( m_widget ); g_openDialogs--; diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index 00d8ba7631..d13acd7d68 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -37,6 +37,7 @@ #include "wx/gtk/private.h" #include "wx/timer.h" #include "wx/settings.h" +#include "wx/evtloop.h" #include #include @@ -1202,7 +1203,7 @@ void wxTopLevelWindowGTK::AddGrab() { m_grabbed = TRUE; gtk_grab_add( m_widget ); - gtk_main(); + wxEventLoop().Run(); gtk_grab_remove( m_widget ); } } diff --git a/src/gtk1/dialog.cpp b/src/gtk1/dialog.cpp index 115965adc4..17df0e50d0 100644 --- a/src/gtk1/dialog.cpp +++ b/src/gtk1/dialog.cpp @@ -18,6 +18,7 @@ #include "wx/frame.h" #include "wx/app.h" #include "wx/cursor.h" +#include "wx/evtloop.h" #include #include @@ -212,7 +213,9 @@ int wxDialog::ShowModal() g_openDialogs++; gtk_grab_add( m_widget ); - gtk_main(); + + wxEventLoop().Run(); + gtk_grab_remove( m_widget ); g_openDialogs--; diff --git a/src/gtk1/toplevel.cpp b/src/gtk1/toplevel.cpp index 00d8ba7631..d13acd7d68 100644 --- a/src/gtk1/toplevel.cpp +++ b/src/gtk1/toplevel.cpp @@ -37,6 +37,7 @@ #include "wx/gtk/private.h" #include "wx/timer.h" #include "wx/settings.h" +#include "wx/evtloop.h" #include #include @@ -1202,7 +1203,7 @@ void wxTopLevelWindowGTK::AddGrab() { m_grabbed = TRUE; gtk_grab_add( m_widget ); - gtk_main(); + wxEventLoop().Run(); gtk_grab_remove( m_widget ); } } diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp index 4325bbdd0a..27877fa3f2 100644 --- a/src/msw/evtloop.cpp +++ b/src/msw/evtloop.cpp @@ -207,74 +207,48 @@ int wxEventLoop::Run() // should undo wxEventLoopActivator activate(&ms_activeLoop, this); - // 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 - for ( ;; ) + try { - try +#endif + // this is the event loop itself + for ( ;; ) { -#endif // wxUSE_EXCEPTIONS - - // this is the event loop itself - 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() && (wxTheApp && wxTheApp->ProcessIdle()) ) + ; + + // 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_shouldExit ) { - #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() && (wxTheApp && wxTheApp->ProcessIdle()) ) - ; - - // 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_shouldExit ) - { - while ( Pending() ) - Dispatch(); - - 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; - } - } + while ( Pending() ) + Dispatch(); -#if wxUSE_EXCEPTIONS - // exit the outer loop as well - break; - } - catch ( ... ) - { - try - { - if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() ) - { - OnExit(); - break; - } - //else: continue running the event loop + break; } - catch ( ... ) + + // a message came or no more idle processing to do, sit in + // Dispatch() waiting for the next message + if ( !Dispatch() ) { - // OnException() throwed, possibly rethrowing the same - // exception again: very good, but we still need OnExit() to - // be called - OnExit(); - throw; + // we got WM_QUIT + break; } } +#if wxUSE_EXCEPTIONS + } + catch ( ... ) + { + // we need OnExit() to be called before the event loop stops + OnExit(); + throw; } #endif // wxUSE_EXCEPTIONS -- 2.45.2