vcl/inc/unx/gtk/gtkframe.hxx  |    9 ++
 vcl/unx/gtk/gtksalframe.cxx   |   15 ++--
 vcl/unx/gtk3/gtk3gtkframe.cxx |  131 ++++++++++++++++++++++++++++++------------
 3 files changed, 112 insertions(+), 43 deletions(-)

New commits:
commit 8b6a29398315bf7a0b1a7d54b18d3902cb8e9dfa
Author: Caolán McNamara <caol...@redhat.com>
Date:   Thu May 18 15:05:27 2017 +0100

    Related: rhbz#1367846 queue and merge scroll events
    
    Change-Id: Ib45f61bbb35bd240829491ac8a79803222974778
    Reviewed-on: https://gerrit.libreoffice.org/37780
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 00a687422f82..37a4facabd0c 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -30,6 +30,7 @@
 #include <gdk/gdkkeysyms.h>
 
 #include <salframe.hxx>
+#include <vcl/idle.hxx>
 #include <vcl/sysdata.hxx>
 #include <unx/nativewindowhandleprovider.hxx>
 #include <unx/saltype.h>
@@ -280,7 +281,7 @@ class GtkSalFrame : public SalFrame
     static gboolean     signalKey( GtkWidget*, GdkEventKey*, gpointer );
     static gboolean     signalDelete( GtkWidget*, GdkEvent*, gpointer );
     static gboolean     signalWindowState( GtkWidget*, GdkEvent*, gpointer );
-    static gboolean     signalScroll( GtkWidget*, GdkEventScroll*, gpointer );
+    static gboolean     signalScroll( GtkWidget*, GdkEvent*, gpointer );
     static gboolean     signalCrossing( GtkWidget*, GdkEventCrossing*, 
gpointer );
     static gboolean     signalVisibility( GtkWidget*, GdkEventVisibility*, 
gpointer );
     static void         signalDestroy( GtkWidget*, gpointer );
@@ -347,6 +348,8 @@ public:
     cairo_surface_t*                m_pSurface;
     basegfx::B2IVector              m_aFrameSize;
     DamageHandler                   m_aDamageHandler;
+    std::vector<GdkEvent*>          m_aPendingScrollEvents;
+    Idle                            m_aSmoothScrollIdle;
     int                             m_nGrabLevel;
     bool                            m_bSalObjectSetPosSize;
 #endif
@@ -427,6 +430,10 @@ public:
     void removeGrabLevel();
 
     void nopaint_container_resize_children(GtkContainer*);
+
+    void LaunchAsyncScroll(GdkEvent* pEvent);
+    DECL_LINK(AsyncScroll, Timer *, void);
+
 #endif
     virtual ~GtkSalFrame() override;
 
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
index 02e06ae8c053..f32e49ad4f7b 100644
--- a/vcl/unx/gtk/gtksalframe.cxx
+++ b/vcl/unx/gtk/gtksalframe.cxx
@@ -2782,8 +2782,9 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, 
GdkEventButton* pEvent, gpointer
     return true;
 }
 
-gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, 
gpointer frame )
+gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEvent* pInEvent, gpointer 
frame)
 {
+    GdkEventScroll& rEvent = pInEvent->scroll;
     GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
 
     static sal_uLong        nLines = 0;
@@ -2795,16 +2796,16 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, 
GdkEventScroll* pEvent, gpointer
             nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
     }
 
-    bool bNeg = (pEvent->direction == GDK_SCROLL_DOWN || pEvent->direction == 
GDK_SCROLL_RIGHT );
+    bool bNeg = (rEvent.direction == GDK_SCROLL_DOWN || rEvent.direction == 
GDK_SCROLL_RIGHT );
     SalWheelMouseEvent aEvent;
-    aEvent.mnTime           = pEvent->time;
-    aEvent.mnX              = (sal_uLong)pEvent->x;
-    aEvent.mnY              = (sal_uLong)pEvent->y;
+    aEvent.mnTime           = rEvent.time;
+    aEvent.mnX              = (sal_uLong)rEvent.x;
+    aEvent.mnY              = (sal_uLong)rEvent.y;
     aEvent.mnDelta          = bNeg ? -120 : 120;
     aEvent.mnNotchDelta     = bNeg ? -1 : 1;
     aEvent.mnScrollLines    = nLines;
