From 924b84ab9461c95cf5c5386d1091ae0f7a8e7ce7 Mon Sep 17 00:00:00 2001
From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= <vslavik@fastmail.fm>
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 <gdk/gdk.h>
 #include <gtk/gtk.h>
@@ -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 <glib.h>
 #include <gdk/gdk.h>
@@ -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 <gdk/gdk.h>
 #include <gtk/gtk.h>
@@ -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 <glib.h>
 #include <gdk/gdk.h>
@@ -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.50.0

