6f4496d
From fa929caca17523110eea3b0bab315d400d447652 Mon Sep 17 00:00:00 2001
1835cbd
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
1835cbd
Date: Thu, 18 May 2017 15:05:27 +0100
1835cbd
Subject: [PATCH] Related: rhbz#1367846 queue and merge scroll events
1835cbd
MIME-Version: 1.0
1835cbd
Content-Type: text/plain; charset=UTF-8
1835cbd
Content-Transfer-Encoding: 8bit
1835cbd
1835cbd
Reviewed-on: https://gerrit.libreoffice.org/37779
1835cbd
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
1835cbd
Tested-by: Caolán McNamara <caolanm@redhat.com>
1835cbd
(cherry picked from commit 7f60978b2ccd0e17816b78bde60c6e0e60a9d52e)
1835cbd
1835cbd
Change-Id: Ib45f61bbb35bd240829491ac8a79803222974778
1835cbd
---
1835cbd
 vcl/inc/unx/gtk/gtkframe.hxx  |   8 ++-
1835cbd
 vcl/unx/gtk/gtksalframe.cxx   |  15 ++---
6f4496d
 vcl/unx/gtk3/gtk3gtkframe.cxx | 133 ++++++++++++++++++++++++++++++------------
6f4496d
 3 files changed, 112 insertions(+), 44 deletions(-)
1835cbd
1835cbd
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
1835cbd
index 874566d..907757b 100644
1835cbd
--- a/vcl/inc/unx/gtk/gtkframe.hxx
1835cbd
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
1835cbd
@@ -32,6 +32,7 @@
1835cbd
 #include <gdk/gdkkeysyms.h>
1835cbd
 
1835cbd
 #include <salframe.hxx>
1835cbd
+#include <vcl/idle.hxx>
1835cbd
 #include <vcl/sysdata.hxx>
1835cbd
 #include <unx/nativewindowhandleprovider.hxx>
1835cbd
 #include <unx/saltype.h>
1835cbd
@@ -284,7 +285,7 @@ class GtkSalFrame : public SalFrame
1835cbd
     static gboolean     signalKey( GtkWidget*, GdkEventKey*, gpointer );
1835cbd
     static gboolean     signalDelete( GtkWidget*, GdkEvent*, gpointer );
1835cbd
     static gboolean     signalWindowState( GtkWidget*, GdkEvent*, gpointer );
1835cbd
-    static gboolean     signalScroll( GtkWidget*, GdkEventScroll*, gpointer );
1835cbd
+    static gboolean     signalScroll( GtkWidget*, GdkEvent*, gpointer );
1835cbd
     static gboolean     signalCrossing( GtkWidget*, GdkEventCrossing*, gpointer );
1835cbd
     static gboolean     signalVisibility( GtkWidget*, GdkEventVisibility*, gpointer );
1835cbd
     static void         signalDestroy( GtkWidget*, gpointer );
1835cbd
@@ -354,6 +355,8 @@ public:
1835cbd
 #if GTK_CHECK_VERSION(3,0,0)
1835cbd
     cairo_surface_t*                m_pSurface;
1835cbd
     DamageHandler                   m_aDamageHandler;
1835cbd
+    std::vector<GdkEvent*>          m_aPendingScrollEvents;
1835cbd
+    Idle                            m_aSmoothScrollIdle;
1835cbd
     bool                            m_bSalObjectSetPosSize;
1835cbd
 #endif
1835cbd
     GtkSalFrame( SalFrame* pParent, SalFrameStyleFlags nStyle );
1835cbd
@@ -433,6 +436,9 @@ public:
1835cbd
     static void closePopup();
1835cbd
 
1835cbd
     void nopaint_container_resize_children(GtkContainer*);
1835cbd
+
1835cbd
+    void LaunchAsyncScroll(GdkEvent* pEvent);
1835cbd
+    DECL_LINK_TYPED(AsyncScroll, Idle *, void);
1835cbd
 #endif
1835cbd
     virtual ~GtkSalFrame();
1835cbd
 
1835cbd
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
1835cbd
index b56c899..81c3cba 100644
1835cbd
--- a/vcl/unx/gtk/gtksalframe.cxx
1835cbd
+++ b/vcl/unx/gtk/gtksalframe.cxx
1835cbd
@@ -2827,8 +2827,9 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
1835cbd
     return true;
