Blob Blame History Raw
From 02dd477a3b6b927c78b19f4be6ffcb835bb6dcd5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
Date: Fri, 21 Oct 2016 14:14:10 +0100
Subject: [PATCH] catch and rethrow later uno exceptions within glib signals

after g_main_context_iteration when its safe to do so again

otherwise if something happens inside the glib signal
callback and the exception skips the code waiting
for the callback to return, subsequent attempts to
show the native gtk3 error dialog will fail

(cherry picked from commit 28fe78604ca46319ae596d04ddca206e6b2672a7)

Change-Id: I271c09f8f1f00c0eca76191fcb63ddf56c10060f
---
 vcl/inc/unx/gtk/gtkdata.hxx   |  2 ++
 vcl/inc/unx/gtk/gtkframe.hxx  |  7 ++++
 vcl/unx/gtk3/gtk3gtkdata.cxx  |  4 +++
 vcl/unx/gtk3/gtk3gtkframe.cxx | 77 ++++++++++++++++++++++++++-----------------
 4 files changed, 59 insertions(+), 31 deletions(-)

diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index 037d213..9fc7d28 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -100,6 +100,7 @@ class GtkData : public SalGenericData
     GSource*     m_pUserEvent;
     osl::Mutex   m_aDispatchMutex;
     oslCondition m_aDispatchCondition;
+    css::uno::Any m_aException;
     bool         blockIdleTimeout;
 
 public:
@@ -123,6 +124,7 @@ public:
 
     inline GtkSalDisplay *GetGtkDisplay() const;
     bool BlockIdleTimeout() const { return blockIdleTimeout; }
+    void setException(const css::uno::Any& rException) { m_aException = rException; }
 };
 
 class GtkSalFrame;
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 1b48aa3..52a0b94 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -540,6 +540,13 @@ public:
     sal_uIntPtr                 GetNativeWindowHandle(GtkWidget *pWidget);
     virtual sal_uIntPtr         GetNativeWindowHandle() override;
 
+    //Call the usual SalFrame Callback, but catch uno exceptionss and delegate
+    //to GtkData to rethrow them after the gsignal is processed when its safe
+    //to do so again in our own code after the g_main_context_iteration call
+    //which triggers the gsignals.
+    long                        CallCallbackExc(SalEvent nEvent, const void* pEvent) const;
+
+
     static void                 KeyCodeToGdkKey(const vcl::KeyCode& rKeyCode,
         guint* pGdkKeyCode, GdkModifierType *pGdkModifiers);
 
diff --git a/vcl/unx/gtk3/gtk3gtkdata.cxx b/vcl/unx/gtk3/gtk3gtkdata.cxx
index ca210e0..b3cf23c 100644
--- a/vcl/unx/gtk3/gtk3gtkdata.cxx
+++ b/vcl/unx/gtk3/gtk3gtkdata.cxx
@@ -51,6 +51,8 @@
 #  include <gdk/gdkx.h>
 #endif
 