-    aEvent.mnCode           = GetMouseModCode( pEvent->state );
-    aEvent.mbHorz           = (pEvent->direction == GDK_SCROLL_LEFT || 
pEvent->direction == GDK_SCROLL_RIGHT);
+    aEvent.mnCode           = GetMouseModCode( rEvent.state );
+    aEvent.mbHorz           = (rEvent.direction == GDK_SCROLL_LEFT || 
rEvent.direction == GDK_SCROLL_RIGHT);
 
     if( AllSettings::GetLayoutRTL() )
         aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index bc19821cbdf5..30a729c5cbcc 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -807,6 +807,9 @@ void GtkSalFrame::InvalidateGraphics()
 
 GtkSalFrame::~GtkSalFrame()
 {
+    m_aSmoothScrollIdle.Stop();
+    m_aSmoothScrollIdle.ClearInvokeHandler();
+
     if (m_pDropTarget)
     {
         m_pDropTarget->deinitialize();
@@ -992,6 +995,8 @@ void GtkSalFrame::InitCommon()
     m_aDamageHandler.handle = this;
     m_aDamageHandler.damaged = ::damaged;
 
+    m_aSmoothScrollIdle.SetInvokeHandler(LINK(this, GtkSalFrame, AsyncScroll));
+
     m_pTopLevelGrid = GTK_GRID(gtk_grid_new());
     gtk_container_add(GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pTopLevelGrid));
 
@@ -2653,53 +2658,107 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, 
GdkEventButton* pEvent, gpointer
     return true;
 }
 
-gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEventScroll* pEvent, 
gpointer frame)
+void GtkSalFrame::LaunchAsyncScroll(GdkEvent* pEvent)
 {
-    UpdateLastInputEventTime(pEvent->time);
+    //if we don't match previous pending states, flush that queue now
+    if (!m_aPendingScrollEvents.empty() && pEvent->scroll.state != 
m_aPendingScrollEvents.back()->scroll.state)
+    {
+        m_aSmoothScrollIdle.Stop();
+        m_aSmoothScrollIdle.Invoke();
+        assert(m_aPendingScrollEvents.empty());
+    }
+    //add scroll event to queue
+    m_aPendingScrollEvents.push_back(gdk_event_copy(pEvent));
+    if (!m_aSmoothScrollIdle.IsActive())
+        m_aSmoothScrollIdle.Start();
+}
 