1835cbd
 }
1835cbd
 
1835cbd
-gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer frame )
1835cbd
+gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEvent* pInEvent, gpointer frame)
1835cbd
 {
1835cbd
+    GdkEventScroll& rEvent = pInEvent->scroll;
1835cbd
     GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
1835cbd
 
1835cbd
     static sal_uLong        nLines = 0;
1835cbd
@@ -2840,16 +2841,16 @@ gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEventScroll* pEvent, gpointer
1835cbd
             nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
1835cbd
     }
1835cbd
 
1835cbd
-    bool bNeg = (pEvent->direction == GDK_SCROLL_DOWN || pEvent->direction == GDK_SCROLL_RIGHT );
1835cbd
+    bool bNeg = (rEvent.direction == GDK_SCROLL_DOWN || rEvent.direction == GDK_SCROLL_RIGHT );
1835cbd
     SalWheelMouseEvent aEvent;
1835cbd
-    aEvent.mnTime           = pEvent->time;
1835cbd
-    aEvent.mnX              = (sal_uLong)pEvent->x;
1835cbd
-    aEvent.mnY              = (sal_uLong)pEvent->y;
1835cbd
+    aEvent.mnTime           = rEvent.time;
1835cbd
+    aEvent.mnX              = (sal_uLong)rEvent.x;
1835cbd
+    aEvent.mnY              = (sal_uLong)rEvent.y;
1835cbd
     aEvent.mnDelta          = bNeg ? -120 : 120;
1835cbd
     aEvent.mnNotchDelta     = bNeg ? -1 : 1;
1835cbd
     aEvent.mnScrollLines    = nLines;
1835cbd
-    aEvent.mnCode           = GetMouseModCode( pEvent->state );
1835cbd
-    aEvent.mbHorz           = (pEvent->direction == GDK_SCROLL_LEFT || pEvent->direction == GDK_SCROLL_RIGHT);
1835cbd
+    aEvent.mnCode           = GetMouseModCode( rEvent.state );
1835cbd
+    aEvent.mbHorz           = (rEvent.direction == GDK_SCROLL_LEFT || rEvent.direction == GDK_SCROLL_RIGHT);
1835cbd
 
1835cbd
     // --- RTL --- (mirror mouse pos)
1835cbd
     if( AllSettings::GetLayoutRTL() )
1835cbd
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
6f4496d
index 5bed078..b47dd88 100644
1835cbd
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
1835cbd
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
1835cbd
@@ -781,6 +781,9 @@ void GtkSalFrame::InvalidateGraphics()
1835cbd
 
1835cbd
 GtkSalFrame::~GtkSalFrame()
1835cbd
 {
1835cbd
+    m_aSmoothScrollIdle.Stop();
1835cbd
+    m_aSmoothScrollIdle.SetIdleHdl(Link<Idle *, void>());
1835cbd
+
1835cbd
     if (m_pDropTarget)
1835cbd
     {
1835cbd
         m_pDropTarget->deinitialize();
1835cbd
@@ -965,6 +968,8 @@ void GtkSalFrame::InitCommon()
1835cbd
     m_aDamageHandler.handle = this;
1835cbd
     m_aDamageHandler.damaged = ::damaged;
1835cbd
 
1835cbd
+    m_aSmoothScrollIdle.SetIdleHdl(LINK(this, GtkSalFrame, AsyncScroll));
1835cbd
+
1835cbd
     m_pTopLevelGrid = GTK_GRID(gtk_grid_new());
1835cbd
     gtk_container_add(GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pTopLevelGrid));
1835cbd
 
6f4496d
@@ -2665,53 +2670,107 @@ gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer
1835cbd
     return true;
1835cbd
 }
1835cbd
 
