Fix tst_gestures flakiness on XCB

X11 spawns painting threads and sends an expose event at the same time.
While the worker is still paining, QXcbScreen::topLevelAt() may not
find the window, even if it reports being exposed.

Wait until windows are exposed and painted.
Remove workaround to intercept warnings about undeliverable gestures.
Remove qWait() antipattern.

Fixes: QTBUG-130811
Fixes: QTBUG-84258
Fixes: QTBUG-69648
Fixes: QTBUG-67393
Fixes: QTBUG-67392
Fixes: QTBUG-67389
Fixes: QTBUG-68861
Fixes: QTBUG-70224
Fixes: QTBUG-70223
Fixes: QTBUG-67395
Fixes: QTBUG-70227
Fixes: QTBUG-70226
Fixes: QTBUG-70209
Fixes: QTBUG-70153
Pick-to: 6.5
Change-Id: Id126fe884ba360551425f3e2b29674f5b9419fff
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 705bac063cc5ec535ff5467a208d5653555ae8f9)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Axel Spoerl 2024-11-14 11:00:28 +01:00 committed by Qt Cherry-pick Bot
parent d0ff36878d
commit d952be28ff

View File

@ -322,6 +322,7 @@ private slots:
void testReuseCanceledGestures();
void bug_13501_gesture_not_accepted();
private:
bool waitForWindowPainted(QWidget *wid) const;
QPoint m_availableTopLeft;
};
@ -347,30 +348,34 @@ void tst_Gestures::cleanup()
QGestureRecognizer::unregisterRecognizer(CustomGesture::GestureType);
}
static QtMessageHandler originalMessageHandler = nullptr;
static bool skipCustomGesture = false;
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &text)
bool tst_Gestures::waitForWindowPainted(QWidget *wid) const
{
if (type == QtMsgType::QtWarningMsg && text == "QGestureManager::deliverEvent: could not find the target for gesture")
skipCustomGesture = true;
originalMessageHandler(type, context, text);
#ifdef Q_OS_LINUX
if (!QTest::qWaitForWindowExposed(wid))
return false;
if (!QGuiApplication::platformName().contains("xcb"))
return true;
return QTest::qWaitFor([wid]{ return QApplication::topLevelAt(wid->geometry().center()) == wid; });
#else
return QTest::qWaitForWindowExposed(wid);
#endif
}
#define CHECK_EXPOSED(widget) QVERIFY(waitForWindowPainted(widget))
void tst_Gestures::customGesture()
{
originalMessageHandler = qInstallMessageHandler(messageHandler);
auto guard = qScopeGuard([](){ qInstallMessageHandler(originalMessageHandler); });
GestureWidget widget;
widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
widget.show();
QVERIFY(QTest::qWaitForWindowActive(&widget));
CHECK_EXPOSED(&widget);
CustomEvent event;
event.hotSpot = widget.mapToGlobal(QPoint(5,5));
event.hasHotSpot = true;
sendCustomGesture(&event, &widget);
if (skipCustomGesture)
QSKIP("QApplication unable to access test widget.");
static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
@ -412,11 +417,10 @@ void tst_Gestures::autoCancelingGestures()
QApplication::sendEvent(&widget, &ev);
}
// wait long enough so the gesture manager will cancel the gesture
QTest::qWait(5000);
QCOMPARE(widget.customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
QCOMPARE(widget.gestureEventsReceived, 0);
QCOMPARE(widget.gestureOverrideEventsReceived, 0);
QCOMPARE(widget.events.all.size(), 0);
QTRY_COMPARE(widget.customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
QTRY_COMPARE(widget.gestureEventsReceived, 0);
QTRY_COMPARE(widget.gestureOverrideEventsReceived, 0);
QTRY_COMPARE(widget.events.all.size(), 0);
}
void tst_Gestures::gestureOverChild()
@ -837,7 +841,7 @@ void tst_Gestures::graphicsItemGesture()
item->setPos(100, 100);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item->grabGesture(CustomGesture::GestureType);
@ -900,7 +904,7 @@ void tst_Gestures::graphicsView()
item->setPos(100, 100);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item->grabGesture(CustomGesture::GestureType);
@ -977,7 +981,7 @@ void tst_Gestures::graphicsItemTreeGesture()
item1_child2->setParentItem(item1);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item1->grabGesture(CustomGesture::GestureType);
@ -1035,7 +1039,7 @@ void tst_Gestures::explicitGraphicsObjectTarget()
item2_child1->setPos(10, 10);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item1->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
@ -1094,7 +1098,7 @@ void tst_Gestures::gestureOverChildGraphicsItem()
item2_child1->setPos(0, 0);
view.show();
QTRY_VERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item1->grabGesture(CustomGesture::GestureType);
@ -1395,7 +1399,7 @@ void tst_Gestures::testMapToScene()
item0->setPos(14, 16);
view.show(); // need to show to give it a global coordinate
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
QPoint origin = view.mapToGlobal(QPoint());
@ -1524,7 +1528,7 @@ void tst_Gestures::autoCancelGestures()
parent.grabGesture(CustomGesture::GestureType);
child->grabGesture(secondGesture);
parent.show();
QVERIFY(QTest::qWaitForWindowExposed(&parent));
CHECK_EXPOSED(&parent);
/*
An event is sent to both the child and the parent, when the child gets it a gesture is triggered
@ -1588,7 +1592,7 @@ void tst_Gestures::autoCancelGestures2()
child->grabGesture(secondGesture);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
CustomEvent event;
@ -1635,7 +1639,7 @@ void tst_Gestures::graphicsViewParentPropagation()
item1_c1_c1->setPos(0, 0);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item0->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
@ -1706,8 +1710,8 @@ void tst_Gestures::panelPropagation()
item1_child1_child1->setZValue(10);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
view.ensureVisible(scene.sceneRect());
CHECK_EXPOSED(&view);
static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
@ -1818,8 +1822,8 @@ void tst_Gestures::panelStacksBehindParent()
panel->setZValue(5);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
view.ensureVisible(scene.sceneRect());
CHECK_EXPOSED(&view);
static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
@ -1927,7 +1931,7 @@ void tst_Gestures::deleteGestureTargetItem()
items.insert(item2->objectName(), item2);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
if (propagateUpdateGesture)
@ -1972,7 +1976,7 @@ void tst_Gestures::viewportCoordinates()
scene.addItem(item1);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
CustomEvent event;
@ -2010,7 +2014,7 @@ void tst_Gestures::partialGesturePropagation()
scene.addItem(item4);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
item1->ignoredUpdatedGestures << CustomGesture::GestureType;
@ -2233,7 +2237,7 @@ void tst_Gestures::testReuseCanceledGestures()
gv->viewport()->grabGesture(tapGestureTypeId);
mw.show();
QVERIFY(QTest::qWaitForWindowExposed(&mw));
CHECK_EXPOSED(&mw);
QPoint targetPos(gv->mapFromScene(target->mapToScene(target->rect().center())));
targetPos = gv->viewport()->mapFromParent(targetPos);
@ -2287,7 +2291,7 @@ void tst_Gestures::conflictingGesturesInGraphicsView()
view.setWindowFlags(Qt::X11BypassWindowManagerHint);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
CHECK_EXPOSED(&view);
view.ensureVisible(scene.sceneRect());
const QRectF gestureRect(0, 0, view.width() * 0.9, view.height() * 0.9);
@ -2366,11 +2370,12 @@ void tst_Gestures::bug_13501_gesture_not_accepted()
NoConsumeWidgetBug13501 w;
w.grabGesture(Qt::TapGesture);
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
CHECK_EXPOSED(&w);
//QTest::mousePress(&ignoreEvent, Qt::LeftButton);
QPointingDevice *device = QTest::createTouchDevice();
QTest::touchEvent(&w, device).press(0, QPoint(10, 10), &w);
}
#undef CHECK_EXPOSED
QTEST_MAIN(tst_Gestures)
#include "tst_gestures.moc"