diff options
Diffstat (limited to 'tests/auto/widgets')
14 files changed, 603 insertions, 19 deletions
diff --git a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp index 94afff6e40..26a6245164 100644 --- a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp @@ -63,6 +63,7 @@ private slots: void hideNativeByDestruction(); void explicitDoneAfterButtonClicked(); + void legacyApiReturnValue(); void cleanup(); }; @@ -511,7 +512,7 @@ QT_WARNING_DISABLE_DEPRECATED // the button text versions closeHelper.start(Qt::Key_Enter); ret = QMessageBox::information(nullptr, "title", "text", "Yes", "No", QString(), 1); - COMPARE(ret, 3); // Custom button opaque result + COMPARE(ret, 1); QVERIFY(closeHelper.done()); #endif // QT_DEPRECATED_SINCE(6, 2) #undef COMPARE @@ -863,5 +864,21 @@ void tst_QMessageBox::explicitDoneAfterButtonClicked() QCOMPARE(rejectedSpy.size(), 3); } +void tst_QMessageBox::legacyApiReturnValue() +{ + ExecCloseHelper closeHelper; + for (int i = 0; i < 3; ++i) { + closeHelper.start(Qt::Key_Enter); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + QCOMPARE(QMessageBox::warning(nullptr, "Title", "Text", + "Button 0", "Button 1", "Button 2", i), i); + closeHelper.start(Qt::Key_Escape); + QCOMPARE(QMessageBox::warning(nullptr, "Title", "Text", + "Button 0", "Button 1", "Button 2", 0, i), i); +QT_WARNING_POP + } +} + QTEST_MAIN(tst_QMessageBox) #include "tst_qmessagebox.moc" diff --git a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp index c91a0803ee..fad75ec045 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsgridlayout/tst_qgraphicsgridlayout.cpp @@ -2976,11 +2976,6 @@ static QSizeF wfh(Qt::SizeHint /*which*/, const QSizeF &constraint) return result; } -bool qFuzzyCompare(const QSizeF &a, const QSizeF &b) -{ - return qFuzzyCompare(a.width(), b.width()) && qFuzzyCompare(a.height(), b.height()); -} - void tst_QGraphicsGridLayout::heightForWidth() { QGraphicsWidget *widget = new QGraphicsWidget; diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index ee1a8c530a..c3f77957f8 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -3872,6 +3872,7 @@ void tst_QGraphicsProxyWidget::touchEventPropagation() break; } case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: mousePressReceiver = qobject_cast<QWidget*>(receiver); break; default: diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 7ed1f28b0a..5a316dd55e 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -26,6 +26,7 @@ #include <QtWidgets/QStyle> #include <QtWidgets/QPushButton> #include <QtWidgets/QScroller> +#include <QtWidgets/QStackedWidget> #if QT_CONFIG(opengl) #include <QtOpenGLWidgets/QOpenGLWidget> #endif @@ -114,6 +115,7 @@ protected: #if defined QT_BUILD_INTERNAL class FriendlyGraphicsScene : public QGraphicsScene { + using QGraphicsScene::QGraphicsScene; friend class tst_QGraphicsView; Q_DECLARE_PRIVATE(QGraphicsScene); }; @@ -254,6 +256,9 @@ private slots: #ifndef QT_NO_CURSOR void QTBUG_7438_cursor(); #endif +#ifdef QT_BUILD_INTERNAL + void QTBUG_53974_mismatched_hide_show_events(); +#endif void resizeContentsOnItemDrag_data(); void resizeContentsOnItemDrag(); @@ -4975,6 +4980,86 @@ void tst_QGraphicsView::QTBUG_70255_scrollTo() QCOMPARE(point, QPoint(0, -500)); } +#ifdef QT_BUILD_INTERNAL +void tst_QGraphicsView::QTBUG_53974_mismatched_hide_show_events() +{ + QGraphicsView *view = new QGraphicsView; + FriendlyGraphicsScene *scene = new FriendlyGraphicsScene(view); + view->setScene(scene); + + QStackedWidget *lowLevel = new QStackedWidget; + lowLevel->addWidget(new QLabel); + lowLevel->addWidget(view); + + QStackedWidget topLevel; + topLevel.addWidget(new QLabel); + topLevel.addWidget(lowLevel); + + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + topLevel.show(); + topLevel.activateWindow(); + QVERIFY(QTest::qWaitForWindowActive(&topLevel)); + + // Starting point + QCOMPARE_EQ(topLevel.currentIndex(), 0); + QCOMPARE_EQ(lowLevel->currentIndex(), 0); + + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // lowLevel is not visible. Changing the current index there + // should not affect the refcount. + lowLevel->setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + lowLevel->setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Make lowLevel visible. + topLevel.setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Show and hide the QGV a couple of times. + lowLevel->setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 1); + + lowLevel->setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + lowLevel->setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 1); + + lowLevel->setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Make lowLevel hidden again. + topLevel.setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Change the current index in the hidden lowLevel + lowLevel->setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + lowLevel->setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Make lowLevel and the QGV visible. + lowLevel->setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + topLevel.setCurrentIndex(1); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 1); + + // Make lowLevel hidden (keeping the QGV as current index). + topLevel.setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); + + // Hide the QGV: + lowLevel->setCurrentIndex(0); + QCOMPARE_EQ(scene->d_func()->activationRefCount, 0); +} +#endif + void tst_QGraphicsView::resizeContentsOnItemDrag_data() { QTest::addColumn<Qt::Alignment>("alignment"); diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index 34972bc3e8..25e681a415 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -9,6 +9,16 @@ #include <QTableWidget> #include <QTest> +QT_BEGIN_NAMESPACE +QDebug operator<<(QDebug dbg, const QTableWidgetSelectionRange &range) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "Range(" << range.topRow() << "," << range.leftColumn() << "->" + << range.bottomRow() << "," << range.rightColumn() << ")"; + return dbg; +} +QT_END_NAMESPACE + class QObjectTableItem : public QObject, public QTableWidgetItem { Q_OBJECT @@ -578,7 +588,7 @@ void tst_QTableWidget::selectedSpannedCells_data() QTest::newRow("merge 2 cells in column, select those and one more") << QRect(1, 2, 1, 2) << QPoint(1, 1) << QPoint(1, 3) - << 3 << QTableWidgetSelectionRange(1, 1, 1, 1); + << 1 << QTableWidgetSelectionRange(1, 1, 3, 1); QTest::newRow("merge 2 cells in column, select rows above") << QRect(1, 2, 1, 2) << QPoint(0, 0) << QPoint(3, 1) @@ -590,7 +600,7 @@ void tst_QTableWidget::selectedSpannedCells_data() QTest::newRow("merge 3 cells in row, select those and one more") << QRect(0, 1, 3, 1) << QPoint(0, 1) << QPoint(3, 1) - << 4 << QTableWidgetSelectionRange(1, 0, 1, 0); + << 1 << QTableWidgetSelectionRange(1, 0, 1, 3); QTest::newRow("merge 3 cells in row, select adjacent to right") << QRect(0, 1, 3, 1) << QPoint(3, 0) << QPoint(3, 2) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 3447c9af28..cac968c5dd 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -432,6 +432,7 @@ private slots: void touchUpdateOnNewTouch(); void touchCancel(); void touchEventsForGesturePendingWidgets(); + void synthMouseDoubleClick(); void styleSheetPropagation(); @@ -477,6 +478,10 @@ private slots: void reparentWindowHandles_data(); void reparentWindowHandles(); +#ifndef QT_NO_CONTEXTMENU + void contextMenuTrigger(); +#endif + private: const QString m_platform; QSize m_testWidgetSize; @@ -1898,6 +1903,7 @@ void tst_QWidget::focusChainOnReparent() } QWidget window2; + child22->setParent(child21); child2->setParent(&window2); QWidget *expectedNewChain[5] = {&window2, child2, child21, child22, &window2}; @@ -11149,6 +11155,10 @@ void tst_QWidget::hoverPosition() QVERIFY(QTest::qWaitForWindowExposed(&root)); const QPoint middle(50, 50); + // wait until we got the correct global pos + QPoint expectedGlobalPos = root.geometry().topLeft() + QPoint(100, 100) + middle; + if (!QTest::qWaitFor([&]{ return expectedGlobalPos == h.mapToGlobal(middle); })) + QSKIP("Can't move cursor"); QPoint curpos = h.mapToGlobal(middle); QCursor::setPos(curpos); if (!QTest::qWaitFor([curpos]{ return QCursor::pos() == curpos; })) @@ -12248,7 +12258,24 @@ protected: case QEvent::MouseMove: case QEvent::MouseButtonRelease: ++m_mouseEventCount; - m_lastMouseEventPos = static_cast<QMouseEvent *>(e)->position(); + { + QMouseEvent *me = static_cast<QMouseEvent *>(e); + m_lastMouseEventPos = me->position(); + m_lastMouseTimestamp = me->timestamp(); + } + if (m_acceptMouse) + e->accept(); + else + e->ignore(); + return true; + + case QEvent::MouseButtonDblClick: + ++m_mouseEventCount; + { + QMouseEvent *me = static_cast<QMouseEvent *>(e); + m_lastMouseEventPos = me->position(); + m_doubleClickTimestamp = me->timestamp(); + } if (m_acceptMouse) e->accept(); else @@ -12274,6 +12301,8 @@ public: int m_mouseEventCount = 0; bool m_acceptMouse = true; QPointF m_lastMouseEventPos; + quint64 m_lastMouseTimestamp = 0; + quint64 m_doubleClickTimestamp = 0; }; void tst_QWidget::touchEventSynthesizedMouseEvent() @@ -12515,6 +12544,50 @@ void tst_QWidget::touchEventsForGesturePendingWidgets() QVERIFY(parent.m_gestureEventCount > 0); } +void tst_QWidget::synthMouseDoubleClick() +{ + TouchMouseWidget widget; + widget.setWindowTitle(QLatin1String(QTest::currentTestFunction())); + widget.show(); + QWindow* window = widget.windowHandle(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + // tap once; move slightly from press to release + QPoint p(20, 20); + int expectedMouseEventCount = 0; + QTest::touchEvent(window, m_touchScreen).press(1, p, window); + QCOMPARE(widget.m_touchBeginCount, 0); + QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount); + QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p); + quint64 mouseTimestamp = widget.m_lastMouseTimestamp; + p += {1, 0}; + QTest::touchEvent(window, m_touchScreen).move(1, p, window); + QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount); + QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p); + QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp); + mouseTimestamp = widget.m_lastMouseTimestamp; + QTest::touchEvent(window, m_touchScreen).release(1, p, window); + QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount); + QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p); + QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp); + mouseTimestamp = widget.m_lastMouseTimestamp; + + // tap again nearby: a double-click event should be synthesized + p += {0, 1}; + QTest::touchEvent(window, m_touchScreen).press(2, p, window); + QCOMPARE(widget.m_touchBeginCount, 0); + QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount); + QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p); + QCOMPARE_GT(widget.m_doubleClickTimestamp, mouseTimestamp); + mouseTimestamp = widget.m_doubleClickTimestamp; + + QTest::touchEvent(window, m_touchScreen).release(2, p, window); + QCOMPARE(widget.m_mouseEventCount, ++expectedMouseEventCount); + QCOMPARE(widget.m_lastMouseEventPos.toPoint(), p); + QCOMPARE_GT(widget.m_lastMouseTimestamp, mouseTimestamp); + mouseTimestamp = widget.m_lastMouseTimestamp; +} + void tst_QWidget::styleSheetPropagation() { QTableView tw; @@ -14040,5 +14113,41 @@ void tst_QWidget::reparentWindowHandles() } } +#ifndef QT_NO_CONTEXTMENU +void tst_QWidget::contextMenuTrigger() +{ + class ContextMenuWidget : public QWidget + { + public: + int events = 0; + + protected: + void contextMenuEvent(QContextMenuEvent *) override { ++events; } + }; + + const Qt::ContextMenuTrigger wasTrigger = QGuiApplication::styleHints()->contextMenuTrigger(); + auto restoreTriggerGuard = qScopeGuard([wasTrigger]{ + QGuiApplication::styleHints()->setContextMenuTrigger(wasTrigger); + }); + + ContextMenuWidget widget; + widget.show(); + QVERIFY(!qApp->topLevelWindows().empty()); + auto *window = qApp->topLevelWindows()[0]; + QVERIFY(window); + QCOMPARE(widget.events, 0); + QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Press); + QTest::mousePress(window, Qt::RightButton); + QCOMPARE(widget.events, 1); + QTest::mouseRelease(window, Qt::RightButton); + QCOMPARE(widget.events, 1); + QGuiApplication::styleHints()->setContextMenuTrigger(Qt::ContextMenuTrigger::Release); + QTest::mousePress(window, Qt::RightButton); + QCOMPARE(widget.events, 1); + QTest::mouseRelease(window, Qt::RightButton); + QCOMPARE(widget.events, 2); +} +#endif + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index e771737ae0..1fab69fdcc 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -1634,8 +1634,7 @@ void tst_QWidget_window::mouseMoveWithPopup() // but the release event will still be delivered to the first popup - dialogs might not get it QCOMPARE(mouseAction(Qt::LeftButton), QEvent::MouseButtonRelease); - if (topLevel.popup->mouseReleaseCount != 1 - && !QGuiApplication::platformName().startsWith(QLatin1String("windows"), Qt::CaseInsensitive)) + if (topLevel.popup->mouseReleaseCount != 1) QEXPECT_FAIL("Dialog", "Platform specific behavior", Continue); QCOMPARE(topLevel.popup->mouseReleaseCount, 1); } diff --git a/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp index 9059a9262e..64ebeb08b0 100644 --- a/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp +++ b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp @@ -260,6 +260,7 @@ private slots: void staticContents(); void scroll(); void paintOnScreenUpdates(); + void evaluateRhi(); #if defined(QT_BUILD_INTERNAL) void scrollWithOverlap(); @@ -581,6 +582,222 @@ void tst_QWidgetRepaintManager::paintOnScreenUpdates() } } +class RhiWidgetPrivate : public QWidgetPrivate +{ +public: + RhiWidgetPrivate(const QPlatformBackingStoreRhiConfig &config) + : config(config) + { + } + + QPlatformBackingStoreRhiConfig rhiConfig() const override + { + return config; + } + + QPlatformBackingStoreRhiConfig config = QPlatformBackingStoreRhiConfig::Null; +}; + +class RhiWidget : public QWidget +{ +public: + RhiWidget(const QPlatformBackingStoreRhiConfig &config = QPlatformBackingStoreRhiConfig::Null, QWidget *parent = nullptr) + : QWidget(*new RhiWidgetPrivate(config), parent, {}) + { + } +}; + +void tst_QWidgetRepaintManager::evaluateRhi() +{ + const auto *integration = QGuiApplicationPrivate::platformIntegration(); + if (!integration->hasCapability(QPlatformIntegration::RhiBasedRendering)) + QSKIP("Platform does not support RHI based rendering"); + + // We need full control over whether widgets are native or not + const bool nativeSiblingsOriginal = qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); + auto nativeSiblingGuard = qScopeGuard([&]{ + qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, nativeSiblingsOriginal); + }); + + auto defaultSurfaceType = QSurface::RasterSurface; + bool usesRhiBackingStore = false; + + { + // Plain QWidget doesn't enable RHI + QWidget regularWidget; + regularWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(®ularWidget)); + QVERIFY(!QWidgetPrivate::get(®ularWidget)->usesRhiFlush); + + // The platform might use a non-raster surface type if it uses + // an RHI backingstore by default (e.g. Android, iOS, QNX). + defaultSurfaceType = regularWidget.windowHandle()->surfaceType(); + + // Record whether the platform uses an RHI backingstore, + // so we can opt out of some tests further down. + if (defaultSurfaceType != QSurface::RasterSurface) + usesRhiBackingStore = QWidgetPrivate::get(®ularWidget)->rhi(); + else + QVERIFY(!QWidgetPrivate::get(®ularWidget)->rhi()); + } + + { + // But a top level RHI widget does + RhiWidget rhiWidget; + rhiWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&rhiWidget)); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + } + +#if QT_CONFIG(opengl) + { + // Non-native child RHI widget enables RHI for top level regular widget + QWidget topLevel; + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + // Only the native widget that actually flushes will report usesRhiFlush + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + // But it should have an RHI it can use + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + } + + { + // Native child RHI widget does not enable RHI for top level + QWidget topLevel; + RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); + QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); + + if (!usesRhiBackingStore) + QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); + } + + { + // Non-native RHI child of native child enables RHI for native child, + // but not top level. + QWidget topLevel; + QWidget nativeChild(&topLevel); + nativeChild.setAttribute(Qt::WA_NativeWindow); + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); + QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); + if (!usesRhiBackingStore) + QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); + } + + { + // Native child RHI widget does not prevent RHI for top level + // if non-native RHI child widget is also present. + QWidget topLevel; + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + RhiWidget nativeRhiWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + nativeRhiWidget.setAttribute(Qt::WA_NativeWindow); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeRhiWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeRhiWidget)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + } + + { + // Reparenting into a window that already matches the required + // surface type should still mark the parent as flushing with RHI. + QWidget topLevel; + + RhiWidget rhiWidget(QPlatformBackingStoreRhiConfig::Null); + rhiWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&rhiWidget)); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiWidget)->rhi()); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + rhiWidget.setParent(&topLevel); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + } + + { + // Non-native RHI child of native child enables RHI for native child, + // but does not prevent top level from flushing with RHI. + QWidget topLevel; + QWidget nativeChild(&topLevel); + nativeChild.setAttribute(Qt::WA_NativeWindow); + RhiWidget rhiGranchild(QPlatformBackingStoreRhiConfig::OpenGL, &nativeChild); + RhiWidget rhiChild(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(nativeChild.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&nativeChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&nativeChild)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiGranchild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiGranchild)->rhi()); + QCOMPARE(topLevel.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&topLevel)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&topLevel)->rhi()); + QVERIFY(!QWidgetPrivate::get(&rhiChild)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&rhiChild)->rhi()); + } + +#if QT_CONFIG(metal) + QRhiMetalInitParams metalParams; + if (QRhi::probe(QRhi::Metal, &metalParams)) { + // Native RHI childen allows mixing RHI backends + QWidget topLevel; + RhiWidget openglWidget(QPlatformBackingStoreRhiConfig::OpenGL, &topLevel); + openglWidget.setAttribute(Qt::WA_NativeWindow); + RhiWidget metalWidget(QPlatformBackingStoreRhiConfig::Metal, &topLevel); + metalWidget.setAttribute(Qt::WA_NativeWindow); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(topLevel.windowHandle()->surfaceType(), defaultSurfaceType); + QVERIFY(!QWidgetPrivate::get(&topLevel)->usesRhiFlush); + if (!usesRhiBackingStore) + QVERIFY(!QWidgetPrivate::get(&topLevel)->rhi()); + + QCOMPARE(openglWidget.windowHandle()->surfaceType(), QSurface::OpenGLSurface); + QVERIFY(QWidgetPrivate::get(&openglWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&openglWidget)->rhi()); + + QCOMPARE(metalWidget.windowHandle()->surfaceType(), QSurface::MetalSurface); + QVERIFY(QWidgetPrivate::get(&metalWidget)->usesRhiFlush); + QVERIFY(QWidgetPrivate::get(&metalWidget)->rhi()); + + QVERIFY(QWidgetPrivate::get(&openglWidget)->rhi() != QWidgetPrivate::get(&metalWidget)->rhi()); + } +#endif // QT_CONFIG(metal) + +#endif // QT_CONFIG(opengl) +} + #if defined(QT_BUILD_INTERNAL) /*! diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 52aaf094b4..e7d65db550 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -62,6 +62,7 @@ private slots: void testPlatformSurfaceEvent(); void embedWidgetWindow(); void testFocus(); + void parentDestroyed(); void cleanup(); private: @@ -530,6 +531,36 @@ void tst_QWindowContainer::testFocus() QVERIFY(!lineEdit->hasFocus()); } +class CreateDestroyWidget : public QWidget +{ +public: + void create() { QWidget::create(); } + void destroy() { QWidget::destroy(); } +}; + +void tst_QWindowContainer::parentDestroyed() +{ + CreateDestroyWidget topLevel; + topLevel.setAttribute(Qt::WA_NativeWindow); + QVERIFY(topLevel.windowHandle()); + + QPointer<QWindow> window = new QWindow; + QWidget *container = QWidget::createWindowContainer(window.get()); + container->setParent(&topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(window->parent(), topLevel.windowHandle()); + + // Destroying the widget should not wipe out the contained QWindow + topLevel.destroy(); + QVERIFY(window); + + // Recreating the top level should once again reparent the contained window + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(window->parent(), topLevel.windowHandle()); +} + QTEST_MAIN(tst_QWindowContainer) #include "tst_qwindowcontainer.moc" diff --git a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp index b2e77bc935..0623ab4167 100644 --- a/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/widgets/util/qcompleter/tst_qcompleter.cpp @@ -613,6 +613,9 @@ void tst_QCompleter::fileSystemModel_data() const QString androidDir = androidHomePath(); const QString tag = QStringLiteral("%1/fil").arg(androidDir); QTest::newRow(tag.toUtf8().data()) << tag << "" << "files" << androidDir + "/files"; +#elif defined(Q_OS_VXWORKS) + QTest::newRow("()") << "" << "" << "/" << "/"; + QTest::newRow("(/tm)") << "/tm" << "" << "tmp" << "/tmp"; #else QTest::newRow("()") << "" << "" << "/" << "/"; #if !defined(Q_OS_AIX) && !defined(Q_OS_HPUX) && !defined(Q_OS_QNX) diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp index fa1f799855..f91d984656 100644 --- a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp +++ b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp @@ -431,6 +431,18 @@ void tst_QAbstractScrollArea::sizeHint() QSize sizeHint = scrollArea.sizeHint(); QCOMPARE(sizeHint, scrollArea.viewportSizeHint()); + // check if the hScrollbar is taken into account + scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + QCOMPARE_GT(scrollArea.sizeHint().height(), scrollArea.viewportSizeHint().height()); + + // check if the vScrollbar is taken into account + scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + QCOMPARE_GT(scrollArea.sizeHint().width(), scrollArea.viewportSizeHint().width()); + + scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); const QSize sizeHintWithScrollBars = scrollArea.sizeHint(); diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index af62d0d089..88a7057d2e 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -96,6 +96,20 @@ private: QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2, QList<int> &path1, QList<int> &path2) const; +#if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || defined(Q_OS_QNX) +#define qCreateFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2)\ + mainWindow = nullptr;\ + Q_UNUSED(path1);\ + Q_UNUSED(path2);\ + QSKIP("Platform not supported"); +#else +#define qCreateFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2)\ + createFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2);\ + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);\ + if (!platformSupportingRaise)\ + QSKIP("Platform not supporting raise(). Floating tab based tests will fail.") +#endif + static inline QPoint dragPoint(QDockWidget* dockWidget); static inline QPoint home1(QMainWindow* MainWindow) { return MainWindow->mapToGlobal(MainWindow->rect().topLeft() + QPoint(0.1 * MainWindow->width(), 0.1 * MainWindow->height())); } @@ -447,6 +461,23 @@ void tst_QDockWidget::setFloating() dw.setFloating(dw.isFloating()); QCOMPARE(spy.size(), 0); spy.clear(); + +#if defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) + // Check that setFloating() reparents the dock widget to the main window, + // in case it has a QDockWidgetGroupWindow parent + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + QList<int> path1; + QList<int> path2; + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); + QVERIFY(qobject_cast<QDockWidgetGroupWindow *>(d1->parentWidget())); + QVERIFY(qobject_cast<QDockWidgetGroupWindow *>(d2->parentWidget())); + d1->setFloating(true); + QTRY_COMPARE(mainWindow, d1->parentWidget()); + QTRY_COMPARE(mainWindow, d2->parentWidget()); +#endif // defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) } void tst_QDockWidget::allowedAreas() @@ -1399,7 +1430,7 @@ void tst_QDockWidget::createFloatingTabs(QMainWindow* &mainWindow, QPointer<QWid // Test will fail if platform doesn't support raise. mainWindow->windowHandle()->handle()->raise(); if (!platformSupportingRaise) - QSKIP("Platform not supporting raise(). Floating tab based tests will fail."); + return; // remember paths to d1 and d2 QMainWindowLayout* layout = qobject_cast<QMainWindowLayout *>(mainWindow->layout()); @@ -1443,8 +1474,7 @@ void tst_QDockWidget::floatingTabs() QMainWindow* mainWindow; QList<int> path1; QList<int> path2; - createFloatingTabs(mainWindow, cent, d1, d2, path1, path2); - std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); QCOMPARE(mainWindow->tabifiedDockWidgets(d1), {d2}); QCOMPARE(mainWindow->tabifiedDockWidgets(d2), {d1}); @@ -1497,9 +1527,13 @@ void tst_QDockWidget::floatingTabs() QTest::mouseClick(floatButton, Qt::LeftButton, Qt::KeyboardModifiers(), pos1); QTest::qWait(waitingTime); - // d1 must be floating again, while d2 is still in its GroupWindow + // d1 and d2 must be floating again QTRY_VERIFY(d1->isFloating()); - QTRY_VERIFY(!d2->isFloating()); + QTRY_VERIFY(d2->isFloating()); + + // d2 was the active tab, so d1 was not visible + QTRY_VERIFY(d1->isVisible()); + QTRY_VERIFY(d2->isVisible()); // Plug back into dock areas qCDebug(lcTestDockWidget) << "*** test plugging back to dock areas ***"; @@ -1562,8 +1596,7 @@ void tst_QDockWidget::deleteFloatingTabWithSingleDockWidget() QMainWindow* mainWindow; QList<int> path1; QList<int> path2; - createFloatingTabs(mainWindow, cent, d1, d2, path1, path2); - std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); switch (removalReason) { case ChildRemovalReason::Destroyed: @@ -1698,6 +1731,9 @@ void tst_QDockWidget::closeAndDelete() if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Test skipped on Wayland."); #ifdef QT_BUILD_INTERNAL + if (QSysInfo::productType() == "rhel") + QSKIP("Memory leak on RHEL 9.2 QTBUG-124559", TestFailMode::Abort); + // Create a mainwindow with a central widget and two dock widgets QPointer<QDockWidget> d1; QPointer<QDockWidget> d2; @@ -1992,6 +2028,7 @@ void tst_QDockWidget::saveAndRestore() QCOMPARE(d1->isFloating(), isFloating1); QCOMPARE(d2->isFloating(), isFloating2); +#undef qCreateFloatingTabs #endif // QT_BUILD_INTERNAL } diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 7c1fb97b97..06750b099b 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -124,6 +124,9 @@ private slots: void platformMenu(); void addActionQt5connect(); void QTBUG_65488_hiddenActionTriggered(); + void pressDragRelease_data(); + void pressDragRelease(); + protected slots: void onSimpleActivated( QAction*); void onComplexActionTriggered(); @@ -141,6 +144,7 @@ private: int m_simpleActivatedCount; int m_complexTriggerCount[int('k')]; QMenuBar* taskQTBUG53205MenuBar; + QScopedPointer<QPointingDevice> m_touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice()); }; // Testing get/set functions @@ -1420,6 +1424,70 @@ void tst_QMenuBar::QTBUG_65488_hiddenActionTriggered() QCOMPARE(spy.size(), 0); } +void tst_QMenuBar::pressDragRelease_data() +{ + QTest::addColumn<QPointingDevice *>("device"); + + QTest::newRow("mouse") << const_cast<QPointingDevice *>(QPointingDevice::primaryPointingDevice()); + QTest::newRow("touchscreen") << m_touchScreen.get(); +} + +void tst_QMenuBar::pressDragRelease() +{ + QFETCH(QPointingDevice *, device); + + QMainWindow w; + const TestMenu menu = initWindowWithComplexMenuBar(w); + const QMenu *firstMenu = menu.menus.first(); + QAction *hoveredAction = nullptr; + connect(firstMenu, &QMenu::hovered, firstMenu, [&hoveredAction](QAction *hov) { hoveredAction = hov; }); + w.show(); + QVERIFY(QTest::qWaitForWindowActive(&w)); + QWindow *win = w.windowHandle(); + const QPoint p1(50, w.menuBar()->geometry().height() / 2); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mousePress(win, Qt::LeftButton, {}, p1); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).press(0, p1); + break; + default: + break; + } + + QTRY_VERIFY(firstMenu->isVisible()); + const QPoint firstMenuItemPos = firstMenu->geometry().center() - QPoint(0, 2); + const QPoint firstMenuItemPosInWin = w.mapFromGlobal(firstMenuItemPos); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mouseMove(win, firstMenuItemPosInWin); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).move(0, firstMenuItemPosInWin); + break; + default: + break; + } + QVERIFY(hoveredAction); + QCOMPARE(hoveredAction, firstMenu->actionAt(firstMenu->mapFromGlobal(firstMenuItemPos))); + QSignalSpy triggeredSpy(hoveredAction, &QAction::triggered); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mouseRelease(win, Qt::LeftButton, {}, firstMenuItemPosInWin); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).release(0, firstMenuItemPosInWin); + break; + default: + break; + } + QTRY_COMPARE(triggeredSpy.size(), 1); +} + // QTBUG-56526 void tst_QMenuBar::platformMenu() { diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index 773ccd894c..51f898c953 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -203,7 +203,7 @@ void tst_QOpenGLWidget::deviceLoss() w->resize(640, 480); w->show(); - auto rhi = w->backingStore()->handle()->rhi(); + auto rhi = w->backingStore()->handle()->rhi(w->windowHandle()); QNativeInterface::QEGLContext *rhiContext = nullptr; if (rhi->backend() == QRhi::OpenGLES2) { auto rhiHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles()); |