+#include <cppuhelper/exc_hlp.hxx>
+
 using namespace vcl_sal;
 
 /***************************************************************
@@ -478,6 +480,8 @@ SalYieldResult GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
                 if( wasOneEvent )
                     bWasEvent = true;
             }
+            if (m_aException.hasValue())
+                ::cppu::throwException(m_aException);
         }
         else if( bWait )
         {
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 931ed03..fe348ab 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -37,6 +37,7 @@
 #include <vcl/svapp.hxx>
 #include <vcl/window.hxx>
 #include <vcl/settings.hxx>
+#include <cppuhelper/exc_hlp.hxx>
 
 #include <config_gio.h>
 
@@ -437,7 +438,7 @@ void GtkSalFrame::doKeyCallback( guint state,
 
     if( bDown )
     {
-        bool bHandled = CallCallback( SalEvent::KeyInput, &aEvent );
+        bool bHandled = CallCallbackExc( SalEvent::KeyInput, &aEvent );
         // #i46889# copy AlternateKeyCode handling from generic plugin
         if( ! bHandled )
         {
@@ -447,16 +448,16 @@ void GtkSalFrame::doKeyCallback( guint state,
                 aEvent.mnCode = aAlternate.nKeyCode;
                 if( aAlternate.nCharCode )
                     aEvent.mnCharCode = aAlternate.nCharCode;
-                CallCallback( SalEvent::KeyInput, &aEvent );
+                CallCallbackExc( SalEvent::KeyInput, &aEvent );
             }
         }
         if( bSendRelease && ! aDel.isDeleted() )
         {
-            CallCallback( SalEvent::KeyUp, &aEvent );
+            CallCallbackExc( SalEvent::KeyUp, &aEvent );
         }
     }
     else
-        CallCallback( SalEvent::KeyUp, &aEvent );
+        CallCallbackExc( SalEvent::KeyUp, &aEvent );
 }
 
 GtkSalFrame::GtkSalFrame( SalFrame* pParent, SalFrameStyleFlags nStyle )
@@ -2629,7 +2630,7 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
 
     if (!aDel.isDeleted())
     {
-        pThis->CallCallback( nEventType, &aEvent );
+        pThis->CallCallbackExc( nEventType, &aEvent );
     }
 
     if (!aDel.isDeleted())
@@ -2652,7 +2653,7 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
         {
             pThis->maGeometry.nX = frame_x;
             pThis->maGeometry.nY = frame_y;
-            pThis->CallCallback( SalEvent::Move, nullptr );
+            pThis->CallCallbackExc( SalEvent::Move, nullptr );
         }
     }
 
@@ -2694,7 +2695,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
                 if (aEvent.mnScrollLines == 0)
                     aEvent.mnScrollLines = 1;
 
-                pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             }
 
             if (pEvent->delta_y != 0.0)
@@ -2708,7 +2709,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
                 if (aEvent.mnScrollLines == 0)
                     aEvent.mnScrollLines = 1;
 
-                pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             }
 
             break;
@@ -2718,7 +2719,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
             aEvent.mnNotchDelta = 1;
             aEvent.mnScrollLines = 3;
             aEvent.mbHorz = false;
-            pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+            pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             break;
 
         case GDK_SCROLL_DOWN:
@@ -2726,7 +2727,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
             aEvent.mnNotchDelta = -1;
             aEvent.mnScrollLines = 3;
             aEvent.mbHorz = false;
-            pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+            pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             break;
 
         case GDK_SCROLL_LEFT:
@@ -2734,7 +2735,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
             aEvent.mnNotchDelta = 1;
             aEvent.mnScrollLines = 3;
             aEvent.mbHorz = true;
-            pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+            pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             break;
 
         case GDK_SCROLL_RIGHT:
@@ -2742,7 +2743,7 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
             aEvent.mnNotchDelta = -1;
             aEvent.mnScrollLines = 3;
             aEvent.mbHorz = true;
-            pThis->CallCallback(SalEvent::WheelMouse, &aEvent);
+            pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             break;
     }
 
@@ -2767,7 +2768,7 @@ void GtkSalFrame::gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdo
         aEvent.mnX = x;
         aEvent.mnY = y;
 
-        pThis->CallCallback(SalEvent::Swipe, &aEvent);
+        pThis->CallCallbackExc(SalEvent::Swipe, &aEvent);
     }
 }
 
@@ -2785,7 +2786,7 @@ void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
         aEvent.mnX = x;
         aEvent.mnY = y;
 
-        pThis->CallCallback(SalEvent::LongPress, &aEvent);
+        pThis->CallCallbackExc(SalEvent::LongPress, &aEvent);
     }
 }
 
@@ -2810,7 +2811,7 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer
 
     vcl::DeletionListener aDel( pThis );
 
-    pThis->CallCallback( SalEvent::MouseMove, &aEvent );
+    pThis->CallCallbackExc( SalEvent::MouseMove, &aEvent );
 
     if( ! aDel.isDeleted() )
     {
@@ -2820,7 +2821,7 @@ gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer
         {
             pThis->maGeometry.nX = frame_x;
             pThis->maGeometry.nY = frame_y;
-            pThis->CallCallback( SalEvent::Move, nullptr );
+            pThis->CallCallbackExc( SalEvent::Move, nullptr );
         }
 
         if( ! aDel.isDeleted() )
@@ -2847,7 +2848,7 @@ gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpoi
     aEvent.mnCode   = GetMouseModCode( pEvent->state );
     aEvent.mnButton = 0;
 
-    pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SalEvent::MouseMove : SalEvent::MouseLeave, &aEvent );
+    pThis->CallCallbackExc( (pEvent->type == GDK_ENTER_NOTIFY) ? SalEvent::MouseMove : SalEvent::MouseLeave, &aEvent );
 
     return true;
 }
@@ -2894,7 +2895,7 @@ void GtkSalFrame::sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer
     pThis->maGeometry.nWidth = pAllocation->width;
     pThis->maGeometry.nHeight = pAllocation->height;
     pThis->AllocateFrame();
-    pThis->CallCallback( SalEvent::Resize, nullptr );
+    pThis->CallCallbackExc( SalEvent::Resize, nullptr );
     pThis->TriggerPaintEvent();
 }
 
@@ -2927,7 +2928,7 @@ gboolean GtkSalFrame::signalConfigure(GtkWidget*, GdkEventConfigure* pEvent, gpo
     pThis->updateScreenNumber();
 
     if (bMoved)
-        pThis->CallCallback(SalEvent::Move, nullptr);
+        pThis->CallCallbackExc(SalEvent::Move, nullptr);
 
     return false;
 }
@@ -2948,7 +2949,7 @@ void GtkSalFrame::TriggerPaintEvent()
     //that duplicates the amount of drawing and is hideously slow
     SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
     SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
-    CallCallback(SalEvent::Paint, &aPaintEvt);
+    CallCallbackExc(SalEvent::Paint, &aPaintEvt);
     gtk_widget_queue_draw(GTK_WIDGET(m_pFixedContainer));
 }
 
@@ -2982,7 +2983,7 @@ gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer f
 
     // in the meantime do not propagate focus get/lose if floats are open
     if( m_nFloats == 0 )
-        pThis->CallCallback( pEvent->in ? SalEvent::GetFocus : SalEvent::LoseFocus, nullptr );
+        pThis->CallCallbackExc( pEvent->in ? SalEvent::GetFocus : SalEvent::LoseFocus, nullptr );
 
     return false;
 }
@@ -2997,7 +2998,7 @@ gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
     (void)pWidget; (void)bSetFocus;
     //FIXME: no set input focus ...
 
-    pThis->CallCallback( SalEvent::Resize, nullptr );
+    pThis->CallCallbackExc( SalEvent::Resize, nullptr );
     pThis->TriggerPaintEvent();
 
     return false;
@@ -3007,7 +3008,7 @@ gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
 {
     GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
 
-    pThis->CallCallback( SalEvent::Resize, nullptr );
+    pThis->CallCallbackExc( SalEvent::Resize, nullptr );
 
     return false;
 }
@@ -3107,7 +3108,7 @@ gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame
         aModEvt.mnTime = pEvent->time;
         aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
 
-        pThis->CallCallback( SalEvent::KeyModChange, &aModEvt );
+        pThis->CallCallbackExc( SalEvent::KeyModChange, &aModEvt );
 
     }
     else
@@ -3140,7 +3141,7 @@ gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
     if (bBackDrop)
         pThis->GetWindow()->Enable();
 
-    pThis->CallCallback( SalEvent::Close, nullptr );
+    pThis->CallCallbackExc( SalEvent::Close, nullptr );
 
     return true;
 }
@@ -3577,13 +3578,13 @@ void GtkSalFrame::IMHandler::deleteIMContext()
 void GtkSalFrame::IMHandler::doCallEndExtTextInput()
 {
     m_aInputEvent.mpTextAttr = nullptr;
-    m_pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
+    m_pFrame->CallCallbackExc( SalEvent::EndExtTextInput, nullptr );
 }
 
 void GtkSalFrame::IMHandler::updateIMSpotLocation()
 {
     SalExtTextInputPosEvent aPosEvent;
-    m_pFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void*>(&aPosEvent) );
+    m_pFrame->CallCallbackExc( SalEvent::ExtTextInputPos, static_cast<void*>(&aPosEvent) );
     GdkRectangle aArea;
     aArea.x = aPosEvent.mnX;
     aArea.y = aPosEvent.mnY;
@@ -3605,9 +3606,9 @@ void GtkSalFrame::IMHandler::sendEmptyCommit()
     aEmptyEv.mnCursorPos        = 0;
     aEmptyEv.mnCursorFlags      = 0;
     aEmptyEv.mbOnlyCursor       = False;
-    m_pFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void*>(&aEmptyEv) );
+    m_pFrame->CallCallbackExc( SalEvent::ExtTextInput, static_cast<void*>(&aEmptyEv) );
     if( ! aDel.isDeleted() )
-        m_pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
+        m_pFrame->CallCallbackExc( SalEvent::EndExtTextInput, nullptr );
 }
 
 void GtkSalFrame::IMHandler::endExtTextInput( EndExtTextInputFlags /*nFlags*/ )
