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