aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2021-08-12 14:33:04 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-08-16 18:17:08 +0000
commita9fe872b7a43d5083832b1fa62f36ed0f99c7c8b (patch)
treefc8ea00fdd82dd2f329ddd5c8b518e8916c52244 /tests
parentaeaef5a2b181c9830d1d994857435d2b6b21060b (diff)
Check for exposed instead of just visible in grabWindow
This issue is reproducable both in Qt 5 and 6. When calling grabWindow() "early enough", such as from an Component.onCompleted handler, the window is not ready for rendering (as it has not yet been exposed, there is no scenegraph initialized, etc.). Checking the visible property is not safe here, because it may well be true right from the start during the window object's life, while telling nothing about the actual low-level state. This becomes fatal in particular when one relies on setting Window.visible to true from QML, instead of calling show() from C++, because then the isVisible() check is clearly wrong (already true, while the window is nowhere near to be ready for rendering) and leads to hitting the wrong branch in the main condition of grabWindow(). It is probably safe to assume that the isVisible() check in grabWindow() was never actually correct, and perhaps was an oversight. What it wants to test for is being exposed (i.e. ready to render, with the scenegraph and related machinery up and running), but it rather just tests the visible property of the QWindow. It's just that in the majority of uses that happens not to cause any problems in practice, either because grabWindow() is only called once the window is up and running, or because toggling visible is deferred to show() from C++ which masks the underlying issue in the logic. Switch over to isRenderable() which is a helper function based on the exposed state. Add an autotest case as well. Fixes: QTBUG-95393 Change-Id: Ia0193229f6b3980ff6bd51d85db1408017c43b38 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> (cherry picked from commit b6ac70b9219ad9a2036b61686f2890b830b425c2) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/quick/qquickwindow/data/earlyGrab.qml25
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp35
2 files changed, 60 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickwindow/data/earlyGrab.qml b/tests/auto/quick/qquickwindow/data/earlyGrab.qml
new file mode 100644
index 0000000000..74427c9492
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/earlyGrab.qml
@@ -0,0 +1,25 @@
+import QtQuick
+import Test
+
+Window {
+ id: window
+ width: 400
+ height: 400
+ color: "red"
+
+ // Important for the test to set visible early on, not wait until
+ // show() from C++. What is really verified here is that the
+ // content grabbing takes the real window state into account
+ // (visible vs. exposed).
+ visible: true
+
+ Grabber {
+ id: grabber
+ objectName: "grabber"
+ }
+
+ Item {
+ anchors.fill: parent
+ Component.onCompleted: grabber.grab(window)
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index edfe487c5e..8d1fd7c0ba 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -446,6 +446,7 @@ private slots:
void grab_data();
void grab();
+ void earlyGrab();
void multipleWindows();
void animationsWhileHidden();
@@ -1564,6 +1565,40 @@ void tst_qquickwindow::grab()
}
}
+class Grabber : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE void grab(QObject *obj) {
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(obj);
+ images.append(window->grabWindow());
+ }
+ QVector<QImage> images;
+};
+
+void tst_qquickwindow::earlyGrab()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+
+ qmlRegisterType<Grabber>("Test", 1, 0, "Grabber");
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("earlyGrab.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->setTitle(QTest::currentTestFunction());
+
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ Grabber *grabber = qobject_cast<Grabber *>(window->findChild<QObject *>("grabber"));
+ QVERIFY(grabber);
+ QCOMPARE(grabber->images.count(), 1);
+ QVERIFY(!grabber->images[0].isNull());
+ QCOMPARE(grabber->images[0].convertToFormat(QImage::Format_RGBX8888).pixel(10, 20), QColor(Qt::red).rgb());
+}
+
void tst_qquickwindow::multipleWindows()
{
QList<QQuickWindow *> windows;