tdf#124146 add (general) gesture event support to VCL

Change-Id: I766930bb35071442e132b91477cd3d55e8f00f48
Reviewed-on: https://gerrit.libreoffice.org/69655
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/vcl/GestureEvent.hxx b/include/vcl/GestureEvent.hxx
new file mode 100644
index 0000000..2070fc7
--- /dev/null
+++ b/include/vcl/GestureEvent.hxx
@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#ifndef INCLUDED_VCL_GESTUREEVENT_HXX
#define INCLUDED_VCL_GESTUREEVENT_HXX

#include <vcl/dllapi.h>

enum class GestureEventType
{
    PanningBegin,
    PanningUpdate,
    PanningEnd
};

enum class PanningOrientation
{
    Horizontal,
    Vertical
};

class VCL_DLLPUBLIC GestureEvent
{
public:
    sal_Int32 mnX;
    sal_Int32 mnY;
    GestureEventType meEventType;

    sal_Int32 mnOffset;
    PanningOrientation meOrientation;
};

#endif // INCLUDED_VCL_GESTUREEVENT_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/commandevent.hxx b/include/vcl/commandevent.hxx
index 88185ef..a3ee2fb 100644
--- a/include/vcl/commandevent.hxx
+++ b/include/vcl/commandevent.hxx
@@ -27,6 +27,7 @@
#include <vcl/keycodes.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <rtl/ustring.hxx>
#include <vcl/GestureEvent.hxx>

class CommandExtTextInputData;
class CommandWheelData;
@@ -37,6 +38,8 @@
class CommandSelectionChangeData;
class CommandSwipeData;
class CommandLongPressData;
class CommandGestureData;

enum class CommandEventId;

enum class ExtTextInputAttr {
@@ -86,6 +89,7 @@
    const CommandSelectionChangeData*   GetSelectionChangeData() const;
    const CommandSwipeData*             GetSwipeData() const;
    const CommandLongPressData*         GetLongPressData() const;
    const CommandGestureData*           GetGestureData() const;
};

class VCL_DLLPUBLIC CommandExtTextInputData
@@ -300,6 +304,25 @@
    double getY() const { return mnY; }
};

class VCL_DLLPUBLIC CommandGestureData
{
public:
    double const mfX;
    double const mfY;
    GestureEventType const meEventType;

    double const mfOffset;
    PanningOrientation const meOrientation;

    CommandGestureData(double fX, double fY, GestureEventType eEventType, double fOffset, PanningOrientation eOrientation)
        : mfX(fX)
        , mfY(fY)
        , meEventType(eEventType)
        , mfOffset(fOffset)
        , meOrientation(eOrientation)
    {}
};

enum class CommandEventId
{
    NONE                    = 0,
@@ -323,6 +346,7 @@
    QueryCharPosition       = 20,
    Swipe                   = 21,
    LongPress               = 22,
    Gesture                 = 23,
};

#endif // INCLUDED_VCL_COMMANDEVENT_HXX
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index 712f75a..d89a23e 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -63,6 +63,7 @@
class NotifyEvent;
class KeyEvent;
class MouseEvent;
class GestureEvent;
struct ImplSVEvent;
struct ConvertData;