1835cbd
-gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEventScroll* pEvent, gpointer frame)
1835cbd
+void GtkSalFrame::LaunchAsyncScroll(GdkEvent* pEvent)
1835cbd
 {
1835cbd
-    UpdateLastInputEventTime(pEvent->time);
1835cbd
-
1835cbd
-    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
1835cbd
+    //if we don't match previous pending states, flush that queue now
1835cbd
+    if (!m_aPendingScrollEvents.empty() && pEvent->scroll.state != m_aPendingScrollEvents.back()->scroll.state)
1835cbd
+    {
1835cbd
+        m_aSmoothScrollIdle.Stop();
1835cbd
+        m_aSmoothScrollIdle.Invoke();
1835cbd
+        assert(m_aPendingScrollEvents.empty());
1835cbd
+    }
1835cbd
+    //add scroll event to queue
1835cbd
+    m_aPendingScrollEvents.push_back(gdk_event_copy(pEvent));
1835cbd
+    if (!m_aSmoothScrollIdle.IsActive())
1835cbd
+        m_aSmoothScrollIdle.Start();
1835cbd
+}
1835cbd
+ 
1835cbd
+IMPL_LINK_NOARG_TYPED(GtkSalFrame, AsyncScroll, Idle *, void)
1835cbd
+{
1835cbd
+    assert(!m_aPendingScrollEvents.empty());
1835cbd
 
1835cbd
     SalWheelMouseEvent aEvent;
1835cbd
 
1835cbd
-    aEvent.mnTime = pEvent->time;
1835cbd
-    aEvent.mnX = (sal_uLong)pEvent->x;
1835cbd
+    GdkEvent* pEvent = m_aPendingScrollEvents.back();
1835cbd
+
1835cbd
+    aEvent.mnTime = pEvent->scroll.time;
1835cbd
+    aEvent.mnX = (sal_uLong)pEvent->scroll.x;
1835cbd
     // --- RTL --- (mirror mouse pos)
1835cbd
     if (AllSettings::GetLayoutRTL())
1835cbd
-        aEvent.mnX = pThis->maGeometry.nWidth - 1 - aEvent.mnX;
1835cbd
-    aEvent.mnY = (sal_uLong)pEvent->y;
1835cbd
-    aEvent.mnCode = GetMouseModCode( pEvent->state );
1835cbd
+        aEvent.mnX = maGeometry.nWidth - 1 - aEvent.mnX;
1835cbd
+    aEvent.mnY = (sal_uLong)pEvent->scroll.y;
1835cbd
+    aEvent.mnCode = GetMouseModCode( pEvent->scroll.state );
1835cbd
 
6f4496d
-    switch (pEvent->direction)
1835cbd
+    double delta_x(0.0), delta_y(0.0);
1835cbd
+    for (auto pSubEvent : m_aPendingScrollEvents)
1835cbd
     {
1835cbd
-        case GDK_SCROLL_SMOOTH:
1835cbd
-            // rhbz#1344042 "Traditionally" in gtk3 we tool a single up/down event as
1835cbd
-            // equating to 3 scroll lines and a delta of 120. So scale the delta here
1835cbd
-            // by 120 where a single mouse wheel click is an incoming delta_x of 1
1835cbd
-            // and divide that by 40 to get the number of scrollines
1835cbd
-            if (pEvent->delta_x != 0.0)
1835cbd
-            {
1835cbd
-                aEvent.mnDelta = -pEvent->delta_x * 120;
1835cbd
-                aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
1835cbd
-                if (aEvent.mnDelta == 0)
1835cbd
-                    aEvent.mnDelta = aEvent.mnNotchDelta;
1835cbd
-                aEvent.mbHorz = true;
1835cbd
-                aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
1835cbd
-                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
1835cbd
-            }
1835cbd
+        delta_x += pSubEvent->scroll.delta_x;
1835cbd
+        delta_y += pSubEvent->scroll.delta_y;
1835cbd
+        gdk_event_free(pSubEvent);
1835cbd
+    }
1835cbd
+    m_aPendingScrollEvents.clear();
1835cbd
 
1835cbd
-            if (pEvent->delta_y != 0.0)
1835cbd
-            {
1835cbd
-                aEvent.mnDelta = -pEvent->delta_y * 120;
1835cbd
-                aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
1835cbd
-                if (aEvent.mnDelta == 0)
1835cbd
-                    aEvent.mnDelta = aEvent.mnNotchDelta;
1835cbd
-                aEvent.mbHorz = false;
1835cbd
-                aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
1835cbd
-                pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
1835cbd
-            }
1835cbd
+    // rhbz#1344042 "Traditionally" in gtk3 we tool a single up/down event as
1835cbd
+    // equating to 3 scroll lines and a delta of 120. So scale the delta here
1835cbd
+    // by 120 where a single mouse wheel click is an incoming delta_x of 1
1835cbd
+    // and divide that by 40 to get the number of scroll lines
1835cbd
+    if (delta_x != 0.0)
1835cbd
+    {
1835cbd
+        aEvent.mnDelta = -delta_x * 120;
1835cbd
+        aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
1835cbd
+        if (aEvent.mnDelta == 0)
1835cbd
+            aEvent.mnDelta = aEvent.mnNotchDelta;
1835cbd
+        aEvent.mbHorz = true;
1835cbd
+        aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
1835cbd
+        CallCallback(SalEvent::WheelMouse, &aEvent);
1835cbd
+    }
1835cbd
 
1835cbd
-            break;
1835cbd
+    if (delta_y != 0.0)
1835cbd
+    {
1835cbd
+        aEvent.mnDelta = -delta_y * 120;
1835cbd
+        aEvent.mnNotchDelta = aEvent.mnDelta < 0 ? -1 : +1;
1835cbd
+        if (aEvent.mnDelta == 0)
1835cbd
+            aEvent.mnDelta = aEvent.mnNotchDelta;
1835cbd
+        aEvent.mbHorz = false;
1835cbd
+        aEvent.mnScrollLines = std::abs(aEvent.mnDelta) / 40.0;
1835cbd
+        CallCallback(SalEvent::WheelMouse, &aEvent);
1835cbd
+    }
1835cbd
+}
1835cbd
+ 
1835cbd
+gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEvent* pInEvent, gpointer frame)
1835cbd
+{
1835cbd
+    GdkEventScroll& rEvent = pInEvent->scroll;
1835cbd
+
1835cbd
+    UpdateLastInputEventTime(rEvent.time);
1835cbd
 
1835cbd
+    GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
1835cbd
+
1835cbd
+    if (rEvent.direction == GDK_SCROLL_SMOOTH)
1835cbd
+    {
1835cbd
+        pThis->LaunchAsyncScroll(pInEvent);
1835cbd
+        return true;
1835cbd
+    }
1835cbd
+
1835cbd
+    //if we have smooth scrolling previous pending states, flush that queue now
1835cbd
+    if (!pThis->m_aPendingScrollEvents.empty())
1835cbd
+    {
1835cbd
+        pThis->m_aSmoothScrollIdle.Stop();
1835cbd
+        pThis->m_aSmoothScrollIdle.Invoke();
1835cbd
+        assert(pThis->m_aPendingScrollEvents.empty());
1835cbd
+    }
1835cbd
+
1835cbd
+    SalWheelMouseEvent aEvent;
1835cbd
+
1835cbd
+    aEvent.mnTime = rEvent.time;
1835cbd
+    aEvent.mnX = (sal_uLong)rEvent.x;
1835cbd
+    // --- RTL --- (mirror mouse pos)
1835cbd
+    if (AllSettings::GetLayoutRTL())
1835cbd
+        aEvent.mnX = pThis->maGeometry.nWidth - 1 - aEvent.mnX;
1835cbd
+    aEvent.mnY = (sal_uLong)rEvent.y;
1835cbd
+    aEvent.mnCode = GetMouseModCode(rEvent.state);
1835cbd
+
1835cbd
+    switch (rEvent.direction)
1835cbd
+    {
1835cbd
         case GDK_SCROLL_UP:
1835cbd
             aEvent.mnDelta = 120;
1835cbd
             aEvent.mnNotchDelta = 1;
6f4496d
@@ -2743,6 +2802,8 @@ gboolean GtkSalFrame::signalScroll(GtkWidget*, GdkEventScroll* pEvent, gpointer
1835cbd
             aEvent.mbHorz = true;
1835cbd
             pThis->CallCallbackExc(SalEvent::WheelMouse, &aEvent);
1835cbd
             break;
1835cbd
+        default:
1835cbd
+            break;
1835cbd
     }
1835cbd
 
1835cbd
     return true;
1835cbd
-- 
1835cbd
2.9.3
1835cbd