blob: 794562fea0b47dda19b0eccfba746e8161ec70ee [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
#include <QtQuick/private/qquickdraghandler_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include "../../../shared/util.h"
#include "../../shared/viewtestutil.h"
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
class tst_MouseAreaInterop : public QQmlDataTest
{
Q_OBJECT
public:
tst_MouseAreaInterop()
: touchDevice(QTest::createTouchDevice())
, touchPointerDevice(QQuickPointerDevice::touchDevice(touchDevice))
{}
private slots:
void dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse();
void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch_data();
void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
QTouchDevice *touchDevice;
QQuickPointerDevice *touchPointerDevice;
};
void tst_MouseAreaInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName)
{
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
QQuickViewTestUtil::centerOnScreen(window.data());
QQuickViewTestUtil::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
}
void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse()
{
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "dragTakeOverFromSibling.qml");
QQuickView * window = windowPtr.data();
auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(QQuickPointerDevice::genericMouseDevice());
QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>();
QVERIFY(handler);
QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>();
QVERIFY(ma);
QPoint p1(150, 150);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
QCOMPARE(window->mouseGrabberItem(), ma);
QCOMPARE(ma->pressed(), true);
// Start dragging
// DragHandler keeps monitoring, due to its passive grab,
// and eventually steals the exclusive grab from MA
int dragStoleGrab = 0;
for (int i = 0; i < 4; ++i) {
p1 += QPoint(dragThreshold / 2, 0);
QTest::mouseMove(window, p1);
if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler)
dragStoleGrab = i;
}
if (dragStoleGrab)
qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab);
QVERIFY(dragStoleGrab > 1);
QCOMPARE(handler->active(), true);
QCOMPARE(ma->pressed(), false);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QCOMPARE(handler->active(), false);
}
void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch_data()
{
QTest::addColumn<bool>("preventStealing");
QTest::newRow("allow stealing") << false;
QTest::newRow("prevent stealing") << true;
}
void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch() // QTBUG-77624 and QTBUG-79163
{
QFETCH(bool, preventStealing);
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "dragTakeOverFromSibling.qml");
QQuickView * window = windowPtr.data();
auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchPointerDevice);
QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>();
QVERIFY(handler);
QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>();
QVERIFY(ma);
ma->setPreventStealing(preventStealing);
QPoint p1(150, 150);
QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice);
touch.press(1, p1).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(pointerEvent->point(0)->passiveGrabbers().contains(handler));
QCOMPARE(pointerEvent->point(0)->grabberItem(), ma);
QCOMPARE(window->mouseGrabberItem(), ma);
QCOMPARE(ma->pressed(), true);
// Start dragging
// DragHandler keeps monitoring, due to its passive grab,
// and eventually steals the exclusive grab from MA if MA allows it
int dragStoleGrab = 0;
for (int i = 0; i < 4; ++i) {
p1 += QPoint(dragThreshold / 2, 0);
touch.move(1, p1).commit();
QQuickTouchUtils::flush(window);
if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == handler)
dragStoleGrab = i;
}
if (dragStoleGrab)
qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab);
if (preventStealing) {
QCOMPARE(dragStoleGrab, 0);
QCOMPARE(handler->active(), false);
QCOMPARE(ma->pressed(), true);
} else {
QVERIFY(dragStoleGrab > 1);
QCOMPARE(handler->active(), true);
QCOMPARE(ma->pressed(), false);
}
touch.release(1, p1).commit();
QQuickTouchUtils::flush(window);
QCOMPARE(handler->active(), false);
}
QTEST_MAIN(tst_MouseAreaInterop)
#include "tst_mousearea_interop.moc"