@@ -747,6 +748,8 @@
    */
    static ImplSVEvent *        PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent );

    static ImplSVEvent* PostGestureEvent(VclEventId nEvent, vcl::Window* pWin, GestureEvent const * pGestureEvent);

    /** Remove mouse and keypress events from a window... any also zoom and scroll events
     if the platform supports it.

diff --git a/include/vcl/vclevent.hxx b/include/vcl/vclevent.hxx
index 26cf1a6..4ba0717 100644
--- a/include/vcl/vclevent.hxx
+++ b/include/vcl/vclevent.hxx
@@ -170,6 +170,7 @@
    WindowShow,
    WindowStartDocking,     // pData = DockingData
    WindowToggleFloating,
    WindowGestureEvent,
};

class VCL_DLLPUBLIC VclSimpleEvent
diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx
index 4fab141..3585c01 100644
--- a/vcl/inc/salwtype.hxx
+++ b/vcl/inc/salwtype.hxx
@@ -24,6 +24,7 @@
#include <rtl/ref.hxx>
#include <rtl/ustring.hxx>
#include <tools/solar.h>
#include <vcl/GestureEvent.hxx>

class LogicalFontInstance;
class SalGraphics;
@@ -82,7 +83,9 @@
    StartReconversion,
    QueryCharPosition,
    Swipe,
    LongPress
    LongPress,
    ExternalGesture,
    Gesture,
};

// MOUSELEAVE must send, when the pointer leave the client area and
@@ -255,6 +258,15 @@
    long mnY;
};

struct SalGestureEvent
{
    GestureEventType meEventType;
    PanningOrientation meOrientation;
    double mfOffset;
    long mnX;
    long mnY;
};

typedef void (*SALTIMERPROC)();

#endif // INCLUDED_VCL_INC_SALWTYPE_HXX
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index c3f3b078..ca29108 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -133,11 +133,26 @@
    ImplSVEvent *   mnEventId;
    KeyEvent        maKeyEvent;
    MouseEvent      maMouseEvent;
    GestureEvent    maGestureEvent;

    ImplPostEventData( VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent ) :
        mnEvent( nEvent ), mpWin( pWin ), mnEventId( nullptr ), maKeyEvent( rKeyEvent ) {}
    ImplPostEventData( VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent ) :
        mnEvent( nEvent ), mpWin( pWin ), mnEventId( nullptr ), maMouseEvent( rMouseEvent ) {}
    ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
        : mnEvent(nEvent)
        , mpWin(pWin)
        , mnEventId(nullptr)
        , maKeyEvent(rKeyEvent)
    {}
    ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
        : mnEvent(nEvent)
        , mpWin(pWin)
        , mnEventId(nullptr)
        , maMouseEvent(rMouseEvent)
    {}
    ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEvent& rGestureEvent)
        : mnEvent(nEvent)
        , mpWin(pWin)
        , mnEventId(nullptr)
        , maGestureEvent(rGestureEvent)
    {}
};

Application* GetpApp()
@@ -829,7 +844,43 @@
    return nEventId;
}

ImplSVEvent * Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
ImplSVEvent* Application::PostGestureEvent(VclEventId nEvent, vcl::Window* pWin, GestureEvent const * pGestureEvent)
{
    const SolarMutexGuard aGuard;
    ImplSVEvent * nEventId = nullptr;

    if (pWin && pGestureEvent)
    {
        Point aTransformedPosition(pGestureEvent->mnX, pGestureEvent->mnY);

        aTransformedPosition.AdjustX(pWin->GetOutOffXPixel());
        aTransformedPosition.AdjustY(pWin->GetOutOffYPixel());

        const GestureEvent aGestureEvent{
            sal_Int32(aTransformedPosition.X()),
            sal_Int32(aTransformedPosition.Y()),
            pGestureEvent->meEventType,
            pGestureEvent->mnOffset,
            pGestureEvent->meOrientation
        };

        std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData(nEvent, pWin, aGestureEvent));

        nEventId = PostUserEvent(
                       LINK( nullptr, Application, PostEventHandler ),
                       pPostEventData.get());

        if (nEventId)
        {
            pPostEventData->mnEventId = nEventId;
            ImplGetSVData()->maAppData.maPostedEventList.emplace_back(pWin, pPostEventData.release());
        }
    }

    return nEventId;
}

ImplSVEvent* Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
{
    const SolarMutexGuard aGuard;
    ImplSVEvent * nEventId = nullptr;
@@ -896,6 +947,11 @@
            pEventData = &pData->maKeyEvent;
        break;

        case VclEventId::WindowGestureEvent:
            nEvent = SalEvent::ExternalGesture;
            pEventData = &pData->maGestureEvent;
        break;

        default:
            nEvent = SalEvent::NONE;
            pEventData = nullptr;
diff --git a/vcl/source/window/commandevent.cxx b/vcl/source/window/commandevent.cxx
index c8b486e..06e974c 100644
--- a/vcl/source/window/commandevent.cxx
+++ b/vcl/source/window/commandevent.cxx
@@ -186,4 +186,13 @@
        return nullptr;
}

const CommandGestureData* CommandEvent::GetGestureData() const
{
    if (mnCommand == CommandEventId::Gesture)
        return static_cast<const CommandGestureData*>(mpData);
    else
        return nullptr;
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx
index b0e1ea9..3ebcc26 100644
--- a/vcl/source/window/winproc.cxx
+++ b/vcl/source/window/winproc.cxx
@@ -28,6 +28,7 @@
#include <vcl/unohelp.hxx>
#include <vcl/timer.hxx>
#include <vcl/event.hxx>
#include <vcl/GestureEvent.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/cursor.hxx>
@@ -1550,6 +1551,30 @@
    return aHandler.HandleEvent();
}

class HandleGeneralGestureEvent : public HandleGestureEvent
{
private:
    CommandGestureData m_aGestureData;

public:
    HandleGeneralGestureEvent(vcl::Window* pWindow, const SalGestureEvent& rEvent)
        : HandleGestureEvent(pWindow, Point(rEvent.mnX, rEvent.mnY))
        , m_aGestureData(rEvent.mnX, rEvent.mnY, rEvent.meEventType, rEvent.mfOffset, rEvent.meOrientation)
    {
    }

    virtual bool CallCommand(vcl::Window* pWindow, const Point& /*rMousePos*/) override
    {
        return ImplCallCommand(pWindow, CommandEventId::Gesture, &m_aGestureData);
    }
};

static bool ImplHandleGestureEvent(vcl::Window* pWindow, const SalGestureEvent& rEvent)
{
    HandleGeneralGestureEvent aHandler(pWindow, rEvent);
    return aHandler.HandleEvent();
}

static void ImplHandlePaint( vcl::Window* pWindow, const tools::Rectangle& rBoundRect, bool bImmediateUpdate )
{
    // system paint events must be checked for re-mirroring
@@ -2537,7 +2562,26 @@
            bRet = ImplHandleLongPress(pWindow, *static_cast<const SalLongPressEvent*>(pEvent));
            break;

        case SalEvent::ExternalGesture:
        {
            auto const * pGestureEvent = static_cast<GestureEvent const *>(pEvent);

            SalGestureEvent aSalGestureEvent;
            aSalGestureEvent.mfOffset = pGestureEvent->mnOffset;
            aSalGestureEvent.mnX = pGestureEvent->mnX;
            aSalGestureEvent.mnY = pGestureEvent->mnY;
            aSalGestureEvent.meEventType = pGestureEvent->meEventType;
            aSalGestureEvent.meOrientation = pGestureEvent->meOrientation;

            bRet = ImplHandleGestureEvent(pWindow, aSalGestureEvent);
        }
        break;
        case SalEvent::Gesture:
        {
            auto const * aSalGestureEvent = static_cast<SalGestureEvent const *>(pEvent);
            bRet = ImplHandleGestureEvent(pWindow, *aSalGestureEvent);
        }
        break;
        default:
            SAL_WARN( "vcl.layout", "ImplWindowFrameProc(): unknown event (" << static_cast<int>(nEvent) << ")" );
            break;