include/vcl/commandevent.hxx       |    6 -
 include/vcl/window.hxx             |    2 
 vcl/inc/salwtype.hxx               |    2 
 vcl/inc/unx/gtk/gtkframe.hxx       |    9 ++
 vcl/source/window/commandevent.cxx |    4 -
 vcl/source/window/window2.cxx      |   14 +--
 vcl/unx/gtk/gtksalframe.cxx        |   15 ++--
 vcl/unx/gtk3/gtk3gtkframe.cxx      |  137 +++++++++++++++++++++++++------------
 8 files changed, 126 insertions(+), 63 deletions(-)

New commits:
commit f7d2bf216afa10268e6a7c1d4613a2fd8f7c7f3c
Author: Caolán McNamara <caol...@redhat.com>
Date:   Tue May 16 10:12:09 2017 +0100

    Resolves: tdf#103174 & rhbz#1367846 improve gtk3 trackpad scrolling
    
    convert number of "lines" scrolled to double and allow
    fractional parts of lines/columns
    
    Change-Id: Ib99c815cfc8823e22fc1d76e201903c34ed0f61b
    
    Related: rhbz#1367846 queue and merge scroll events
    
    Reviewed-on: https://gerrit.libreoffice.org/37779
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 7f60978b2ccd0e17816b78bde60c6e0e60a9d52e)
    
    Change-Id: Ib45f61bbb35bd240829491ac8a79803222974778
    Reviewed-on: https://gerrit.libreoffice.org/37913
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk>

diff --git a/include/vcl/commandevent.hxx b/include/vcl/commandevent.hxx
index 5b9cc09a7eaa..371fd54716d9 100644
--- a/include/vcl/commandevent.hxx
+++ b/include/vcl/commandevent.hxx
@@ -140,7 +140,7 @@ class VCL_DLLPUBLIC CommandWheelData
 private:
     long              mnDelta;
     long              mnNotchDelta;
-    sal_uLong         mnLines;
+    double            mnLines;
     CommandWheelMode  mnWheelMode;
     sal_uInt16        mnCode;
     bool              mbHorz;
@@ -149,13 +149,13 @@ private:
 public:
                     CommandWheelData();
                     CommandWheelData( long nWheelDelta, long nWheelNotchDelta,
-                                      sal_uLong nScrollLines,
+                                      double nScrollLines,
                                       CommandWheelMode nWheelMode, sal_uInt16 
nKeyModifier,
                                       bool bHorz, bool bDeltaIsPixel = false );
 
     long            GetDelta() const { return mnDelta; }
     long            GetNotchDelta() const { return mnNotchDelta; }
-    sal_uLong       GetScrollLines() const { return mnLines; }
+    double          GetScrollLines() const { return mnLines; }
     bool            IsHorz() const { return mbHorz; }
     bool            IsDeltaPixel() const { return mbDeltaIsPixel; }
 
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 4fdb80560d68..7d6f69ce9b28 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -719,7 +719,7 @@ private:
     SAL_DLLPRIVATE void                 
ImplCallActivateListeners(vcl::Window*);
     SAL_DLLPRIVATE void                 
ImplCallDeactivateListeners(vcl::Window*);
 
-    SAL_DLLPRIVATE static void          ImplHandleScroll( ScrollBar* pHScrl, 
long nX, ScrollBar* pVScrl, long nY );
+    SAL_DLLPRIVATE static void          ImplHandleScroll(ScrollBar* pHScrl, 
double nX, ScrollBar* pVScrl, double nY);
 
     SAL_DLLPRIVATE Rectangle            
ImplOutputToUnmirroredAbsoluteScreenPixel( const Rectangle& rRect ) const;
     SAL_DLLPRIVATE long                 ImplGetUnmirroredOutOffX();
diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx
index b7f803eee86e..c25ca80909dc 100644
--- a/vcl/inc/salwtype.hxx
+++ b/vcl/inc/salwtype.hxx
@@ -149,7 +149,7 @@ struct SalWheelMouseEvent
     long            mnY;            // Y-Position (Pixel, TopLeft-Output)
     long            mnDelta;        // Number of rotations
     long            mnNotchDelta;   // Number of fixed rotations
-    sal_uLong       mnScrollLines;  // Actual number of lines to scroll
+    double          mnScrollLines;  // Actual number of lines to scroll
     sal_uInt16      mnCode;         // SV-Modifiercode 
(KEY_SHIFT|KEY_MOD1|KEY_MOD2|MOUSE_LEFT|MOUSE_MIDDLE|MOUSE_RIGHT)
     bool        mbHorz;         // Horizontal
     bool        mbDeltaIsPixel; // delta value is a pixel value (on touch 
devices)
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 3deb4c4a8c28..fcb4498512d9 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>
@@ -281,7 +282,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:
 #if GTK_CHECK_VERSION(3,0,0)
     cairo_surface_t*                m_pSurface;
     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, Idle *, void);
+
 #endif
     virtual ~GtkSalFrame() override;
 
