summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2017-05-16 10:12:09 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2017-05-24 10:36:16 +0200
commitf7d2bf216afa10268e6a7c1d4613a2fd8f7c7f3c (patch)
treea7a36402f4d630b4bc9006ba153018a4bf2fa2d9
parentc05f35f4f56a1e65b92f4b1bc43b0fa6138d209c (diff)
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 <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com> (cherry picked from commit 7f60978b2ccd0e17816b78bde60c6e0e60a9d52e) Change-Id: Ib45f61bbb35bd240829491ac8a79803222974778 Reviewed-on: https://gerrit.libreoffice.org/37913 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r--include/vcl/commandevent.hxx6
-rw-r--r--include/vcl/window.hxx2
-rw-r--r--vcl/inc/salwtype.hxx2
-rw-r--r--vcl/inc/unx/gtk/gtkframe.hxx9
-rw-r--r--vcl/source/window/commandevent.cxx4
-rw-r--r--vcl/source/window/window2.cxx14
-rw-r--r--vcl/unx/gtk/gtksalframe.cxx15
-rw-r--r--vcl/unx/gtk3/gtk3gtkframe.cxx137
8 files changed, 126 insertions, 63 deletions
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;