@@ -3824,7 +3825,7 @@ void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* pContext, gchar* pTex
         }
         if( ! bSingleCommit )
         {
-            pThis->m_pFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void*>(&pThis->m_aInputEvent));
+            pThis->m_pFrame->CallCallbackExc( SalEvent::ExtTextInput, static_cast<void*>(&pThis->m_aInputEvent));
             if( ! aDel.isDeleted() )
                 pThis->doCallEndExtTextInput();
         }
@@ -3949,7 +3950,7 @@ void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_
     SolarMutexGuard aGuard;
     vcl::DeletionListener aDel( pThis->m_pFrame );
 
-    pThis->m_pFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void*>(&pThis->m_aInputEvent));
+    pThis->m_pFrame->CallCallbackExc( SalEvent::ExtTextInput, static_cast<void*>(&pThis->m_aInputEvent));
     if( bEndPreedit && ! aDel.isDeleted() )
         pThis->doCallEndExtTextInput();
     if( ! aDel.isDeleted() )
@@ -4257,5 +4258,19 @@ void GtkSalFrame::signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*con
     pThis->m_pDragSource->dragDataGet(data, info);
 }
 
+long GtkSalFrame::CallCallbackExc(SalEvent nEvent, const void* pEvent) const
+{
+    long nRet = 0;
+    try
+    {
+        nRet = CallCallback(nEvent, pEvent);
+    }
+    catch (const css::uno::Exception&)
+    {
+        GtkData *pSalData = static_cast<GtkData*>(GetSalData());
+        pSalData->setException(::cppu::getCaughtException());
+    }
+    return nRet;
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
-- 
2.9.3