diff --git a/vcl/source/window/commandevent.cxx 
b/vcl/source/window/commandevent.cxx
index e7f7dcd8569d..8ef928f3a571 100644
--- a/vcl/source/window/commandevent.cxx
+++ b/vcl/source/window/commandevent.cxx
@@ -73,7 +73,7 @@ CommandWheelData::CommandWheelData()
 {
     mnDelta         = 0;
     mnNotchDelta    = 0;
-    mnLines         = 0;
+    mnLines         = 0.0;
     mnWheelMode     = CommandWheelMode::NONE;
     mnCode          = 0;
     mbHorz          = false;
@@ -81,7 +81,7 @@ CommandWheelData::CommandWheelData()
 }
 
 CommandWheelData::CommandWheelData( long nWheelDelta, long nWheelNotchDelta,
-                                    sal_uLong nScrollLines,
+                                    double nScrollLines,
                                     CommandWheelMode nWheelMode, sal_uInt16 
nKeyModifier,
                                     bool bHorz, bool bDeltaIsPixel )
 {
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
index 24d1fa79eae2..9607be6e3d21 100644
--- a/vcl/source/window/window2.cxx
+++ b/vcl/source/window/window2.cxx
@@ -664,7 +664,7 @@ long Window::GetDrawPixel( OutputDevice* pDev, long nPixels 
) const
     return nP;
 }
 
-static void lcl_HandleScrollHelper( ScrollBar* pScrl, long nN, bool 
isMultiplyByLineSize )
+static void lcl_HandleScrollHelper( ScrollBar* pScrl, double nN, bool 
isMultiplyByLineSize )
 {
     if ( pScrl && nN && pScrl->IsEnabled() && pScrl->IsInputEnabled() && ! 
pScrl->IsInModalMode() )
     {
@@ -681,7 +681,7 @@ static void lcl_HandleScrollHelper( ScrollBar* pScrl, long 
nN, bool isMultiplyBy
                 nN*=pScrl->GetLineSize();
             }
 
-            const double fVal = (double)(nNewPos - nN);
+            const double fVal = nNewPos - nN;
 
             if ( fVal < LONG_MIN )
                 nNewPos = LONG_MIN;
@@ -737,8 +737,8 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
                 {
                     if (!pData->IsDeltaPixel())
                     {
-                        sal_uLong nScrollLines = pData->GetScrollLines();
-                        long nLines;
+                        double nScrollLines = pData->GetScrollLines();
+                        double nLines;
                         if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
                         {
                             if ( pData->GetDelta() < 0 )
@@ -747,7 +747,7 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
                                 nLines = LONG_MAX;
                         }
                         else
-                            nLines = pData->GetNotchDelta() * 
(long)nScrollLines;
+                            nLines = pData->GetNotchDelta() * nScrollLines;
                         if ( nLines )
                         {
                             ImplHandleScroll( nullptr,
@@ -860,8 +860,8 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
 // horizontal or vertical scroll bar. nY is correspondingly either
 // the horizontal or vertical scroll amount.
 
-void Window::ImplHandleScroll( ScrollBar* pHScrl, long nX,
-                               ScrollBar* pVScrl, long nY )
+void Window::ImplHandleScroll( ScrollBar* pHScrl, double nX,
+                               ScrollBar* pVScrl, double nY )
 {
     lcl_HandleScrollHelper( pHScrl, nX, true );
     lcl_HandleScrollHelper( pVScrl, nY, true );
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
index cfc6f4548f8c..2bb6718725dc 100644
--- a/vcl/unx/gtk/gtksalframe.cxx
+++ b/vcl/unx/gtk/gtksalframe.cxx
@@ -2788,8 +2788,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;
@@ -2801,16 +2802,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);
 
     // --- RTL --- (mirror mouse pos)
     if( AllSettings::GetLayoutRTL() )
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 93a3d0138c8d..f22e8ebcbaa7 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -801,6 +801,9 @@ void GtkSalFrame::InvalidateGraphics()
 
 GtkSalFrame::~GtkSalFrame()
 {
+    m_aSmoothScrollIdle.Stop();
+    m_aSmoothScrollIdle.SetIdleHdl(Link<Idle *, void>());
+
     if (m_pDropTarget)
     {
         m_pDropTarget->deinitialize();
@@ -986,6 +989,8 @@ void GtkSalFrame::InitCommon()
     m_aDamageHandler.handle = this;
     m_aDamageHandler.damaged = ::damaged;
 
+    m_aSmoothScrollIdle.SetIdleHdl(LINK(this, GtkSalFrame, AsyncScroll));
+
     m_pTopLevelGrid = GTK_GRID(gtk_grid_new());
     gtk_container_add(GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pTopLevelGrid));
 
@@ -2649,59 +2654,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, Idle *, 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 scrollines
-            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;
-                if (aEvent.mnScrollLines == 0)
-                    aEvent.mnScrollLines = 1;
-
-                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;
-                if (aEvent.mnScrollLines == 0)
-                    aEvent.mnScrollLines = 1;
-
-                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;
@@ -2733,6 +2786,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