-    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+IMPL_LINK_NOARG(GtkSalFrame, AsyncScroll, Timer *, void)
+{
+    assert(!m_aPendingScrollEvents.empty());
 
     SalWheelMouseEvent aEvent;
 
-    aEvent.mnTime = pEvent->time;
-    aEvent.mnX = (sal_uLong)pEvent->x;
+    GdkEvent* pEvent = m_aPendingScrollEvents.back();
 
+    aEvent.mnTime = pEvent->scroll.time;
+    aEvent.mnX = (sal_uLong)pEvent->scroll.x;
+    // --- RTL --- (mirror mouse pos)
     if (AllSettings::GetLayoutRTL())
-        aEvent.mnX = pThis->maGeometry.nWidth - 1 - aEvent.mnX;
-    aEvent.mnY = (sal_uLong)pEvent->y;
-    aEvent.mnCode = GetMouseModCode( pEvent->state );
+        aEvent.mnX = maGeometry.nWidth - 1 - aEvent.mnX;
+    aEvent.mnY = (sal_uLong)pEvent->scroll.y;
+    aEvent.mnCode = GetMouseModCode( pEvent->scroll.state );
 
-    switch (pEvent->direction)
+    double delta_x(0.0), delta_y(0.0);
+    for (auto pSubEvent : m_aPendingScrollEvents)
     {
-        case GDK_SCROLL_SMOOTH:
-            // rhbz#1344042 "Traditionally" in gtk3 we tool a single up/down 
event as
-            // equating to 3 scroll lines and a delta of 120. So scale the 
delta here
-            // by 120 where a single mouse wheel click is an incoming delta_x 
of 1
-            // and divide that by 40 to get the number of scroll lines
-            if (pEvent->delta_x != 0.0)
-            {
-                aEvent.mnDelta = -pEvent->delta_x * 120;
-                aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
-                if (aEvent.mnDelta == 0)
-                    aEvent.mnDelta = aEvent.mnNotchDelta;
-                aEvent.mbHorz = true;
-                aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
-                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
-            }
+        delta_x += pSubEvent->scroll.delta_x;
+        delta_y += pSubEvent->scroll.delta_y;
+        gdk_event_free(pSubEvent);
+    }
+    m_aPendingScrollEvents.clear();
 
-            if (pEvent->delta_y != 0.0)
-            {
-                aEvent.mnDelta = -pEvent->delta_y * 120;
-                aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
-                if (aEvent.mnDelta == 0)
-                    aEvent.mnDelta = aEvent.mnNotchDelta;
-                aEvent.mbHorz = false;
-                aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
-                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
-            }
+    // rhbz#1344042 "Traditionally" in gtk3 we tool a single up/down event as
+    // equating to 3 scroll lines and a delta of 120. So scale the delta here
+    // by 120 where a single mouse wheel click is an incoming delta_x of 1
+    // and divide that by 40 to get the number of scroll lines
+    if (delta_x != 0.0)
+    {
+        aEvent.mnDelta = -delta_x * 120;
+        aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
+        if (aEvent.mnDelta == 0)
+            aEvent.mnDelta = aEvent.mnNotchDelta;
+        aEvent.mbHorz = true;
+        aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
+        CallCallbackExc(SalEvent::WheelMouse, &aEvent);
+    }
 
-            break;
+    if (delta_y != 0.0)
+    {
+        aEvent.mnDelta = -delta_y * 120;
+        aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
+        if (aEvent.mnDelta == 0)
+            aEvent.mnDelta = aEvent.mnNotchDelta;
+        aEvent.mbHorz = false;
+        aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
+        CallCallbackExc(SalEvent::WheelMouse, &aEvent);
+    }
+}
 
+gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEvent* pInEvent, gpointer 
frame)
+{
+    GdkEventScroll& rEvent = pInEvent->scroll;
+
+    UpdateLastInputEventTime(rEvent.time);
+
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+    if (rEvent.direction == GDK_SCROLL_SMOOTH)
+    {
+        pThis->LaunchAsyncScroll(pInEvent);
+        return true;
+    }
+
+    //if we have smooth scrolling previous pending states, flush that queue now
+    if (!pThis->m_aPendingScrollEvents.empty())
+    {
+        pThis->m_aSmoothScrollIdle.Stop();
+        pThis->m_aSmoothScrollIdle.Invoke();
+        assert(pThis->m_aPendingScrollEvents.empty());
+    }
+
+    SalWheelMouseEvent aEvent;
+
+    aEvent.mnTime = rEvent.time;
+    aEvent.mnX = (sal_uLong)rEvent.x;
+    // --- RTL --- (mirror mouse pos)
+    if (AllSettings::GetLayoutRTL())
+        aEvent.mnX = pThis->maGeometry.nWidth - 1 - aEvent.mnX;
+    aEvent.mnY = (sal_uLong)rEvent.y;
+    aEvent.mnCode = GetMouseModCode(rEvent.state);
+
+    switch (rEvent.direction)
+    {
         case GDK_SCROLL_UP:
             aEvent.mnDelta = 120;
             aEvent.mnNotchDelta = 1;
@@ -2731,6 +2790,8 @@ gboolean GtkSalFrame::signalScroll(GtkWidget*, 
GdkEventScroll* pEvent, gpointer
             aEvent.mbHorz = true;
             pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
             break;
+        default:
+            break;
     }
 
     return true;
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to