summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/kernel')
-rw-r--r--tests/auto/widgets/kernel/CMakeLists.txt9
-rw-r--r--tests/auto/widgets/kernel/qaction/CMakeLists.txt12
-rw-r--r--tests/auto/widgets/kernel/qaction/tst_qaction.cpp154
-rw-r--r--tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp29
-rw-r--r--tests/auto/widgets/kernel/qapplication/BLACKLIST2
-rw-r--r--tests/auto/widgets/kernel/qapplication/CMakeLists.txt14
-rw-r--r--tests/auto/widgets/kernel/qapplication/desktopsettingsaware/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp29
-rw-r--r--tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qapplication/modal/base.cpp29
-rw-r--r--tests/auto/widgets/kernel/qapplication/modal/base.h29
-rw-r--r--tests/auto/widgets/kernel/qapplication/modal/main.cpp29
-rw-r--r--tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt23
-rw-r--r--tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp316
-rw-r--r--tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp37
-rw-r--r--tests/auto/widgets/kernel/qformlayout/BLACKLIST3
-rw-r--r--tests/auto/widgets/kernel/qformlayout/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp230
-rw-r--r--tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp53
-rw-r--r--tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp45
-rw-r--r--tests/auto/widgets/kernel/qlayout/CMakeLists.txt28
-rw-r--r--tests/auto/widgets/kernel/qlayout/testdata.qrc5
-rw-r--r--tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp41
-rw-r--r--tests/auto/widgets/kernel/qshortcut/CMakeLists.txt26
-rw-r--r--tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp257
-rw-r--r--tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp36
-rw-r--r--tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt12
-rw-r--r--tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp39
-rw-r--r--tests/auto/widgets/kernel/qtooltip/CMakeLists.txt12
-rw-r--r--tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp64
-rw-r--r--tests/auto/widgets/kernel/qwidget/BLACKLIST61
-rw-r--r--tests/auto/widgets/kernel/qwidget/CMakeLists.txt50
-rw-r--r--tests/auto/widgets/kernel/qwidget/qwidget.qrc8
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnapbin722 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnapbin1509 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnapbin7965 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnapbin8265 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnapbin710 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnapbin1497 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnapbin7953 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnapbin8253 -> 0 bytes
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp2972
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h35
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm57
-rw-r--r--tests/auto/widgets/kernel/qwidget_window/BLACKLIST4
-rw-r--r--tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt12
-rw-r--r--tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp352
-rw-r--r--tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp33
-rw-r--r--tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp29
-rw-r--r--tests/auto/widgets/kernel/qwidgetrepaintmanager/CMakeLists.txt20
-rw-r--r--tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp831
-rw-r--r--tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qwidgetsvariant/tst_qwidgetsvariant.cpp29
-rw-r--r--tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt11
-rw-r--r--tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp174
62 files changed, 4678 insertions, 1684 deletions
diff --git a/tests/auto/widgets/kernel/CMakeLists.txt b/tests/auto/widgets/kernel/CMakeLists.txt
index c94c48aaa4..2d4880ea3c 100644
--- a/tests/auto/widgets/kernel/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from kernel.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qapplication)
add_subdirectory(qboxlayout)
@@ -9,16 +10,14 @@ add_subdirectory(qstackedlayout)
add_subdirectory(qtooltip)
add_subdirectory(qwidget_window)
add_subdirectory(qwidgetmetatype)
+add_subdirectory(qwidgetrepaintmanager)
add_subdirectory(qwidgetsvariant)
add_subdirectory(qwindowcontainer)
add_subdirectory(qsizepolicy)
if(NOT APPLE)
add_subdirectory(qgesturerecognizer)
endif()
-# QTBUG-87668 # special case
-if(NOT ANDROID)
- add_subdirectory(qwidget)
-endif()
+add_subdirectory(qwidget)
if(QT_FEATURE_shortcut)
add_subdirectory(qshortcut)
endif()
diff --git a/tests/auto/widgets/kernel/qaction/CMakeLists.txt b/tests/auto/widgets/kernel/qaction/CMakeLists.txt
index dd70d5448f..9d1985da0b 100644
--- a/tests/auto/widgets/kernel/qaction/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qaction/CMakeLists.txt
@@ -1,15 +1,23 @@
-# Generated from qaction.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qaction Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qaction LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qaction
SOURCES
tst_qaction.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
index 63d49e1216..36985c0de3 100644
--- a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
+++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QDialog>
#include <QMainWindow>
@@ -36,10 +11,14 @@
#include <qaction.h>
#include <qactiongroup.h>
#include <qmenu.h>
+#include <qmenubar.h>
+#include <qtoolbar.h>
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
+#include <QtWidgets/private/qapplication_p.h>
+
class tst_QAction : public QObject
{
Q_OBJECT
@@ -65,6 +44,8 @@ private slots:
void disableShortcutsWithBlockedWidgets_data();
void disableShortcutsWithBlockedWidgets();
void shortcutFromKeyEvent(); // QTBUG-48325
+ void disableShortcutInMenuAction_data();
+ void disableShortcutInMenuAction();
#endif
private:
@@ -132,7 +113,7 @@ void tst_QAction::actionEvent()
// add action
MyWidget testWidget(this);
testWidget.show();
- QApplication::setActiveWindow(&testWidget);
+ QApplicationPrivate::setActiveWindow(&testWidget);
testWidget.addAction(&a);
qApp->processEvents();
@@ -162,7 +143,7 @@ void tst_QAction::alternateShortcuts()
MyWidget testWidget(this);
testWidget.show();
- QApplication::setActiveWindow(&testWidget);
+ QApplicationPrivate::setActiveWindow(&testWidget);
{
QAction act(&testWidget);
@@ -174,11 +155,11 @@ void tst_QAction::alternateShortcuts()
act.setAutoRepeat(true);
QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier);
- QCOMPARE(spy.count(), 1); //act should have been triggered
+ QCOMPARE(spy.size(), 1); //act should have been triggered
act.setAutoRepeat(false);
QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier);
- QCOMPARE(spy.count(), 2); //act should have been triggered a 2nd time
+ QCOMPARE(spy.size(), 2); //act should have been triggered a 2nd time
//end of the scope of the action, it will be destroyed and removed from wid
//This action should also unregister its shortcuts
@@ -193,7 +174,7 @@ void tst_QAction::keysequence()
{
MyWidget testWidget(this);
testWidget.show();
- QApplication::setActiveWindow(&testWidget);
+ QApplicationPrivate::setActiveWindow(&testWidget);
{
QAction act(&testWidget);
@@ -208,12 +189,12 @@ void tst_QAction::keysequence()
act.setAutoRepeat(true);
QTest::keySequence(&testWidget, ks);
QCoreApplication::processEvents();
- QCOMPARE(spy.count(), 1); // act should have been triggered
+ QCOMPARE(spy.size(), 1); // act should have been triggered
act.setAutoRepeat(false);
QTest::keySequence(&testWidget, ks);
QCoreApplication::processEvents();
- QCOMPARE(spy.count(), 2); //act should have been triggered a 2nd time
+ QCOMPARE(spy.size(), 2); //act should have been triggered a 2nd time
// end of the scope of the action, it will be destroyed and removed from widget
// This action should also unregister its shortcuts
@@ -227,7 +208,7 @@ void tst_QAction::enabledVisibleInteraction()
{
MyWidget testWidget(this);
testWidget.show();
- QApplication::setActiveWindow(&testWidget);
+ QApplicationPrivate::setActiveWindow(&testWidget);
QAction act(nullptr);
// check defaults
@@ -249,15 +230,15 @@ void tst_QAction::enabledVisibleInteraction()
act.setEnabled(true);
act.setVisible(false);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
- QCOMPARE(spy.count(), 0); //act is not visible, so don't trigger
+ QCOMPARE(spy.size(), 0); //act is not visible, so don't trigger
act.setVisible(false);
act.setEnabled(true);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
- QCOMPARE(spy.count(), 0); //act is not visible, so don't trigger
+ QCOMPARE(spy.size(), 0); //act is not visible, so don't trigger
act.setVisible(true);
act.setEnabled(true);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
- QCOMPARE(spy.count(), 1); //act is visible and enabled, so trigger
+ QCOMPARE(spy.size(), 1); //act is visible and enabled, so trigger
}
#endif // QT_CONFIG(shortcut)
@@ -275,12 +256,12 @@ void tst_QAction::task229128TriggeredSignalWhenInActiongroup()
QSignalSpy actionSpy(checkedAction, QOverload<bool>::of(&QAction::triggered));
QSignalSpy actionGroupSpy(&ag, QOverload<QAction*>::of(&QActionGroup::triggered));
- QCOMPARE(actionGroupSpy.count(), 0);
- QCOMPARE(actionSpy.count(), 0);
+ QCOMPARE(actionGroupSpy.size(), 0);
+ QCOMPARE(actionSpy.size(), 0);
checkedAction->trigger();
// check that both the group and the action have emitted the signal
- QCOMPARE(actionGroupSpy.count(), 1);
- QCOMPARE(actionSpy.count(), 1);
+ QCOMPARE(actionGroupSpy.size(), 1);
+ QCOMPARE(actionSpy.size(), 1);
}
#if QT_CONFIG(shortcut)
@@ -292,7 +273,7 @@ void tst_QAction::repeat()
MyWidget testWidget(this);
testWidget.show();
- QApplication::setActiveWindow(&testWidget);
+ QApplicationPrivate::setActiveWindow(&testWidget);
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
QAction act(&testWidget);
@@ -303,7 +284,7 @@ void tst_QAction::repeat()
act.setAutoRepeat(true);
QTest::keyPress(&testWidget, Qt::Key_F);
QTest::keyRelease(&testWidget, Qt::Key_F);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
spy.clear();
QTest::keyPress(&testWidget, Qt::Key_F);
@@ -311,7 +292,7 @@ void tst_QAction::repeat()
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
spy.clear();
act.setAutoRepeat(false);
@@ -319,14 +300,14 @@ void tst_QAction::repeat()
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
spy.clear();
act.setAutoRepeat(true);
QTest::keyPress(&testWidget, Qt::Key_F);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_QAction::disableShortcutsWithBlockedWidgets_data()
@@ -371,12 +352,12 @@ void tst_QAction::disableShortcutsWithBlockedWidgets()
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
- QApplication::setActiveWindow(&window);
+ QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QSignalSpy spy(&action, &QAction::triggered);
QTest::keyPress(&window, Qt::Key_1);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
class ShortcutOverrideWidget : public QWidget
@@ -414,10 +395,83 @@ void tst_QAction::shortcutFromKeyEvent()
// shortcut route for us
QKeyEvent e(QEvent::KeyPress, Qt::Key_1, Qt::NoModifier);
QApplication::sendEvent(&testWidget, &e);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(testWidget.shortcutOverrideCount, 1);
}
+/*
+ Ignore actions in menus whose menu action has been hidden or disabled.
+ The menu entry will not be in the menu bar or parent menu, so the action
+ is not reachable through interactive means. QTBUG-25743
+*/
+void tst_QAction::disableShortcutInMenuAction_data()
+{
+ QTest::addColumn<QByteArray>("property");
+
+ QTest::addRow("visible") << QByteArray("visible");
+ QTest::addRow("enabled") << QByteArray("enabled");
+}
+
+void tst_QAction::disableShortcutInMenuAction()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
+ QFETCH(QByteArray, property);
+
+ QMainWindow mw;
+ QMenu *testMenu = mw.menuBar()->addMenu("Test");
+ QAction *testAction = testMenu->addAction("Test Action");
+ testAction->setShortcut(Qt::ControlModifier | Qt::Key_A);
+ QToolBar *toolBar = new QToolBar;
+ mw.addToolBar(toolBar);
+
+ mw.show();
+ QVERIFY(QTest::qWaitForWindowActive(&mw));
+
+ int expectedTriggerCount = 0;
+ QSignalSpy spy(testAction, &QAction::triggered);
+
+ QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), ++expectedTriggerCount);
+
+ testMenu->menuAction()->setProperty(property, false);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), expectedTriggerCount);
+
+ testMenu->menuAction()->setProperty(property, true);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), ++expectedTriggerCount);
+
+ // If the action lives somewhere else, then keep firing even
+ // if the menu has been hidden or disabled.
+ toolBar->addAction(testAction);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), ++expectedTriggerCount);
+
+ testMenu->menuAction()->setProperty(property, false);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), ++expectedTriggerCount);
+
+ // unless all other widgets in which the action lives have
+ // been hidden...
+ toolBar->hide();
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), expectedTriggerCount);
+
+ // ... or disabled
+ toolBar->show();
+ toolBar->setEnabled(false);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), expectedTriggerCount);
+
+ // back to normal
+ toolBar->setEnabled(true);
+ QApplication::sendEvent(&mw, &event);
+ QCOMPARE(spy.size(), ++expectedTriggerCount);
+}
+
#endif // QT_CONFIG(shortcut)
QTEST_MAIN(tst_QAction)
diff --git a/tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt b/tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt
index 927802103c..e26ee75bc1 100644
--- a/tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qactiongroup.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qactiongroup Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qactiongroup LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qactiongroup
SOURCES
tst_qactiongroup.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp
index 7462fd8bbf..0d42340bfb 100644
--- a/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp
+++ b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/kernel/qapplication/BLACKLIST b/tests/auto/widgets/kernel/qapplication/BLACKLIST
index cce10602e4..c68c7d6b14 100644
--- a/tests/auto/widgets/kernel/qapplication/BLACKLIST
+++ b/tests/auto/widgets/kernel/qapplication/BLACKLIST
@@ -1,5 +1,3 @@
-[sendEventsOnProcessEvents]
-ubuntu-20.04
[touchEventPropagation]
# QTBUG-66745
opensuse-leap
diff --git a/tests/auto/widgets/kernel/qapplication/CMakeLists.txt b/tests/auto/widgets/kernel/qapplication/CMakeLists.txt
index 3bb7e31691..524db06560 100644
--- a/tests/auto/widgets/kernel/qapplication/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qapplication/CMakeLists.txt
@@ -1,5 +1,17 @@
-# Generated from qapplication.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qapplication LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
add_subdirectory(desktopsettingsaware)
add_subdirectory(modal)
add_subdirectory(test)
+
+add_dependencies(tst_qapplication
+ desktopsettingsaware_helper
+ modal_helper
+)
diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/CMakeLists.txt b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/CMakeLists.txt
index a391d5b13d..f094a451d2 100644
--- a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/CMakeLists.txt
@@ -1,15 +1,16 @@
-# Generated from desktopsettingsaware.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## desktopsettingsaware Binary:
#####################################################################
-qt_internal_add_executable(desktopsettingsaware_helper # special case
+qt_internal_add_executable(desktopsettingsaware_helper
SOURCES
main.cpp
- OUTPUT_DIRECTORY # special case
- ${CMAKE_CURRENT_BINARY_DIR}/.. # special case
- PUBLIC_LIBRARIES
+ OUTPUT_DIRECTORY
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp
index 5e86bcb529..1bf3eef55c 100644
--- a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp
+++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QApplication>
diff --git a/tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt b/tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt
index 95c429f936..79c5660650 100644
--- a/tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt
@@ -1,16 +1,17 @@
-# Generated from modal.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## modal Binary:
#####################################################################
-qt_internal_add_executable(modal_helper # special case
+qt_internal_add_executable(modal_helper
SOURCES
base.cpp base.h
main.cpp
- OUTPUT_DIRECTORY # special case
- ${CMAKE_CURRENT_BINARY_DIR}/.. # special case
- PUBLIC_LIBRARIES
+ OUTPUT_DIRECTORY
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.cpp b/tests/auto/widgets/kernel/qapplication/modal/base.cpp
index 249d402f2e..49a90723dd 100644
--- a/tests/auto/widgets/kernel/qapplication/modal/base.cpp
+++ b/tests/auto/widgets/kernel/qapplication/modal/base.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "base.h"
diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.h b/tests/auto/widgets/kernel/qapplication/modal/base.h
index 153d9ca420..168da92f97 100644
--- a/tests/auto/widgets/kernel/qapplication/modal/base.h
+++ b/tests/auto/widgets/kernel/qapplication/modal/base.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef BASE_H
#define BASE_H
diff --git a/tests/auto/widgets/kernel/qapplication/modal/main.cpp b/tests/auto/widgets/kernel/qapplication/modal/main.cpp
index 9dcb6732fa..3f3496834d 100644
--- a/tests/auto/widgets/kernel/qapplication/modal/main.cpp
+++ b/tests/auto/widgets/kernel/qapplication/modal/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QApplication>
#include "base.h"
diff --git a/tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt b/tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt
index ad5209f9bf..fc80b8af7e 100644
--- a/tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Generated from test.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## test Test:
@@ -8,35 +9,23 @@
list(APPEND test_data "../tmp/README")
list(APPEND test_data "../modal")
-qt_internal_add_test(tst_qapplication # special case
+qt_internal_add_test(tst_qapplication
SOURCES
../tst_qapplication.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
TESTDATA ${test_data}
- OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.." # special case
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
)
## Scopes:
#####################################################################
-qt_internal_extend_target(tst_qapplication CONDITION builtin_testdata # special case
+qt_internal_extend_target(tst_qapplication CONDITION builtin_testdata
DEFINES
BUILTIN_TESTDATA
)
-
-#### Keys ignored in scope 3:.:.:test.pro:NOT ANDROID:
-# SUBPROGRAMS = "desktopsettingsaware" "modal"
-
-#### Keys ignored in scope 6:.:.:test.pro:NOT ANDROID:
-# TEST_HELPER_INSTALLS = "../debug/helper"
-
-#### Keys ignored in scope 8:.:.:test.pro:NOT ANDROID:
-# TEST_HELPER_INSTALLS = "../release/helper"
-
-#### Keys ignored in scope 10:.:.:test.pro:NOT ANDROID:
-# TEST_HELPER_INSTALLS = "../helper"
diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
index 8216cfbab0..b71a7a0a31 100644
--- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#define QT_STATICPLUGIN
#include <QtWidgets/qstyleplugin.h>
@@ -119,12 +94,15 @@ private slots:
void libraryPaths_qt_plugin_path_2();
#endif
+#ifdef QT_BUILD_INTERNAL
void sendPostedEvents();
+#endif // ifdef QT_BUILD_INTERNAL
void thread();
void desktopSettingsAware();
void setActiveWindow();
+ void activateDeactivateEvent();
void focusWidget();
void focusChanged();
@@ -152,6 +130,7 @@ private slots:
void wheelEventPropagation();
void qtbug_12673();
+ void qtbug_103611();
void noQuitOnHide();
void globalStaticObjectDestruction(); // run this last
@@ -187,6 +166,21 @@ void tst_QApplication::sendEventsOnProcessEvents()
QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1)));
QCoreApplication::processEvents();
+
+#ifdef Q_OS_LINUX
+ if ((QSysInfo::productType() == "rhel" && QSysInfo::productVersion().startsWith(u'9'))
+ || (QSysInfo::productType() == "ubuntu" && QSysInfo::productVersion().startsWith(u'2')))
+ {
+ QFile f("/proc/self/maps");
+ QVERIFY(f.open(QIODevice::ReadOnly));
+
+ QByteArray libs = f.readAll();
+ if (libs.contains("libqgtk3.") || libs.contains("libqgtk3TestInfix.")) {
+ QEXPECT_FAIL("", "Fails if qgtk3 (Glib) is loaded, see QTBUG-87137", Abort);
+ }
+ }
+#endif
+
QVERIFY(spy.recordedEvents.contains(QEvent::User + 1));
}
@@ -239,10 +233,12 @@ void tst_QApplication::staticSetup()
EventWatcher()
{
qApp->installEventFilter(this);
+#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QObject::connect(qApp, &QApplication::paletteChanged, [&]{ ++palette_changed; });
QObject::connect(qApp, &QApplication::fontChanged, [&]{ ++font_changed; });
QT_WARNING_POP
+#endif
}
protected:
@@ -272,8 +268,13 @@ QT_WARNING_POP
font.setBold(!font.bold());
qApp->setFont(font);
QApplication::processEvents();
+#if QT_DEPRECATED_SINCE(6, 0)
QCOMPARE(watcher.palette_changed, 2);
QCOMPARE(watcher.font_changed, 2);
+#else
+ QCOMPARE(watcher.palette_changed, 1);
+ QCOMPARE(watcher.font_changed, 1);
+#endif
}
@@ -310,10 +311,10 @@ void tst_QApplication::alert()
QApplication::alert(&widget, -1);
QApplication::alert(&widget, 250);
widget2.activateWindow();
- QApplication::setActiveWindow(&widget2);
+ QApplicationPrivate::setActiveWindow(&widget2);
QApplication::alert(&widget, 0);
widget.activateWindow();
- QApplication::setActiveWindow(&widget);
+ QApplicationPrivate::setActiveWindow(&widget);
QApplication::alert(&widget, 200);
}
@@ -502,7 +503,7 @@ static char **QString2cstrings(const QString &args)
static QByteArrayList cache;
const auto &list = QStringView{ args }.split(' ');
- auto argarray = new char*[list.count() + 1];
+ auto argarray = new char*[list.size() + 1];
int i = 0;
for (; i < list.size(); ++i ) {
@@ -591,7 +592,7 @@ void tst_QApplication::lastWindowClosed()
QTimer::singleShot(1000, dialog.data(), &QDialog::accept);
dialog->exec();
QVERIFY(dialog);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QPointer<CloseWidget>widget = new CloseWidget;
widget->setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("CloseWidget"));
@@ -600,7 +601,7 @@ void tst_QApplication::lastWindowClosed()
QObject::connect(&app, &QGuiApplication::lastWindowClosed, widget.data(), &QObject::deleteLater);
QCoreApplication::exec();
QVERIFY(!widget);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
spy.clear();
delete dialog;
@@ -618,7 +619,7 @@ void tst_QApplication::lastWindowClosed()
QTimer::singleShot(1000, &app, &QApplication::closeAllWindows);
QCoreApplication::exec();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
class QuitOnLastWindowClosedDialog : public QDialog
@@ -651,8 +652,8 @@ public slots:
other.exec();
// verify that the eventloop ran and let the timer fire
- QCOMPARE(spy.count(), 1);
- QCOMPARE(appSpy.count(), 1);
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE(appSpy.size(), 1);
}
private:
@@ -677,7 +678,7 @@ public slots:
timer1.setSingleShot(true);
timer1.start(1000);
dialog.exec();
- QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy1.size(), 1);
show();
}
@@ -698,7 +699,7 @@ void tst_QApplication::quitOnLastWindowClosed()
QCoreApplication::exec();
// lastWindowClosed() signal should only be sent after the last dialog is closed
- QCOMPARE(appSpy.count(), 2);
+ QCOMPARE(appSpy.size(), 2);
}
{
int argc = 0;
@@ -713,8 +714,8 @@ void tst_QApplication::quitOnLastWindowClosed()
timer1.setSingleShot(true);
timer1.start(1000);
dialog.exec();
- QCOMPARE(spy1.count(), 1);
- QCOMPARE(appSpy.count(), 0);
+ QCOMPARE(spy1.size(), 1);
+ QCOMPARE(appSpy.size(), 0);
QTimer timer2;
connect(&timer2, &QTimer::timeout, &app, &QCoreApplication::quit);
@@ -723,8 +724,8 @@ void tst_QApplication::quitOnLastWindowClosed()
timer2.start(1000);
int returnValue = QCoreApplication::exec();
QCOMPARE(returnValue, 0);
- QCOMPARE(spy2.count(), 1);
- QCOMPARE(appSpy.count(), 0);
+ QCOMPARE(spy2.size(), 1);
+ QCOMPARE(appSpy.size(), 0);
}
{
int argc = 0;
@@ -755,8 +756,8 @@ void tst_QApplication::quitOnLastWindowClosed()
QCoreApplication::exec();
- QCOMPARE(spy.count(), 1);
- QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit
+ QCOMPARE(spy.size(), 1);
+ QVERIFY(spy2.size() < 15); // Should be around 10 if closing caused the quit
}
bool quitApplicationTriggered = false;
@@ -786,13 +787,13 @@ void tst_QApplication::quitOnLastWindowClosed()
QCoreApplication::exec();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(quitApplicationTriggered);
}
{
int argc = 0;
QApplication app(argc, nullptr);
- QSignalSpy appSpy(&app, &QApplication::lastWindowClosed);
+ QSignalSpy appSpy(&app, &QGuiApplication::lastWindowClosed);
// exec a dialog for 1 second, then show the window
QuitOnLastWindowClosedWindow window;
@@ -808,8 +809,8 @@ void tst_QApplication::quitOnLastWindowClosed()
QCOMPARE(returnValue, 0);
// failure here means the timer above didn't fire, and the
// quit was caused the dialog being closed (not the window)
- QCOMPARE(timerSpy.count(), 1);
- QCOMPARE(appSpy.count(), 2);
+ QCOMPARE(timerSpy.size(), 1);
+ QCOMPARE(appSpy.size(), 2);
}
{
int argc = 0;
@@ -858,7 +859,7 @@ void tst_QApplication::quitOnLastWindowClosed()
QTimer::singleShot(100, &w1, &QWidget::close);
QCoreApplication::exec();
- QVERIFY(timerSpy.count() < 10);
+ QVERIFY(timerSpy.size() < 10);
}
}
@@ -902,6 +903,7 @@ void tst_QApplication::closeAllWindows()
{
int argc = 0;
QApplication app(argc, nullptr);
+ app.setAttribute(Qt::AA_DontUseNativeDialogs, true);
// create some windows
new QWidget;
@@ -910,7 +912,7 @@ void tst_QApplication::closeAllWindows()
// show all windows
auto topLevels = QApplication::topLevelWidgets();
- for (QWidget *w : qAsConst(topLevels)) {
+ for (QWidget *w : std::as_const(topLevels)) {
w->show();
QVERIFY(QTest::qWaitForWindowExposed(w));
}
@@ -927,14 +929,14 @@ void tst_QApplication::closeAllWindows()
PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget;
// show all windows
topLevels = QApplication::topLevelWidgets();
- for (QWidget *w : qAsConst(topLevels)) {
+ for (QWidget *w : std::as_const(topLevels)) {
w->show();
QVERIFY(QTest::qWaitForWindowExposed(w));
}
// close the last window to open the prompt (eventloop recurses)
promptOnCloseWidget->close();
// all windows should not be visible, except the one that opened the prompt
- for (QWidget *w : qAsConst(topLevels)) {
+ for (QWidget *w : std::as_const(topLevels)) {
if (w == promptOnCloseWidget)
QVERIFY(w->isVisible());
else
@@ -946,8 +948,8 @@ void tst_QApplication::closeAllWindows()
bool isPathListIncluded(const QStringList &l, const QStringList &r)
{
- int size = r.count();
- if (size > l.count())
+ int size = r.size();
+ if (size > l.size())
return false;
#if defined (Q_OS_WIN)
Qt::CaseSensitivity cs = Qt::CaseInsensitive;
@@ -955,13 +957,13 @@ bool isPathListIncluded(const QStringList &l, const QStringList &r)
Qt::CaseSensitivity cs = Qt::CaseSensitive;
#endif
int i = 0, j = 0;
- for ( ; i < l.count() && j < r.count(); ++i) {
+ for ( ; i < l.size() && j < r.size(); ++i) {
if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) {
++j;
i = -1;
}
}
- return j == r.count();
+ return j == r.size();
}
#if QT_CONFIG(library)
@@ -1021,7 +1023,7 @@ void tst_QApplication::libraryPaths()
{
qCDebug(lcTests) << "Initial library path:" << QApplication::libraryPaths();
- int count = QApplication::libraryPaths().count();
+ int count = QApplication::libraryPaths().size();
#if 0
// this test doesn't work if KDE 4 is installed
QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths()
@@ -1030,9 +1032,9 @@ void tst_QApplication::libraryPaths()
QApplication::addLibraryPath(installPathPlugins);
qCDebug(lcTests) << "installPathPlugins" << installPathPlugins;
qCDebug(lcTests) << "After adding plugins path:" << QApplication::libraryPaths();
- QCOMPARE(QApplication::libraryPaths().count(), count);
+ QCOMPARE(QApplication::libraryPaths().size(), count);
QApplication::addLibraryPath(testDir);
- QCOMPARE(QApplication::libraryPaths().count(), count + 1);
+ QCOMPARE(QApplication::libraryPaths().size(), count + 1);
// creating QApplication adds the applicationDirPath to the libraryPath
int argc = 1;
@@ -1042,19 +1044,19 @@ void tst_QApplication::libraryPaths()
// On Windows CE these are identical and might also be the case for other
// systems too
if (appDirPath != installPathPlugins)
- QCOMPARE(QApplication::libraryPaths().count(), count + 2);
+ QCOMPARE(QApplication::libraryPaths().size(), count + 2);
}
{
int argc = 1;
QApplication app(argc, &argv0);
qCDebug(lcTests) << "Initial library path:" << QCoreApplication::libraryPaths();
- int count = QCoreApplication::libraryPaths().count();
+ int count = QCoreApplication::libraryPaths().size();
QString installPathPlugins = QLibraryInfo::path(QLibraryInfo::PluginsPath);
QCoreApplication::addLibraryPath(installPathPlugins);
qCDebug(lcTests) << "installPathPlugins" << installPathPlugins;
qCDebug(lcTests) << "After adding plugins path:" << QCoreApplication::libraryPaths();
- QCOMPARE(QCoreApplication::libraryPaths().count(), count);
+ QCOMPARE(QCoreApplication::libraryPaths().size(), count);
QString appDirPath = QCoreApplication::applicationDirPath();
@@ -1062,14 +1064,14 @@ void tst_QApplication::libraryPaths()
QCoreApplication::addLibraryPath(appDirPath + "/..");
qCDebug(lcTests) << "appDirPath" << appDirPath;
qCDebug(lcTests) << "After adding appDirPath && appDirPath + /..:" << QCoreApplication::libraryPaths();
- QCOMPARE(QCoreApplication::libraryPaths().count(), count + 1);
+ QCOMPARE(QCoreApplication::libraryPaths().size(), count + 1);
#ifdef Q_OS_MACOS
QCoreApplication::addLibraryPath(appDirPath + "/../MacOS");
#else
QCoreApplication::addLibraryPath(appDirPath + "/tmp/..");
#endif
qCDebug(lcTests) << "After adding appDirPath + /tmp/..:" << QCoreApplication::libraryPaths();
- QCOMPARE(QCoreApplication::libraryPaths().count(), count + 1);
+ QCOMPARE(QCoreApplication::libraryPaths().size(), count + 1);
}
}
@@ -1136,11 +1138,12 @@ void tst_QApplication::libraryPaths_qt_plugin_path_2()
<< QCoreApplication::applicationDirPath();
QVERIFY(isPathListIncluded(QCoreApplication::libraryPaths(), expected));
- qputenv("QT_PLUGIN_PATH", QByteArray());
+ qputenv("QT_PLUGIN_PATH", nullptr);
}
}
#endif
+#ifdef QT_BUILD_INTERNAL
class SendPostedEventsTester : public QObject
{
Q_OBJECT
@@ -1162,14 +1165,14 @@ void SendPostedEventsTester::doTest()
QPointer<SendPostedEventsTester> p = this;
QApplication::postEvent(this, new QEvent(QEvent::User));
// DeferredDelete should not be delivered until returning from this function
- QApplication::postEvent(this, new QDeferredDeleteEvent());
+ deleteLater();
QEventLoop eventLoop;
QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);
eventLoop.exec();
QVERIFY(p != nullptr);
- QCOMPARE(eventSpy.count(), 2);
+ QCOMPARE(eventSpy.size(), 2);
QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall));
QCOMPARE(eventSpy.at(1), int(QEvent::User));
eventSpy.clear();
@@ -1186,6 +1189,7 @@ void tst_QApplication::sendPostedEvents()
(void) QCoreApplication::exec();
QVERIFY(p.isNull());
}
+#endif
void tst_QApplication::thread()
{
@@ -1330,12 +1334,9 @@ void DeleteLaterWidget::checkDeleteLater()
void tst_QApplication::testDeleteLater()
{
-#ifdef Q_OS_MAC
- QSKIP("This test fails and then hangs on OS X, see QTBUG-24318");
-#endif
int argc = 0;
QApplication app(argc, nullptr);
- connect(&app, &QApplication::lastWindowClosed, &app, &QCoreApplication::quit);
+ connect(&app, &QGuiApplication::lastWindowClosed, &app, &QCoreApplication::quit);
DeleteLaterWidget *wgt = new DeleteLaterWidget(&app);
QTimer::singleShot(500, wgt, &DeleteLaterWidget::runTest);
@@ -1530,7 +1531,7 @@ void tst_QApplication::desktopSettingsAware()
environment += QLatin1String("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM=1");
testProcess.setEnvironment(environment);
#endif
- testProcess.start("desktopsettingsaware_helper");
+ testProcess.start("./desktopsettingsaware_helper");
QVERIFY2(testProcess.waitForStarted(),
qPrintable(QString::fromLatin1("Cannot start 'desktopsettingsaware_helper': %1").arg(testProcess.errorString())));
QVERIFY(testProcess.waitForFinished(10000));
@@ -1558,11 +1559,61 @@ void tst_QApplication::setActiveWindow()
delete pb2;
w->show();
- QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse)
+ QApplicationPrivate::setActiveWindow(w); // needs this on twm (focus follows mouse)
QVERIFY(pb1->hasFocus());
delete w;
}
+void tst_QApplication::activateDeactivateEvent()
+{
+ // Ensure that QWindows (other than QWidgetWindow)
+ // are activated / deactivated.
+ class Window : public QWindow
+ {
+ public:
+ using QWindow::QWindow;
+
+ int activateCount = 0;
+ int deactivateCount = 0;
+ protected:
+ bool event(QEvent *e) override
+ {
+ switch (e->type()) {
+ case QEvent::WindowActivate:
+ ++activateCount;
+ break;
+ case QEvent::WindowDeactivate:
+ ++deactivateCount;
+ break;
+ default:
+ break;
+ }
+ return QWindow::event(e);
+ }
+ };
+
+ int argc = 0;
+ QApplication app(argc, nullptr);
+
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
+ Window w1;
+ Window w2;
+
+ w1.show();
+ w1.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&w1));
+ QCOMPARE(w1.activateCount, 1);
+ QCOMPARE(w1.deactivateCount, 0);
+
+ w2.show();
+ w2.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&w2));
+ QCOMPARE(w1.deactivateCount, 1);
+ QCOMPARE(w2.activateCount, 1);
+}
+
void tst_QApplication::focusWidget()
{
int argc = 0;
@@ -1573,7 +1624,7 @@ void tst_QApplication::focusWidget()
QTextEdit te;
te.show();
- QApplication::setActiveWindow(&te);
+ QApplicationPrivate::setActiveWindow(&te);
QVERIFY(QTest::qWaitForWindowActive(&te));
const auto focusWidget = QApplication::focusWidget();
@@ -1589,7 +1640,7 @@ void tst_QApplication::focusWidget()
QTextEdit te(&w);
w.show();
- QApplication::setActiveWindow(&w);
+ QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
const auto focusWidget = QApplication::focusWidget();
@@ -1622,22 +1673,22 @@ void tst_QApplication::focusChanged()
hbox1.addWidget(&le1);
hbox1.addWidget(&pb1);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
parent1.show();
- QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
- QCOMPARE(spy.count(), 1);
- QCOMPARE(spy.at(0).count(), 2);
+ QApplicationPrivate::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
+ QCOMPARE(spy.size(), 1);
+ QCOMPARE(spy.at(0).size(), 2);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &le1);
QCOMPARE(now, QApplication::focusWidget());
QVERIFY(!old);
spy.clear();
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
pb1.setFocus();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &pb1);
@@ -1646,7 +1697,7 @@ void tst_QApplication::focusChanged()
spy.clear();
lb1.setFocus();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &lb1);
@@ -1655,7 +1706,7 @@ void tst_QApplication::focusChanged()
spy.clear();
lb1.clearFocus();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QVERIFY(!now);
@@ -1674,10 +1725,10 @@ void tst_QApplication::focusChanged()
hbox2.addWidget(&pb2);
parent2.show();
- QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse)
- QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows
- old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
- now = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(1));
+ QApplicationPrivate::setActiveWindow(&parent2); // needs this on twm (focus follows mouse)
+ QVERIFY(spy.size() > 0); // one for deactivation, one for activation on Windows
+ old = qvariant_cast<QWidget*>(spy.at(spy.size()-1).at(0));
+ now = qvariant_cast<QWidget*>(spy.at(spy.size()-1).at(1));
QCOMPARE(now, &le2);
QCOMPARE(now, QApplication::focusWidget());
QVERIFY(!old);
@@ -1702,10 +1753,10 @@ void tst_QApplication::focusChanged()
tab.simulate(now);
if (!tabAllControls) {
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QCOMPARE(now, QApplication::focusWidget());
} else {
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &pb2);
@@ -1715,11 +1766,11 @@ void tst_QApplication::focusChanged()
}
if (!tabAllControls) {
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QCOMPARE(now, QApplication::focusWidget());
} else {
tab.simulate(now);
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &le2);
@@ -1729,11 +1780,11 @@ void tst_QApplication::focusChanged()
}
if (!tabAllControls) {
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QCOMPARE(now, QApplication::focusWidget());
} else {
backtab.simulate(now);
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &pb2);
@@ -1744,12 +1795,12 @@ void tst_QApplication::focusChanged()
if (!tabAllControls) {
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QCOMPARE(now, QApplication::focusWidget());
old = &pb2;
} else {
backtab.simulate(now);
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &le2);
@@ -1760,10 +1811,10 @@ void tst_QApplication::focusChanged()
click.simulate(old);
if (!(pb2.focusPolicy() & Qt::ClickFocus)) {
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QCOMPARE(now, QApplication::focusWidget());
} else {
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &pb2);
@@ -1772,7 +1823,7 @@ void tst_QApplication::focusChanged()
spy.clear();
click.simulate(old);
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
old = qvariant_cast<QWidget*>(spy.at(0).at(0));
now = qvariant_cast<QWidget*>(spy.at(0).at(1));
QCOMPARE(now, &le2);
@@ -1782,16 +1833,16 @@ void tst_QApplication::focusChanged()
}
parent1.activateWindow();
- QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
- QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows
+ QApplicationPrivate::setActiveWindow(&parent1); // needs this on twm (focus follows mouse)
+ QVERIFY(spy.size() == 1 || spy.size() == 2); // one for deactivation, one for activation on Windows
//on windows, the change of focus is made in 2 steps
//(the focusChanged SIGNAL is emitted twice)
- if (spy.count()==1)
- old = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(0));
+ if (spy.size()==1)
+ old = qvariant_cast<QWidget*>(spy.at(spy.size()-1).at(0));
else
- old = qvariant_cast<QWidget*>(spy.at(spy.count()-2).at(0));
- now = qvariant_cast<QWidget*>(spy.at(spy.count()-1).at(1));
+ old = qvariant_cast<QWidget*>(spy.at(spy.size()-2).at(0));
+ now = qvariant_cast<QWidget*>(spy.at(spy.size()-1).at(1));
QCOMPARE(now, &le1);
QCOMPARE(now, QApplication::focusWidget());
QCOMPARE(old, &le2);
@@ -1865,7 +1916,7 @@ void tst_QApplication::focusMouseClick()
// front most widget has Qt::TabFocus, parent widget accepts clicks as well
// now send a mouse button press event and check what happens with the focus
// it should be given to the parent widget
- QMouseEvent ev(QEvent::MouseButtonPress, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ QMouseEvent ev(QEvent::MouseButtonPress, QPointF(), w.mapToGlobal(QPointF()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QSpontaneKeyEvent::setSpontaneous(&ev);
QVERIFY(ev.spontaneous());
qApp->notify(&w2, &ev);
@@ -2026,11 +2077,11 @@ void tst_QApplication::topLevelWidgets()
#endif
QCoreApplication::processEvents();
QVERIFY(QApplication::topLevelWidgets().contains(w));
- QCOMPARE(QApplication::topLevelWidgets().count(), 1);
+ QCOMPARE(QApplication::topLevelWidgets().size(), 1);
delete w;
w = nullptr;
QCoreApplication::processEvents();
- QCOMPARE(QApplication::topLevelWidgets().count(), 0);
+ QCOMPARE(QApplication::topLevelWidgets().size(), 0);
}
@@ -2447,7 +2498,7 @@ void tst_QApplication::wheelEventPropagation()
int vcount = 0;
int hcount = 0;
- for (const auto &event : qAsConst(events)) {
+ for (const auto &event : std::as_const(events)) {
const QPoint pixelDelta = event.orientation == Qt::Vertical ? QPoint(0, -scrollStep) : QPoint(-scrollStep, 0);
const QPoint angleDelta = event.orientation == Qt::Vertical ? QPoint(0, -120) : QPoint(-120, 0);
QWindowSystemInterface::handleWheelEvent(outerArea.windowHandle(), center, global,
@@ -2458,10 +2509,10 @@ void tst_QApplication::wheelEventPropagation()
else
++hcount;
QCoreApplication::processEvents();
- QCOMPARE(innerVSpy.count(), innerScrolls ? vcount : 0);
- QCOMPARE(innerHSpy.count(), innerScrolls ? hcount : 0);
- QCOMPARE(outerVSpy.count(), innerScrolls ? 0 : vcount);
- QCOMPARE(outerHSpy.count(), innerScrolls ? 0 : hcount);
+ QCOMPARE(innerVSpy.size(), innerScrolls ? vcount : 0);
+ QCOMPARE(innerHSpy.size(), innerScrolls ? hcount : 0);
+ QCOMPARE(outerVSpy.size(), innerScrolls ? 0 : vcount);
+ QCOMPARE(outerHSpy.size(), innerScrolls ? 0 : hcount);
}
}
@@ -2470,7 +2521,7 @@ void tst_QApplication::qtbug_12673()
#if QT_CONFIG(process)
QProcess testProcess;
QStringList arguments;
- testProcess.start("modal_helper", arguments);
+ testProcess.start("./modal_helper", arguments);
QVERIFY2(testProcess.waitForStarted(),
qPrintable(QString::fromLatin1("Cannot start 'modal_helper': %1").arg(testProcess.errorString())));
QVERIFY(testProcess.waitForFinished(20000));
@@ -2480,6 +2531,20 @@ void tst_QApplication::qtbug_12673()
#endif
}
+void tst_QApplication::qtbug_103611()
+{
+ {
+ int argc = 0;
+ QApplication app(argc, nullptr);
+ auto ll = QLocale().uiLanguages();
+ }
+ {
+ int argc = 0;
+ QApplication app(argc, nullptr);
+ auto ll = QLocale().uiLanguages();
+ }
+}
+
class NoQuitOnHideWidget : public QWidget
{
Q_OBJECT
@@ -2509,8 +2574,26 @@ public:
explicit ShowCloseShowWidget(bool showAgain, QWidget *parent = nullptr)
: QWidget(parent), showAgain(showAgain)
{
+ int timeout = 500;
+#ifdef Q_OS_ANDROID
+ // On Android, CI Android emulator is not running HW accelerated graphics and can be slow,
+ // use a longer timeout to avoid flaky failures
+ timeout = 1000;
+#endif
+ QTimer::singleShot(timeout, this, [] () { QCoreApplication::exit(1); });
+ }
+
+ bool shown = false;
+
+protected:
+ void showEvent(QShowEvent *) override
+ {
QTimer::singleShot(0, this, &ShowCloseShowWidget::doClose);
- QTimer::singleShot(500, this, [] () { QCoreApplication::exit(1); });
+ shown = true;
+ }
+ void hideEvent(QHideEvent *) override
+ {
+ shown = false;
}
private slots:
@@ -2526,16 +2609,21 @@ private:
void tst_QApplication::abortQuitOnShow()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Wayland: This crash, see QTBUG-123172.");
+
int argc = 0;
QApplication app(argc, nullptr);
ShowCloseShowWidget window1(false);
window1.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
window1.show();
+ QVERIFY(QTest::qWaitFor([&window1](){ return window1.shown; }));
QCOMPARE(QCoreApplication::exec(), 0);
ShowCloseShowWidget window2(true);
window2.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
window2.show();
+ QVERIFY(QTest::qWaitFor([&window2](){ return window2.shown; }));
QCOMPARE(QCoreApplication::exec(), 1);
}
@@ -2550,7 +2638,7 @@ void tst_QApplication::staticFunctions()
QApplication::activeModalWidget();
QApplication::focusWidget();
QApplication::activeWindow();
- QApplication::setActiveWindow(nullptr);
+ QApplicationPrivate::setActiveWindow(nullptr);
QApplication::widgetAt(QPoint(0, 0));
QApplication::topLevelAt(QPoint(0, 0));
QTest::ignoreMessage(QtWarningMsg, "Must construct a QApplication first.");
diff --git a/tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt b/tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt
index 8fdc0d21a9..5b60382fba 100644
--- a/tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qboxlayout.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qboxlayout Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qboxlayout LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qboxlayout
SOURCES
tst_qboxlayout.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
diff --git a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp
index a410a7bf00..4313d9891c 100644
--- a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp
+++ b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -141,7 +116,7 @@ void tst_QBoxLayout::insertLayout()
QCOMPARE(dummyParentLayout->count(), 1);
// add subLayout to another layout
- QTest::ignoreMessage(QtWarningMsg, "QLayout::addChildLayout: layout \"\" already has a parent");
+ QTest::ignoreMessage(QtWarningMsg, "QLayout::addChildLayout: layout QHBoxLayout \"\" already has a parent");
vbox->addLayout(subLayout);
QCOMPARE((subLayout->parent() == vbox), (vbox->count() == 1));
}
@@ -217,7 +192,7 @@ void tst_QBoxLayout::setStyleShouldChangeSpacing()
window.setWindowTitle(QTest::currentTestFunction());
QHBoxLayout *hbox = new QHBoxLayout(&window);
QPushButton *pb1 = new QPushButton(tr("The spacing between this"));
- QPushButton *pb2 = new QPushButton(tr("and this button should depend on the style of the parent widget"));;
+ QPushButton *pb2 = new QPushButton(tr("and this button should depend on the style of the parent widget"));
pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect);
pb2->setAttribute(Qt::WA_LayoutUsesWidgetRect);
hbox->addWidget(pb1);
@@ -542,14 +517,14 @@ void tst_QBoxLayout::testLayoutEngine()
QHBoxLayout box;
box.setSpacing(spacing);
int i;
- for (i = 0; i < itemDescriptions.count(); ++i) {
+ for (i = 0; i < itemDescriptions.size(); ++i) {
Descr descr = itemDescriptions.at(i);
LayoutItem *li = new LayoutItem(descr);
box.addItem(li);
box.setStretch(i, descr.stretch);
}
box.setGeometry(QRect(0,0,size,100));
- for (i = 0; i < expectedSizes.count(); ++i) {
+ for (i = 0; i < expectedSizes.size(); ++i) {
int xSize = expectedSizes.at(i);
int xPos = expectedPositions.at(i);
QLayoutItem *item = box.itemAt(i);
diff --git a/tests/auto/widgets/kernel/qformlayout/BLACKLIST b/tests/auto/widgets/kernel/qformlayout/BLACKLIST
deleted file mode 100644
index 375682e788..0000000000
--- a/tests/auto/widgets/kernel/qformlayout/BLACKLIST
+++ /dev/null
@@ -1,3 +0,0 @@
-# QTBUG-87401
-[wrapping]
-android
diff --git a/tests/auto/widgets/kernel/qformlayout/CMakeLists.txt b/tests/auto/widgets/kernel/qformlayout/CMakeLists.txt
index b084fe1634..9e1da4c6a3 100644
--- a/tests/auto/widgets/kernel/qformlayout/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qformlayout/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qformlayout.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qformlayout Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qformlayout LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qformlayout
SOURCES
tst_qformlayout.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
diff --git a/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp
index 4aa9f8ac2d..9638823538 100644
--- a/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp
+++ b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -135,6 +110,9 @@ private slots:
void takeRow_QLayout();
void setWidget();
void setLayout();
+ void hideShowRow();
+ void showWithHiddenRow();
+ void hiddenRowAndStretch();
/*
QLayoutItem *itemAt(int row, ItemRole role) const;
@@ -274,7 +252,9 @@ void tst_QFormLayout::wrapping()
fl->setRowWrapPolicy(QFormLayout::WrapLongRows);
QLineEdit *le = new QLineEdit;
- QLabel *lbl = new QLabel("A long label");
+ QLabel *lbl = new QLabel("A long label which is actually long enough to trigger wrapping,"
+ " even on Android and even if it is executed on a tiling window"
+ " manager which forces the window into fullscreen mode.");
le->setMinimumWidth(200);
fl->addRow(lbl, le);
@@ -814,6 +794,7 @@ void tst_QFormLayout::removeRow_QWidget()
QCOMPARE(layout->rowCount(), 0);
QWidget *w3 = new QWidget;
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayout::takeRow: Invalid widget");
layout->removeRow(w3);
delete w3;
}
@@ -854,6 +835,7 @@ void tst_QFormLayout::removeRow_QLayout()
QCOMPARE(layout->rowCount(), 0);
QHBoxLayout *l3 = new QHBoxLayout;
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayout::takeRow: Invalid layout");
layout->removeRow(l3);
delete l3;
}
@@ -893,6 +875,7 @@ void tst_QFormLayout::takeRow()
QCOMPARE(layout->rowCount(), 0);
QCOMPARE(result.fieldItem->widget(), w1.data());
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayout::takeRow: Invalid row 0");
result = layout->takeRow(0);
QVERIFY(!result.fieldItem);
@@ -933,6 +916,7 @@ void tst_QFormLayout::takeRow_QWidget()
QCOMPARE(layout->rowCount(), 0);
QWidget *w3 = new QWidget;
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayout::takeRow: Invalid widget");
result = layout->takeRow(w3);
delete w3;
@@ -980,6 +964,7 @@ void tst_QFormLayout::takeRow_QLayout()
QCOMPARE(layout->rowCount(), 0);
QHBoxLayout *l3 = new QHBoxLayout;
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayout::takeRow: Invalid layout");
result = layout->takeRow(l3);
delete l3;
@@ -1009,7 +994,9 @@ void tst_QFormLayout::setWidget()
QCOMPARE(layout.rowCount(), 6);
// should be ignored and generate warnings
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayoutPrivate::setItem: Cell (3, 1) already occupied");
layout.setWidget(3, QFormLayout::FieldRole, &w4);
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayoutPrivate::setItem: Invalid cell (-1, 1)");
layout.setWidget(-1, QFormLayout::FieldRole, &w4);
{
@@ -1077,7 +1064,9 @@ void tst_QFormLayout::setLayout()
QCOMPARE(layout.rowCount(), 6);
// should be ignored and generate warnings
+ QTest::ignoreMessage(QtWarningMsg, "QFormLayoutPrivate::setItem: Cell (3, 1) already occupied");
layout.setLayout(3, QFormLayout::FieldRole, &l4);
+ QTest::ignoreMessage(QtWarningMsg, "QLayout::addChildLayout: layout QHBoxLayout \"\" already has a parent");
layout.setLayout(-1, QFormLayout::FieldRole, &l4);
QCOMPARE(layout.count(), 3);
QCOMPARE(layout.rowCount(), 6);
@@ -1123,6 +1112,191 @@ void tst_QFormLayout::setLayout()
}
}
+void tst_QFormLayout::hideShowRow()
+{
+ QWidget topLevel;
+ QFormLayout layout;
+
+ const auto makeComplex = []{
+ QHBoxLayout *hboxField = new QHBoxLayout;
+ hboxField->addWidget(new QLineEdit("Left"));
+ hboxField->addWidget(new QLineEdit("Right"));
+ return hboxField;
+ };
+
+ layout.addRow("Label", new QLineEdit("one"));
+ layout.addRow("Label", new QLineEdit("two"));
+ layout.addRow("Label", new QLineEdit("three"));
+ layout.addRow("Label", makeComplex());
+ layout.addRow(new QLineEdit("five")); // spanning widget
+ layout.addRow(makeComplex()); // spanning layout
+
+ topLevel.setLayout(&layout);
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ // returns the top-left position of the items in a row
+ const auto rowPosition = [&layout](int row) {
+ QRect rect;
+ if (QLayoutItem *spanningItem = layout.itemAt(row, QFormLayout::SpanningRole)) {
+ rect = spanningItem->geometry();
+ } else {
+ if (QLayoutItem *labelItem = layout.itemAt(row, QFormLayout::LabelRole)) {
+ rect = labelItem->geometry();
+ }
+ if (QLayoutItem *fieldItem = layout.itemAt(row, QFormLayout::FieldRole)) {
+ rect |= fieldItem->geometry();
+ }
+ }
+ return rect.topLeft();
+ };
+
+ // returns the first widget in a row, even if that row is taken by a layout
+ const auto rowInputWidget = [&layout](int row) -> QWidget* {
+ auto fieldItem = layout.itemAt(row, QFormLayout::FieldRole);
+ if (!fieldItem)
+ return nullptr;
+ QWidget *fieldWidget = fieldItem->widget();
+ // we happen to know our layout structure
+ if (!fieldWidget)
+ fieldWidget = fieldItem->layout()->itemAt(0)->widget();
+ return fieldWidget;
+ };
+
+ // record the reference positions for all rows
+ QList<QPoint> rowPositions(layout.rowCount());
+ for (int row = 0; row < layout.rowCount(); ++row)
+ rowPositions[row] = rowPosition(row);
+
+ // hide each row in turn, the next row should take the space of the hidden row
+ for (int row = 0; row < layout.rowCount(); ++ row) {
+ layout.setRowVisible(row, false);
+ QVERIFY(!layout.isRowVisible(row));
+ if (row < layout.rowCount() - 1)
+ QTRY_COMPARE(rowPosition(row + 1), rowPositions[row]);
+ layout.setRowVisible(row, true);
+ QVERIFY(layout.isRowVisible(row));
+ }
+
+ // Hiding only the label or only the field doesn't hide the row.
+ for (int row = 0; row < layout.rowCount() - 1; ++row) {
+ const auto labelItem = layout.itemAt(0, QFormLayout::LabelRole);
+ if (labelItem) {
+ labelItem->widget()->hide();
+ QVERIFY(layout.isRowVisible(row));
+ QCOMPARE(rowPosition(row), rowPositions[row]);
+ layout.itemAt(0, QFormLayout::LabelRole)->widget()->show();
+ }
+ const auto fieldItem = layout.itemAt(0, QFormLayout::FieldRole);
+ if (fieldItem) {
+ fieldItem->widget()->hide();
+ QVERIFY(layout.isRowVisible(row));
+ QCOMPARE(rowPosition(row), rowPositions[row]);
+ layout.itemAt(0, QFormLayout::FieldRole)->widget()->show();
+ }
+ }
+
+ // If we hide both label and field, then the row should be considered hidden and the
+ // following row should move up into the space of the hidden row. We can only test
+ // this if both label and field are widgets, or if there is a spanning widget.
+ for (int row = 0; row < layout.rowCount() - 1; ++row) {
+ QWidget *labelWidget = nullptr;
+ if (auto labelItem = layout.itemAt(row, QFormLayout::LabelRole))
+ labelWidget = labelItem->widget();
+ QWidget *fieldWidget = nullptr;
+ if (auto fieldItem = layout.itemAt(row, QFormLayout::FieldRole))
+ fieldWidget = fieldItem->widget();
+
+ if (!fieldWidget)
+ continue;
+ if (labelWidget)
+ labelWidget->hide();
+ fieldWidget->hide();
+ QVERIFY(!layout.isRowVisible(row));
+ QVERIFY(!layout.isRowVisible(fieldWidget));
+ if (labelWidget)
+ QVERIFY(!layout.isRowVisible(labelWidget));
+ QTRY_COMPARE(rowPosition(row + 1), rowPositions[row]);
+ if (labelWidget)
+ labelWidget->show();
+ fieldWidget->show();
+ }
+
+ // hiding a row where a widget has focus must move focus to a widget in the next row
+ for (int row = 0; row < layout.rowCount(); ++row) {
+ QWidget *inputWidget = rowInputWidget(row);
+ QVERIFY(inputWidget);
+ inputWidget->setFocus();
+ layout.setRowVisible(row, false);
+ QVERIFY(!inputWidget->hasFocus());
+ }
+
+ // Now hide all rows, hide the toplevel widget, and show the toplevel widget again.
+ // None of the widgets inside must be visible.
+ for (int row = 0; row < layout.rowCount(); ++row)
+ layout.setRowVisible(row, false);
+ topLevel.hide();
+ topLevel.show();
+ for (int row = 0; row < layout.rowCount(); ++row)
+ QVERIFY(rowInputWidget(row)->isHidden());
+}
+
+void tst_QFormLayout::showWithHiddenRow()
+{
+ QWidget topLevel;
+ QFormLayout layout;
+
+ for (int row = 0; row < 3; ++row)
+ layout.addRow(QString("Label %1").arg(row), new QLineEdit);
+ layout.setRowVisible(1, false);
+
+ topLevel.setLayout(&layout);
+ topLevel.show();
+}
+
+/*
+ Test that hiding rows does not leave outdated layout data behind
+ in hidden items that results in out-of-bounds array access. See
+ QTBUG-109237.
+*/
+void tst_QFormLayout::hiddenRowAndStretch()
+{
+ QWidget topLevel;
+ QFormLayout layout;
+ layout.setRowWrapPolicy(QFormLayout::WrapAllRows);
+
+ // We need our own stretcher item so that QFormLayout doesn't insert
+ // it's own, as that would grow the size of the layout data array again.
+ QSpacerItem *stretch = new QSpacerItem(100, 100, QSizePolicy::Expanding, QSizePolicy::Expanding);
+ layout.setItem(0, QFormLayout::FieldRole, stretch);
+
+ QLabel *lastLabel = nullptr;
+ QLineEdit *lastField = nullptr;
+ for (int row = 1; row < 4; ++row) {
+ QLabel *label = new QLabel(QString("Label %1").arg(row));
+ label->setWordWrap(true);
+ QLineEdit *field = new QLineEdit;
+ layout.setWidget(row, QFormLayout::LabelRole, label);
+ layout.setWidget(row, QFormLayout::FieldRole, field);
+ if (row == 3) {
+ lastLabel = label;
+ lastField = field;
+ }
+ }
+
+ Q_ASSERT(lastLabel);
+ Q_ASSERT(lastField);
+
+ topLevel.setLayout(&layout);
+ topLevel.sizeHint();
+
+ lastLabel->setVisible(false);
+ lastField->setVisible(false);
+
+ // should not assert here
+ topLevel.show();
+}
+
void tst_QFormLayout::itemAt()
{
QWidget topLevel;
diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt b/tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt
index 9dfd6cb20c..ffa54992d3 100644
--- a/tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qgesturerecognizer.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qgesturerecognizer Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qgesturerecognizer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qgesturerecognizer
SOURCES
tst_qgesturerecognizer.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp
index b65f6a5ff6..cdab480d84 100644
--- a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp
+++ b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QTest>
@@ -53,6 +28,7 @@ private Q_SLOTS:
void pinchGesture();
void swipeGesture_data();
void swipeGesture();
+ void touchReplay();
#endif // !QT_NO_GESTURES
private:
@@ -95,7 +71,7 @@ TestWidget::TestWidget(const GestureTypeVector &gestureTypes)
{
setAttribute(Qt::WA_AcceptTouchEvents);
- foreach (Qt::GestureType gestureType, gestureTypes) {
+ for (Qt::GestureType gestureType : gestureTypes) {
grabGesture(gestureType);
m_receivedGestures.insert(gestureType, false);
}
@@ -293,7 +269,7 @@ void tst_QGestureRecognizer::swipeGesture()
// Press point #3
points.append(points.last() + fingerDistance);
- swipeSequence.press(points.size() - 1, points.last(), &widget);
+ swipeSequence.stationary(0).stationary(1).press(points.size() - 1, points.last(), &widget);
swipeSequence.commit();
Q_ASSERT(points.size() == swipePoints);
@@ -326,6 +302,25 @@ void tst_QGestureRecognizer::swipeGesture()
}
}
+void tst_QGestureRecognizer::touchReplay()
+{
+ const Qt::GestureType gestureType = Qt::TapGesture;
+ QWidget parent;
+ TestWidget widget(GestureTypeVector(1, gestureType));
+ widget.setParent(&parent);
+ widget.setGeometry(0, 0, 100, 100);
+ parent.adjustSize();
+ parent.show();
+ QVERIFY(QTest::qWaitForWindowActive(&parent));
+
+ QWindow* windowHandle = parent.window()->windowHandle();
+ const QPoint globalPos = QPoint(42, 16);
+ QTest::touchEvent(windowHandle, m_touchDevice).press(1, globalPos);
+ QTest::touchEvent(windowHandle, m_touchDevice).release(1, globalPos);
+
+ QVERIFY(widget.gestureReceived(gestureType));
+}
+
#endif // !QT_NO_GESTURES
QTEST_MAIN(tst_QGestureRecognizer)
diff --git a/tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt b/tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt
index c9ac563f01..bf72bc0ae6 100644
--- a/tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt
@@ -1,14 +1,21 @@
-# Generated from qgridlayout.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qgridlayout Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qgridlayout LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qgridlayout
SOURCES
sortdialog.ui
tst_qgridlayout.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp
index 2cf2462fd5..3c325699a7 100644
--- a/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp
+++ b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -83,7 +58,8 @@ private slots:
static inline int visibleTopLevelWidgetCount()
{
int result= 0;
- foreach (const QWidget *topLevel, QApplication::topLevelWidgets()) {
+ const auto topLevels = QApplication::topLevelWidgets();
+ for (const QWidget *topLevel : topLevels) {
if (topLevel->isVisible())
++result;
}
@@ -235,6 +211,9 @@ void tst_QGridLayout::badDistributionBug()
void tst_QGridLayout::setMinAndMaxSize()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("This test crashes on Wayland, see also QTBUG-107184");
+
QWidget widget;
setFrameless(&widget);
QGridLayout layout(&widget);
@@ -683,7 +662,7 @@ void tst_QGridLayout::spacingsAndMargins()
QSKIP("The screen is too small to run this test case");
// We are relying on the order here...
- for (int pi = 0; pi < sizehinters.count(); ++pi) {
+ for (int pi = 0; pi < sizehinters.size(); ++pi) {
QPoint pt = sizehinters.at(pi)->mapTo(&toplevel, QPoint(0, 0));
QCOMPARE(pt, expectedpositions.at(pi));
}
@@ -853,7 +832,7 @@ void tst_QGridLayout::minMaxSize()
QList<QPointer<SizeHinterFrame> > sizehinters;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
- SizeInfo si = sizeinfos.at(sizehinters.count());
+ SizeInfo si = sizeinfos.at(sizehinters.size());
int numpixels = si.hfwNumPixels;
if (pass == 1 && numpixels == -1)
numpixels = -2; //### yuk, (and don't fake it if it already tests sizehint)
@@ -882,7 +861,7 @@ void tst_QGridLayout::minMaxSize()
QTRY_COMPARE(toplevel.size(), toplevel.sizeHint());
}
// We are relying on the order here...
- for (int pi = 0; pi < sizehinters.count(); ++pi) {
+ for (int pi = 0; pi < sizehinters.size(); ++pi) {
QPoint pt = sizehinters.at(pi)->mapTo(&toplevel, QPoint(0, 0));
QCOMPARE(pt, sizeinfos.at(pi).expectedPos);
}
@@ -1052,7 +1031,7 @@ void tst_QGridLayout::styleDependentSpacingsAndMargins()
widget.adjustSize();
QApplication::processEvents();
- for (int pi = 0; pi < expectedpositions.count(); ++pi) {
+ for (int pi = 0; pi < expectedpositions.size(); ++pi) {
QCOMPARE(sizehinters.at(pi)->pos(), expectedpositions.at(pi));
}
}
@@ -1442,7 +1421,7 @@ void tst_QGridLayout::layoutSpacing()
QLayout *layout = widget->layout();
QVERIFY(layout);
- for (int pi = 0; pi < expectedpositions.count(); ++pi) {
+ for (int pi = 0; pi < expectedpositions.size(); ++pi) {
QLayoutItem *item = layout->itemAt(pi);
//qDebug() << item->widget()->pos();
QCOMPARE(item->widget()->pos(), expectedpositions.at(pi));
diff --git a/tests/auto/widgets/kernel/qlayout/CMakeLists.txt b/tests/auto/widgets/kernel/qlayout/CMakeLists.txt
index 049fab0f02..6bda750c0f 100644
--- a/tests/auto/widgets/kernel/qlayout/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qlayout/CMakeLists.txt
@@ -1,9 +1,16 @@
-# Generated from qlayout.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qlayout Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlayout LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -13,27 +20,10 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qlayout
SOURCES
tst_qlayout.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
TESTDATA ${test_data}
)
-
-## Scopes:
-#####################################################################
-
-if(ANDROID)
- # Resources:
- set(testdata_resource_files
- "baseline/smartmaxsize"
- )
-
- qt_internal_add_resource(tst_qlayout "testdata"
- PREFIX
- "/"
- FILES
- ${testdata_resource_files}
- )
-endif()
diff --git a/tests/auto/widgets/kernel/qlayout/testdata.qrc b/tests/auto/widgets/kernel/qlayout/testdata.qrc
deleted file mode 100644
index 24e8e56263..0000000000
--- a/tests/auto/widgets/kernel/qlayout/testdata.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>baseline/smartmaxsize</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp
index 5c5869c738..bd170ca8ab 100644
--- a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp
+++ b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -403,10 +378,10 @@ void tst_QLayout::removeWidget()
{
QHBoxLayout layout;
QCOMPARE(layout.count(), 0);
- QWidget w;
- layout.addWidget(&w);
+ std::unique_ptr<QWidget> w(new QWidget);
+ layout.addWidget(w.get());
QCOMPARE(layout.count(), 1);
- layout.removeWidget(&w);
+ layout.removeWidget(w.get());
QCOMPARE(layout.count(), 0);
QPointer<QLayout> childLayout(new QHBoxLayout);
@@ -420,6 +395,12 @@ void tst_QLayout::removeWidget()
QCOMPARE(layout.count(), 0);
QVERIFY(!childLayout.isNull());
+
+ // Test inactive layout consumes ChildRemoved event (QTBUG-124151)
+ layout.addWidget(w.get());
+ layout.setEnabled(false);
+ w.reset();
+ layout.setEnabled(true);
}
QTEST_MAIN(tst_QLayout)
diff --git a/tests/auto/widgets/kernel/qshortcut/CMakeLists.txt b/tests/auto/widgets/kernel/qshortcut/CMakeLists.txt
index fd97a436d0..517286f324 100644
--- a/tests/auto/widgets/kernel/qshortcut/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qshortcut/CMakeLists.txt
@@ -1,16 +1,38 @@
-# Generated from qshortcut.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qshortcut Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qshortcut LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qshortcut
SOURCES
tst_qshortcut.cpp
INCLUDE_DIRECTORIES
..
- PUBLIC_LIBRARIES
+ LIBRARIES
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::Widgets
+ Qt::WidgetsPrivate
+)
+
+qt_internal_add_test(tst_qguishortcut_with_qapplication
+ SOURCES
+ ../../../gui/kernel/qshortcut/tst_qshortcut.cpp
+ DEFINES
+ tst_QShortcut=tst_QGuiShortcutWithQApplication
+ INCLUDE_DIRECTORIES
+ ..
+ LIBRARIES
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
index 1266660cea..7468dfa9a6 100644
--- a/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
+++ b/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -48,11 +23,69 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
+#include <QtWidgets/private/qapplication_p.h>
+
QT_BEGIN_NAMESPACE
class QMainWindow;
class QTextEdit;
QT_END_NAMESPACE
+class TestEdit : public QTextEdit
+{
+ Q_OBJECT
+public:
+ TestEdit(QWidget *parent, const char *name)
+ : QTextEdit(parent)
+ {
+ setObjectName(name);
+ }
+
+protected:
+ bool event(QEvent *e) override
+ {
+ // Make testedit allow any Ctrl+Key as shortcut
+ if (e->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->modifiers() == Qt::ControlModifier
+ && ke->key() > Qt::Key_Any
+ && ke->key() < Qt::Key_ydiaeresis) {
+ ke->ignore();
+ return true;
+ }
+ }
+
+ // If keypress not processed as normal, check for
+ // Ctrl+Key event, and input custom string for
+ // result comparison.
+ if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->modifiers() && ke->key() > Qt::Key_Any
+ && ke->key() < Qt::Key_ydiaeresis) {
+ const QChar c = QLatin1Char(char(ke->key()));
+ if (ke->modifiers() == Qt::ControlModifier)
+ insertPlainText(QLatin1String("<Ctrl+") + c + QLatin1Char('>'));
+ else if (ke->modifiers() == Qt::AltModifier)
+ insertPlainText(QLatin1String("<Alt+") + c + QLatin1Char('>'));
+ else if (ke->modifiers() == Qt::ShiftModifier)
+ insertPlainText(QLatin1String("<Shift+") + c + QLatin1Char('>'));
+ return true;
+ }
+ }
+ return QTextEdit::event(e);
+ }
+};
+
+class MainWindow : public QMainWindow
+{
+public:
+ MainWindow();
+
+ TestEdit *testEdit() const { return m_testEdit; }
+
+private:
+ TestEdit *m_testEdit;
+};
+
class tst_QShortcut : public QObject
{
Q_OBJECT
@@ -143,62 +176,7 @@ protected:
void testElement();
Result ambigResult;
-};
-
-class TestEdit : public QTextEdit
-{
- Q_OBJECT
-public:
- TestEdit(QWidget *parent, const char *name)
- : QTextEdit(parent)
- {
- setObjectName(name);
- }
-
-protected:
- bool event(QEvent *e) override
- {
- // Make testedit allow any Ctrl+Key as shortcut
- if (e->type() == QEvent::ShortcutOverride) {
- QKeyEvent *ke = static_cast<QKeyEvent*>(e);
- if (ke->modifiers() == Qt::ControlModifier
- && ke->key() > Qt::Key_Any
- && ke->key() < Qt::Key_ydiaeresis) {
- ke->ignore();
- return true;
- }
- }
-
- // If keypress not processed as normal, check for
- // Ctrl+Key event, and input custom string for
- // result comparison.
- if (e->type() == QEvent::KeyPress) {
- QKeyEvent *ke = static_cast<QKeyEvent*>(e);
- if (ke->modifiers() && ke->key() > Qt::Key_Any
- && ke->key() < Qt::Key_ydiaeresis) {
- const QChar c = QLatin1Char(char(ke->key()));
- if (ke->modifiers() == Qt::ControlModifier)
- insertPlainText(QLatin1String("<Ctrl+") + c + QLatin1Char('>'));
- else if (ke->modifiers() == Qt::AltModifier)
- insertPlainText(QLatin1String("<Alt+") + c + QLatin1Char('>'));
- else if (ke->modifiers() == Qt::ShiftModifier)
- insertPlainText(QLatin1String("<Shift+") + c + QLatin1Char('>'));
- return true;
- }
- }
- return QTextEdit::event(e);
- }
-};
-
-class MainWindow : public QMainWindow
-{
-public:
- MainWindow();
-
- TestEdit *testEdit() const { return m_testEdit; }
-
-private:
- TestEdit *m_testEdit;
+ QScopedPointer<MainWindow> mainWindow;
};
MainWindow::MainWindow()
@@ -337,11 +315,11 @@ void tst_QShortcut::number_data()
Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss
Qt::Key_Plus on Shift + Qt::Key_Pluss
*/
- QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT | Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Plus).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Plus).toCombined() << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
@@ -359,8 +337,8 @@ void tst_QShortcut::number_data()
Qt::Key_F1 on Shift + Qt::Key_F1
*/
- QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
@@ -376,7 +354,7 @@ void tst_QShortcut::number_data()
//QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
// (Shift+)BackTab != Tab, but Shift+BackTab == Shift+Tab
QTest::newRow("N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Backtab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005a - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
@@ -385,11 +363,11 @@ void tst_QShortcut::number_data()
Qt::Key_Backtab on Shift + Qt::Key_Tab
Shift + Qt::Key_Backtab on Shift + Qt::Key_Tab
*/
- QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT | Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Tab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Tab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Backtab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N005b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
@@ -402,10 +380,10 @@ void tst_QShortcut::number_data()
QTest::newRow("N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
// This should work, since platform dependent code will transform the
// Shift+Tab into a Shift+BackTab, which should trigger the shortcut
- QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
+ QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Tab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
QTest::newRow("N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
//commented out because the behaviour changed, those tests should be updated
- //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Backtab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N006a - clear") << ClearAll << NoWidget<< QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
@@ -414,11 +392,11 @@ void tst_QShortcut::number_data()
Qt::Key_Backtab on Shift + Qt::Key_Backtab
Shift + Qt::Key_Backtab on Shift + Qt::Key_Backtab
*/
- QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT | Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Backtab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Tab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
+ QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Backtab).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
QTest::newRow("N006b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
//===========================================
@@ -431,9 +409,9 @@ void tst_QShortcut::number_data()
Shift + Qt::Key_F1
*/
QTest::newRow("N007 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
@@ -443,13 +421,13 @@ void tst_QShortcut::number_data()
Alt + Qt::Key_M
*/
QTest::newRow("N01 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT | Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::CTRL | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::ALT | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::CTRL, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString() << QKeyCombination(Qt::ALT, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
- QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::CTRL, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::ALT, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
/* Testing Single Sequence Ambiguity
Qt::Key_M on shortcut2
@@ -464,11 +442,11 @@ void tst_QShortcut::number_data()
Qt::Key_K
*/
QTest::newRow("N06 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT | Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Aring).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N08 - slot2") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Aring).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Qt::Qt::Key_K") << TestAccel << NoWidget << QString() << int(Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
@@ -481,11 +459,11 @@ void tst_QShortcut::number_data()
*/
QTest::newRow("N10 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N11 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT | Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
+ QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_I).toCombined() << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered;
- QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_I).toCombined() << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
}
@@ -527,10 +505,10 @@ void tst_QShortcut::text_data()
Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss
*/
QTest::newRow("T002 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Plus).toCombined() << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
@@ -542,7 +520,7 @@ void tst_QShortcut::text_data()
QTest::newRow("T002b - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("T002b:Shift+Ctrl++ [Ctrl++]")<< TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::CTRL | Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::CTRL, Qt::Key_Plus).toCombined() << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
@@ -561,7 +539,7 @@ void tst_QShortcut::text_data()
Qt::Key_F1 on Shift + Qt::Key_F1
*/
QTest::newRow("T004 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
- QTest::newRow("T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
@@ -577,7 +555,7 @@ void tst_QShortcut::text_data()
QTest::newRow("T007 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T007 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_F1).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
@@ -592,9 +570,9 @@ void tst_QShortcut::text_data()
QTest::newRow("T04 - slot2") << SetupAccel << TriggerSlot2 << QString("Alt+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
- QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT | Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_M).toCombined() << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::CTRL, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::ALT, Qt::Key_M).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
/* Testing Single Sequence Ambiguity
Qt::Key_M on shortcut2
@@ -613,7 +591,7 @@ void tst_QShortcut::text_data()
QTest::newRow("T07 - slot2") << SetupAccel << TriggerSlot2 << QString::fromLatin1("Shift+\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T08 - slot2") << SetupAccel << TriggerSlot1 << QString("K") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
- QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
+ QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_Aring).toCombined() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Qt::Key_K") << TestAccel << NoWidget << QString() << int(Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
@@ -629,7 +607,7 @@ void tst_QShortcut::text_data()
QTest::newRow("T12 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered;
- QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT | Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
+ QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << QKeyCombination(Qt::SHIFT, Qt::Key_I).toCombined() << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
}
@@ -1086,7 +1064,7 @@ void tst_QShortcut::context()
// Focus on 'other1' edit, so Active Window context should trigger
other1->activateWindow(); // <---
- QApplication::setActiveWindow(other1);
+ QApplicationPrivate::setActiveWindow(other1);
QCOMPARE(QApplication::activeWindow(), other1->window());
QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
@@ -1178,7 +1156,7 @@ void tst_QShortcut::duplicatedShortcutOverride()
w.resize(200, 200);
w.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
w.show();
- QApplication::setActiveWindow(&w);
+ QApplicationPrivate::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyPress(w.windowHandle(), Qt::Key_A);
QCoreApplication::processEvents();
@@ -1276,8 +1254,6 @@ void tst_QShortcut::testElement()
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
- static QScopedPointer<MainWindow> mainW;
-
currentResult = NoResult;
QFETCH(tst_QShortcut::Action, action);
QFETCH(tst_QShortcut::Widget, testWidget);
@@ -1292,28 +1268,35 @@ void tst_QShortcut::testElement()
QFETCH(int, c4);
QFETCH(tst_QShortcut::Result, result);
- if (mainW.isNull()) {
- mainW.reset(new MainWindow);
- mainW->setWindowTitle(QTest::currentTestFunction());
- mainW->show();
- mainW->activateWindow();
- QVERIFY(QTest::qWaitForWindowActive(mainW.data()));
- }
+ auto mainWindowDeleter = qScopeGuard([&]{
+ if (action == TestEnd)
+ mainWindow.reset();
+ });
+
+ if (mainWindow.isNull())
+ mainWindow.reset(new MainWindow);
+ mainWindow->setWindowTitle(QTest::currentTestFunction());
+ mainWindow->show();
+ mainWindow->activateWindow();
+ // Don't use QVERIFY here; the data function uses QEXPECT_FAIL,
+ // which would result in an XPASS failure.
+ if (!QTest::qWaitForWindowActive(mainWindow.data()))
+ QVERIFY(false);
switch (action) {
case ClearAll:
- qDeleteAll(mainW->findChildren<QShortcut *>());
+ qDeleteAll(mainWindow->findChildren<QShortcut *>());
break;
case SetupAccel:
- setupShortcut(mainW.data(), txt, testWidget, txt.isEmpty()
+ setupShortcut(mainWindow.data(), txt, testWidget, txt.isEmpty()
? QKeySequence(k1, k2, k3, k4) : QKeySequence::fromString(txt));
break;
case TestAccel:
- sendKeyEvents(mainW.data(), k1, char16_t(c1), k2, char16_t(c2), k3, char16_t(c3), k4, char16_t(c4));
+ sendKeyEvents(mainWindow.data(), k1, char16_t(c1), k2, char16_t(c2), k3, char16_t(c3), k4, char16_t(c4));
QCOMPARE(currentResult, result);
break;
case TestEnd:
- mainW.reset();
+ // taken care of by the mainWindowDeleter
break;
}
}
@@ -1369,10 +1352,10 @@ void tst_QShortcut::keys()
QCOMPARE(QApplication::focusWidget(), &le);
QTest::keyEvent(QTest::Press, QApplication::focusWidget(), Qt::Key_Enter);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
QTest::keyEvent(QTest::Press, QApplication::focusWidget(), Qt::Key_Return);
- QTRY_COMPARE(spy.count(), 2);
+ QTRY_COMPARE(spy.size(), 2);
}
QTEST_MAIN(tst_QShortcut)
diff --git a/tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt b/tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt
index 36450d4f80..efdd72db73 100644
--- a/tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qsizepolicy.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qsizepolicy Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsizepolicy LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qsizepolicy
SOURCES
tst_qsizepolicy.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
diff --git a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
index d6a5ec218d..19d267f7e5 100644
--- a/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
+++ b/tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
@@ -1,32 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QTest>
#include <qsizepolicy.h>
Q_DECLARE_METATYPE(Qt::Orientations)
@@ -34,6 +8,8 @@ Q_DECLARE_METATYPE(QSizePolicy)
Q_DECLARE_METATYPE(QSizePolicy::Policy)
Q_DECLARE_METATYPE(QSizePolicy::ControlType)
+#include <QTest>
+
class tst_QSizePolicy : public QObject
{
Q_OBJECT
@@ -109,7 +85,7 @@ void tst_QSizePolicy::constExpr()
{
/* gcc < 4.8.0 has problems with init'ing variant members in constexpr ctors */
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54922 */
-#if !defined(Q_CC_GNU) || defined(Q_CC_INTEL) || defined(Q_CC_CLANG) || Q_CC_GNU >= 408
+#if !defined(Q_CC_GNU) || defined(Q_CC_CLANG) || Q_CC_GNU >= 408
// check that certain ctors are constexpr (compile-only):
{ constexpr QSizePolicy sp; Q_UNUSED(sp); }
{ constexpr QSizePolicy sp = QSizePolicy(); Q_UNUSED(sp); }
@@ -119,7 +95,7 @@ void tst_QSizePolicy::constExpr()
{
// QTBUG-69983: For ControlType != QSizePolicy::DefaultType, qCountTrailingZeroBits()
// is used, which MSVC 15.8.1 does not consider constexpr due to built-ins
-# if defined(QT_HAS_CONSTEXPR_BUILTINS) && (!defined(Q_CC_MSVC) || _MSC_VER < 1915)
+# if defined(QT_HAS_CONSTEXPR_BITOPS)
constexpr auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::CheckBox);
# else
constexpr auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType);
diff --git a/tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt b/tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt
index 2c1c3da277..5701f455b5 100644
--- a/tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt
@@ -1,13 +1,21 @@
-# Generated from qstackedlayout.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qstackedlayout Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qstackedlayout LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qstackedlayout
SOURCES
tst_qstackedlayout.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
index 711ffeda03..ca002a1375 100644
--- a/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
+++ b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -36,6 +11,8 @@
#include <QPushButton>
#include <QSignalSpy>
+#include <QtWidgets/private/qapplication_p.h>
+
class tst_QStackedLayout : public QObject
{
Q_OBJECT
@@ -132,7 +109,7 @@ void tst_QStackedLayout::testCase()
// One widget added to layout
QWidget *w1 = new QWidget(testWidget);
testLayout->addWidget(w1);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toInt(), 0);
spy.clear();
QCOMPARE(testLayout->currentIndex(), 0);
@@ -149,7 +126,7 @@ void tst_QStackedLayout::testCase()
// Change the current index
testLayout->setCurrentIndex(1);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toInt(), 1);
spy.clear();
QCOMPARE(testLayout->currentIndex(), 1);
@@ -163,7 +140,7 @@ void tst_QStackedLayout::testCase()
// Second widget removed from layout; back to nothing
testLayout->removeWidget(w2);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toInt(), -1);
spy.clear();
QCOMPARE(testLayout->currentIndex(), -1);
@@ -312,7 +289,7 @@ void tst_QStackedLayout::keepFocusAfterSetCurrent()
stackLayout->setCurrentIndex(0);
testWidget->show();
- QApplication::setActiveWindow(testWidget);
+ QApplicationPrivate::setActiveWindow(testWidget);
QVERIFY(QTest::qWaitForWindowActive(testWidget));
edit1->setFocus();
diff --git a/tests/auto/widgets/kernel/qtooltip/CMakeLists.txt b/tests/auto/widgets/kernel/qtooltip/CMakeLists.txt
index a07cd1aa65..af2de80e24 100644
--- a/tests/auto/widgets/kernel/qtooltip/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qtooltip/CMakeLists.txt
@@ -1,13 +1,21 @@
-# Generated from qtooltip.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtooltip Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtooltip LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtooltip
SOURCES
tst_qtooltip.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
index 8e4e2a0ea4..c3b53addcc 100644
--- a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
+++ b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -36,6 +11,8 @@
#include <qwhatsthis.h>
#include <qscreen.h>
+#include <QtWidgets/private/qapplication_p.h>
+
class tst_QToolTip : public QObject
{
Q_OBJECT
@@ -49,6 +26,7 @@ private slots:
void setPalette();
void qtbug64550_stylesheet();
void dontCrashOutsideScreenGeometry();
+ void marginSetWithStyleSheet();
};
void tst_QToolTip::init()
@@ -120,7 +98,7 @@ void tst_QToolTip::keyEvent()
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction())
+ QLatin1Char(' ') + QLatin1String(QTest::currentDataTag()));
widget.show();
- QApplication::setActiveWindow(&widget);
+ QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
@@ -140,7 +118,8 @@ void tst_QToolTip::keyEvent()
static QWidget *findWhatsThat()
{
- foreach (QWidget *widget, QApplication::topLevelWidgets()) {
+ const auto widgets = QApplication::topLevelWidgets();
+ for (QWidget *widget : widgets) {
if (widget->inherits("QWhatsThat"))
return widget;
}
@@ -214,7 +193,7 @@ void tst_QToolTip::qtbug64550_stylesheet()
Widget widget;
widget.setStyleSheet(QStringLiteral("* { font-size: 48pt; }\n"));
widget.show();
- QApplication::setActiveWindow(&widget);
+ QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
@@ -236,5 +215,30 @@ void tst_QToolTip::dontCrashOutsideScreenGeometry() {
QToolTip::hideText();
}
+void tst_QToolTip::marginSetWithStyleSheet()
+{
+ const char *toolTipText = "Test Tool Tip";
+
+ qApp->setStyleSheet("QToolTip {font-size: 8px; margin: 5px;}");
+ QToolTip::showText(QGuiApplication::primaryScreen()->availableGeometry().topLeft(), toolTipText);
+ QTRY_VERIFY(QToolTip::isVisible());
+ QWidget *toolTip = findToolTip();
+ QVERIFY(toolTip);
+ QTRY_VERIFY(toolTip->isVisible());
+ int toolTipHeight = toolTip->size().height();
+ qApp->setStyleSheet(QString());
+ QToolTip::hideText();
+
+ qApp->setStyleSheet("QToolTip {font-size: 8px; margin: 10px;}");
+ QToolTip::showText(QGuiApplication::primaryScreen()->availableGeometry().topLeft(), toolTipText);
+ QTRY_VERIFY(QToolTip::isVisible());
+ toolTip = findToolTip();
+ QVERIFY(toolTip);
+ QTRY_VERIFY(toolTip->isVisible());
+ QCOMPARE_LE(toolTip->size().height(), toolTipHeight + 10);
+ qApp->setStyleSheet(QString());
+ QToolTip::hideText();
+}
+
QTEST_MAIN(tst_QToolTip)
#include "tst_qtooltip.moc"
diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST
index 254ca784ab..4c17af245b 100644
--- a/tests/auto/widgets/kernel/qwidget/BLACKLIST
+++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST
@@ -1,74 +1,49 @@
-# OSX QTBUG-25300 QTBUG-45502
-[normalGeometry]
-ubuntu-16.04
-[restoreVersion1Geometry]
-ubuntu-16.04
-[focusProxyAndInputMethods]
-rhel-7.6
-centos
-opensuse-leap
-ubuntu
[raise]
opensuse-leap
-# QTBUG-68175
-opensuse-42.3
-[childEvents]
-macos
-[renderInvisible]
-macos
-[optimizedResizeMove]
-osx
[optimizedResize_topLevel]
osx
[render_windowOpacity]
macos arm
[render_systemClip]
osx
-[showMinimizedKeepsFocus]
-macos
-[maskedUpdate]
-opensuse
-opensuse-leap
-[moveInResizeEvent]
-ubuntu-16.04
[multipleToplevelFocusCheck]
-rhel-7.6
centos
opensuse-leap
ubuntu
sles-15
-
-[syntheticEnterLeave]
-macos # Can't move cursor (QTBUG-76312)
-[taskQTBUG_4055_sendSyntheticEnterLeave]
-macos # Can't move cursor (QTBUG-76312)
-
# QTBUG-87668
-[reparent]
-android
-[windowState]
-android
[showMinimizedKeepsFocus]
android
+macos-13 ci
+macos-14 ci
[normalGeometry]
android
[saveRestoreGeometry]
android
[optimizedResizeMove]
android
-[resizeEvent]
-android
[update]
android
[scroll]
android
-[setWindowGeometry]
+[moveChild]
android
-[windowMoveResize]
+[multipleToplevelFocusCheck]
android
-[moveChild]
+[renderInvisible]
android
-[showAndMoveChild]
+[updateWhileMinimized]
android
-[multipleToplevelFocusCheck]
+[doubleRepaint]
+android
+[setMaskInResizeEvent]
+android
+[activateWindow]
+android
+[optimizedResize_topLevel]
+android
+[hoverPosition]
+macos-14 x86
+# QTBUG-124291
+[setParentChangesFocus:make dialog parentless, after]
android
diff --git a/tests/auto/widgets/kernel/qwidget/CMakeLists.txt b/tests/auto/widgets/kernel/qwidget/CMakeLists.txt
index d04db40e87..f18bc98bb3 100644
--- a/tests/auto/widgets/kernel/qwidget/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwidget/CMakeLists.txt
@@ -1,20 +1,15 @@
-# Generated from qwidget.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidget Test:
#####################################################################
-qt_internal_add_test(tst_qwidget
- SOURCES
- tst_qwidget.cpp
- PUBLIC_LIBRARIES
- Qt::CorePrivate
- Qt::Gui
- Qt::GuiPrivate
- Qt::TestPrivate
- Qt::Widgets
- Qt::WidgetsPrivate
-)
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
# Resources:
set(qwidget_resource_files
@@ -24,17 +19,20 @@ set(qwidget_resource_files
"hellotr_la.qm"
)
-qt_internal_add_resource(tst_qwidget "qwidget"
- PREFIX
- "/"
- FILES
- ${qwidget_resource_files}
+qt_internal_add_test(tst_qwidget
+ SOURCES
+ tst_qwidget.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::TestPrivate
+ Qt::Widgets
+ Qt::WidgetsPrivate
+ TESTDATA ${qwidget_resource_files}
+ BUILTIN_TESTDATA
)
-
-#### Keys ignored in scope 1:.:.:qwidget.pro:<TRUE>:
-# testcase.timeout = "600"
-
## Scopes:
#####################################################################
@@ -43,16 +41,8 @@ qt_internal_extend_target(tst_qwidget CONDITION AIX
-fpermissive
)
-qt_internal_extend_target(tst_qwidget CONDITION APPLE
- SOURCES
- tst_qwidget_mac_helpers.mm
- PUBLIC_LIBRARIES
- ${FWAppKit}
- ${FWSecurity}
-)
-
qt_internal_extend_target(tst_qwidget CONDITION WIN32
- PUBLIC_LIBRARIES
+ LIBRARIES
gdi32
user32
)
diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.qrc b/tests/auto/widgets/kernel/qwidget/qwidget.qrc
deleted file mode 100644
index 597ea872a5..0000000000
--- a/tests/auto/widgets/kernel/qwidget/qwidget.qrc
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
- <qresource>
- <file>geometry.dat</file>
- <file>geometry-maximized.dat</file>
- <file>geometry-fullscreen.dat</file>
- <file>hellotr_la.qm</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap
deleted file mode 100644
index b3473cdefe..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap
deleted file mode 100644
index 10007733ca..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap
deleted file mode 100644
index cde5964a30..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap
deleted file mode 100644
index 23ea1410e4..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap
deleted file mode 100644
index a8918c1d1b..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap
deleted file mode 100644
index 0981cf5dd1..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap
deleted file mode 100644
index 75d09136cf..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap
deleted file mode 100644
index f58f74d030..0000000000
--- a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap
+++ /dev/null
Binary files differ
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 5cd88f9ab8..0dde95cada 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "../../../shared/highdpi.h"
@@ -38,6 +13,7 @@
#include <qlineedit.h>
#include <qlistview.h>
#include <qmessagebox.h>
+#include <qmimedata.h>
#include <qpainter.h>
#include <qpoint.h>
#include <qpushbutton.h>
@@ -62,6 +38,7 @@
#include <QtGui/qbackingstore.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformwindow.h>
+#include <QtGui/qpa/qplatformdrag.h>
#include <QtGui/qscreen.h>
#include <qmenubar.h>
#include <qcompleter.h>
@@ -74,15 +51,13 @@
#include <QtGui/qwindow.h>
#include <qtimer.h>
#include <QtWidgets/QDoubleSpinBox>
-
-#if defined(Q_OS_MACOS)
-#include "tst_qwidget_mac_helpers.h" // Abstract the ObjC stuff out so not everyone must run an ObjC++ compile.
-#endif
+#include <QtWidgets/QComboBox>
#include <QtTest/QTest>
#include <QtTest/private/qtesthelpers_p.h>
using namespace QTestPrivate;
+using namespace Qt::StringLiterals;
#if defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
@@ -147,6 +122,34 @@ static QByteArray msgComparisonFailed(T v1, const char *op, T v2)
return s.toLocal8Bit();
}
+template<class T> class EventSpy : public QObject
+{
+public:
+ EventSpy(T *widget, QEvent::Type event)
+ : m_widget(widget), eventToSpy(event)
+ {
+ if (m_widget)
+ m_widget->installEventFilter(this);
+ }
+
+ T *widget() const { return m_widget; }
+ int count() const { return m_count; }
+ void clear() { m_count = 0; }
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override
+ {
+ if (event->type() == eventToSpy)
+ ++m_count;
+ return QObject::eventFilter(object, event);
+ }
+
+private:
+ T *m_widget;
+ const QEvent::Type eventToSpy;
+ int m_count = 0;
+};
+
Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests")
class tst_QWidget : public QObject
@@ -160,7 +163,9 @@ public:
public slots:
void initTestCase();
void cleanup();
+
private slots:
+ void nativeWindowAttribute();
void addActionOverloads();
void getSetCheck();
void fontPropagation();
@@ -186,10 +191,15 @@ private slots:
void mapFromAndTo();
void focusChainOnHide();
void focusChainOnReparent();
+ void focusAbstraction();
void defaultTabOrder();
void reverseTabOrder();
void tabOrderWithProxy();
+ void tabOrderWithProxyDisabled();
+ void tabOrderWithProxyOutOfOrder();
void tabOrderWithCompoundWidgets();
+ void tabOrderWithCompoundWidgetsInflection_data();
+ void tabOrderWithCompoundWidgetsInflection();
void tabOrderWithCompoundWidgetsNoFocusPolicy();
void tabOrderNoChange();
void tabOrderNoChange2();
@@ -197,12 +207,16 @@ private slots:
void appFocusWidgetWhenLosingFocusProxy();
void explicitTabOrderWithComplexWidget();
void explicitTabOrderWithSpinBox_QTBUG81097();
+ void tabOrderList();
+ void tabOrderComboBox_data();
+ void tabOrderComboBox();
#if defined(Q_OS_WIN)
void activation();
#endif
void reparent();
void setScreen();
void windowState();
+ void resizePropagation();
void showMaximized();
void showFullScreen();
void showMinimized();
@@ -220,6 +234,8 @@ private slots:
void saveRestoreGeometry();
void restoreVersion1Geometry_data();
void restoreVersion1Geometry();
+ void restoreGeometryAfterScreenChange_data();
+ void restoreGeometryAfterScreenChange();
void widgetAt();
#ifdef Q_OS_MACOS
@@ -240,11 +256,14 @@ private slots:
void ensureCreated();
void createAndDestroy();
+ void eventsAndAttributesOnDestroy();
void winIdChangeEvent();
void persistentWinId();
void showNativeChild();
+ void closeAndShowNativeChild();
+ void closeAndShowWithNativeChild();
void transientParent();
- void qobject_castInDestroyedSlot();
+ void qobject_castOnDestruction();
void showHideEvent_data();
void showHideEvent();
@@ -296,6 +315,8 @@ private slots:
void childEvents();
void render();
+ void renderChildFillsBackground();
+ void renderTargetOffset();
void renderInvisible();
void renderWithPainter();
void render_task188133();
@@ -330,6 +351,8 @@ private slots:
void resizeInPaintEvent();
void opaqueChildren();
+ void dumpObjectTree();
+
void setMaskInResizeEvent();
void moveInResizeEvent();
@@ -361,6 +384,7 @@ private slots:
void enterLeaveOnWindowShowHide_data();
void enterLeaveOnWindowShowHide();
void taskQTBUG_4055_sendSyntheticEnterLeave();
+ void hoverPosition();
void underMouse();
void taskQTBUG_27643_enterEvents();
#endif
@@ -372,6 +396,8 @@ private slots:
void focusWidget_task254563();
void rectOutsideCoordinatesLimit_task144779();
void setGraphicsEffect();
+ void render_graphicsEffect_data();
+ void render_graphicsEffect();
#ifdef QT_BUILD_INTERNAL
void destroyBackingStore();
@@ -382,7 +408,8 @@ private slots:
void openModal_taskQTBUG_5804();
void focusProxy();
- void focusProxyAndInputMethods();
+ void imEnabledNotImplemented();
+
#ifdef QT_BUILD_INTERNAL
void scrollWithoutBackingStore();
#endif
@@ -431,9 +458,25 @@ private slots:
void deleteWindowInCloseEvent();
void quitOnClose();
-private:
- bool ensureScreenSize(int width, int height);
+ void setParentChangesFocus_data();
+ void setParentChangesFocus();
+
+ void activateWhileModalHidden();
+
+#ifdef Q_OS_ANDROID
+ void showFullscreenAndroid();
+#endif
+
+ void setVisibleDuringDestruction();
+
+ void explicitShowHide();
+
+ void dragEnterLeaveSymmetry();
+ void reparentWindowHandles_data();
+ void reparentWindowHandles();
+
+private:
const QString m_platform;
QSize m_testWidgetSize;
QPoint m_availableTopLeft;
@@ -441,13 +484,17 @@ private:
const bool m_windowsAnimationsEnabled;
QPointingDevice *m_touchScreen;
const int m_fuzz;
-};
+ QPalette simplePalette();
-bool tst_QWidget::ensureScreenSize(int width, int height)
-{
- const QSize available = QGuiApplication::primaryScreen()->availableGeometry().size();
- return (available.width() >= width && available.height() >= height);
-}
+private:
+ enum class ScreenPosition {
+ OffAbove,
+ OffLeft,
+ OffBelow,
+ OffRight,
+ Contained
+ };
+};
// Testing get/set functions
void tst_QWidget::getSetCheck()
@@ -463,18 +510,24 @@ void tst_QWidget::getSetCheck()
QVERIFY(var1.data() != obj1.style());
QVERIFY(obj1.style() != nullptr); // style can never be 0 for a widget
+ const QRegularExpression negativeNotPossible(u"^.*Negative sizes \\(.*\\) are not possible$"_s);
+ const QRegularExpression largestAllowedSize(u"^.*The largest allowed size is \\(.*\\)$"_s);
// int QWidget::minimumWidth()
// void QWidget::setMinimumWidth(int)
obj1.setMinimumWidth(0);
QCOMPARE(obj1.minimumWidth(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
obj1.setMinimumWidth(INT_MIN);
QCOMPARE(obj1.minimumWidth(), 0); // A widgets width can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
obj1.setMinimumWidth(INT_MAX);
child1.setMinimumWidth(0);
QCOMPARE(child1.minimumWidth(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
child1.setMinimumWidth(INT_MIN);
QCOMPARE(child1.minimumWidth(), 0); // A widgets width can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
child1.setMinimumWidth(INT_MAX);
QCOMPARE(child1.minimumWidth(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium
@@ -482,14 +535,18 @@ void tst_QWidget::getSetCheck()
// void QWidget::setMinimumHeight(int)
obj1.setMinimumHeight(0);
QCOMPARE(obj1.minimumHeight(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
obj1.setMinimumHeight(INT_MIN);
QCOMPARE(obj1.minimumHeight(), 0); // A widgets height can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
obj1.setMinimumHeight(INT_MAX);
child1.setMinimumHeight(0);
QCOMPARE(child1.minimumHeight(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
child1.setMinimumHeight(INT_MIN);
QCOMPARE(child1.minimumHeight(), 0); // A widgets height can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
child1.setMinimumHeight(INT_MAX);
QCOMPARE(child1.minimumHeight(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium
@@ -497,8 +554,10 @@ void tst_QWidget::getSetCheck()
// void QWidget::setMaximumWidth(int)
obj1.setMaximumWidth(0);
QCOMPARE(obj1.maximumWidth(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
obj1.setMaximumWidth(INT_MIN);
QCOMPARE(obj1.maximumWidth(), 0); // A widgets width can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
obj1.setMaximumWidth(INT_MAX);
QCOMPARE(obj1.maximumWidth(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX
@@ -506,8 +565,10 @@ void tst_QWidget::getSetCheck()
// void QWidget::setMaximumHeight(int)
obj1.setMaximumHeight(0);
QCOMPARE(obj1.maximumHeight(), 0);
+ QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
obj1.setMaximumHeight(INT_MIN);
QCOMPARE(obj1.maximumHeight(), 0); // A widgets height can never be less than 0
+ QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
obj1.setMaximumHeight(INT_MAX);
QCOMPARE(obj1.maximumHeight(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX
@@ -567,6 +628,7 @@ void tst_QWidget::getSetCheck()
QBoxLayout *var11 = new QBoxLayout(QBoxLayout::LeftToRight);
obj1.setLayout(var11);
QCOMPARE(static_cast<QLayout *>(var11), obj1.layout());
+ QTest::ignoreMessage(QtWarningMsg, "QWidget::setLayout: Cannot set layout to 0");
obj1.setLayout(nullptr);
QCOMPARE(static_cast<QLayout *>(var11), obj1.layout()); // You cannot set a 0-pointer layout, that keeps the current
delete var11; // This will remove the layout from the widget
@@ -590,7 +652,7 @@ void tst_QWidget::getSetCheck()
#if defined (Q_OS_WIN)
obj1.setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
const HWND handle = reinterpret_cast<HWND>(obj1.winId()); // explicitly create window handle
- QVERIFY(GetWindowLong(handle, GWL_STYLE) & LONG(WS_POPUP));
+ QVERIFY(GetWindowLongPtr(handle, GWL_STYLE) & LONG_PTR(WS_POPUP));
#endif
}
@@ -627,6 +689,10 @@ tst_QWidget::~tst_QWidget()
void tst_QWidget::initTestCase()
{
+#ifdef Q_OS_ANDROID
+ if (QNativeInterface::QAndroidApplication::sdkVersion() == 33)
+ QSKIP("Is flaky on Android 13 / RHEL 8.6 and 8.8 (QTQAINFRA-5606)");
+#endif
// Size of reference widget, 200 for < 2000, scale up for larger screens
// to avoid Windows warnings about minimum size for decorated windows.
int width = 200;
@@ -659,6 +725,24 @@ struct ImplicitlyConvertibleTo {
void testFunction0() {}
void testFunction1(bool) {}
+void tst_QWidget::nativeWindowAttribute()
+{
+ QWidget parent;
+ QWidget child(&parent);
+
+ QCOMPARE(parent.windowHandle(), nullptr);
+ QCOMPARE(child.windowHandle(), nullptr);
+
+ // Setting WA_NativeWindow should create window handle
+ parent.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(parent.windowHandle() != nullptr);
+ // But not its child's window handle
+ QCOMPARE(child.windowHandle(), nullptr);
+ // Until the child also gains WA_NativeWindow
+ child.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(child.windowHandle() != nullptr);
+}
+
void tst_QWidget::addActionOverloads()
{
// almost exhaustive check of addAction() overloads:
@@ -1237,6 +1321,8 @@ void tst_QWidget::ignoreKeyEventsWhenDisabled_QTBUG27417()
centerOnScreen(&lineEdit);
lineEdit.setDisabled(true);
lineEdit.show();
+ QTest::ignoreMessage(QtWarningMsg, "Keyboard event not accepted by receiving widget");
+ QTest::ignoreMessage(QtWarningMsg, "Keyboard event not accepted by receiving widget");
QTest::keyClick(&lineEdit, Qt::Key_A);
QTRY_VERIFY(lineEdit.text().isEmpty());
}
@@ -1851,8 +1937,6 @@ void tst_QWidget::focusChainOnHide()
QWidget::setTabOrder(child, parent.data());
parent->show();
- QApplication::setActiveWindow(parent->window());
- child->activateWindow();
child->setFocus();
QTRY_VERIFY(child->hasFocus());
@@ -1893,8 +1977,11 @@ public:
setObjectName(name);
lineEdit1 = new QLineEdit;
+ lineEdit1->setObjectName(name + "/lineEdit1");
lineEdit2 = new QLineEdit;
+ lineEdit2->setObjectName(name + "/lineEdit2");
lineEdit3 = new QLineEdit;
+ lineEdit3->setObjectName(name + "/lineEdit3");
lineEdit3->setEnabled(false);
QHBoxLayout* hbox = new QHBoxLayout(this);
@@ -1909,6 +1996,111 @@ public:
QLineEdit *lineEdit3;
};
+static QList<QWidget *> getFocusChain(QWidget *start, bool bForward)
+{
+ QList<QWidget *> ret;
+ QWidget *cur = start;
+ // detect infinite loop
+ int count = 100;
+ auto loopGuard = qScopeGuard([]{
+ QFAIL("Inifinite loop detected in focus chain");
+ });
+ do {
+ ret += cur;
+ cur = bForward ? cur->nextInFocusChain() : cur->previousInFocusChain();
+ if (!--count)
+ return ret;
+ } while (cur != start);
+ loopGuard.dismiss();
+ return ret;
+}
+
+void tst_QWidget::focusAbstraction()
+{
+ QWidget *widget1 = new QWidget;
+ widget1->setObjectName("Widget 1");
+ QWidget *widget2 = new QWidget;
+ widget2->setObjectName("Widget 2");
+ QWidget *widget3 = new QWidget;
+ widget3->setObjectName("Widget 3");
+ QWidgetPrivate *priv1 = QWidgetPrivate::get(widget1);
+ QWidgetPrivate *priv2 = QWidgetPrivate::get(widget2);
+ QWidgetPrivate *priv3 = QWidgetPrivate::get(widget3);
+
+ // Verify initialization
+ QVERIFY(!priv1->isInFocusChain());
+ QVERIFY(!priv2->isInFocusChain());
+ QVERIFY(!priv3->isInFocusChain());
+
+ // Verify, that parenting builds a focus chain.
+ QWidget parent;
+ parent.setObjectName("Parent");
+ widget1->setParent(&parent);
+ widget2->setParent(&parent);
+ widget3->setParent(&parent);
+ QVERIFY(priv1->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+ QVERIFY(priv3->isInFocusChain());
+ QWidgetList expected{widget1, widget2, widget3, &parent};
+ QCOMPARE(getFocusChain(widget1, true), expected);
+
+ // Verify, that reparented focus children end up behind parent.
+ widget1->setParent(widget2);
+ priv2->insertIntoFocusChainAfter(widget3);
+ priv2->reparentFocusChildren(QWidgetPrivate::FocusDirection::Next);
+ expected = {widget1, &parent, widget3, widget2};
+ QCOMPARE(getFocusChain(widget1, true), expected);
+ QVERIFY(priv1->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+ QVERIFY(priv3->isInFocusChain());
+
+ // Check removal
+ priv3->removeFromFocusChain(QWidgetPrivate::FocusChainRemovalRule::AssertConsistency);
+ expected.removeOne(widget3);
+ QCOMPARE(getFocusChain(widget1, true), expected);
+ QVERIFY(priv1->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+ QVERIFY(!priv3->isInFocusChain());
+
+ // Check insert
+ priv3->insertIntoFocusChain(QWidgetPrivate::FocusDirection::Previous, widget1);
+ expected = {widget3, widget1, &parent, widget2};
+ QCOMPARE(getFocusChain(widget3, true), expected);
+
+ // Verify, that take doesn't break
+ const QWidgetList taken = QWidgetPrivate::takeFromFocusChain(widget1, widget2);
+ QVERIFY(priv1->isFocusChainConsistent());
+ expected = {widget1, &parent, widget2};
+ QCOMPARE(taken, expected);
+ QVERIFY(priv1->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+ QVERIFY(!priv3->isInFocusChain());
+
+ // Verify insertion of multiple widgets
+ QWidgetPrivate::insertIntoFocusChain(taken, QWidgetPrivate::FocusDirection::Next, widget3);
+ expected = {widget3, widget1, &parent, widget2};
+ QCOMPARE(getFocusChain(widget3, true), expected);
+ QVERIFY(priv1->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+ QVERIFY(priv2->isInFocusChain());
+
+ // Verify broken chain identification
+ // d'tor asserts chain consistency => repair before going out of scope
+ auto guard = qScopeGuard([priv2, widget3]{ priv2->focus_next = widget3; });
+
+ // Nullptr is not allowed
+ priv2->focus_next = nullptr;
+ QVERIFY(!priv1->isFocusChainConsistent());
+
+ // Chain looping back in the middle
+ priv2->focus_next = widget1;
+ QVERIFY(!priv1->isFocusChainConsistent());
+
+ // "last" element pointing to itself
+ priv2->focus_next = widget2;
+ QVERIFY(!priv1->isFocusChainConsistent());
+}
+
void tst_QWidget::defaultTabOrder()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
@@ -1932,7 +2124,6 @@ void tst_QWidget::defaultTabOrder()
container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
container.show();
container.activateWindow();
- QApplication::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
QTRY_VERIFY(firstEdit->hasFocus());
@@ -1968,23 +2159,29 @@ void tst_QWidget::defaultTabOrder()
void tst_QWidget::reverseTabOrder()
{
- if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ if (QGuiApplication::platformName().startsWith(QLatin1StringView("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
const int compositeCount = 2;
Container container;
- container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ container.setObjectName(QLatin1StringView("Container"));
+ container.setWindowTitle(QLatin1StringView(QTest::currentTestFunction()));
Composite* composite[compositeCount];
QLineEdit *firstEdit = new QLineEdit();
+ firstEdit->setObjectName(QLatin1StringView("FirstEdit"));
container.box->addWidget(firstEdit);
+ static constexpr QLatin1StringView comp("Composite-%1");
for (int i = 0; i < compositeCount; i++) {
- composite[i] = new Composite();
+ const QString name = QString(comp).arg(i);
+ composite[i] = new Composite(nullptr, name);
+ composite[i]->setObjectName(name);
container.box->addWidget(composite[i]);
}
QLineEdit *lastEdit = new QLineEdit();
+ lastEdit->setObjectName(QLatin1StringView("LastEdit"));
container.box->addWidget(lastEdit);
// Reverse tab order inside each composite
@@ -1993,7 +2190,6 @@ void tst_QWidget::reverseTabOrder()
container.show();
container.activateWindow();
- QApplication::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
QTRY_VERIFY(firstEdit->hasFocus());
@@ -2028,6 +2224,139 @@ void tst_QWidget::reverseTabOrder()
QVERIFY(firstEdit->hasFocus());
}
+void tst_QWidget::tabOrderList()
+{
+ Composite c;
+ QCOMPARE(getFocusChain(&c, true),
+ QList<QWidget *>({&c, c.lineEdit1, c.lineEdit2, c.lineEdit3}));
+ QWidget::setTabOrder({c.lineEdit3, c.lineEdit2, c.lineEdit1});
+ // not starting with 3 like one would maybe expect, but still 3, 2, 1
+ QCOMPARE(getFocusChain(&c, true),
+ QList<QWidget *>({&c, c.lineEdit1, c.lineEdit3, c.lineEdit2}));
+}
+
+void tst_QWidget::tabOrderComboBox_data()
+{
+ QTest::addColumn<const bool>("editableAtBeginning");
+ QTest::addColumn<const QList<int>>("firstTabOrder");
+ QTest::addColumn<const QList<int>>("secondTabOrder");
+
+ QTest::addRow("3 not editable") << false << QList<int>{2, 1, 0} << QList<int>{0, 1, 2};
+ QTest::addRow("4 editable") << true << QList<int>{2, 1, 0, 3} << QList<int>{3, 0, 2, 1};
+}
+
+QWidgetList expectedFocusChain(const QList<QComboBox *> &boxes, const QList<int> &sequence)
+{
+ Q_ASSERT(boxes.count() == sequence.count());
+ QWidgetList widgets;
+ for (int i : sequence) {
+ Q_ASSERT(i >= 0);
+ Q_ASSERT(i < boxes.count());
+ QComboBox *box = boxes.at(i);
+ widgets.append(box);
+ if (box->lineEdit())
+ widgets.append(box->lineEdit());
+ }
+
+ return widgets;
+}
+
+QWidgetList realFocusChain(const QList<QComboBox *> &boxes, const QList<int> &sequence)
+{
+ const QWidgetList all = getFocusChain(boxes.at(sequence.at(0)), true);
+ QWidgetList chain;
+ // Filter everything with NoFocus
+ for (auto *widget : all) {
+ if (widget->focusPolicy() != Qt::NoFocus)
+ chain << widget;
+ }
+ return chain;
+}
+
+void setTabOrder(const QList<QComboBox *> &boxes, const QList<int> &sequence)
+{
+ Q_ASSERT(boxes.count() == sequence.count());
+ QWidget *previous = nullptr;
+ for (int i : sequence) {
+ Q_ASSERT(i >= 0);
+ Q_ASSERT(i < boxes.count());
+ QWidget *box = boxes.at(i);
+ if (!previous) {
+ previous = box;
+ } else {
+ QWidget::setTabOrder(previous, box);
+ previous = box;
+ }
+ }
+}
+
+void tst_QWidget::tabOrderComboBox()
+{
+ QFETCH(const bool, editableAtBeginning);
+ QFETCH(const QList<int>, firstTabOrder);
+ QFETCH(const QList<int>, secondTabOrder);
+ const int count = firstTabOrder.count();
+ Q_ASSERT(count == secondTabOrder.count());
+ Q_ASSERT(count > 1);
+
+ QWidget w;
+ w.setObjectName("MainWidget");
+ QVBoxLayout* layout = new QVBoxLayout();
+ w.setLayout(layout);
+
+ QList<QComboBox *> boxes;
+ for (int i = 0; i < count; ++i) {
+ auto box = new QComboBox;
+ box->setObjectName("ComboBox " + QString::number(i));
+ if (editableAtBeginning) {
+ box->setEditable(true);
+ box->lineEdit()->setObjectName("LineEdit " + QString::number(i));
+ }
+ boxes.append(box);
+ layout->addWidget(box);
+ }
+ layout->addStretch();
+
+#define COMPARE(seq)\
+ setTabOrder(boxes, seq);\
+ QCOMPARE(realFocusChain(boxes, seq), expectedFocusChain(boxes, seq))
+
+ COMPARE(firstTabOrder);
+
+ if (!editableAtBeginning) {
+ for (auto *box : boxes)
+ box->setEditable(box);
+ }
+
+ COMPARE(secondTabOrder);
+
+ // Remove the focus proxy of the first combobox's line edit.
+ QComboBox *box = boxes.at(0);
+ QLineEdit *lineEdit = box->lineEdit();
+ const QWidget *prev = lineEdit->previousInFocusChain();
+ const QWidget *next = lineEdit->nextInFocusChain();
+ const QWidget *proxy = lineEdit->focusProxy();
+ QCOMPARE(proxy, box);
+ lineEdit->setFocusProxy(nullptr);
+ QCOMPARE(lineEdit->focusProxy(), nullptr);
+ QCOMPARE(lineEdit->previousInFocusChain(), prev);
+ QCOMPARE(lineEdit->nextInFocusChain(), next);
+
+ // Remove first item and check chain consistency
+ boxes.removeFirst();
+ delete box;
+
+ // Create new list with 0 removed and other indexes updated
+ QList<int> thirdTabOrder(secondTabOrder);
+ thirdTabOrder.removeIf([](int i){ return i == 0; });
+ for (int &i : thirdTabOrder)
+ --i;
+
+ COMPARE(thirdTabOrder);
+
+#undef COMPARE
+}
+
void tst_QWidget::tabOrderWithProxy()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
@@ -2055,7 +2384,6 @@ void tst_QWidget::tabOrderWithProxy()
container.show();
container.activateWindow();
- QApplication::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
QTRY_VERIFY(firstEdit->hasFocus());
@@ -2089,6 +2417,74 @@ void tst_QWidget::tabOrderWithProxy()
QVERIFY(firstEdit->hasFocus());
}
+void tst_QWidget::tabOrderWithProxyDisabled()
+{
+ Container container;
+ container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+
+ QLineEdit lineEdit1;
+ lineEdit1.setObjectName("lineEdit1");
+
+ QWidget containingWidget;
+ containingWidget.setFocusPolicy(Qt::StrongFocus);
+ auto *containingLayout = new QVBoxLayout;
+ QLineEdit lineEdit2;
+ lineEdit2.setObjectName("lineEdit2");
+ QLineEdit lineEdit3;
+ lineEdit3.setObjectName("lineEdit3");
+ containingLayout->addWidget(&lineEdit2);
+ containingLayout->addWidget(&lineEdit3);
+ containingWidget.setLayout(containingLayout);
+ containingWidget.setFocusProxy(&lineEdit2);
+ lineEdit2.setEnabled(false);
+
+ container.box->addWidget(&lineEdit1);
+ container.box->addWidget(&containingWidget);
+
+ container.show();
+ container.activateWindow();
+
+ if (!QTest::qWaitForWindowActive(&container))
+ QSKIP("Window failed to activate, skipping test");
+
+ QVERIFY2(lineEdit1.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ container.tab();
+ QVERIFY2(!lineEdit2.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ QVERIFY2(lineEdit3.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ container.tab();
+ QVERIFY2(lineEdit1.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ container.backTab();
+ QVERIFY2(lineEdit3.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ container.backTab();
+ QVERIFY2(!lineEdit2.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+ QVERIFY2(lineEdit1.hasFocus(),
+ qPrintable(QApplication::focusWidget()->objectName()));
+}
+
+//#define DEBUG_FOCUS_CHAIN
+static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
+{
+#ifdef DEBUG_FOCUS_CHAIN
+ qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
+ QWidget *cur = start;
+ do {
+ qDebug() << "-" << cur;
+ auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
+ cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
+ } while (cur != start);
+#else
+ Q_UNUSED(start);
+ Q_UNUSED(bForward);
+ Q_UNUSED(desc);
+#endif
+}
+
void tst_QWidget::tabOrderWithCompoundWidgets()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
@@ -2129,7 +2525,6 @@ void tst_QWidget::tabOrderWithCompoundWidgets()
container.show();
container.activateWindow();
- QApplication::setActiveWindow(&container);
QVERIFY(QTest::qWaitForWindowActive(&container));
lastEdit->setFocus();
@@ -2180,34 +2575,180 @@ void tst_QWidget::tabOrderWithCompoundWidgets()
QVERIFY(lastEdit->hasFocus());
}
-static QList<QWidget *> getFocusChain(QWidget *start, bool bForward)
+void tst_QWidget::tabOrderWithProxyOutOfOrder()
{
- QList<QWidget *> ret;
- QWidget *cur = start;
- do {
- ret += cur;
- auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
- cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
- } while (cur != start);
- return ret;
+ Container container;
+ container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ container.setObjectName(QLatin1StringView("Container"));
+
+ // important to create the widgets with parent so that they are
+ // added to the focus chain already now, and with the buttonBox
+ // before the outsideButton.
+ QWidget buttonBox(&container);
+ buttonBox.setObjectName(QLatin1StringView("buttonBox"));
+ QPushButton outsideButton(&container);
+ outsideButton.setObjectName(QLatin1StringView("outsideButton"));
+
+ container.box->addWidget(&outsideButton);
+ container.box->addWidget(&buttonBox);
+ QCOMPARE(getFocusChain(&container, true),
+ QList<QWidget*>({&container, &buttonBox, &outsideButton}));
+
+ // this now adds okButon and cancelButton to the focus chain,
+ // after the outsideButton - so the outsideButton is in between
+ // the buttonBox and the children of the buttonBox!
+ QPushButton okButton(&buttonBox);
+ okButton.setObjectName("okButton");
+ QPushButton cancelButton(&buttonBox);
+ cancelButton.setObjectName("cancelButton");
+ QCOMPARE(getFocusChain(&container, true),
+ QList<QWidget*>({&container, &buttonBox, &outsideButton, &okButton, &cancelButton}));
+
+ // by setting the okButton as the focusProxy, the outsideButton becomes
+ // unreachable when navigating the focus chain as the buttonBox is in front
+ // of, and proxies to the okButton behind the outsideButton. setFocusProxy
+ // must fix that by moving the buttonBox in front of the first sibling of
+ // the proxy.
+ buttonBox.setFocusProxy(&okButton);
+ QCOMPARE(getFocusChain(&container, true),
+ QList<QWidget*>({&container, &outsideButton, &buttonBox, &okButton, &cancelButton}));
+
+ container.show();
+ container.activateWindow();
+ if (!QTest::qWaitForWindowActive(&container))
+ QSKIP("Window failed to activate, skipping test");
+
+ QCOMPARE(QApplication::focusWidget(), &outsideButton);
+ container.tab();
+ QCOMPARE(QApplication::focusWidget(), &okButton);
+ container.tab();
+ QCOMPARE(QApplication::focusWidget(), &cancelButton);
+ container.tab();
+ QCOMPARE(QApplication::focusWidget(), &outsideButton);
+
+ container.backTab();
+ QCOMPARE(QApplication::focusWidget(), &cancelButton);
+ container.backTab();
+ QCOMPARE(QApplication::focusWidget(), &okButton);
+ container.backTab();
+ QCOMPARE(QApplication::focusWidget(), &outsideButton);
+ container.backTab();
+ QCOMPARE(QApplication::focusWidget(), &cancelButton);
}
-//#define DEBUG_FOCUS_CHAIN
-static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
+static bool isFocusChainConsistent(QWidget *widget)
{
-#ifdef DEBUG_FOCUS_CHAIN
- qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
- QWidget *cur = start;
- do {
- qDebug() << cur;
- auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
- cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
- } while (cur != start);
-#else
- Q_UNUSED(start);
- Q_UNUSED(bForward);
- Q_UNUSED(desc);
-#endif
+ auto forward = getFocusChain(widget, true);
+ auto backward = getFocusChain(widget, false);
+ auto logger = qScopeGuard([=]{
+ qCritical("Focus chain is not consistent!");
+ qWarning() << forward.size() << "forwards: " << forward;
+ qWarning() << backward.size() << "backwards:" << backward;
+ });
+ // both lists start with the same, the widget
+ if (forward.takeFirst() != backward.takeFirst())
+ return false;
+ const qsizetype chainLength = forward.size();
+ if (backward.size() != chainLength)
+ return false;
+ for (qsizetype i = 0; i < chainLength; ++i) {
+ if (forward.at(i) != backward.at(chainLength - i - 1))
+ return false;
+ }
+ logger.dismiss();
+ return true;
+}
+
+/*
+ This tests that we end up with consistent and complete chains when we set
+ the tab order from a widget (the lineEdit) inside a compound (the tabWidget)
+ to the compound, or visa versa. In that case, QWidget::setTabOrder will walk
+ the focus chain to the focus child inside the compound to replace the compound
+ itself when manipulating the tab order. If that last focus child is then
+ however also the lineEdit, then we must not create an inconsistent or
+ incomplete loop.
+
+ The tabWidget is seen as a compound because QTabWidget sets the tab bar as
+ the focus proxy, and it has more widgets inside, like pages, toolbuttons etc.
+*/
+void tst_QWidget::tabOrderWithCompoundWidgetsInflection_data()
+{
+ QTest::addColumn<QByteArrayList>("tabOrder");
+
+ QTest::addRow("forward")
+ << QByteArrayList{"dialog", "tabWidget", "lineEdit", "compound", "okButton", "cancelButton"};
+ QTest::addRow("backward")
+ << QByteArrayList{"dialog", "cancelButton", "okButton", "compound", "lineEdit", "tabWidget"};
+}
+
+void tst_QWidget::tabOrderWithCompoundWidgetsInflection()
+{
+ QFETCH(const QByteArrayList, tabOrder);
+
+ QDialog dialog;
+ dialog.setObjectName("dialog");
+ QTabWidget *tabWidget = new QTabWidget;
+ tabWidget->setObjectName("tabWidget");
+ tabWidget->setFocusPolicy(Qt::TabFocus);
+ QWidget *page = new QWidget;
+ page->setObjectName("page");
+ QLineEdit *lineEdit = new QLineEdit;
+ lineEdit->setObjectName("lineEdit");
+ QWidget *compound = new QWidget;
+ compound->setObjectName("compound");
+ compound->setFocusPolicy(Qt::TabFocus);
+ QPushButton *okButton = new QPushButton("Ok");
+ okButton->setObjectName("okButton");
+ okButton->setFocusPolicy(Qt::TabFocus);
+ QPushButton *cancelButton = new QPushButton("Cancel");
+ cancelButton->setObjectName("cancelButton");
+ cancelButton->setFocusPolicy(Qt::TabFocus);
+
+ QVBoxLayout *pageLayout = new QVBoxLayout;
+ pageLayout->addWidget(lineEdit);
+ page->setLayout(pageLayout);
+ tabWidget->addTab(page, "Tab");
+
+ QHBoxLayout *compoundLayout = new QHBoxLayout;
+ compoundLayout->addStretch();
+ compoundLayout->addWidget(cancelButton);
+ compoundLayout->addWidget(okButton);
+ compound->setFocusProxy(okButton);
+ compound->setLayout(compoundLayout);
+
+ QVBoxLayout *dialogLayout = new QVBoxLayout;
+ dialogLayout->addWidget(tabWidget);
+ dialogLayout->addWidget(compound);
+ dialog.setLayout(dialogLayout);
+
+ QVERIFY(isFocusChainConsistent(&dialog));
+
+ QList<QWidget *> expectedFocusChain;
+ for (qsizetype i = 0; i < tabOrder.size() - 1; ++i) {
+ QWidget *first = dialog.findChild<QWidget *>(tabOrder.at(i));
+ if (!first && tabOrder.at(i) == dialog.objectName())
+ first = &dialog;
+ QVERIFY(first);
+ if (i == 0)
+ expectedFocusChain.append(first);
+ QWidget *second = dialog.findChild<QWidget *>(tabOrder.at(i + 1));
+ QVERIFY(second);
+ expectedFocusChain.append(second);
+ QWidget::setTabOrder(first, second);
+ QVERIFY(isFocusChainConsistent(&dialog));
+ }
+
+ const auto forwardChain = getFocusChain(&dialog, true);
+ auto logger = qScopeGuard([=]{
+ qCritical("Order of widgets in focus chain not matching:");
+ qCritical() << " Actual :" << forwardChain;
+ qCritical() << " Expected:" << expectedFocusChain;
+ });
+ for (qsizetype i = 0; i < expectedFocusChain.size() - 2; ++i) {
+ QCOMPARE_LT(forwardChain.indexOf(expectedFocusChain.at(i)),
+ forwardChain.indexOf(expectedFocusChain.at(i + 1)));
+ }
+ logger.dismiss();
}
void tst_QWidget::tabOrderWithCompoundWidgetsNoFocusPolicy()
@@ -2231,7 +2772,6 @@ void tst_QWidget::tabOrderWithCompoundWidgetsNoFocusPolicy()
container.show();
container.activateWindow();
- QApplication::setActiveWindow(&container);
if (!QTest::qWaitForWindowActive(&container))
QSKIP("Window failed to activate, skipping test");
@@ -2337,7 +2877,6 @@ void tst_QWidget::appFocusWidgetWithFocusProxyLater()
QLineEdit *lineEdit = new QLineEdit(&window);
lineEdit->setFocus();
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::focusWidget(), lineEdit);
@@ -2365,7 +2904,6 @@ void tst_QWidget::appFocusWidgetWhenLosingFocusProxy()
lineEdit->setFocusProxy(lineEditFocusProxy);
lineEdit->setFocus();
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QApplication::focusWidget(), lineEditFocusProxy);
QVERIFY(lineEdit->hasFocus());
@@ -2392,7 +2930,6 @@ void tst_QWidget::explicitTabOrderWithComplexWidget()
QWidget::setTabOrder(lineEditOne, lineEditTwo);
lineEditOne->setFocus();
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QTRY_COMPARE(QApplication::focusWidget(), lineEditOne);
@@ -2421,7 +2958,6 @@ void tst_QWidget::explicitTabOrderWithSpinBox_QTBUG81097()
QWidget::setTabOrder(spinBoxTwo, lineEdit);
spinBoxOne->setFocus();
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QTRY_COMPARE(QApplication::focusWidget(), spinBoxOne);
@@ -2468,6 +3004,24 @@ void tst_QWidget::activation()
}
#endif // Q_OS_WIN
+struct WindowStateChangeWatcher : public QObject
+{
+ WindowStateChangeWatcher(QWidget *widget)
+ {
+ Q_ASSERT(widget->window()->windowHandle());
+ widget->window()->windowHandle()->installEventFilter(this);
+ lastWindowStates = widget->window()->windowHandle()->windowState();
+ }
+ Qt::WindowStates lastWindowStates;
+protected:
+ bool eventFilter(QObject *receiver, QEvent *event) override
+ {
+ if (event->type() == QEvent::WindowStateChange)
+ lastWindowStates = static_cast<QWindow *>(receiver)->windowState();
+ return QObject::eventFilter(receiver, event);
+ }
+};
+
void tst_QWidget::windowState()
{
#ifdef Q_OS_MACOS
@@ -2481,12 +3035,14 @@ void tst_QWidget::windowState()
QPoint pos;
QSize size = m_testWidgetSize;
- if (QGuiApplicationPrivate::platformIntegration()->defaultWindowState(Qt::Widget)
- == Qt::WindowFullScreen) {
+ const Qt::WindowState defaultWidgetState =
+ QGuiApplicationPrivate::platformIntegration()->defaultWindowState(Qt::Widget);
+ if (defaultWidgetState == Qt::WindowFullScreen)
size = QGuiApplication::primaryScreen()->size();
- } else {
+ else if (defaultWidgetState == Qt::WindowMaximized)
+ size = QGuiApplication::primaryScreen()->availableSize();
+ else
pos = QPoint(10, 10);
- }
QWidget widget1;
widget1.move(pos);
@@ -2601,6 +3157,119 @@ void tst_QWidget::windowState()
QTRY_COMPARE(widget1.size(), size);
}
+// Test propagation of size and state from platform window to QWidget
+// Windows and linux/XCB only
+void tst_QWidget::resizePropagation()
+{
+#if !defined(Q_OS_LINUX) && !defined(Q_OS_WIN)
+ QSKIP("resizePropagation test is designed for Linux/XCB and Windows only");
+#endif
+ const bool xcb = (m_platform == QStringLiteral("xcb"));
+#ifdef Q_OS_LINUX
+ if (!xcb)
+ QSKIP("resizePropagation test is designed for XCB only");
+#endif
+
+ // Windows:
+ // When a widget is maximized after it has been resized, the widget retains its original size,
+ // while the window shows maximum size.
+ // windowStateChanged signal gets fired on a no-op change from/to WindowNoState
+
+ // Initialize widget and signal spy for window handle
+ QWidget widget;
+ widget.showMaximized();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+ QWindow *window = widget.windowHandle();
+ QTRY_VERIFY(window);
+ QSignalSpy spy(window, &QWindow::windowStateChanged);
+ int count = 0;
+
+ const QSize screenSize = QGuiApplication::primaryScreen()->size();
+ const QSize size1 = QSize(screenSize.width() * 0.5, screenSize.height() * 0.5);
+ const QSize size2 = QSize(screenSize.width() * 0.625, screenSize.height() * 0.833);
+
+ enum CountIncrementCheck {Equal, Greater};
+ enum TargetSizeCheck {Fail, Warn};
+ auto verifyResize = [&](const QSize &size, Qt::WindowState windowState,
+ CountIncrementCheck checkCountIncrement,
+ TargetSizeCheck checkTargetSize)
+ {
+ // Capture count of latest async signals
+ if (checkCountIncrement == Equal)
+ count = spy.count();
+
+ // Resize if required
+ if (size.isValid())
+ widget.resize(size);
+
+ // Wait for the widget anyway
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ // Check signal count and qDebug output for fail analysis
+ switch (checkCountIncrement) {
+ case Greater: {
+ auto logger = qScopeGuard([&](){
+ qDebug() << "spy count:" << spy.count() << "previous count:" << count;
+ });
+ QTRY_VERIFY(spy.count() > count);
+ logger.dismiss();
+ count = spy.count();
+ }
+ break;
+ case Equal: {
+ auto logger = qScopeGuard([&](){
+ qDebug() << spy << widget.windowState() << window->windowState();
+ });
+ QCOMPARE(spy.count(), count);
+ logger.dismiss();
+ }
+ break;
+ }
+
+ // QTRY necessary because state changes are propagated async
+ QTRY_COMPARE(widget.windowState(), windowState);
+ QTRY_COMPARE(window->windowState(), windowState);
+
+ // Check target size with fail or warning
+ switch (checkTargetSize) {
+ case Fail:
+ QCOMPARE(widget.size(), window->size());
+ break;
+ case Warn:
+ if (widget.size() != window->size()) {
+ qWarning() << m_platform << "size mismtach tolerated. Widget:"
+ << widget.size() << "Window:" << window->size();
+ }
+ break;
+ }
+ };
+
+ // test state and size consistency of maximized window
+ verifyResize(QSize(), Qt::WindowMaximized, Equal, Fail);
+ if (QTest::currentTestFailed())
+ return;
+
+ // test state transition, state and size consistency after resize
+ verifyResize(size1, Qt::WindowNoState, Greater, xcb ? Warn : Fail );
+ if (QTest::currentTestFailed())
+ return;
+
+ // test unchanged state, state and size consistency after resize
+ verifyResize(size2, Qt::WindowNoState, Equal, xcb ? Warn : Fail);
+ if (QTest::currentTestFailed())
+ return;
+
+ // test state transition, state and size consistency after maximize
+ widget.showMaximized();
+ verifyResize(QSize(), Qt::WindowMaximized, Greater, xcb ? Fail : Warn);
+ if (QTest::currentTestFailed())
+ return;
+
+#ifdef Q_OS_WIN
+ QCOMPARE(widget.size(), size2);
+#endif
+}
+
void tst_QWidget::showMaximized()
{
QWidget plain;
@@ -2790,7 +3459,7 @@ void tst_QWidget::resizeEvent()
wParent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
wParent.resize(m_testWidgetSize);
ResizeWidget wChild(&wParent);
- wParent.show();
+ QTestPrivate::androidCompatibleShow(&wParent);
QVERIFY(QTest::qWaitForWindowExposed(&wParent));
QCOMPARE (wChild.m_resizeEventCount, 1); // initial resize event before paint
wParent.hide();
@@ -2799,7 +3468,7 @@ void tst_QWidget::resizeEvent()
safeSize.setWidth(639);
wChild.resize(safeSize);
QCOMPARE (wChild.m_resizeEventCount, 1);
- wParent.show();
+ QTestPrivate::androidCompatibleShow(&wParent);
QCOMPARE (wChild.m_resizeEventCount, 2);
}
@@ -2807,7 +3476,7 @@ void tst_QWidget::resizeEvent()
ResizeWidget wTopLevel;
wTopLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
wTopLevel.resize(m_testWidgetSize);
- wTopLevel.show();
+ QTestPrivate::androidCompatibleShow(&wTopLevel);
QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel));
QCOMPARE (wTopLevel.m_resizeEventCount, 1); // initial resize event before paint for toplevels
wTopLevel.hide();
@@ -2816,7 +3485,7 @@ void tst_QWidget::resizeEvent()
safeSize.setWidth(639);
wTopLevel.resize(safeSize);
QCOMPARE (wTopLevel.m_resizeEventCount, 1);
- wTopLevel.show();
+ QTestPrivate::androidCompatibleShow(&wTopLevel);
QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel));
QCOMPARE (wTopLevel.m_resizeEventCount, 2);
}
@@ -2892,7 +3561,7 @@ void tst_QWidget::showMinimizedKeepsFocus()
child1.setFocusPolicy(Qt::StrongFocus);
child2.setFocusPolicy(Qt::StrongFocus);
window.show();
- QApplication::setActiveWindow(&window);
+ QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
child2.setFocus();
@@ -2916,7 +3585,6 @@ void tst_QWidget::showMinimizedKeepsFocus()
QWidget *child = new QWidget(&window);
child->setFocusPolicy(Qt::StrongFocus);
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
child->setFocus();
QTRY_COMPARE(window.focusWidget(), child);
@@ -2935,7 +3603,6 @@ void tst_QWidget::showMinimizedKeepsFocus()
QWidget *child = new QWidget(&window);
child->setFocusPolicy(Qt::StrongFocus);
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
child->setFocus();
QTRY_COMPARE(window.focusWidget(), child);
@@ -2955,7 +3622,6 @@ void tst_QWidget::showMinimizedKeepsFocus()
QWidget *child = new QWidget(&window);
child->setFocusPolicy(Qt::StrongFocus);
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
child->setFocus();
QTRY_COMPARE(window.focusWidget(), child);
@@ -2976,7 +3642,6 @@ void tst_QWidget::showMinimizedKeepsFocus()
QWidget *child = new QWidget(&window);
child->setFocusPolicy(Qt::StrongFocus);
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
child->setFocus();
QTRY_COMPARE(window.focusWidget(), child);
@@ -2993,7 +3658,6 @@ void tst_QWidget::showMinimizedKeepsFocus()
QTRY_COMPARE(QApplication::focusWidget(), nullptr);
window.showNormal();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
#ifdef Q_OS_MACOS
if (!macHasAccessToWindowsServer())
@@ -3031,8 +3695,8 @@ void tst_QWidget::reparent()
pal2.setColor(childTLW.backgroundRole(), Qt::yellow);
childTLW.setPalette(pal2);
- parent.show();
- childTLW.show();
+ QTestPrivate::androidCompatibleShow(&parent);
+ QTestPrivate::androidCompatibleShow(&childTLW);
QVERIFY(QTest::qWaitForWindowExposed(&parent));
parent.move(parentPosition);
@@ -3042,7 +3706,7 @@ void tst_QWidget::reparent()
child.setParent(nullptr, child.windowFlags() & ~Qt::WindowType_Mask);
child.setGeometry(childPos.x(), childPos.y(), child.width(), child.height());
- child.show();
+ QTestPrivate::androidCompatibleShow(&child);
#if 0 // QTBUG-26424
if (m_platform == QStringLiteral("xcb"))
@@ -3058,7 +3722,7 @@ void tst_QWidget::reparent()
void tst_QWidget::setScreen()
{
const auto screens = QApplication::screens();
- if (screens.count() < 2)
+ if (screens.size() < 2)
QSKIP("This test tests nothing on a machine with a single screen.");
QScreen *screen0 = screens.at(0);
@@ -3147,109 +3811,111 @@ void tst_QWidget::hideWhenFocusWidgetIsChild()
void tst_QWidget::normalGeometry()
{
-#ifdef Q_OS_MACOS
- QSKIP("QTBUG-52974");
-#endif
-
if (m_platform == QStringLiteral("wayland"))
QSKIP("Wayland: This fails. Figure out why.");
QWidget parent;
+ QCOMPARE(parent.normalGeometry(), parent.geometry());
parent.setWindowTitle("NormalGeometry parent");
QWidget *child = new QWidget(&parent);
QCOMPARE(parent.normalGeometry(), parent.geometry());
QCOMPARE(child->normalGeometry(), QRect());
- const QRect testGeom = QRect(m_availableTopLeft + QPoint(100 ,100), m_testWidgetSize);
- parent.setGeometry(testGeom);
+ parent.setGeometry(QRect(m_availableTopLeft + QPoint(100 ,100), m_testWidgetSize));
parent.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&parent));
- QApplication::processEvents();
+ WindowStateChangeWatcher stateChangeWatcher(&parent);
- QRect geom = parent.geometry();
- // ### the window manager places the top-left corner at
- // ### 100,100... making geom something like 102,124 (offset by
- // ### the frame/frame)... this indicates a rather large different
- // ### between how X11 and Windows works
- // QCOMPARE(geom, QRect(100, 100, 200, 200));
- QCOMPARE(parent.normalGeometry(), geom);
+ const QRect normalGeometry = parent.geometry();
+ // We can't make any assumptions about the actual geometry compared to the
+ // requested geometry. In this test, we only care about normalGeometry.
+ QCOMPARE(parent.normalGeometry(), normalGeometry);
parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized);
- QTRY_VERIFY(parent.geometry() != geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_VERIFY(parent.geometry() != normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
- QTRY_COMPARE(parent.geometry(), geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_COMPARE(parent.geometry(), normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
parent.showMaximized();
- QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized);
- QTRY_VERIFY(parent.geometry() != geom);
- QCOMPARE(parent.normalGeometry(), geom);
+ QTRY_VERIFY(parent.windowHandle()->windowState() & Qt::WindowMaximized);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_VERIFY(parent.geometry() != normalGeometry);
+ QCOMPARE(parent.normalGeometry(), normalGeometry);
parent.showNormal();
QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
- QTRY_COMPARE(parent.geometry(), geom);
- QCOMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_COMPARE(parent.geometry(), normalGeometry);
+ QCOMPARE(parent.normalGeometry(), normalGeometry);
+
+ parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen);
+ QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_VERIFY(parent.geometry() != normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
+
+ parent.setWindowState(Qt::WindowNoState);
+ QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen));
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_COMPARE(parent.geometry(), normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
+
+ parent.showFullScreen();
+ QTRY_VERIFY(parent.window()->windowState() & Qt::WindowFullScreen);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_VERIFY(parent.geometry() != normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
+
+ parent.showNormal();
+ QTRY_VERIFY(!(parent.windowHandle()->windowState() & Qt::WindowFullScreen));
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_COMPARE(parent.geometry(), normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
- parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized);
- QTest::qWait(10);
- parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
- QTest::qWait(10);
if (m_platform == QStringLiteral("xcb"))
QSKIP("QTBUG-26424");
- QTRY_VERIFY(parent.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized));
+
+ parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
+ QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMaximized);
+ parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized);
+ QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMinimized);
+
+ QTRY_COMPARE(parent.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized), Qt::WindowMinimized|Qt::WindowMaximized);
+ QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt::WindowMinimized|Qt::WindowMaximized));
// ### when minimized and maximized at the same time, the geometry
// ### does *NOT* have to be the normal geometry, it could be the
// ### maximized geometry.
// QCOMPARE(parent.geometry(), geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized);
- QTest::qWait(10);
QTRY_VERIFY(!(parent.windowState() & Qt::WindowMinimized));
QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized);
- QTRY_VERIFY(parent.geometry() != geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_VERIFY(parent.geometry() != normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
- QTest::qWait(10);
QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
- QTRY_COMPARE(parent.geometry(), geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
-
- parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen);
- QTest::qWait(10);
- QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen);
- QTRY_VERIFY(parent.geometry() != geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
-
- parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen);
- QTest::qWait(10);
- QVERIFY(!(parent.windowState() & Qt::WindowFullScreen));
- QTRY_COMPARE(parent.geometry(), geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
-
- parent.showFullScreen();
- QTest::qWait(10);
- QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen);
- QTRY_VERIFY(parent.geometry() != geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
-
- parent.showNormal();
- QTest::qWait(10);
- QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen));
- QTRY_COMPARE(parent.geometry(), geom);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
+ QTRY_COMPARE(parent.geometry(), normalGeometry);
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
parent.showNormal();
+ stateChangeWatcher.lastWindowStates = {};
parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized);
parent.setWindowState(Qt::WindowMinimized | Qt:: WindowFullScreen | Qt::WindowMaximized);
parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized);
- QTest::qWait(10);
- QTRY_COMPARE(parent.normalGeometry(), geom);
+ // the actual window will be either fullscreen or maximized
+ QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt:: WindowFullScreen | Qt::WindowMaximized));
+ QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
}
void tst_QWidget::setGeometry()
@@ -3258,9 +3924,8 @@ void tst_QWidget::setGeometry()
tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
QWidget child(&tlw);
- const QPoint topLeft = QGuiApplication::primaryScreen()->availableGeometry().topLeft();
const QSize initialSize = 2 * m_testWidgetSize;
- QRect tr(topLeft + QPoint(100,100), initialSize);
+ QRect tr(m_availableTopLeft + QPoint(100,100), initialSize);
QRect cr(50,50,50,50);
tlw.setGeometry(tr);
child.setGeometry(cr);
@@ -3269,15 +3934,14 @@ void tst_QWidget::setGeometry()
QCOMPARE(child.geometry(), cr);
tlw.setParent(nullptr, Qt::Window|Qt::FramelessWindowHint);
- tr = QRect(topLeft, initialSize / 2);
+ tr = QRect(m_availableTopLeft, initialSize / 2);
tlw.setGeometry(tr);
QCOMPARE(tlw.geometry(), tr);
tlw.showNormal();
- QTest::qWait(50);
- if (tlw.frameGeometry() != tlw.geometry())
+ if (!QTest::qWaitFor([&tlw]{ return tlw.frameGeometry() == tlw.geometry(); }))
QSKIP("Your window manager is too broken for this test");
- if (m_platform == QStringLiteral("xcb"))
- QSKIP("QTBUG-26424");
+ if (m_platform == QStringLiteral("xcb") && tlw.geometry() != tr)
+ QEXPECT_FAIL("", "QTBUG-26424", Continue);
QCOMPARE(tlw.geometry(), tr);
}
@@ -3452,9 +4116,9 @@ void tst_QWidget::raise()
QObjectList list1{child1, child2, child3, child4};
QCOMPARE(parentPtr->children(), list1);
- QCOMPARE(allChildren.count(), list1.count());
+ QCOMPARE(allChildren.size(), list1.size());
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child4 ? 1 : 0;
if (expectedPaintEvents == 0) {
QCOMPARE(child->numPaintEvents, 0);
@@ -3468,9 +4132,10 @@ void tst_QWidget::raise()
for (int i = 0; i < 5; ++i)
child2->raise();
- QTest::qWait(50);
+ QVERIFY(QTest::qWaitForWindowExposed(child2));
+ QApplication::processEvents(); // process events that could be triggered by raise();
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child2 ? 1 : 0;
int expectedZOrderChangeEvents = child == child2 ? 1 : 0;
QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
@@ -3497,15 +4162,17 @@ void tst_QWidget::raise()
onTop->show();
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
QTRY_VERIFY(onTop->numPaintEvents > 0);
+ QApplication::processEvents(); // process remaining paint events if there's more than one
onTop->reset();
// Reset all the children.
- for (UpdateWidget *child : qAsConst(allChildren))
+ for (UpdateWidget *child : std::as_const(allChildren))
child->reset();
for (int i = 0; i < 5; ++i)
child3->raise();
- QTest::qWait(50);
+ QVERIFY(QTest::qWaitForWindowExposed(child3));
+ QApplication::processEvents(); // process events that could be triggered by raise();
QCOMPARE(onTop->numPaintEvents, 0);
QCOMPARE(onTop->numZOrderChangeEvents, 0);
@@ -3513,7 +4180,7 @@ void tst_QWidget::raise()
QObjectList list3{child1, child4, child2, child3};
QCOMPARE(parent->children(), list3);
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = 0;
int expectedZOrderChangeEvents = child == child3 ? 1 : 0;
QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
@@ -3551,9 +4218,9 @@ void tst_QWidget::lower()
QObjectList list1{child1, child2, child3, child4};
QCOMPARE(parent->children(), list1);
- QCOMPARE(allChildren.count(), list1.count());
+ QCOMPARE(allChildren.size(), list1.size());
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child4 ? 1 : 0;
if (expectedPaintEvents == 0) {
QCOMPARE(child->numPaintEvents, 0);
@@ -3570,7 +4237,7 @@ void tst_QWidget::lower()
QTest::qWait(100);
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child3 ? 1 : 0;
int expectedZOrderChangeEvents = child == child4 ? 1 : 0;
QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
@@ -3616,7 +4283,7 @@ void tst_QWidget::stackUnder()
QObjectList list1{child1, child2, child3, child4};
QCOMPARE(parent->children(), list1);
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child4 ? 1 : 0;
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
if (expectedPaintEvents == 1 && child->numPaintEvents == 2)
@@ -3634,7 +4301,7 @@ void tst_QWidget::stackUnder()
QObjectList list2{child1, child4, child2, child3};
QCOMPARE(parent->children(), list2);
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedPaintEvents = child == child3 ? 1 : 0;
int expectedZOrderChangeEvents = child == child4 ? 1 : 0;
QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
@@ -3649,7 +4316,7 @@ void tst_QWidget::stackUnder()
QObjectList list3{child4, child2, child1, child3};
QCOMPARE(parent->children(), list3);
- for (UpdateWidget *child : qAsConst(allChildren)) {
+ for (UpdateWidget *child : std::as_const(allChildren)) {
int expectedZOrderChangeEvents = child == child1 ? 1 : 0;
if (child == child3) {
#ifndef Q_OS_MACOS
@@ -3771,6 +4438,13 @@ void tst_QWidget::saveRestoreGeometry()
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QApplication::processEvents();
+
+ /* ---------------------------------------------------------------------
+ * This test function is likely to flake when debugged with Qt Creator.
+ * (29px offset making the following QTRY_VERIFY2 fail)
+ * ---------------------------------------------------------------------
+ */
+
QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), position, m_fuzz),
qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
QCOMPARE(widget.size(), size);
@@ -3926,10 +4600,9 @@ void tst_QWidget::restoreVersion1Geometry()
const Qt::WindowStates WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized;
QFile f(fileName);
- QVERIFY(f.exists());
- f.open(QIODevice::ReadOnly);
+ QVERIFY(f.open(QIODevice::ReadOnly));
const QByteArray savedGeometry = f.readAll();
- QCOMPARE(savedGeometry.count(), 46);
+ QCOMPARE(savedGeometry.size(), 46);
f.close();
QWidget widget;
@@ -3983,6 +4656,68 @@ void tst_QWidget::restoreVersion1Geometry()
#endif
}
+void tst_QWidget::restoreGeometryAfterScreenChange_data()
+{
+ QTest::addColumn<ScreenPosition>("screenPosition");
+ QTest::addColumn<int>("deltaWidth");
+ QTest::addColumn<int>("deltaHeight");
+ QTest::addColumn<int>("frameMargin");
+ QTest::addColumn<bool>("outside");
+
+ QTest::newRow("offAboveLarge") << ScreenPosition::OffAbove << 200 << 250 << 20 << true;
+ QTest::newRow("fitting") << ScreenPosition::Contained << 80 << 80 << 20 << false;
+ QTest::newRow("offRightWide") << ScreenPosition::OffRight << 150 << 80 << 20 << false;
+ QTest::newRow("offLeftFitting") << ScreenPosition::OffLeft << 70 << 70 << 20 << true;
+ QTest::newRow("offBelowHigh") << ScreenPosition::OffBelow << 80 << 200 << 20 << false;
+}
+
+void tst_QWidget::restoreGeometryAfterScreenChange()
+{
+ const QList<QScreen *> &screens = QApplication::screens();
+ QVERIFY2(!screens.isEmpty(), "No screens found.");
+ const QRect screenGeometry = screens.at(0)->geometry();
+
+ QFETCH(ScreenPosition, screenPosition);
+ QFETCH(int, deltaWidth);
+ QFETCH(int, deltaHeight);
+ QFETCH(int, frameMargin);
+ QFETCH(bool, outside);
+
+ QRect restoredGeometry = screenGeometry;
+ restoredGeometry.setHeight(screenGeometry.height() * deltaHeight / 100);
+ restoredGeometry.setWidth(screenGeometry.width() * deltaWidth / 100);
+ const float moveMargin = outside ? 1.2 : 0.75;
+
+ switch (screenPosition) {
+ case ScreenPosition::OffLeft:
+ restoredGeometry.setLeft(restoredGeometry.width() * (-moveMargin));
+ break;
+ case ScreenPosition::OffAbove:
+ restoredGeometry.setTop(restoredGeometry.height() * (-moveMargin));
+ break;
+ case ScreenPosition::OffRight:
+ restoredGeometry.setRight(restoredGeometry.width() * moveMargin);
+ break;
+ case ScreenPosition::OffBelow:
+ restoredGeometry.setBottom(restoredGeometry.height() * moveMargin);
+ break;
+ case ScreenPosition::Contained:
+ break;
+ }
+
+ // If restored geometry fits into screen and has not been moved,
+ // it is changed only by frame margin plus one pixel at each edge
+ const QRect originalGeometry = restoredGeometry.adjusted(1, frameMargin + 1, 1, frameMargin + 1);
+
+ QWidgetPrivate::checkRestoredGeometry(screenGeometry, &restoredGeometry, frameMargin);
+
+ if (deltaHeight < 100 && deltaWidth < 100 && screenPosition == ScreenPosition::Contained)
+ QCOMPARE(originalGeometry, restoredGeometry);
+
+ // new geometry has to fit on the screen
+ QVERIFY(screenGeometry.contains(restoredGeometry));
+}
+
void tst_QWidget::widgetAt()
{
#ifdef Q_OS_MACOS
@@ -4141,7 +4876,8 @@ void tst_QWidget::testDeletionInEventHandlers()
w = new Widget;
w->show();
w->deleteThis = true;
- QMouseEvent me(QEvent::MouseButtonRelease, QPoint(1, 1), Qt::LeftButton, Qt::LeftButton, Qt::KeyboardModifiers());
+ QMouseEvent me(QEvent::MouseButtonRelease, QPoint(1, 1), w->mapToGlobal(QPoint(1, 1)),
+ Qt::LeftButton, Qt::LeftButton, Qt::KeyboardModifiers());
qApp->notify(w, &me);
QVERIFY(w.isNull());
delete w;
@@ -4180,7 +4916,8 @@ void tst_QWidget::testDeletionInEventHandlers()
w->setMouseTracking(true);
w->show();
w->deleteThis = true;
- QMouseEvent me2 = QMouseEvent(QEvent::MouseMove, QPoint(0, 0), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
+ QMouseEvent me2 = QMouseEvent(QEvent::MouseMove, QPoint(0, 0), w->mapToGlobal(QPoint(0, 0)),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QApplication::sendEvent(w, &me2);
QVERIFY(w.isNull());
delete w;
@@ -4246,22 +4983,20 @@ class StaticWidget : public QWidget
Q_OBJECT
public:
bool partial = false;
- bool gotPaintEvent = false;
QRegion paintedRegion;
- explicit StaticWidget(QWidget *parent = nullptr) : QWidget(parent)
+ explicit StaticWidget(const QPalette &palette, QWidget *parent = nullptr) : QWidget(parent)
{
setAttribute(Qt::WA_StaticContents);
setAttribute(Qt::WA_OpaquePaintEvent);
- setPalette(Qt::red); // Make sure we have an opaque palette.
+ setPalette(palette);
setAutoFillBackground(true);
}
void paintEvent(QPaintEvent *e) override
{
paintedRegion += e->region();
- gotPaintEvent = true;
-// qDebug() << "paint" << e->region();
+ ++paintEvents;
// Look for a full update, set partial to false if found.
for (QRect r : e->region()) {
partial = (r != rect());
@@ -4269,107 +5004,114 @@ public:
break;
}
}
+
+ // Wait timeout ms until at least one paint event has been consumed
+ // and the counter is no longer increasing.
+ // => making sure to consume multiple paint events relating to one operation
+ // before returning true.
+ bool waitForPaintEvent(int timeout = 100)
+ {
+ QDeadlineTimer deadline(timeout);
+ int count = -1;
+ while (!deadline.hasExpired() && count != paintEvents) {
+ count = paintEvents;
+ QCoreApplication::processEvents();
+ if (count == paintEvents && count > 0) {
+ paintEvents = 0;
+ return true;
+ }
+ }
+ paintEvents = 0;
+ return false;
+ }
+private:
+ int paintEvents = 0;
};
/*
Test that widget resizes and moves can be done with minimal repaints when WA_StaticContents
- and WA_OpaquePaintEvent is set. Test is mac-only for now.
+ and WA_OpaquePaintEvent is set.
*/
void tst_QWidget::optimizedResizeMove()
{
- if (m_platform == QStringLiteral("wayland"))
- QSKIP("Wayland: This fails. Figure out why.");
+ const bool wayland = QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
+
QWidget parent;
- parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ parent.setPalette(simplePalette());
+ parent.setWindowTitle(QTest::currentTestFunction());
parent.resize(400, 400);
- StaticWidget staticWidget(&parent);
- staticWidget.gotPaintEvent = false;
+ StaticWidget staticWidget(simplePalette(), &parent);
staticWidget.move(150, 150);
staticWidget.resize(150, 150);
parent.show();
QVERIFY(QTest::qWaitForWindowExposed(&parent));
- QTRY_VERIFY(staticWidget.gotPaintEvent);
+ QVERIFY(staticWidget.waitForPaintEvent());
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(10, 10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ if (!wayland) {
+ QVERIFY(!staticWidget.waitForPaintEvent());
+ } else {
+ if (staticWidget.waitForPaintEvent())
+ QSKIP("Wayland is not optimising paint events. Skipping test.");
+ }
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(-10, 10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
- staticWidget.gotPaintEvent = false;
staticWidget.resize(staticWidget.size() + QSize(10, 10));
- QTRY_VERIFY(staticWidget.gotPaintEvent);
+ QVERIFY(staticWidget.waitForPaintEvent());
QCOMPARE(staticWidget.partial, true);
- staticWidget.gotPaintEvent = false;
staticWidget.resize(staticWidget.size() + QSize(-10, -10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
- staticWidget.gotPaintEvent = false;
staticWidget.resize(staticWidget.size() + QSize(10, -10));
- QTRY_VERIFY(staticWidget.gotPaintEvent);
+ QVERIFY(staticWidget.waitForPaintEvent());
QCOMPARE(staticWidget.partial, true);
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(10, 10));
staticWidget.resize(staticWidget.size() + QSize(-10, -10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(10, 10));
staticWidget.resize(staticWidget.size() + QSize(10, 10));
- QTRY_VERIFY(staticWidget.gotPaintEvent);
+ QVERIFY(staticWidget.waitForPaintEvent());
QCOMPARE(staticWidget.partial, true);
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
staticWidget.resize(staticWidget.size() + QSize(-10, -10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
staticWidget.setAttribute(Qt::WA_StaticContents, false);
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
staticWidget.resize(staticWidget.size() + QSize(-10, -10));
- QTRY_VERIFY(staticWidget.gotPaintEvent);
+ QVERIFY(staticWidget.waitForPaintEvent());
QCOMPARE(staticWidget.partial, false);
staticWidget.setAttribute(Qt::WA_StaticContents, true);
staticWidget.setAttribute(Qt::WA_StaticContents, false);
- staticWidget.gotPaintEvent = false;
staticWidget.move(staticWidget.pos() + QPoint(10, 10));
- QTest::qWait(20);
- QCOMPARE(staticWidget.gotPaintEvent, false);
+ QVERIFY(!staticWidget.waitForPaintEvent());
staticWidget.setAttribute(Qt::WA_StaticContents, true);
}
void tst_QWidget::optimizedResize_topLevel()
{
- if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
- QSKIP("Wayland: This fails. Figure out why.");
+ const bool wayland = QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
if (QHighDpiScaling::isActive())
QSKIP("Skip due to rounding errors in the regions.");
- StaticWidget topLevel;
+ StaticWidget topLevel(simplePalette());
+ topLevel.setPalette(simplePalette());
topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- topLevel.gotPaintEvent = false;
topLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
- QTRY_VERIFY(topLevel.gotPaintEvent);
+ QVERIFY(topLevel.waitForPaintEvent());
- topLevel.gotPaintEvent = false;
topLevel.partial = false;
topLevel.paintedRegion = QRegion();
@@ -4394,10 +5136,15 @@ void tst_QWidget::optimizedResize_topLevel()
QRegion expectedUpdateRegion(topLevel.rect());
expectedUpdateRegion -= QRect(QPoint(), topLevel.size() - QSize(10, 10));
- QTRY_VERIFY(topLevel.gotPaintEvent);
+ QVERIFY(topLevel.waitForPaintEvent());
if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("offscreen"))
QSKIP("QTBUG-26424");
- QCOMPARE(topLevel.partial, true);
+ if (!wayland) {
+ QCOMPARE(topLevel.partial, true);
+ } else {
+ if (!topLevel.partial)
+ QSKIP("Wayland does repaint partially. Skipping test.");
+ }
QCOMPARE(topLevel.paintedRegion, expectedUpdateRegion);
}
@@ -4567,7 +5314,7 @@ protected:
}
public:
QList<WId> m_winIdList;
- int winIdChangeEventCount() const { return m_winIdList.count(); }
+ int winIdChangeEventCount() const { return m_winIdList.size(); }
};
class CreateDestroyWidget : public WinIdChangeWidget
@@ -4622,6 +5369,84 @@ void tst_QWidget::createAndDestroy()
QVERIFY(widget.internalWinId());
}
+void tst_QWidget::eventsAndAttributesOnDestroy()
+{
+ // The events and attributes when destroying a widget should
+ // include those of hiding the widget.
+
+ CreateDestroyWidget widget;
+ EventSpy<QWidget> showEventSpy(&widget, QEvent::Show);
+ EventSpy<QWidget> hideEventSpy(&widget, QEvent::Hide);
+
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_Mapped), false);
+
+ widget.show();
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), true);
+ QTRY_COMPARE(widget.testAttribute(Qt::WA_Mapped), true);
+ QCOMPARE(showEventSpy.count(), 1);
+ QCOMPARE(hideEventSpy.count(), 0);
+
+ widget.hide();
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_Mapped), false);
+ QCOMPARE(showEventSpy.count(), 1);
+ QCOMPARE(hideEventSpy.count(), 1);
+
+ widget.show();
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), true);
+ QTRY_COMPARE(widget.testAttribute(Qt::WA_Mapped), true);
+ QCOMPARE(showEventSpy.count(), 2);
+ QCOMPARE(hideEventSpy.count(), 1);
+
+ widget.destroy();
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_Mapped), false);
+ QCOMPARE(showEventSpy.count(), 2);
+ QCOMPARE(hideEventSpy.count(), 2);
+
+ const int hideEventsAfterDestroy = hideEventSpy.count();
+
+ widget.create();
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_Mapped), false);
+ QCOMPARE(showEventSpy.count(), 2);
+ QCOMPARE(hideEventSpy.count(), hideEventsAfterDestroy);
+
+ QWidgetPrivate::get(&widget)->setVisible(true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), true);
+ QTRY_COMPARE(widget.testAttribute(Qt::WA_Mapped), true);
+ QCOMPARE(showEventSpy.count(), 3);
+ QCOMPARE(hideEventSpy.count(), hideEventsAfterDestroy);
+
+ // Make sure the destroy that happens when a top level
+ // is moved to being a child does not prevent the child
+ // being shown again.
+
+ QWidget parent;
+ QWidget child;
+ parent.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&parent));
+ child.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&child));
+
+ child.setParent(&parent);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Created), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), false);
+
+ child.show();
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Created), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), true);
+ QVERIFY(QTest::qWaitForWindowExposed(&child));
+}
+
void tst_QWidget::winIdChangeEvent()
{
{
@@ -4761,6 +5586,75 @@ void tst_QWidget::showNativeChild()
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
}
+void tst_QWidget::closeAndShowNativeChild()
+{
+ QWidget topLevel;
+ QWidget *nativeChild = new QWidget;
+ nativeChild->winId();
+ nativeChild->setFixedSize(200, 200);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(nativeChild);
+ topLevel.setLayout(layout);
+
+ topLevel.show();
+ QVERIFY(!nativeChild->isHidden());
+ nativeChild->close();
+ QVERIFY(nativeChild->isHidden());
+ nativeChild->show();
+ QVERIFY(!nativeChild->isHidden());
+}
+
+void tst_QWidget::closeAndShowWithNativeChild()
+{
+ bool dontCreateNativeWidgetSiblings = QApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+ auto resetAttribute = qScopeGuard([&]{
+ QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, dontCreateNativeWidgetSiblings);
+ });
+ QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+
+ QWidget topLevel;
+ topLevel.setObjectName("TopLevel");
+ QWidget *nativeChild = new QWidget;
+ nativeChild->setObjectName("NativeChild");
+ nativeChild->setFixedSize(200, 200);
+ QWidget *normalChild = new QWidget;
+ normalChild->setObjectName("NormalChild");
+ normalChild->setFixedSize(200, 200);
+
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(nativeChild);
+ layout->addWidget(normalChild);
+ topLevel.setLayout(layout);
+
+ nativeChild->setAttribute(Qt::WA_NativeWindow);
+
+ QCOMPARE(normalChild->testAttribute(Qt::WA_WState_Hidden), false);
+ QCOMPARE(normalChild->testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+
+ QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_Hidden), false);
+ QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ const QSize originalSize = topLevel.size();
+ topLevel.close();
+
+ // all children must have the same state
+ QCOMPARE(nativeChild->isHidden(), normalChild->isHidden());
+ QCOMPARE(nativeChild->isVisible(), normalChild->isVisible());
+ QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_Visible),
+ normalChild->testAttribute(Qt::WA_WState_Visible));
+ QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_Hidden),
+ normalChild->testAttribute(Qt::WA_WState_Hidden));
+ QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_ExplicitShowHide),
+ normalChild->testAttribute(Qt::WA_WState_ExplicitShowHide));
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ QCOMPARE(topLevel.size(), originalSize);
+}
+
class ShowHideEventWidget : public QWidget
{
public:
@@ -4910,6 +5804,7 @@ void tst_QWidget::update()
Q_CHECK_PAINTEVENTS
UpdateWidget w;
+ w.setPalette(simplePalette());
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
w.resize(100, 100);
centerOnScreen(&w);
@@ -4923,6 +5818,7 @@ void tst_QWidget::update()
w.reset();
UpdateWidget child(&w);
+ child.setPalette(simplePalette());
child.setGeometry(10, 10, 80, 80);
child.show();
@@ -4994,6 +5890,7 @@ void tst_QWidget::update()
// overlapping sibling
UpdateWidget sibling(&w);
+ sibling.setPalette(simplePalette());
child.setGeometry(10, 10, 20, 20);
sibling.setGeometry(15, 15, 20, 20);
sibling.show();
@@ -5073,9 +5970,11 @@ void tst_QWidget::isOpaque()
{
#ifndef Q_OS_MACOS
QWidget w;
+ w.setPalette(simplePalette());
QVERIFY(::isOpaque(&w));
QWidget child(&w);
+ child.setPalette(simplePalette());
QVERIFY(!::isOpaque(&child));
child.setAutoFillBackground(true);
@@ -5157,11 +6056,11 @@ void tst_QWidget::scroll()
const int h = qMin(500, screen->availableGeometry().height() / 2);
UpdateWidget updateWidget;
+ updateWidget.setPalette(simplePalette());
updateWidget.resize(w, h);
updateWidget.reset();
- updateWidget.move(QGuiApplication::primaryScreen()->geometry().center() - QPoint(250, 250));
+ updateWidget.move(m_availableTopLeft);
updateWidget.showNormal();
- QApplication::setActiveWindow(&updateWidget);
QVERIFY(QTest::qWaitForWindowActive(&updateWidget));
QVERIFY(updateWidget.numPaintEvents > 0);
@@ -5236,34 +6135,74 @@ void tst_QWidget::scrollNativeChildren()
#endif // Mac OS
-class DestroyedSlotChecker : public QObject
+/*
+ This class is used as a slot object to test two different steps of
+ QWidget destruction.
+
+ The first step is connecting the destroyed() signal to an object of
+ this class (through its operator()). In widgets, destroyed() is
+ emitted by ~QWidget, and not by ~QObject. This means that in our
+ operator() we expect the sender of the signal to still be a
+ QWidget.
+
+ The connection realized at the first step means that now there's
+ an instance of this class owned by the sender object. That instance
+ is destroyed when the signal/slot connections are destroyed.
+ That happens in ~QObject, not in ~QWidget. Therefore, in the
+ destructor of this class, check that indeed the target is no longer
+ a QWidget but just a QObject.
+*/
+class QObjectCastChecker
{
- Q_OBJECT
-
public:
- bool wasQWidget = false;
+ explicit QObjectCastChecker(QWidget *target)
+ : m_target(target)
+ {
+ }
-public slots:
- void destroyedSlot(QObject *object)
+ ~QObjectCastChecker()
{
- wasQWidget = (qobject_cast<QWidget *>(object) != nullptr || object->isWidgetType());
+ if (!m_target)
+ return;
+
+ // When ~QObject is reached, check that indeed the object is no
+ // longer a QWidget. This relies on slots being disconnected in
+ // ~QObject (and this "slot object" being destroyed there).
+ QVERIFY(!qobject_cast<QWidget *>(m_target));
+ QVERIFY(!dynamic_cast<QWidget *>(m_target));
+ QVERIFY(!m_target->isWidgetType());
}
-};
-/*
- Test that qobject_cast<QWidget*> returns 0 in a slot
- connected to QObject::destroyed.
-*/
-void tst_QWidget::qobject_castInDestroyedSlot()
-{
- DestroyedSlotChecker checker;
+ QObjectCastChecker(QObjectCastChecker &&other) noexcept
+ : m_target(std::exchange(other.m_target, nullptr))
+ {}
- QWidget *widget = new QWidget();
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QObjectCastChecker)
- QObject::connect(widget, &QObject::destroyed, &checker, &DestroyedSlotChecker::destroyedSlot);
- delete widget;
+ void swap(QObjectCastChecker &other) noexcept
+ {
+ qSwap(m_target, other.m_target);
+ }
+
+ void operator()(QObject *object) const
+ {
+ // Test that in a slot connected to destroyed() the emitter is
+ // still a QWidget. This is because ~QWidget() itself emits the
+ // signal.
+ QVERIFY(qobject_cast<QWidget *>(object));
+ QVERIFY(dynamic_cast<QWidget *>(object));
+ QVERIFY(object->isWidgetType());
+ }
+
+private:
+ Q_DISABLE_COPY(QObjectCastChecker)
+ QObject *m_target;
+};
- QVERIFY(checker.wasQWidget);
+void tst_QWidget::qobject_castOnDestruction()
+{
+ QWidget widget;
+ QObject::connect(&widget, &QObject::destroyed, QObjectCastChecker(&widget));
}
// Since X11 WindowManager operations are all async, and we have no way to know if the window
@@ -5309,7 +6248,7 @@ void tst_QWidget::setWindowGeometry_data()
const Qt::WindowFlags windowFlags[] = {Qt::WindowFlags(), Qt::FramelessWindowHint};
const bool skipEmptyRects = (m_platform == QStringLiteral("windows"));
- for (Rects l : qAsConst(rects)) {
+ for (Rects l : std::as_const(rects)) {
if (skipEmptyRects)
l.removeIf([] (const QRect &r) { return r.isEmpty(); });
const QRect &rect = l.constFirst();
@@ -5328,8 +6267,8 @@ void tst_QWidget::setWindowGeometry_data()
void tst_QWidget::setWindowGeometry()
{
- if (m_platform == QStringLiteral("xcb"))
- QSKIP("X11: Skip this test due to Window manager positioning issues.");
+ if (m_platform == QStringLiteral("xcb") || m_platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("X11/Wayland: Skip this test due to Window manager positioning issues.");
QFETCH(Rects, rects);
QFETCH(int, windowFlags);
@@ -5346,7 +6285,7 @@ void tst_QWidget::setWindowGeometry()
QCOMPARE(widget.geometry(), rect);
// setGeometry() without showing
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.setGeometry(r);
QTest::qWait(100);
QCOMPARE(widget.geometry(), r);
@@ -5372,7 +6311,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// setGeometry() while shown
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.setGeometry(r);
QTest::qWait(10);
QTRY_COMPARE(widget.geometry(), r);
@@ -5387,7 +6326,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// setGeometry() after hide()
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.setGeometry(r);
QTest::qWait(10);
QTRY_COMPARE(widget.geometry(), r);
@@ -5397,7 +6336,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// show() again, geometry() should still be the same
- widget.show();
+ QTestPrivate::androidCompatibleShow(&widget);
if (rect.isValid())
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QTRY_COMPARE(widget.geometry(), rect);
@@ -5423,7 +6362,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// setGeometry() while shown
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.setGeometry(r);
QTest::qWait(10);
QTRY_COMPARE(widget.geometry(), r);
@@ -5438,7 +6377,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// setGeometry() after hide()
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.setGeometry(r);
QTest::qWait(10);
QTRY_COMPARE(widget.geometry(), r);
@@ -5448,7 +6387,7 @@ void tst_QWidget::setWindowGeometry()
QTRY_COMPARE(widget.geometry(), rect);
// show() again, geometry() should still be the same
- widget.show();
+ QTestPrivate::androidCompatibleShow(&widget);
if (rect.isValid())
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QTest::qWait(10);
@@ -5517,7 +6456,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// move() without showing
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.move(r.topLeft());
widget.resize(r.size());
QApplication::processEvents();
@@ -5547,7 +6486,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// move() while shown
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
// XCB: First resize after show of zero-sized gets wrong win_gravity.
const bool expectMoveFail = !windowFlags
&& ((widget.width() == 0 || widget.height() == 0) && r.width() != 0 && r.height() != 0)
@@ -5576,7 +6515,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// move() after hide()
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.move(r.topLeft());
widget.resize(r.size());
QApplication::processEvents();
@@ -5596,7 +6535,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// show() again, pos() should be the same
- widget.show();
+ QTestPrivate::androidCompatibleShow(&widget);
if (rect.isValid())
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QApplication::processEvents();
@@ -5627,7 +6566,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// move() while shown
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.move(r.topLeft());
widget.resize(r.size());
QApplication::processEvents();
@@ -5647,7 +6586,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// move() after hide()
- for (const QRect &r : qAsConst(rects)) {
+ for (const QRect &r : std::as_const(rects)) {
widget.move(r.topLeft());
widget.resize(r.size());
QApplication::processEvents();
@@ -5667,7 +6606,7 @@ void tst_QWidget::windowMoveResize()
QTRY_COMPARE(widget.size(), rect.size());
// show() again, pos() should be the same
- widget.show();
+ QTestPrivate::androidCompatibleShow(&widget);
if (rect.isValid())
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QTest::qWait(10);
@@ -5809,8 +6748,7 @@ void tst_QWidget::moveChild()
parent.setStyle(style.data());
ColorWidget child(&parent, Qt::Widget, Qt::blue);
- parent.setGeometry(QRect(parent.screen()->availableGeometry().topLeft() + QPoint(50, 50),
- QSize(200, 200)));
+ parent.setGeometry(QRect(m_availableTopLeft + QPoint(50, 50), QSize(200, 200)));
child.setGeometry(25, 25, 50, 50);
#ifndef QT_NO_CURSOR // Try to make sure the cursor is not in a taskbar area to prevent tooltips or window highlighting
QCursor::setPos(parent.geometry().topRight() + QPoint(50 , 50));
@@ -5846,16 +6784,18 @@ void tst_QWidget::moveChild()
QTRY_COMPARE(pos, child.pos());
QTRY_COMPARE(parent.r, QRegion(oldGeometry) - child.geometry());
-#if !defined(Q_OS_MACOS)
+
// should be scrolled in backingstore
QCOMPARE(child.r, QRegion());
-#endif
VERIFY_COLOR(child, child.rect(), child.color);
VERIFY_COLOR(parent, QRegion(parent.rect()) - child.geometry(), parent.color);
}
void tst_QWidget::showAndMoveChild()
{
+#ifdef ANDROID
+ QSKIP("Fails on Android due to removed grabWindow(): QTBUG-118849");
+#endif
if (m_platform == QStringLiteral("wayland"))
QSKIP("Wayland: This fails. Figure out why.");
QWidget parent(nullptr, Qt::Window | Qt::WindowStaysOnTopHint);
@@ -5873,7 +6813,6 @@ void tst_QWidget::showAndMoveChild()
parent.setGeometry(desktopDimensions);
parent.setPalette(Qt::red);
parent.show();
- QApplication::setActiveWindow(&parent);
QVERIFY(QTest::qWaitForWindowActive(&parent));
QWidget child(&parent);
@@ -5992,17 +6931,17 @@ void tst_QWidget::multipleToplevelFocusCheck()
w2.show();
QVERIFY(QTest::qWaitForWindowExposed(&w2));
- QApplication::setActiveWindow(&w1);
w1.activateWindow();
+ QApplicationPrivate::setActiveWindow(&w1);
QVERIFY(QTest::qWaitForWindowActive(&w1));
- QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
QTest::mouseDClick(&w1, Qt::LeftButton);
QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w1.edit));
w2.activateWindow();
- QApplication::setActiveWindow(&w2);
+ QApplicationPrivate::setActiveWindow(&w2);
QVERIFY(QTest::qWaitForWindowActive(&w2));
- QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
QTest::mouseClick(&w2, Qt::LeftButton);
QTRY_COMPARE(QApplication::focusWidget(), nullptr);
@@ -6010,16 +6949,16 @@ void tst_QWidget::multipleToplevelFocusCheck()
QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w2.edit));
w1.activateWindow();
- QApplication::setActiveWindow(&w1);
+ QApplicationPrivate::setActiveWindow(&w1);
QVERIFY(QTest::qWaitForWindowActive(&w1));
- QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
QTest::mouseDClick(&w1, Qt::LeftButton);
QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w1.edit));
w2.activateWindow();
- QApplication::setActiveWindow(&w2);
+ QApplicationPrivate::setActiveWindow(&w2);
QVERIFY(QTest::qWaitForWindowActive(&w2));
- QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
+ QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
QTest::mouseClick(&w2, Qt::LeftButton);
QTRY_COMPARE(QApplication::focusWidget(), nullptr);
}
@@ -6082,7 +7021,7 @@ void tst_QWidget::setFocus()
{
// move focus to another window
testWidget->activateWindow();
- QApplication::setActiveWindow(testWidget.data());
+ QApplicationPrivate::setActiveWindow(testWidget.data());
if (testWidget->focusWidget())
testWidget->focusWidget()->clearFocus();
else
@@ -6128,7 +7067,7 @@ void tst_QWidget::setFocus()
// note: window may be active, but we don't want it to be
testWidget->activateWindow();
- QApplication::setActiveWindow(testWidget.data());
+ QApplicationPrivate::setActiveWindow(testWidget.data());
if (testWidget->focusWidget())
testWidget->focusWidget()->clearFocus();
else
@@ -6304,34 +7243,6 @@ void tst_QWidget::setFocus()
}
}
-template<class T> class EventSpy : public QObject
-{
-public:
- EventSpy(T *widget, QEvent::Type event)
- : m_widget(widget), eventToSpy(event)
- {
- if (m_widget)
- m_widget->installEventFilter(this);
- }
-
- T *widget() const { return m_widget; }
- int count() const { return m_count; }
- void clear() { m_count = 0; }
-
-protected:
- bool eventFilter(QObject *object, QEvent *event) override
- {
- if (event->type() == eventToSpy)
- ++m_count;
- return QObject::eventFilter(object, event);
- }
-
-private:
- T *m_widget;
- const QEvent::Type eventToSpy;
- int m_count = 0;
-};
-
#ifndef QT_NO_CURSOR
void tst_QWidget::setCursor()
{
@@ -6481,6 +7392,9 @@ void tst_QWidget::setToolTip()
QCOMPARE(widget.toolTip(), QString());
QCOMPARE(spy.count(), 2);
+ const int wakeUpDelay = widget.style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
+ const int fallAsleepDelay = widget.style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
+
for (int pass = 0; pass < 2; ++pass) {
QCursor::setPos(m_safeCursorPos);
QScopedPointer<QWidget> popup(new QWidget(nullptr, Qt::Popup));
@@ -6500,12 +7414,12 @@ void tst_QWidget::setToolTip()
QWindow *popupWindow = popup->windowHandle();
QTest::qWait(10);
QTest::mouseMove(popupWindow, QPoint(25, 25));
- QTest::qWait(900); // delay is 700
+ QTest::qWait(wakeUpDelay + 200);
QCOMPARE(spy1.count(), 1);
QCOMPARE(spy2.count(), 0);
if (pass == 0)
- QTest::qWait(2200); // delay is 2000
+ QTest::qWait(fallAsleepDelay + 200);
QTest::mouseMove(popupWindow);
}
@@ -6532,7 +7446,7 @@ void tst_QWidget::testWindowIconChangeEventPropagation()
QWidgetList widgets;
widgets << &topLevelWidget << &topLevelChild
<< &dialog << &dialogChild;
- QCOMPARE(widgets.count(), 4);
+ QCOMPARE(widgets.size(), 4);
topLevelWidget.show();
dialog.show();
@@ -6546,13 +7460,13 @@ void tst_QWidget::testWindowIconChangeEventPropagation()
// Create spy lists.
QList <EventSpyPtr> applicationEventSpies;
QList <EventSpyPtr> widgetEventSpies;
- for (QWidget *widget : qAsConst(widgets)) {
+ for (QWidget *widget : std::as_const(widgets)) {
applicationEventSpies.append(EventSpyPtr::create(widget, QEvent::ApplicationWindowIconChange));
widgetEventSpies.append(EventSpyPtr::create(widget, QEvent::WindowIconChange));
}
QList <WindowEventSpyPtr> appWindowEventSpies;
QList <WindowEventSpyPtr> windowEventSpies;
- for (QWindow *window : qAsConst(windows)) {
+ for (QWindow *window : std::as_const(windows)) {
appWindowEventSpies.append(WindowEventSpyPtr::create(window, QEvent::ApplicationWindowIconChange));
windowEventSpies.append(WindowEventSpyPtr::create(window, QEvent::WindowIconChange));
}
@@ -6561,7 +7475,7 @@ void tst_QWidget::testWindowIconChangeEventPropagation()
const QIcon windowIcon = qApp->style()->standardIcon(QStyle::SP_TitleBarMenuButton);
qApp->setWindowIcon(windowIcon);
- for (int i = 0; i < widgets.count(); ++i) {
+ for (int i = 0; i < widgets.size(); ++i) {
// Check QEvent::ApplicationWindowIconChange
EventSpyPtr spy = applicationEventSpies.at(i);
QWidget *widget = spy->widget();
@@ -6578,7 +7492,7 @@ void tst_QWidget::testWindowIconChangeEventPropagation()
QCOMPARE(spy->count(), 1);
spy->clear();
}
- for (int i = 0; i < windows.count(); ++i) {
+ for (int i = 0; i < windows.size(); ++i) {
// Check QEvent::ApplicationWindowIconChange (sent to QWindow)
// QWidgetWindows don't get this event, since the widget takes care of changing the icon
WindowEventSpyPtr spy = appWindowEventSpies.at(i);
@@ -6596,7 +7510,7 @@ void tst_QWidget::testWindowIconChangeEventPropagation()
// Set icon on a top-level widget.
topLevelWidget.setWindowIcon(QIcon());
- for (int i = 0; i < widgets.count(); ++i) {
+ for (int i = 0; i < widgets.size(); ++i) {
// Check QEvent::ApplicationWindowIconChange
EventSpyPtr spy = applicationEventSpies.at(i);
QCOMPARE(spy->count(), 0);
@@ -6753,14 +7667,12 @@ void tst_QWidget::clean_qt_x11_enforce_cursor()
child->setAttribute(Qt::WA_SetCursor, true);
window.show();
- QApplication::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QTest::qWait(100);
QCursor::setPos(window.geometry().center());
QTest::qWait(100);
child->setFocus();
- QApplication::processEvents();
QTest::qWait(100);
delete w;
@@ -6796,8 +7708,19 @@ public:
bool eventFilter(QObject *object, QEvent *event) override
{
QWidget *widget = qobject_cast<QWidget *>(object);
- if (widget && !event->spontaneous())
- events.append(qMakePair(widget, event->type()));
+ if (widget && !event->spontaneous()) {
+ switch (event->type()) {
+ // we might get those events if we couldn't move the cursor
+ case QEvent::Enter:
+ case QEvent::Leave:
+ // we might get this on systems that have an input method installed
+ case QEvent::InputMethodQuery:
+ break;
+ default:
+ events.append(qMakePair(widget, event->type()));
+ break;
+ }
+ }
return false;
}
@@ -6839,11 +7762,6 @@ void tst_QWidget::childEvents()
{
EventRecorder::EventList expected;
- // Move away the cursor; otherwise it might result in an enter event if it's
- // inside the widget when the widget is shown.
- QCursor::setPos(m_safeCursorPos);
- QTest::qWait(100);
-
{
// no children created, not shown
QWidget widget;
@@ -6883,7 +7801,9 @@ void tst_QWidget::childEvents()
<< qMakePair(&widget, QEvent::Move)
<< qMakePair(&widget, QEvent::Resize)
<< qMakePair(&widget, QEvent::Show)
+#ifndef Q_OS_ANDROID
<< qMakePair(&widget, QEvent::CursorChange)
+#endif
<< qMakePair(&widget, QEvent::ShowToParent);
QVERIFY2(spy.eventList() == expected,
@@ -6972,7 +7892,9 @@ void tst_QWidget::childEvents()
<< qMakePair(&widget, QEvent::Move)
<< qMakePair(&widget, QEvent::Resize)
<< qMakePair(&widget, QEvent::Show)
+#ifndef Q_OS_ANDROID
<< qMakePair(&widget, QEvent::CursorChange)
+#endif
<< qMakePair(&widget, QEvent::ShowToParent);
QVERIFY2(spy.eventList() == expected,
@@ -7064,7 +7986,9 @@ void tst_QWidget::childEvents()
<< qMakePair(&widget, QEvent::Move)
<< qMakePair(&widget, QEvent::Resize)
<< qMakePair(&widget, QEvent::Show)
+#ifndef Q_OS_ANDROID
<< qMakePair(&widget, QEvent::CursorChange)
+#endif
<< qMakePair(&widget, QEvent::ShowToParent);
QVERIFY2(spy.eventList() == expected,
@@ -7119,7 +8043,9 @@ private:
void tst_QWidget::render()
{
- return;
+#ifdef Q_OS_ANDROID
+ QSKIP("QTBUG-118984: crashes on Android.");
+#endif
QCalendarWidget source;
source.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
// disable anti-aliasing to eliminate potential differences when subpixel antialiasing
@@ -7134,16 +8060,11 @@ void tst_QWidget::render()
RenderWidget target(&source);
target.resize(source.size());
target.show();
-
- QCoreApplication::processEvents();
- QCoreApplication::sendPostedEvents();
- QTest::qWait(250);
+ QVERIFY(QTest::qWaitForWindowExposed(&target));
const QImage sourceImage = source.grab(QRect(QPoint(0, 0), QSize(-1, -1))).toImage();
- QCoreApplication::processEvents();
QImage targetImage = target.grab(QRect(QPoint(0, 0), QSize(-1, -1))).toImage();
- QCoreApplication::processEvents();
- QCOMPARE(sourceImage, targetImage);
+ QTRY_COMPARE(sourceImage, targetImage);
// Fill target.rect() will Qt::red and render
// QRegion(0, 0, source->width(), source->height() / 2, QRegion::Ellipse)
@@ -7156,66 +8077,73 @@ void tst_QWidget::render()
QVERIFY(sourceImage != targetImage);
QCOMPARE(targetImage.pixel(target.width() / 2, 29), QColor(Qt::red).rgb());
+ if (targetImage.devicePixelRatioF() > 1)
+ QEXPECT_FAIL("", "This test fails on high-DPI displays", Continue);
QCOMPARE(targetImage.pixel(target.width() / 2, 30), sourceImage.pixel(source.width() / 2, 0));
+}
- // Test that a child widget properly fills its background
- {
- QWidget window;
- window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- window.resize(100, 100);
- // prevent custom styles
- window.setStyle(QStyleFactory::create(QLatin1String("Windows")));
- window.show();
- QVERIFY(QTest::qWaitForWindowExposed(&window));
- QWidget child(&window);
- child.resize(window.size());
- child.show();
+// Test that a child widget properly fills its background
+void tst_QWidget::renderChildFillsBackground()
+{
+ QWidget window;
+ window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ window.resize(100, 100);
+ // prevent custom styles
+ window.setStyle(QStyleFactory::create(QLatin1String("Windows")));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QWidget child(&window);
+ child.resize(window.size());
+ child.show();
- QCoreApplication::processEvents();
- const QPixmap childPixmap = child.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
- const QPixmap windowPixmap = window.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
- QCOMPARE(childPixmap, windowPixmap);
- }
+ QCoreApplication::processEvents();
+ const QPixmap childPixmap = child.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
+ const QPixmap windowPixmap = window.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
+#ifndef Q_OS_ANDROID
+ // On Android all widgets are shown maximized, so the pixmaps
+ // will be similar
+ if (!m_platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QEXPECT_FAIL("", "This test fails on all platforms", Continue);
+#endif
+ QCOMPARE(childPixmap, windowPixmap);
+}
- { // Check that the target offset is correct.
- QWidget widget;
- widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- widget.resize(200, 200);
- widget.setAutoFillBackground(true);
- widget.setPalette(Qt::red);
- // prevent custom styles
- widget.setStyle(QStyleFactory::create(QLatin1String("Windows")));
- widget.show();
- QVERIFY(QTest::qWaitForWindowExposed(&widget));
- QImage image(widget.size(), QImage::Format_RGB32);
- image.fill(QColor(Qt::blue).rgb());
-
- // Target offset (0, 0)
- widget.render(&image, QPoint(), QRect(20, 20, 100, 100));
- QCOMPARE(image.pixel(0, 0), QColor(Qt::red).rgb());
- QCOMPARE(image.pixel(99, 99), QColor(Qt::red).rgb());
- QCOMPARE(image.pixel(100, 100), QColor(Qt::blue).rgb());
-
- // Target offset (20, 20).
- image.fill(QColor(Qt::blue).rgb());
- widget.render(&image, QPoint(20, 20), QRect(20, 20, 100, 100));
- QCOMPARE(image.pixel(0, 0), QColor(Qt::blue).rgb());
- QCOMPARE(image.pixel(19, 19), QColor(Qt::blue).rgb());
- QCOMPARE(image.pixel(20, 20), QColor(Qt::red).rgb());
- QCOMPARE(image.pixel(119, 119), QColor(Qt::red).rgb());
- QCOMPARE(image.pixel(120, 120), QColor(Qt::blue).rgb());
- }
-}
-
-// On Windows the active palette is used instead of the inactive palette even
-// though the widget is invisible. This is probably related to task 178507/168682,
-// but for the renderInvisible test it doesn't matter, we're mostly interested
-// in testing the geometry so just workaround the palette issue for now.
+void tst_QWidget::renderTargetOffset()
+{ // Check that the target offset is correct.
+ QWidget widget;
+ widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ widget.resize(200, 200);
+ widget.setAutoFillBackground(true);
+ widget.setPalette(Qt::red);
+ // prevent custom styles
+ widget.setStyle(QStyleFactory::create(QLatin1String("Windows")));
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+ QImage image(widget.size(), QImage::Format_RGB32);
+ image.fill(QColor(Qt::blue).rgb());
+
+ // Target offset (0, 0)
+ widget.render(&image, QPoint(), QRect(20, 20, 100, 100));
+ QCOMPARE(image.pixel(0, 0), QColor(Qt::red).rgb());
+ QCOMPARE(image.pixel(99, 99), QColor(Qt::red).rgb());
+ QCOMPARE(image.pixel(100, 100), QColor(Qt::blue).rgb());
+
+ // Target offset (20, 20).
+ image.fill(QColor(Qt::blue).rgb());
+ widget.render(&image, QPoint(20, 20), QRect(20, 20, 100, 100));
+ QCOMPARE(image.pixel(0, 0), QColor(Qt::blue).rgb());
+ QCOMPARE(image.pixel(19, 19), QColor(Qt::blue).rgb());
+ QCOMPARE(image.pixel(20, 20), QColor(Qt::red).rgb());
+ QCOMPARE(image.pixel(119, 119), QColor(Qt::red).rgb());
+ QCOMPARE(image.pixel(120, 120), QColor(Qt::blue).rgb());
+}
+
+// On some platforms the active palette is used instead of the inactive palette even
+// though the widget is invisible, but for the renderInvisible test it doesn't matter,
+// as we're mostly interested in testing the geometry, so just workaround the palette
+// issue for now.
static void workaroundPaletteIssue(QWidget *widget)
{
-#ifndef Q_OS_WIN
- return;
-#endif
if (!widget)
return;
@@ -7236,6 +8164,9 @@ void tst_QWidget::renderInvisible()
if (m_platform == QStringLiteral("xcb"))
QSKIP("QTBUG-26424");
+ if (m_platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Wayland: Skip this test, see also QTBUG-107157");
+
QScopedPointer<QCalendarWidget> calendar(new QCalendarWidget);
calendar->move(m_availableTopLeft + QPoint(100, 100));
calendar->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
@@ -7253,12 +8184,10 @@ void tst_QWidget::renderInvisible()
dummyFocusWidget.move(calendar->geometry().bottomLeft() + QPoint(0, 100));
dummyFocusWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&dummyFocusWidget));
- QCoreApplication::processEvents();
- QTest::qWait(120);
// Create normal reference image.
const QSize calendarSize = calendar->size();
- QImage referenceImage(calendarSize, QImage::Format_ARGB32);
+ QImage referenceImage(calendarSize, QImage::Format_ARGB32_Premultiplied);
calendar->render(&referenceImage);
#ifdef RENDER_DEBUG
referenceImage.save("referenceImage.png");
@@ -7268,9 +8197,8 @@ void tst_QWidget::renderInvisible()
// Create resized reference image.
const QSize calendarSizeResized = calendar->size() + QSize(50, 50);
calendar->resize(calendarSizeResized);
- QCoreApplication::processEvents();
QTest::qWait(30);
- QImage referenceImageResized(calendarSizeResized, QImage::Format_ARGB32);
+ QImage referenceImageResized(calendarSizeResized, QImage::Format_ARGB32_Premultiplied);
calendar->render(&referenceImageResized);
#ifdef RENDER_DEBUG
referenceImageResized.save("referenceImageResized.png");
@@ -7279,12 +8207,11 @@ void tst_QWidget::renderInvisible()
// Explicitly hide the calendar.
calendar->hide();
- QCoreApplication::processEvents();
QTest::qWait(30);
workaroundPaletteIssue(calendar.data());
{ // Make sure we get the same image when the calendar is explicitly hidden.
- QImage testImage(calendarSizeResized, QImage::Format_ARGB32);
+ QImage testImage(calendarSizeResized, QImage::Format_ARGB32_Premultiplied);
calendar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("explicitlyHiddenCalendarResized.png");
@@ -7300,7 +8227,7 @@ void tst_QWidget::renderInvisible()
workaroundPaletteIssue(calendar.data());
{ // Never been visible, created or laid out.
- QImage testImage(calendarSize, QImage::Format_ARGB32);
+ QImage testImage(calendarSize, QImage::Format_ARGB32_Premultiplied);
calendar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("neverBeenVisibleCreatedOrLaidOut.png");
@@ -7309,11 +8236,10 @@ void tst_QWidget::renderInvisible()
}
calendar->hide();
- QCoreApplication::processEvents();
QTest::qWait(30);
{ // Calendar explicitly hidden.
- QImage testImage(calendarSize, QImage::Format_ARGB32);
+ QImage testImage(calendarSize, QImage::Format_ARGB32_Premultiplied);
calendar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("explicitlyHiddenCalendar.png");
@@ -7327,7 +8253,7 @@ void tst_QWidget::renderInvisible()
navigationBar->hide();
{ // Check that the navigation bar isn't drawn when rendering the entire calendar.
- QImage testImage(calendarSize, QImage::Format_ARGB32);
+ QImage testImage(calendarSize, QImage::Format_ARGB32_Premultiplied);
calendar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("calendarWithoutNavigationBar.png");
@@ -7336,7 +8262,7 @@ void tst_QWidget::renderInvisible()
}
{ // Make sure the navigation bar renders correctly even though it's hidden.
- QImage testImage(navigationBar->size(), QImage::Format_ARGB32);
+ QImage testImage(navigationBar->size(), QImage::Format_ARGB32_Premultiplied);
navigationBar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("explicitlyHiddenNavigationBar.png");
@@ -7350,7 +8276,7 @@ void tst_QWidget::renderInvisible()
{ // Render next month button.
// Fill test image with correct background color.
- QImage testImage(nextMonthButton->size(), QImage::Format_ARGB32);
+ QImage testImage(nextMonthButton->size(), QImage::Format_ARGB32_Premultiplied);
navigationBar->render(&testImage, QPoint(), QRegion(), QWidget::RenderFlags());
#ifdef RENDER_DEBUG
testImage.save("nextMonthButtonBackground.png");
@@ -7377,7 +8303,6 @@ void tst_QWidget::renderInvisible()
// Navigation bar isn't explicitly hidden anymore.
navigationBar->show();
- QCoreApplication::processEvents();
QTest::qWait(30);
QVERIFY(!calendar->isVisible());
@@ -7389,7 +8314,7 @@ void tst_QWidget::renderInvisible()
QCoreApplication::processEvents();
{ // Make sure we get an image equal to the resized reference image.
- QImage testImage(calendarSizeResized, QImage::Format_ARGB32);
+ QImage testImage(calendarSizeResized, QImage::Format_ARGB32_Premultiplied);
calendar->render(&testImage);
#ifdef RENDER_DEBUG
testImage.save("calendarResized.png");
@@ -7401,7 +8326,7 @@ void tst_QWidget::renderInvisible()
QCalendarWidget calendar;
const QSize calendarSize = calendar.sizeHint();
- QImage image(2 * calendarSize, QImage::Format_ARGB32);
+ QImage image(2 * calendarSize, QImage::Format_ARGB32_Premultiplied);
image.fill(QColor(Qt::red).rgb());
calendar.render(&image);
@@ -8088,7 +9013,7 @@ void tst_QWidget::moveWindowInShowEvent_data()
QTest::addColumn<QPoint>("initial");
QTest::addColumn<QPoint>("position");
- QPoint p = QGuiApplication::primaryScreen()->availableGeometry().topLeft();
+ QPoint p = m_availableTopLeft;
QTest::newRow("1") << p << (p + QPoint(10, 10));
QTest::newRow("2") << (p + QPoint(10,10)) << p;
@@ -8125,21 +9050,15 @@ void tst_QWidget::moveWindowInShowEvent()
// show it
widget.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
- QTest::qWait(100);
// it should have moved
QCOMPARE(widget.pos(), position);
}
void tst_QWidget::repaintWhenChildDeleted()
{
-#ifdef Q_OS_WIN
- QTest::qWait(1000);
-#endif
ColorWidget w(nullptr, Qt::FramelessWindowHint, Qt::red);
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- QPoint startPoint = w.screen()->availableGeometry().topLeft();
- startPoint.rx() += 50;
- startPoint.ry() += 50;
+ const QPoint startPoint = m_availableTopLeft + QPoint(50, 50);
w.setGeometry(QRect(startPoint, QSize(100, 100)));
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
@@ -8162,9 +9081,7 @@ void tst_QWidget::hideOpaqueChildWhileHidden()
{
ColorWidget w(nullptr, Qt::FramelessWindowHint, Qt::red);
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- QPoint startPoint = w.screen()->availableGeometry().topLeft();
- startPoint.rx() += 50;
- startPoint.ry() += 50;
+ const QPoint startPoint = m_availableTopLeft + QPoint(50, 50);
w.setGeometry(QRect(startPoint, QSize(100, 100)));
ColorWidget child(&w, Qt::Widget, Qt::blue);
@@ -8213,6 +9130,7 @@ void tst_QWidget::updateWhileMinimized()
QSKIP("Platform does not support showMinimized()");
#endif
UpdateWidget widget;
+ widget.setPalette(simplePalette());
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
// Filter out activation change and focus events to avoid update() calls in QWidget.
widget.updateOnActivationChangeAndFocusIn = false;
@@ -8240,7 +9158,8 @@ void tst_QWidget::updateWhileMinimized()
qDebug() << "xcb: XDG_CURRENT_DESKTOP=" << desktop;
if (desktop == QStringLiteral("ubuntu:GNOME")
|| desktop == QStringLiteral("GNOME-Classic:GNOME")
- || desktop == QStringLiteral("GNOME"))
+ || desktop == QStringLiteral("GNOME")
+ || desktop.isEmpty()) // on local VMs
count = 1;
}
QCOMPARE(widget.numPaintEvents, count);
@@ -8785,6 +9704,7 @@ void tst_QWidget::doubleRepaint()
QSKIP("Not having window server access causes the wrong number of repaints to be issues");
#endif
UpdateWidget widget;
+ widget.setPalette(simplePalette());
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
centerOnScreen(&widget);
widget.setFocusPolicy(Qt::StrongFocus);
@@ -8801,9 +9721,6 @@ void tst_QWidget::doubleRepaint()
// Minmize: Should not trigger a repaint.
widget.showMinimized();
QTest::qWait(10);
-#if defined(Q_OS_QNX)
- QEXPECT_FAIL("", "Platform does not support showMinimized()", Continue);
-#endif
QCOMPARE(widget.numPaintEvents, 0);
widget.numPaintEvents = 0;
@@ -8819,9 +9736,10 @@ void tst_QWidget::resizeInPaintEvent()
QWidget window;
window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
UpdateWidget widget(&window);
+ widget.setPalette(simplePalette());
window.resize(200, 200);
window.show();
- QApplication::setActiveWindow(&window);
+ QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowExposed(&window));
QTRY_VERIFY(widget.numPaintEvents > 0);
@@ -8875,6 +9793,46 @@ void tst_QWidget::opaqueChildren()
QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), QRegion());
}
+void tst_QWidget::dumpObjectTree()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
+ QWidget w;
+ w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ Q_SET_OBJECT_NAME(w);
+ w.move(100, 100);
+ w.resize(200, 200);
+
+ QLineEdit le(&w);
+ Q_SET_OBJECT_NAME(le);
+ le.resize(200, 200);
+
+ {
+ const char * const expected[] = {
+ "QWidget::w I",
+ " QLineEdit::le I",
+ " QWidgetLineControl:: ",
+ };
+ for (const char *line : expected)
+ QTest::ignoreMessage(QtDebugMsg, line);
+ w.dumpObjectTree();
+ }
+
+ QTestPrivate::androidCompatibleShow(&w);
+ QVERIFY(QTest::qWaitForWindowActive(&w));
+
+ {
+ const char * const expected[] = {
+ "QWidget::w <200x200+100+100>",
+ " QLineEdit::le F<200x200+0+0>",
+ " QWidgetLineControl:: ",
+ };
+ for (const char *line : expected)
+ QTest::ignoreMessage(QtDebugMsg, line);
+ w.dumpObjectTree();
+ }
+}
class MaskSetWidget : public QWidget
{
@@ -8889,6 +9847,8 @@ public:
paintedRegion += event->region();
for (const QRect &r : event->region())
p.fillRect(r, Qt::red);
+
+ repainted = true;
}
void resizeEvent(QResizeEvent *) override
@@ -8897,6 +9857,7 @@ public:
}
QRegion paintedRegion;
+ bool repainted = false;
public slots:
void resizeDown() { setGeometry(QRect(0, 50, 50, 50)); }
@@ -8906,6 +9867,7 @@ public slots:
void tst_QWidget::setMaskInResizeEvent()
{
UpdateWidget w;
+ w.setPalette(simplePalette());
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
w.reset();
w.resize(200, 200);
@@ -8923,19 +9885,19 @@ void tst_QWidget::setMaskInResizeEvent()
w.reset();
testWidget.paintedRegion = QRegion();
- QTimer::singleShot(0, &testWidget, SLOT(resizeDown()));
- QTest::qWait(100);
+ testWidget.resizeDown();
QRegion expectedParentUpdate(0, 0, 100, 10); // Old testWidget area.
expectedParentUpdate += testWidget.geometry(); // New testWidget area.
+ QTRY_VERIFY(testWidget.repainted);
QTRY_COMPARE(w.paintedRegion, expectedParentUpdate);
QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask());
testWidget.paintedRegion = QRegion();
- // Now resize the widget again, but in the oposite direction
- QTimer::singleShot(0, &testWidget, SLOT(resizeUp()));
- QTest::qWait(100);
-
+ testWidget.repainted = false;
+ // Now resize the widget again, but in the opposite direction
+ testWidget.resizeUp();
+ QTRY_VERIFY(testWidget.repainted);
QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask());
}
@@ -8985,6 +9947,7 @@ void tst_QWidget::immediateRepaintAfterInvalidateBackingStore()
QSKIP("We don't support immediate repaint right after show on other platforms.");
QScopedPointer<UpdateWidget> widget(new UpdateWidget);
+ widget->setPalette(simplePalette());
widget->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
centerOnScreen(widget.data());
widget->show();
@@ -9369,20 +10332,19 @@ void tst_QWidget::translucentWidget()
label.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
label.setFixedSize(16,16);
label.setAttribute(Qt::WA_TranslucentBackground);
- const QPoint labelPos = QGuiApplication::primaryScreen()->availableGeometry().topLeft();
- label.move(labelPos);
+ label.move(m_availableTopLeft);
label.show();
QVERIFY(QTest::qWaitForWindowExposed(&label));
QPixmap widgetSnapshot =
-#ifdef Q_OS_WIN
- QGuiApplication::primaryScreen()->grabWindow(0, labelPos.x(), labelPos.y(), label.width(), label.height());
-#else
label.grab(QRect(QPoint(0, 0), label.size()));
-#endif
const QImage actual = widgetSnapshot.toImage().convertToFormat(QImage::Format_RGB32);
QImage expected = pm.toImage().scaled(label.devicePixelRatio() * pm.size());
expected.setDevicePixelRatio(label.devicePixelRatio());
+#ifdef Q_OS_ANDROID
+ // Android uses Format_ARGB32_Premultiplied by default
+ expected = expected.convertToFormat(QImage::Format_RGB32);
+#endif
QCOMPARE(actual.size(),expected.size());
QCOMPARE(actual,expected);
@@ -9437,11 +10399,12 @@ void tst_QWidget::setClearAndResizeMask()
QSKIP("Wayland: This fails. Figure out why.");
UpdateWidget topLevel;
+ topLevel.setPalette(simplePalette());
topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
topLevel.resize(160, 160);
centerOnScreen(&topLevel);
topLevel.show();
- QApplication::setActiveWindow(&topLevel);
+ QApplicationPrivate::setActiveWindow(&topLevel);
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
QTRY_VERIFY(topLevel.numPaintEvents > 0);
topLevel.reset();
@@ -9471,6 +10434,7 @@ void tst_QWidget::setClearAndResizeMask()
}
UpdateWidget child(&topLevel);
+ child.setPalette(simplePalette());
child.setAutoFillBackground(true); // NB! Opaque child.
child.setPalette(Qt::red);
child.resize(100, 100);
@@ -9750,6 +10714,8 @@ void tst_QWidget::syntheticEnterLeave()
};
QCursor::setPos(m_safeCursorPos);
+ if (!QTest::qWaitFor([this]{ return QCursor::pos() == m_safeCursorPos; }))
+ QSKIP("Can't move cursor");
MyWidget window;
window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
@@ -9790,7 +10756,8 @@ void tst_QWidget::syntheticEnterLeave()
// Position the cursor in the middle of the window.
const QPoint globalPos = window.mapToGlobal(QPoint(100, 100));
QCursor::setPos(globalPos); // Enter child2 and grandChild.
- QTest::qWait(300);
+ if (!QTest::qWaitFor([globalPos]{ return QCursor::pos() == globalPos; }))
+ QSKIP("Can't move cursor");
QCOMPARE(window.numLeaveEvents, 0);
QCOMPARE(child2->numLeaveEvents, 0);
@@ -9861,6 +10828,9 @@ void tst_QWidget::enterLeaveOnWindowShowHide_data()
*/
void tst_QWidget::enterLeaveOnWindowShowHide()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
QFETCH(Qt::WindowType, windowType);
class Widget : public QWidget
{
@@ -9912,6 +10882,8 @@ void tst_QWidget::enterLeaveOnWindowShowHide()
secondary->show();
if (!QTest::qWaitForWindowExposed(secondary))
QEXPECT_FAIL("", "Secondary window failed to show, test will fail", Abort);
+ if (secondaryWindowType == Qt::Dialog && QGuiApplication::platformName() == "windows")
+ QTest::qWait(1000); // on Windows, we have to wait for fade-in effects
}
};
@@ -9928,25 +10900,25 @@ void tst_QWidget::enterLeaveOnWindowShowHide()
if (!QTest::qWaitFor([&]{ return widget.geometry().contains(QCursor::pos()); }))
QSKIP("We can't move the cursor");
widget.show();
- QApplication::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
++expectedEnter;
- QTRY_COMPARE_WITH_TIMEOUT(widget.numEnterEvents, expectedEnter, 250);
+ QTRY_COMPARE_WITH_TIMEOUT(widget.numEnterEvents, expectedEnter, 1000);
QCOMPARE(widget.enterPosition, widget.mapFromGlobal(cursorPos));
QVERIFY(widget.underMouse());
QTest::mouseClick(&widget, Qt::LeftButton, {}, widget.mapFromGlobal(cursorPos));
++expectedLeave;
- QTRY_COMPARE_WITH_TIMEOUT(widget.numLeaveEvents, expectedLeave, 500);
+ QTRY_COMPARE_WITH_TIMEOUT(widget.numLeaveEvents, expectedLeave, 1000);
QVERIFY(!widget.underMouse());
+ QTRY_VERIFY(QApplication::activeModalWidget() || QApplication::activePopupWidget());
if (QApplication::activeModalWidget())
QApplication::activeModalWidget()->close();
else if (QApplication::activePopupWidget())
QApplication::activePopupWidget()->close();
++expectedEnter;
// Use default timeout, the test is flaky on Windows otherwise.
- QVERIFY(QTest::qWaitFor([&]{ return widget.numEnterEvents >= expectedEnter; }));
+ QTRY_VERIFY(widget.numEnterEvents >= expectedEnter);
// When a modal dialog closes we might get more than one enter event on macOS.
// This seems to depend on timing, so we tolerate that flakiness for now.
if (widget.numEnterEvents > expectedEnter && QGuiApplication::platformName() == "cocoa")
@@ -9988,69 +10960,175 @@ void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave()
int numEnterEvents = 0, numMouseMoveEvents = 0;
};
- QCursor::setPos(m_safeCursorPos);
-
- SELParent parent;
- parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- parent.move(200, 200);
- parent.resize(200, 200);
- SELChild child(&parent);
- child.resize(200, 200);
- parent.show();
- QVERIFY(QTest::qWaitForWindowActive(&parent));
-
- QCursor::setPos(child.mapToGlobal(QPoint(100, 100)));
- // Make sure the cursor has entered the child.
- QTRY_VERIFY(child.numEnterEvents > 0);
-
- child.hide();
- child.reset();
- child.show();
-
- // Make sure the child gets enter event and no mouse move event.
- QTRY_COMPARE(child.numEnterEvents, 1);
- QCOMPARE(child.numMouseMoveEvents, 0);
-
- child.hide();
- child.reset();
- child.setMouseTracking(true);
- child.show();
-
- // Make sure the child gets enter event.
- // Note that we verify event->button() and event->buttons()
- // in SELChild::mouseMoveEvent().
- QTRY_COMPARE(child.numEnterEvents, 1);
- QCOMPARE(child.numMouseMoveEvents, 0);
-
- // Sending synthetic enter/leave trough the parent's mousePressEvent handler.
- parent.child = &child;
-
- child.hide();
- child.reset();
- QTest::mouseClick(&parent, Qt::LeftButton);
-
- // Make sure the child gets enter event.
- QTRY_COMPARE(child.numEnterEvents, 1);
- QCOMPARE(child.numMouseMoveEvents, 0);
-
- child.hide();
- child.reset();
- QTest::keyPress(&parent, Qt::Key_Shift);
- QTest::mouseClick(&parent, Qt::LeftButton);
-
- // Make sure the child gets enter event
- QTRY_COMPARE(child.numEnterEvents, 1);
- QCOMPARE(child.numMouseMoveEvents, 0);
- QTest::keyRelease(&child, Qt::Key_Shift);
- child.hide();
- child.reset();
- child.setMouseTracking(false);
- QTest::mouseClick(&parent, Qt::LeftButton);
-
- // Make sure the child gets enter event and no mouse move event.
- QTRY_COMPARE(child.numEnterEvents, 1);
- QCOMPARE(child.numMouseMoveEvents, 0);
+ QCursor::setPos(m_safeCursorPos);
+ if (!QTest::qWaitFor([this]{ return QCursor::pos() == m_safeCursorPos; }))
+ QSKIP("Can't move cursor");
+
+ SELParent parent;
+ parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
+ parent.move(200, 200);
+ parent.resize(200, 200);
+ SELChild child(&parent);
+ child.resize(200, 200);
+ parent.show();
+ QVERIFY(QTest::qWaitForWindowActive(&parent));
+
+ const QPoint childPos = child.mapToGlobal(QPoint(100, 100));
+ QCursor::setPos(childPos);
+ if (!QTest::qWaitFor([childPos]{ return QCursor::pos() == childPos; }))
+ QSKIP("Can't move cursor");
+
+ // Make sure the cursor has entered the child.
+ QTRY_VERIFY(child.numEnterEvents > 0);
+
+ child.hide();
+ child.reset();
+ child.show();
+
+ // Make sure the child gets enter event and no mouse move event.
+ QTRY_COMPARE(child.numEnterEvents, 1);
+ QCOMPARE(child.numMouseMoveEvents, 0);
+
+ child.hide();
+ child.reset();
+ child.setMouseTracking(true);
+ child.show();
+
+ // Make sure the child gets enter event.
+ // Note that we verify event->button() and event->buttons()
+ // in SELChild::mouseMoveEvent().
+ QTRY_COMPARE(child.numEnterEvents, 1);
+ QCOMPARE(child.numMouseMoveEvents, 0);
+
+ // Sending synthetic enter/leave through the parent's mousePressEvent handler.
+ parent.child = &child;
+
+ child.hide();
+ child.reset();
+ QTest::mouseClick(&parent, Qt::LeftButton);
+
+ // Make sure the child gets enter event.
+ QTRY_COMPARE(child.numEnterEvents, 1);
+ QCOMPARE(child.numMouseMoveEvents, 0);
+
+ child.hide();
+ child.reset();
+ QTest::keyPress(&parent, Qt::Key_Shift);
+ QTest::mouseClick(&parent, Qt::LeftButton);
+
+ // Make sure the child gets enter event
+ QTRY_COMPARE(child.numEnterEvents, 1);
+ QCOMPARE(child.numMouseMoveEvents, 0);
+ QTest::keyRelease(&child, Qt::Key_Shift);
+ child.hide();
+ child.reset();
+ child.setMouseTracking(false);
+ QTest::mouseClick(&parent, Qt::LeftButton);
+
+ // Make sure the child gets enter event and no mouse move event.
+ QTRY_COMPARE(child.numEnterEvents, 1);
+ QCOMPARE(child.numMouseMoveEvents, 0);
}
+
+void tst_QWidget::hoverPosition()
+{
+ if (m_platform == QStringLiteral("wayland"))
+ QSKIP("Wayland: Clients can't set cursor position on wayland.");
+
+ class HoverWidget : public QWidget
+ {
+ public:
+ HoverWidget(QWidget *parent = nullptr) : QWidget(parent) {
+ setMouseTracking(true);
+ setAttribute(Qt::WA_Hover);
+ }
+ bool event(QEvent *ev) override {
+ switch (ev->type()) {
+ case QEvent::HoverMove:
+ // The docs say that WA_Hover will cause a paint event on enter and leave, but not on move.
+ update();
+ Q_FALLTHROUGH();
+ case QEvent::HoverEnter:
+ case QEvent::HoverLeave: {
+ qCDebug(lcTests) << ev;
+ lastHoverType = ev->type();
+ ++hoverEventCount;
+ QHoverEvent *hov = static_cast<QHoverEvent *>(ev);
+ mousePos = hov->position().toPoint();
+ mouseScenePos = hov->scenePosition().toPoint();
+ if (ev->type() == QEvent::HoverEnter)
+ mouseEnterScenePos = hov->scenePosition().toPoint();
+ break;
+ }
+ default:
+ break;
+ }
+ return QWidget::event(ev);
+ }
+ void paintEvent(QPaintEvent *) override {
+ ++paintEventCount;
+ QPainter painter(this);
+ if (mousePos.x() > 0)
+ painter.setPen(Qt::red);
+ painter.drawRect(0, 0, width(), height());
+ painter.setPen(Qt::darkGreen);
+ painter.drawLine(mousePos - QPoint(crossHalfWidth, 0), mousePos + QPoint(crossHalfWidth, 0));
+ painter.drawLine(mousePos - QPoint(0, crossHalfWidth), mousePos + QPoint(0, crossHalfWidth));
+ }
+
+ QEvent::Type lastHoverType = QEvent::None;
+ int hoverEventCount = 0;
+ int paintEventCount = 0;
+ QPoint mousePos;
+ QPoint mouseScenePos;
+ QPoint mouseEnterScenePos;
+
+ private:
+ const int crossHalfWidth = 5;
+ };
+
+ QCursor::setPos(m_safeCursorPos);
+ if (!QTest::qWaitFor([this]{ return QCursor::pos() == m_safeCursorPos; }))
+ QSKIP("Can't move cursor");
+
+ QWidget root;
+ root.resize(300, 300);
+ HoverWidget h(&root);
+ h.setGeometry(100, 100, 100, 100);
+ root.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
+
+ const QPoint middle(50, 50);
+ QPoint curpos = h.mapToGlobal(middle);
+ QCursor::setPos(curpos);
+ if (!QTest::qWaitFor([curpos]{ return QCursor::pos() == curpos; }))
+ QSKIP("Can't move cursor");
+ QTRY_COMPARE_GE(h.hoverEventCount, 1); // HoverEnter and then probably HoverMove, so usually 2
+ QTRY_COMPARE_GE(h.paintEventCount, 2);
+ const int enterHoverEventCount = h.hoverEventCount;
+ qCDebug(lcTests) << "hover enter events:" << enterHoverEventCount << "last was" << h.lastHoverType
+ << "; paint events:" << h.paintEventCount;
+ QCOMPARE(h.mousePos, middle);
+ QCOMPARE(h.mouseEnterScenePos, h.mapToParent(middle));
+ QCOMPARE(h.mouseScenePos, h.mapToParent(middle));
+ QCOMPARE(h.lastHoverType, enterHoverEventCount == 1 ? QEvent::HoverEnter : QEvent::HoverMove);
+
+ curpos += {10, 10};
+ QCursor::setPos(curpos);
+ if (!QTest::qWaitFor([curpos]{ return QCursor::pos() == curpos; }))
+ QSKIP("Can't move cursor");
+ QTRY_COMPARE(h.hoverEventCount, enterHoverEventCount + 1);
+ QCOMPARE(h.lastHoverType, QEvent::HoverMove);
+ QTRY_COMPARE_GE(h.paintEventCount, 3);
+
+ curpos += {50, 50}; // in the outer widget, but leaving the inner widget
+ QCursor::setPos(curpos);
+ if (!QTest::qWaitFor([curpos]{ return QCursor::pos() == curpos; }))
+ QSKIP("Can't move cursor");
+ QTRY_COMPARE(h.lastHoverType, QEvent::HoverLeave);
+ QCOMPARE_GE(h.hoverEventCount, enterHoverEventCount + 2);
+ QTRY_COMPARE_GE(h.paintEventCount, 4);
+}
#endif
void tst_QWidget::windowFlags()
@@ -10156,6 +11234,7 @@ void tst_QWidget::focusWidget_task254563()
void tst_QWidget::destroyBackingStore()
{
UpdateWidget w;
+ w.setPalette(simplePalette());
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
centerOnScreen(&w);
w.reset();
@@ -10280,6 +11359,157 @@ void tst_QWidget::setGraphicsEffect()
QVERIFY(!blurEffect);
}
+
+class TestGraphicsEffect : public QGraphicsEffect
+{
+public:
+ TestGraphicsEffect(QObject *parent = nullptr)
+ : QGraphicsEffect(parent)
+ {
+ m_pattern = QPixmap(10, 10);
+ m_pattern.fill(Qt::lightGray);
+ QPainter p(&m_pattern);
+ p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
+ p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
+ }
+ void setExtent(int extent)
+ {
+ m_extent = extent;
+ }
+ QRectF boundingRectFor(const QRectF &sr) const override
+ {
+ return QRectF(sr.x() - m_extent, sr.y() - m_extent,
+ sr.width() + 2 * m_extent, sr.height() + 2 * m_extent);
+ }
+protected:
+ void draw(QPainter *painter) override
+ {
+ QBrush brush;
+ brush.setTexture(m_pattern);
+ brush.setStyle(Qt::TexturePattern);
+ QPaintDevice *p = painter->device();
+ painter->fillRect(QRect(-m_extent, -m_extent,
+ p->width() + m_extent, p->height() + m_extent), brush);
+ }
+ QPixmap m_pattern;
+ int m_extent = 0;
+};
+
+static QImage fillExpected1()
+{
+ QImage expected(QSize(40, 40), QImage::Format_RGB32);
+ QPainter p(&expected);
+ p.fillRect(QRect{{0, 0}, expected.size()}, QBrush(Qt::gray));
+ p.fillRect(QRect(10, 10, 10, 10), QBrush(Qt::red));
+ p.fillRect(QRect(20, 20, 10, 10), QBrush(Qt::blue));
+ return expected;
+}
+static QImage fillExpected2()
+{
+ QImage expected = fillExpected1();
+ QPainter p(&expected);
+ p.fillRect(QRect(10, 10, 5, 5), QBrush(Qt::darkGray));
+ p.fillRect(QRect(15, 15, 5, 5), QBrush(Qt::darkGray));
+ p.fillRect(QRect(15, 10, 5, 5), QBrush(Qt::lightGray));
+ p.fillRect(QRect(10, 15, 5, 5), QBrush(Qt::lightGray));
+ return expected;
+}
+static QImage fillExpected3()
+{
+ QImage expected(QSize(40, 40), QImage::Format_RGB32);
+ QPixmap pattern;
+ pattern = QPixmap(10, 10);
+ pattern.fill(Qt::lightGray);
+ QPainter p(&pattern);
+ p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
+ p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
+ QBrush brush;
+ brush.setTexture(pattern);
+ brush.setStyle(Qt::TexturePattern);
+ QPainter p2(&expected);
+ p2.fillRect(QRect{{0, 0}, expected.size()}, brush);
+ return expected;
+}
+static QImage fillExpected4()
+{
+ QImage expected = fillExpected1();
+ QPixmap pattern;
+ pattern = QPixmap(10, 10);
+ pattern.fill(Qt::lightGray);
+ QPainter p(&pattern);
+ p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
+ p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
+ QBrush brush;
+ brush.setTexture(pattern);
+ brush.setStyle(Qt::TexturePattern);
+ QPainter p2(&expected);
+ p2.fillRect(QRect{{15, 15}, QSize{20, 20}}, brush);
+ return expected;
+}
+
+void tst_QWidget::render_graphicsEffect_data()
+{
+ QTest::addColumn<QImage>("expected");
+ QTest::addColumn<bool>("topLevelEffect");
+ QTest::addColumn<bool>("child1Effect");
+ QTest::addColumn<bool>("child2Effect");
+ QTest::addColumn<int>("extent");
+
+ QTest::addRow("no_effect") << fillExpected1() << false << false << false << 0;
+ QTest::addRow("first_child_effect") << fillExpected2() << false << true << false << 0;
+ QTest::addRow("top_level_effect") << fillExpected3() << true << false << false << 0;
+ QTest::addRow("effect_with_extent") << fillExpected4() << false << false << true << 5;
+}
+
+void tst_QWidget::render_graphicsEffect()
+{
+ QFETCH(QImage, expected);
+ QFETCH(bool, topLevelEffect);
+ QFETCH(bool, child1Effect);
+ QFETCH(bool, child2Effect);
+ QFETCH(int, extent);
+
+ QScopedPointer<QWidget> topLevel(new QWidget);
+ topLevel->setPalette(Qt::gray);
+ topLevel->resize(40, 40);
+ topLevel->setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::")
+ + QLatin1String(QTest::currentDataTag()));
+
+ // Render widget with 2 child widgets
+ QImage image(topLevel->size(), QImage::Format_RGB32);
+ image.fill(QColor(Qt::gray).rgb());
+
+ QPainter painter(&image);
+
+ QWidget *childWidget1(new QWidget(topLevel.data()));
+ childWidget1->setAutoFillBackground(true);
+ childWidget1->setPalette(Qt::red);
+ childWidget1->resize(10, 10);
+ childWidget1->move(10, 10);
+ QWidget *childWidget2(new QWidget(topLevel.data()));
+ childWidget2->setAutoFillBackground(true);
+ childWidget2->setPalette(Qt::blue);
+ childWidget2->resize(10, 10);
+ childWidget2->move(20, 20);
+
+ TestGraphicsEffect *graphicsEffect(new TestGraphicsEffect(topLevel.data()));
+ if (topLevelEffect)
+ topLevel->setGraphicsEffect(graphicsEffect);
+ if (child1Effect)
+ childWidget1->setGraphicsEffect(graphicsEffect);
+ if (child2Effect)
+ childWidget2->setGraphicsEffect(graphicsEffect);
+ graphicsEffect->setExtent(extent);
+
+ // Render without effect
+ topLevel->render(&painter);
+#ifdef RENDER_DEBUG
+ image.save("render_GraphicsEffect" + QTest::currentDataTag() + ".png");
+ expected.save("render_GraphicsEffect_expected" + QTest::currentDataTag() + ".png");
+#endif
+ QCOMPARE(image, expected);
+}
+
void tst_QWidget::activateWindow()
{
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
@@ -10325,6 +11555,9 @@ void tst_QWidget::activateWindow()
void tst_QWidget::openModal_taskQTBUG_5804()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("This test hangs on Android");
+#endif
class Widget : public QWidget
{
public:
@@ -10472,32 +11705,42 @@ void tst_QWidget::focusProxy()
QCOMPARE(container2->focusOutCount, 1);
}
-void tst_QWidget::focusProxyAndInputMethods()
+void tst_QWidget::imEnabledNotImplemented()
{
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
- QSKIP("Window activation is not supported.");
- QScopedPointer<QWidget> toplevel(new QWidget(nullptr, Qt::X11BypassWindowManagerHint));
- toplevel->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- toplevel->resize(200, 200);
- toplevel->setAttribute(Qt::WA_InputMethodEnabled, true);
-
- QWidget *child = new QWidget(toplevel.data());
- child->setFocusProxy(toplevel.data());
- child->setAttribute(Qt::WA_InputMethodEnabled, true);
-
- toplevel->setFocusPolicy(Qt::WheelFocus);
- child->setFocusPolicy(Qt::WheelFocus);
+ QSKIP("QWindow::requestActivate() is not supported.");
- QVERIFY(!child->hasFocus());
- QVERIFY(!toplevel->hasFocus());
+ // Check that a plain widget doesn't report that it supports IM. Only
+ // widgets that implements either Qt::ImEnabled, or the Qt4 backup
+ // solution, Qt::ImSurroundingText, should do so.
+ QWidget topLevel;
+ QWidget plain(&topLevel);
+ QLineEdit edit(&topLevel);
+ topLevel.show();
- toplevel->show();
- QVERIFY(QTest::qWaitForWindowExposed(toplevel.data()));
- QApplication::setActiveWindow(toplevel.data());
- QVERIFY(QTest::qWaitForWindowActive(toplevel.data()));
- QVERIFY(toplevel->hasFocus());
- QVERIFY(child->hasFocus());
- QCOMPARE(qApp->focusObject(), toplevel.data());
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ QVERIFY(QTest::qWaitForWindowActive(&topLevel));
+
+ // A plain widget should return false for ImEnabled
+ plain.setFocus(Qt::OtherFocusReason);
+ QCOMPARE(QApplication::focusWidget(), &plain);
+ QVariant imEnabled = QApplication::inputMethod()->queryFocusObject(Qt::ImEnabled, QVariant());
+ QVERIFY(imEnabled.isValid());
+ QVERIFY(!imEnabled.toBool());
+
+ // But a lineedit should return true
+ edit.setFocus(Qt::OtherFocusReason);
+ QCOMPARE(QApplication::focusWidget(), &edit);
+ imEnabled = QApplication::inputMethod()->queryFocusObject(Qt::ImEnabled, QVariant());
+ QVERIFY(imEnabled.isValid());
+ QVERIFY(imEnabled.toBool());
+
+ // ImEnabled should be false when a lineedit is read-only since
+ // ImEnabled indicates the widget accepts input method _input_.
+ edit.setReadOnly(true);
+ imEnabled = QApplication::inputMethod()->queryFocusObject(Qt::ImEnabled, QVariant());
+ QVERIFY(imEnabled.isValid());
+ QVERIFY(!imEnabled.toBool());
}
#ifdef QT_BUILD_INTERNAL
@@ -10556,7 +11799,7 @@ void tst_QWidget::taskQTBUG_7532_tabOrderWithFocusProxy()
void tst_QWidget::movedAndResizedAttributes()
{
// Use Qt::Tool as fully decorated windows have a minimum width of 160 on
- QWidget w(nullptr, Qt::Tool);
+ QWidget w;
w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
w.show();
@@ -10594,11 +11837,11 @@ void tst_QWidget::movedAndResizedAttributes()
QVERIFY(!w.testAttribute(Qt::WA_Resized));
w.showNormal();
- w.move(10,10);
+ w.move(m_availableTopLeft);
QVERIFY(w.testAttribute(Qt::WA_Moved));
QVERIFY(!w.testAttribute(Qt::WA_Resized));
- w.resize(100, 100);
+ w.resize(m_testWidgetSize);
QVERIFY(w.testAttribute(Qt::WA_Moved));
QVERIFY(w.testAttribute(Qt::WA_Resized));
}
@@ -10856,7 +12099,6 @@ void tst_QWidget::grabMouse()
layout->addWidget(grabber);
centerOnScreen(&w);
w.show();
- QApplication::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QStringList expectedLog;
@@ -10893,7 +12135,6 @@ void tst_QWidget::grabKeyboard()
layout->addWidget(nonGrabber);
centerOnScreen(&w);
w.show();
- QApplication::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
nonGrabber->setFocus();
grabber->grabKeyboard();
@@ -10987,6 +12228,9 @@ public:
void tst_QWidget::touchEventSynthesizedMouseEvent()
{
+ if (m_platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("This test failed on Wayland. See also QTBUG-107157.");
+
{
// Simple case, we ignore the touch events, we get mouse events instead
TouchMouseWidget widget;
@@ -11506,10 +12750,6 @@ void tst_QWidget::underMouse()
// Mouse leaves popup and enters topLevelWidget, should cause leave for popup
// but no enter to topLevelWidget.
-#ifdef Q_OS_DARWIN
- // Artificial leave event needed for Cocoa.
- QWindowSystemInterface::handleLeaveEvent(popupWindow);
-#endif
QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(inWindowPoint)));
QApplication::processEvents();
QVERIFY(!topLevelWidget.underMouse());
@@ -11699,6 +12939,7 @@ void tst_QWidget::resizeStaticContentsChildWidget_QTBUG35282()
widget.resize(200,200);
UpdateWidget childWidget(&widget);
+ childWidget.setPalette(simplePalette());
childWidget.setAttribute(Qt::WA_StaticContents);
childWidget.setAttribute(Qt::WA_OpaquePaintEvent);
childWidget.setGeometry(250, 250, 500, 500);
@@ -11797,60 +13038,54 @@ void tst_QWidget::testForOutsideWSRangeFlag()
}
}
-class TabletWidget : public QWidget
+void tst_QWidget::tabletTracking()
{
-public:
- TabletWidget(QWidget *parent) : QWidget(parent) { }
+ class TabletWidget : public QWidget
+ {
+ public:
+ using QWidget::QWidget;
- int tabletEventCount = 0;
- int pressEventCount = 0;
- int moveEventCount = 0;
- int releaseEventCount = 0;
- int trackingChangeEventCount = 0;
- qint64 uid = -1;
+ int tabletEventCount = 0;
+ int pressEventCount = 0;
+ int moveEventCount = 0;
+ int releaseEventCount = 0;
+ int trackingChangeEventCount = 0;
+ qint64 uid = -1;
-protected:
- void tabletEvent(QTabletEvent *event) override {
- ++tabletEventCount;
- uid = event->pointingDevice()->uniqueId().numericId();
- switch (event->type()) {
- case QEvent::TabletMove:
- ++moveEventCount;
- break;
- case QEvent::TabletPress:
- ++pressEventCount;
- break;
- case QEvent::TabletRelease:
- ++releaseEventCount;
- break;
- default:
- break;
+ protected:
+ void tabletEvent(QTabletEvent *event) override {
+ ++tabletEventCount;
+ uid = event->pointingDevice()->uniqueId().numericId();
+ switch (event->type()) {
+ case QEvent::TabletMove:
+ ++moveEventCount;
+ break;
+ case QEvent::TabletPress:
+ ++pressEventCount;
+ break;
+ case QEvent::TabletRelease:
+ ++releaseEventCount;
+ break;
+ default:
+ break;
+ }
}
- }
- bool event(QEvent *ev) override {
- if (ev->type() == QEvent::TabletTrackingChange)
- ++trackingChangeEventCount;
- return QWidget::event(ev);
- }
-};
-
-void tst_QWidget::tabletTracking()
-{
- QWidget parent;
- parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
- parent.resize(200,200);
- // QWidgetWindow::handleTabletEvent doesn't deliver tablet events to the window's widget, only to a child.
- // So it doesn't do any good to show a TabletWidget directly: it needs a parent.
- TabletWidget widget(&parent);
+ bool event(QEvent *ev) override {
+ if (ev->type() == QEvent::TabletTrackingChange)
+ ++trackingChangeEventCount;
+ return QWidget::event(ev);
+ }
+ } widget;
+ widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
widget.resize(200,200);
- parent.showNormal();
- QVERIFY(QTest::qWaitForWindowExposed(&parent));
+ widget.showNormal();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
widget.setAttribute(Qt::WA_TabletTracking);
QTRY_COMPARE(widget.trackingChangeEventCount, 1);
QVERIFY(widget.hasTabletTracking());
- QWindow *window = parent.windowHandle();
+ QWindow *window = widget.windowHandle();
QPointF local(10, 10);
QPointF global = window->mapToGlobal(local.toPoint());
QPointF deviceLocal = QHighDpi::toNativeLocalPosition(local, window);
@@ -12157,10 +13392,22 @@ protected:
void tst_QWidget::deleteWindowInCloseEvent()
{
- // Just checking if closing this widget causes a crash
+#ifdef Q_OS_ANDROID
+ QSKIP("This test crashes on Android");
+#endif
+ QSignalSpy quitSpy(qApp, &QGuiApplication::lastWindowClosed);
+
+ // Closing this widget should not cause a crash
auto widget = new DeleteOnCloseEventWidget;
- widget->close();
- QVERIFY(true);
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(widget));
+ QTimer::singleShot(0, widget, [&]{
+ widget->close();
+ });
+ QApplication::exec();
+
+ // It should still result in a single lastWindowClosed emit
+ QCOMPARE(quitSpy.size(), 1);
}
/*!
@@ -12169,7 +13416,7 @@ void tst_QWidget::deleteWindowInCloseEvent()
*/
void tst_QWidget::quitOnClose()
{
- QSignalSpy quitSpy(qApp, &QApplication::lastWindowClosed);
+ QSignalSpy quitSpy(qApp, &QGuiApplication::lastWindowClosed);
std::unique_ptr<QWidget>widget(new QWidget);
widget->show();
@@ -12181,7 +13428,7 @@ void tst_QWidget::quitOnClose()
widget->close();
});
QApplication::exec();
- QCOMPARE(quitSpy.count(), 1);
+ QCOMPARE(quitSpy.size(), 1);
widget->show();
QVERIFY(QTest::qWaitForWindowExposed(widget.get()));
@@ -12189,7 +13436,558 @@ void tst_QWidget::quitOnClose()
widget.reset();
});
QApplication::exec();
- QCOMPARE(quitSpy.count(), 2);
+ QCOMPARE(quitSpy.size(), 2);
+}
+
+void tst_QWidget::setParentChangesFocus_data()
+{
+ QTest::addColumn<Qt::WindowType>("initialType");
+ QTest::addColumn<bool>("initialParent");
+ QTest::addColumn<Qt::WindowType>("targetType");
+ QTest::addColumn<bool>("targetParent");
+ QTest::addColumn<bool>("reparentBeforeShow");
+ QTest::addColumn<QString>("focusWidget");
+
+ for (const bool before : {true, false}) {
+ const char *tag = before ? "before" : "after";
+ QTest::addRow("give dialog parent, %s", tag)
+ << Qt::Dialog << false << Qt::Dialog << true << before << "lineEdit";
+ QTest::addRow("make dialog parentless, %s", tag)
+ << Qt::Dialog << true << Qt::Dialog << false << before << "lineEdit";
+ QTest::addRow("dialog to sheet, %s", tag)
+ << Qt::Dialog << true << Qt::Sheet << true << before << "lineEdit";
+ QTest::addRow("window to widget, %s", tag)
+ << Qt::Window << true << Qt::Widget << true << before << "windowEdit";
+ QTest::addRow("widget to window, %s", tag)
+ << Qt::Widget << true << Qt::Window << true << before << "lineEdit";
+ }
+}
+
+void tst_QWidget::setParentChangesFocus()
+{
+ QFETCH(Qt::WindowType, initialType);
+ QFETCH(bool, initialParent);
+ QFETCH(Qt::WindowType, targetType);
+ QFETCH(bool, targetParent);
+ QFETCH(bool, reparentBeforeShow);
+ QFETCH(QString, focusWidget);
+
+ QWidget window;
+ window.setObjectName("window");
+ QLineEdit *windowEdit = new QLineEdit(&window);
+ windowEdit->setObjectName("windowEdit");
+ windowEdit->setFocus();
+
+ std::unique_ptr<QWidget> secondary(new QWidget(initialParent ? &window : nullptr, initialType));
+ secondary->setObjectName("secondary");
+ QLineEdit *lineEdit = new QLineEdit(secondary.get());
+ lineEdit->setObjectName("lineEdit");
+ QPushButton *pushButton = new QPushButton(secondary.get());
+ pushButton->setObjectName("pushButton");
+ lineEdit->setFocus();
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ if (reparentBeforeShow) {
+ secondary->setParent(targetParent ? &window : nullptr, targetType);
+ // making a widget into a window doesn't set a focusWidget until shown
+ if (secondary->focusWidget())
+ QCOMPARE(secondary->focusWidget()->objectName(), focusWidget);
+ }
+ secondary->show();
+ QApplicationPrivate::setActiveWindow(secondary.get());
+ QVERIFY(QTest::qWaitForWindowActive(secondary.get()));
+
+ if (!reparentBeforeShow) {
+ secondary->setParent(targetParent ? &window : nullptr, targetType);
+ secondary->show(); // reparenting hides, so show again
+ QApplicationPrivate::setActiveWindow(secondary.get());
+ QVERIFY(QTest::qWaitForWindowActive(secondary.get()));
+ }
+ QVERIFY(QTest::qWaitFor([]{ return QApplication::focusWidget(); }));
+ QCOMPARE(QApplication::focusWidget()->objectName(), focusWidget);
+}
+
+void tst_QWidget::activateWhileModalHidden()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
+ QDialog dialog;
+ dialog.setWindowModality(Qt::ApplicationModal);
+ dialog.show();
+ QVERIFY(QTest::qWaitForWindowActive(&dialog));
+ QVERIFY(dialog.isActiveWindow());
+ QCOMPARE(QApplication::activeWindow(), &dialog);
+
+ dialog.hide();
+ QTRY_VERIFY(!dialog.isVisible());
+
+ QMainWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QVERIFY(window.isActiveWindow());
+ QCOMPARE(QApplication::activeWindow(), &window);
+}
+
+// Create a simple palette to prevent multiple paint events
+QPalette tst_QWidget::simplePalette()
+{
+ static QPalette simplePalette = []{
+ const QColor windowText = Qt::black;
+ const QColor backGround = QColor(239, 239, 239);
+ const QColor light = backGround.lighter(150);
+ const QColor mid = (backGround.darker(130));
+ const QColor midLight = mid.lighter(110);
+ const QColor base = Qt::white;
+ const QColor dark = backGround.darker(150);
+ const QColor text = Qt::black;
+ const QColor highlight = QColor(48, 140, 198);
+ const QColor hightlightedText = Qt::white;
+ const QColor button = backGround;
+ const QColor shadow = dark.darker(135);
+
+ QPalette defaultPalette(windowText, backGround, light, dark, mid, text, base);
+ defaultPalette.setBrush(QPalette::Midlight, midLight);
+ defaultPalette.setBrush(QPalette::Button, button);
+ defaultPalette.setBrush(QPalette::Shadow, shadow);
+ defaultPalette.setBrush(QPalette::HighlightedText, hightlightedText);
+ defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
+ return defaultPalette;
+ }();
+
+ return simplePalette;
+}
+
+#ifdef Q_OS_ANDROID
+void tst_QWidget::showFullscreenAndroid()
+{
+ QWidget w;
+ w.setAutoFillBackground(true);
+ QPalette p = w.palette();
+ p.setColor(QPalette::Window, Qt::red);
+ w.setPalette(p);
+
+ // Need to toggle showFullScreen() twice, see QTBUG-101968
+ w.showFullScreen();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ w.showFullScreen();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ // Make sure that the lower part of the screen contains the red widget, not
+ // the buttons.
+
+ const QRect fullGeometry = w.screen()->geometry();
+ // Take a rect of (20 x 20) from the bottom area
+ const QRect grabArea(10, fullGeometry.height() - 30, 20, 20);
+ const QImage img = grabFromWidget(&w, grabArea).toImage().convertedTo(QImage::Format_RGB32);
+
+ QPixmap expectedPix(20, 20);
+ expectedPix.fill(Qt::red);
+ const QImage expectedImg = expectedPix.toImage().convertedTo(QImage::Format_RGB32);
+
+ QCOMPARE(img, expectedImg);
+}
+#endif // Q_OS_ANDROID
+
+void tst_QWidget::setVisibleDuringDestruction()
+{
+ CreateDestroyWidget widget;
+ widget.create();
+ QVERIFY(widget.windowHandle());
+
+ QSignalSpy signalSpy(widget.windowHandle(), &QWindow::visibleChanged);
+ EventSpy<QWindow> showEventSpy(widget.windowHandle(), QEvent::Show);
+ widget.show();
+ QTRY_COMPARE(showEventSpy.count(), 1);
+ QTRY_COMPARE(signalSpy.count(), 1);
+
+ EventSpy<QWindow> hideEventSpy(widget.windowHandle(), QEvent::Hide);
+ widget.hide();
+ QTRY_COMPARE(hideEventSpy.count(), 1);
+ QTRY_COMPARE(signalSpy.count(), 2);
+
+ widget.show();
+ QTRY_COMPARE(showEventSpy.count(), 2);
+ QTRY_COMPARE(signalSpy.count(), 3);
+
+ widget.destroy();
+ QTRY_COMPARE(hideEventSpy.count(), 2);
+ QTRY_COMPARE(signalSpy.count(), 4);
+}
+
+void tst_QWidget::explicitShowHide()
+{
+ {
+ QWidget parent;
+ parent.setObjectName("Parent");
+ QWidget child(&parent);
+ child.setObjectName("Child");
+
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ parent.show();
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ // Fix up earlier expected failure
+ child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+
+ parent.hide();
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+ }
+
+ {
+ // Test what happens when a child is reparented after showing it
+
+ QWidget parent;
+ parent.setObjectName("Parent");
+ QWidget child;
+ child.setObjectName("Child");
+
+ child.show();
+ QCOMPARE(child.isVisible(), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ child.setParent(&parent);
+ // As documented, a widget becomes invisible as part of changing
+ // its parent, even if it was previously visible. The user must call
+ // show() to make the widget visible again.
+ QCOMPARE(child.isVisible(), false);
+
+ // However, the widget does not end up with Qt::WA_WState_Hidden,
+ // as QWidget::setParent treats it as a child, which normally will
+ // not get Qt::WA_WState_Hidden out of the box.
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ // For some reason we reset WA_WState_ExplicitShowHide, and it's
+ // not clear whether this is correct or not See QWidget::setParent()
+ // for a comment with more details.
+ QEXPECT_FAIL("", "We reset WA_WState_ExplicitShowHide on widget re-parent", Continue);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+
+ // The fact that the child doesn't have Qt::WA_WState_Hidden means
+ // it's sufficient to show the parent widget. We don't need to
+ // explicitly show the child.
+ parent.show();
+ QCOMPARE(child.isVisible(), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+ }
+
+ {
+ QWidget parent;
+ parent.setObjectName("Parent");
+ QWidget child(&parent);
+ child.setObjectName("Child");
+
+ parent.show();
+
+ // If a non-native child ends up being closed, we will hide the
+ // widget, but do so via QWidget::hide(), which marks the widget
+ // as explicitly hidden.
+
+ child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ QCOMPARE(child.close(), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
+
+ child.show();
+ child.setAttribute(Qt::WA_NativeWindow);
+ child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ QCOMPARE(child.close(), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
+
+ child.show();
+ child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ QCOMPARE(child.windowHandle()->close(), false); // Can't close non-top level QWindows
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ // If we end up in QWidgetPrivate::handleClose via QWidgetWindow::closeEvent,
+ // either through QWindow::close(), or via QWSI::handleCloseEvent, we'll still
+ // do the explicit hide.
+
+ child.show();
+ child.setAttribute(Qt::WA_WState_ExplicitShowHide, false);
+ QCOMPARE(QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(
+ child.windowHandle()), true);
+ QEXPECT_FAIL("", "Closing a native child via QWSI is treated as an explicit hide", Continue);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
+ }
+
+ {
+ QWidget widget;
+ widget.show();
+ widget.hide();
+
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Hidden), true);
+
+ // The widget is now explicitly hidden. Showing it again, via QWindow,
+ // should make the widget visible, and it should not stay hidden, as
+ // that's an invalid state for a widget.
+
+ widget.windowHandle()->setVisible(true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Visible), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_ExplicitShowHide), true);
+ QCOMPARE(widget.testAttribute(Qt::WA_WState_Hidden), false);
+ }
+}
+
+/*!
+ Verify that we deliver DragEnter/Leave events symmetrically, even if the
+ widget entered didn't accept the DragEnter event.
+*/
+void tst_QWidget::dragEnterLeaveSymmetry()
+{
+ QWidget widget;
+ widget.setAcceptDrops(true);
+ QLineEdit lineEdit;
+ QLabel label("Hello world");
+ label.setAcceptDrops(true);
+
+ struct EventFilter : QObject
+ {
+ bool eventFilter(QObject *receiver, QEvent *event) override
+ {
+ switch (event->type()) {
+ case QEvent::DragEnter:
+ case QEvent::DragLeave:
+ receivers[event->type()] << receiver;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ QMap<QEvent::Type, QList<QObject *>> receivers;
+
+ void clear() { receivers.clear(); }
+ bool hasEntered(QWidget *widget) const
+ {
+ return receivers.value(QEvent::DragEnter).contains(widget);
+ }
+ bool hasLeft(QWidget *widget) const
+ {
+ return receivers.value(QEvent::DragLeave).contains(widget);
+ }
+ } filter;
+
+ widget.installEventFilter(&filter);
+ lineEdit.installEventFilter(&filter);
+ label.installEventFilter(&filter);
+
+ QVBoxLayout vbox;
+ vbox.setContentsMargins(10, 10, 10, 10);
+ vbox.addWidget(&lineEdit);
+ vbox.addWidget(&label);
+ widget.setLayout(&vbox);
+
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ QMimeData data;
+ data.setColorData(QVariant::fromValue(Qt::red));
+ QWindowSystemInterface::handleDrag(widget.windowHandle(), &data, QPoint(1, 1),
+ Qt::ActionMask, Qt::LeftButton, {});
+ QVERIFY(filter.hasEntered(&widget));
+ QVERIFY(!filter.hasEntered(&lineEdit));
+ QVERIFY(!filter.hasEntered(&label));
+ QVERIFY(widget.underMouse());
+ QVERIFY(!lineEdit.underMouse());
+ filter.clear();
+
+ QWindowSystemInterface::handleDrag(widget.windowHandle(), &data, lineEdit.geometry().center(),
+ Qt::ActionMask, Qt::LeftButton, {});
+ // DragEnter propagates as the lineEdit doesn't want it, so the widget
+ // sees both a Leave and an Enter event
+ QVERIFY(filter.hasLeft(&widget));
+ QVERIFY(filter.hasEntered(&widget));
+ QVERIFY(filter.hasEntered(&widget));
+ // both have the UnderMouse attribute set
+ QVERIFY(lineEdit.underMouse());
+ QVERIFY(widget.underMouse());
+
+ // The lineEdit didn't accept the DragEnter, but it should still has to
+ // get the DragLeave so that UnderMouse is cleared; the widget gets both
+ // Leave and Enter through propagation.
+ QWindowSystemInterface::handleDrag(widget.windowHandle(), &data, label.geometry().center(),
+ Qt::ActionMask, Qt::LeftButton, {});
+ QVERIFY(filter.hasLeft(&lineEdit));
+ QVERIFY(filter.hasLeft(&widget));
+ QVERIFY(filter.hasEntered(&label));
+ QVERIFY(filter.hasEntered(&widget));
+
+ QVERIFY(!lineEdit.underMouse());
+ QVERIFY(label.underMouse());
+ QVERIFY(widget.underMouse());
+}
+
+void tst_QWidget::reparentWindowHandles_data()
+{
+ QTest::addColumn<int>("stage");
+ QTest::addRow("reparent child") << 1;
+ QTest::addRow("top level to child") << 2;
+ QTest::addRow("transient parent") << 3;
+ QTest::addRow("window container") << 4;
+}
+
+void tst_QWidget::reparentWindowHandles()
+{
+ const bool nativeSiblingsOriginal = qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+ qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
+ auto nativeSiblingGuard = qScopeGuard([&]{
+ qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, nativeSiblingsOriginal);
+ });
+
+ QFETCH(int, stage);
+
+ switch (stage) {
+ case 1: {
+ // Reparent child widget
+
+ QWidget topLevel;
+ topLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(topLevel.windowHandle());
+ QPointer<QWidget> child = new QWidget(&topLevel);
+ child->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ child->setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(child->windowHandle());
+
+ QWidget anotherTopLevel;
+ anotherTopLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(anotherTopLevel.windowHandle());
+ QPointer<QWidget> intermediate = new QWidget(&anotherTopLevel);
+ QPointer<QWidget> leaf = new QWidget(intermediate);
+ leaf->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ leaf->setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(leaf->windowHandle());
+ QVERIFY(!intermediate->windowHandle());
+
+ // Reparenting a native widget should reparent the QWindow
+ child->setParent(leaf);
+ QCOMPARE(child->windowHandle()->parent(), leaf->windowHandle());
+ QCOMPARE(child->windowHandle()->transientParent(), nullptr);
+ QVERIFY(!intermediate->windowHandle());
+
+ // So should reparenting a non-native widget with native children
+ intermediate->setParent(&topLevel);
+ QVERIFY(!intermediate->windowHandle());
+ QCOMPARE(leaf->windowHandle()->parent(), topLevel.windowHandle());
+ QCOMPARE(leaf->windowHandle()->transientParent(), nullptr);
+ QCOMPARE(child->windowHandle()->parent(), leaf->windowHandle());
+ QCOMPARE(child->windowHandle()->transientParent(), nullptr);
+ }
+ break;
+ case 2: {
+ // Top level to child
+
+ QWidget topLevel;
+ topLevel.setAttribute(Qt::WA_NativeWindow);
+
+ // A regular top level loses its nativeness
+ QPointer<QWidget> regularToplevel = new QWidget;
+ regularToplevel->show();
+ QVERIFY(QTest::qWaitForWindowExposed(regularToplevel));
+ QVERIFY(regularToplevel->windowHandle());
+ regularToplevel->setParent(&topLevel);
+ QVERIFY(!regularToplevel->windowHandle());
+
+ // A regular top level loses its nativeness
+ QPointer<QWidget> regularToplevelWithNativeChildren = new QWidget;
+ QPointer<QWidget> nativeChild = new QWidget(regularToplevelWithNativeChildren);
+ nativeChild->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ nativeChild->setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(nativeChild->windowHandle());
+ regularToplevelWithNativeChildren->show();
+ QVERIFY(QTest::qWaitForWindowExposed(regularToplevelWithNativeChildren));
+ QVERIFY(regularToplevelWithNativeChildren->windowHandle());
+ regularToplevelWithNativeChildren->setParent(&topLevel);
+ QVERIFY(!regularToplevelWithNativeChildren->windowHandle());
+ // But the native child does not
+ QVERIFY(nativeChild->windowHandle());
+ QCOMPARE(nativeChild->windowHandle()->parent(), topLevel.windowHandle());
+
+ // An explicitly native top level keeps its nativeness, and the window handle moves
+ QPointer<QWidget> nativeTopLevel = new QWidget;
+ nativeTopLevel->setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(nativeTopLevel->windowHandle());
+ nativeTopLevel->setParent(&topLevel);
+ QVERIFY(nativeTopLevel->windowHandle());
+ QCOMPARE(nativeTopLevel->windowHandle()->parent(), topLevel.windowHandle());
+ }
+ break;
+ case 3: {
+ // Transient parent
+
+ QWidget topLevel;
+ topLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(topLevel.windowHandle());
+ QPointer<QWidget> child = new QWidget(&topLevel);
+ child->setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(child->windowHandle());
+
+ QWidget anotherTopLevel;
+ anotherTopLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(anotherTopLevel.windowHandle());
+
+ // Make transient child of top level
+ anotherTopLevel.setParent(&topLevel, Qt::Window);
+ QCOMPARE(anotherTopLevel.windowHandle()->parent(), nullptr);
+ QCOMPARE(anotherTopLevel.windowHandle()->transientParent(), topLevel.windowHandle());
+
+ // Make transient child of child
+ anotherTopLevel.setParent(child, Qt::Window);
+ QCOMPARE(anotherTopLevel.windowHandle()->parent(), nullptr);
+ QCOMPARE(anotherTopLevel.windowHandle()->transientParent(), topLevel.windowHandle());
+ }
+ break;
+ case 4: {
+ // Window container
+
+ QWidget topLevel;
+ topLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(topLevel.windowHandle());
+
+ QPointer<QWidget> child = new QWidget(&topLevel);
+ QVERIFY(!child->windowHandle());
+
+ QWindow *window = new QWindow;
+ QWidget *container = QWidget::createWindowContainer(window);
+ container->setParent(child);
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ QCOMPARE(window->parent(), topLevel.windowHandle());
+
+ QWidget anotherTopLevel;
+ anotherTopLevel.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(anotherTopLevel.windowHandle());
+
+ child->setParent(&anotherTopLevel);
+ QCOMPARE(window->parent(), anotherTopLevel.windowHandle());
+ }
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
}
QTEST_MAIN(tst_QWidget)
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h
deleted file mode 100644
index 87de300da9..0000000000
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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 <QtCore/QString>
-#include <QtCore/QPair>
-#include <QtWidgets/QWidget>
-
-#pragma once // Yeah, it's deprecated in general, but it's standard practice for Mac OS X.
-
-QString nativeWindowTitle(QWidget *widget, Qt::WindowState state);
-bool nativeWindowModified(QWidget *widget);
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm
deleted file mode 100644
index e2d00aa25b..0000000000
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation 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$
-**
-****************************************************************************/
-
-// some versions of CALayer.h use 'slots' as an identifier
-#define QT_NO_KEYWORDS
-
-#include "tst_qwidget_mac_helpers.h"
-#include <QApplication>
-#include <qpa/qplatformnativeinterface.h>
-#include <private/qcore_mac_p.h>
-
-#include <AppKit/AppKit.h>
-
-QString nativeWindowTitle(QWidget *window, Qt::WindowState state)
-{
- QWindow *qwindow = window->windowHandle();
- NSWindow *nswindow = (NSWindow *) qApp->platformNativeInterface()->nativeResourceForWindow("nswindow", qwindow);
- QCFString macTitle;
- if (state == Qt::WindowMinimized) {
- macTitle = reinterpret_cast<CFStringRef>([[nswindow miniwindowTitle] retain]);
- } else {
- macTitle = reinterpret_cast<CFStringRef>([[nswindow title] retain]);
- }
- return macTitle;
-}
-
-bool nativeWindowModified(QWidget *widget)
-{
- QWindow *qwindow = widget->windowHandle();
- NSWindow *nswindow = (NSWindow *) qApp->platformNativeInterface()->nativeResourceForWindow("nswindow", qwindow);
- return [nswindow isDocumentEdited];
-}
diff --git a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST
index 0e1a2d58dc..77853a3e8c 100644
--- a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST
+++ b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST
@@ -1,7 +1,3 @@
-[tst_resize_count]
-# QTBUG-66345
-opensuse-42.3
-ubuntu-16.04
# QTBUG-87412
[tst_move_show]
android
diff --git a/tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt b/tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt
index 9bae267970..af60c92cbf 100644
--- a/tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt
@@ -1,16 +1,24 @@
-# Generated from qwidget_window.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidget_window Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidget_window LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qwidget_window
SOURCES
tst_qwidget_window.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
+ Qt::WidgetsPrivate
)
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 5b6bccf0b2..8e8cec6d4f 100644
--- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
+++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -43,6 +18,7 @@
#include <qlabel.h>
#include <qmainwindow.h>
#include <qtoolbar.h>
+#include <qsignalspy.h>
#include <private/qwindow_p.h>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -52,6 +28,8 @@
#include <QtTest/private/qtesthelpers_p.h>
+#include <QtWidgets/private/qapplication_p.h>
+
using namespace QTestPrivate;
// Compare a window position that may go through scaling in the platform plugin with fuzz.
@@ -75,6 +53,7 @@ public:
tst_QWidget_window();
public slots:
+ void init();
void initTestCase();
void cleanupTestCase();
void cleanup();
@@ -106,6 +85,7 @@ private slots:
void tst_dnd();
void tst_dnd_events();
void tst_dnd_propagation();
+ void tst_dnd_destroyOnDrop();
#endif
void tst_qtbug35600();
@@ -131,6 +111,13 @@ private slots:
void mouseMoveWithPopup_data();
void mouseMoveWithPopup();
+ void showHideWindowHandle_data();
+ void showHideWindowHandle();
+
+ void resetFocusObjectOnDestruction();
+
+ void cleanupOnDestruction();
+
private:
QSize m_testWidgetSize;
const int m_fuzz;
@@ -148,6 +135,11 @@ void tst_QWidget_window::initTestCase()
{
}
+void tst_QWidget_window::init()
+{
+ QTest::failOnWarning(QRegularExpression(".*No such slot.*"));
+}
+
void tst_QWidget_window::cleanupTestCase()
{
}
@@ -267,9 +259,9 @@ void tst_QWidget_window::close()
int spontClose = -1;
int spontHide = -1;
protected:
- void hideEvent(QHideEvent *e)
+ void hideEvent(QHideEvent *e) override
{ spontHide = e->spontaneous() ? 1 : 0; }
- void closeEvent(QCloseEvent *e)
+ void closeEvent(QCloseEvent *e) override
{ spontClose = e->spontaneous() ? 1 : 0; }
};
@@ -434,14 +426,14 @@ void tst_QWidget_window::tst_windowFilePath()
void tst_QWidget_window::tst_showWithoutActivating()
{
QString platformName = QGuiApplication::platformName().toLower();
- if (platformName == "cocoa")
- QSKIP("Cocoa: This fails. Figure out why.");
- else if (platformName != QStringLiteral("xcb")
- && platformName != QStringLiteral("windows")
- && platformName != QStringLiteral("ios")
- && platformName != QStringLiteral("tvos")
- && platformName != QStringLiteral("watchos"))
- QSKIP("Qt::WA_ShowWithoutActivating is currently supported only on xcb, windows, and ios/tvos/watchos platforms.");
+ if (platformName != QStringLiteral("xcb")
+ && platformName != QStringLiteral("windows")
+ && platformName != QStringLiteral("cocoa")
+ && platformName != QStringLiteral("ios")
+ && platformName != QStringLiteral("tvos")
+ && platformName != QStringLiteral("watchos"))
+ QSKIP("Qt::WA_ShowWithoutActivating is currently supported only on xcb, " \
+ "windows, and macos/ios/tvos/watchos platforms.");
QWidget w1;
w1.setAttribute(Qt::WA_ShowWithoutActivating);
@@ -699,7 +691,7 @@ void tst_QWidget_window::tst_dnd()
dndTestWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&dndTestWidget));
- qApp->setActiveWindow(&dndTestWidget);
+ QApplicationPrivate::setActiveWindow(&dndTestWidget);
QVERIFY(QTest::qWaitForWindowActive(&dndTestWidget));
QMimeData mimeData;
@@ -939,6 +931,78 @@ void tst_QWidget_window::tst_dnd_propagation()
QCOMPARE(target.mDndEvents, "enter leave enter drop ");
}
+
+class ReparentSelfOnDropWidget : public QWidget
+{
+public:
+ ReparentSelfOnDropWidget(QWidget *newFutureParent)
+ : m_newFutureParent(newFutureParent)
+ {
+ setAcceptDrops(true);
+
+ const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
+ auto width = availableGeometry.width() / 6;
+ auto height = availableGeometry.height() / 4;
+
+ setGeometry(availableGeometry.x() + 200, availableGeometry.y() + 200, width, height);
+
+ QLabel *label = new QLabel(QStringLiteral("Test"), this);
+ label->setGeometry(40, 40, 60, 60);
+ label->setAcceptDrops(true);
+ }
+
+ void dragEnterEvent(QDragEnterEvent *event) override
+ {
+ event->accept();
+ }
+
+ void dragMoveEvent(QDragMoveEvent *event) override
+ {
+ event->acceptProposedAction();
+ }
+
+ void dropEvent(QDropEvent *event) override
+ {
+ event->accept();
+ // Turn 'this' from a top-level widget to a child widget.
+ // This destroys the QWidgetWindow since the widget is no longer top-level.
+ setParent(m_newFutureParent);
+ }
+
+private:
+ QWidget *m_newFutureParent;
+};
+
+void tst_QWidget_window::tst_dnd_destroyOnDrop()
+{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Wayland: This fails. Figure out why.");
+
+ QMimeData mimeData;
+ mimeData.setText(QLatin1String("testmimetext"));
+
+ QWidget newParent;
+ newParent.resize(400, 400);
+ newParent.show();
+ QVERIFY(QTest::qWaitForWindowActive(&newParent));
+
+ ReparentSelfOnDropWidget *target = new ReparentSelfOnDropWidget(&newParent);
+ target->show();
+ QVERIFY(QTest::qWaitForWindowActive(target));
+
+ Qt::DropActions supportedActions = Qt::DropAction::CopyAction;
+ QWindow *window = target->windowHandle();
+
+ auto posInsideDropTarget = QHighDpi::toNativePixels(QPoint(20, 20), window->screen());
+ auto posInsideLabel = QHighDpi::toNativePixels(QPoint(60, 60), window->screen());
+
+ QWindowSystemInterface::handleDrag(window, &mimeData, posInsideDropTarget, supportedActions, {}, {});
+ QWindowSystemInterface::handleDrag(window, &mimeData, posInsideLabel, supportedActions, {}, {});
+ QWindowSystemInterface::handleDrop(window, &mimeData, posInsideLabel, supportedActions, {}, {});
+
+ QGuiApplication::processEvents();
+}
+
#endif
void tst_QWidget_window::tst_qtbug35600()
@@ -1399,6 +1463,9 @@ void tst_QWidget_window::mouseMoveWithPopup_data()
void tst_QWidget_window::mouseMoveWithPopup()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Wayland: Skip this test, see also QTBUG-107154");
+
QFETCH(Qt::WindowType, windowType);
class Window : public QWidget
@@ -1574,5 +1641,214 @@ void tst_QWidget_window::mouseMoveWithPopup()
QCOMPARE(topLevel.popup->mouseReleaseCount, 1);
}
+struct ShowHideEntry {
+ QEvent::Type action;
+ Qt::WindowType target;
+ using List = QList<ShowHideEntry>;
+};
+
+void tst_QWidget_window::showHideWindowHandle_data()
+{
+ QTest::addColumn<ShowHideEntry::List>("entries");
+
+ QTest::addRow("show/hide widget") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Hide, Qt::Widget }
+ };
+ QTest::addRow("show/hide window") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Window }, { QEvent::Hide, Qt::Window }
+ };
+ QTest::addRow("show widget, hide window") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Hide, Qt::Window }
+ };
+ QTest::addRow("show window, hide widget") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Window }, { QEvent::Hide, Qt::Widget }
+ };
+ QTest::addRow("show/hide widget, then show window, hide widget") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Hide, Qt::Widget },
+ { QEvent::Show, Qt::Window }, { QEvent::Hide, Qt::Widget }
+ };
+ QTest::addRow("show widget, close widget, show widget") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Close, Qt::Widget }, { QEvent::Show, Qt::Widget }
+ };
+ QTest::addRow("show widget, close widget, show window") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Close, Qt::Widget }, { QEvent::Show, Qt::Window }
+ };
+ QTest::addRow("show widget, close window, show widget") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Close, Qt::Window }, { QEvent::Show, Qt::Widget }
+ };
+ QTest::addRow("show widget, close window, show window") << ShowHideEntry::List{
+ { QEvent::Show, Qt::Widget }, { QEvent::Close, Qt::Window }, { QEvent::Show, Qt::Window }
+ };
+}
+
+void tst_QWidget_window::showHideWindowHandle()
+{
+ QWidget parent;
+ parent.setObjectName("Parent");
+ QCOMPARE(parent.isVisible(), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+
+ QWidget child;
+ child.setObjectName("Child");
+ QCOMPARE(child.isVisible(), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), true);
+
+ child.setParent(&parent);
+ QCOMPARE(child.isVisible(), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ QFETCH(QList<ShowHideEntry>, entries);
+ for (const auto entry : entries) {
+
+ if (entry.action == QEvent::Show) {
+ if (entry.target == Qt::Window && !parent.windowHandle()) {
+ parent.setAttribute(Qt::WA_NativeWindow);
+ QVERIFY(parent.windowHandle());
+
+ QCOMPARE(parent.isVisible(), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+ }
+
+ bool wasExplicitShowHide = parent.testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ if (entry.target == Qt::Widget)
+ parent.show();
+ else
+ parent.windowHandle()->show();
+
+ QVERIFY(QTest::qWaitForWindowActive(&parent));
+
+ QCOMPARE(parent.isVisible(), true);
+ QVERIFY(parent.windowHandle());
+ QCOMPARE(parent.windowHandle()->isVisible(), true);
+
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Visible), true);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide),
+ entry.target == Qt::Widget || wasExplicitShowHide);
+
+ QCOMPARE(child.isVisible(), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), true);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ } else if (entry.action == QEvent::Hide) {
+
+ bool wasExplicitShowHide = parent.testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ if (entry.target == Qt::Widget)
+ parent.hide();
+ else
+ parent.windowHandle()->hide();
+
+ QCOMPARE(parent.isVisible(), false);
+ QVERIFY(parent.windowHandle());
+ QCOMPARE(parent.windowHandle()->isVisible(), false);
+
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide),
+ entry.target == Qt::Widget || wasExplicitShowHide);
+
+ QCOMPARE(child.isVisible(), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+
+ } else if (entry.action == QEvent::Close) {
+
+ bool wasExplicitShowHide = parent.testAttribute(Qt::WA_WState_ExplicitShowHide);
+
+ if (entry.target == Qt::Widget)
+ parent.close();
+ else
+ parent.windowHandle()->close();
+
+ QCOMPARE(parent.isVisible(), false);
+ QVERIFY(parent.windowHandle());
+ QCOMPARE(parent.windowHandle()->isVisible(), false);
+
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_Hidden), true);
+ QCOMPARE(parent.testAttribute(Qt::WA_WState_ExplicitShowHide),
+ entry.target == Qt::Widget || wasExplicitShowHide);
+
+ QCOMPARE(child.isVisible(), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_ExplicitShowHide), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Visible), false);
+ QCOMPARE(child.testAttribute(Qt::WA_WState_Hidden), false);
+ }
+ }
+}
+
+void tst_QWidget_window::resetFocusObjectOnDestruction()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
+ QSignalSpy focusObjectChangedSpy(qApp, &QGuiApplication::focusObjectChanged);
+
+ // single top level widget that has focus
+ std::unique_ptr<QWidget> widget(new QWidget);
+ widget->setObjectName("Widget 1");
+ widget->setFocus();
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowActive(widget.get()));
+
+ int activeCount = focusObjectChangedSpy.size();
+ widget.reset();
+ QVERIFY(focusObjectChangedSpy.size() > activeCount);
+ QCOMPARE(focusObjectChangedSpy.last().last().value<QObject*>(), nullptr);
+ focusObjectChangedSpy.clear();
+
+ // top level widget with focused child
+ widget.reset(new QWidget);
+ widget->setObjectName("Widget 2");
+ QWidget *child = new QWidget(widget.get());
+ child->setObjectName("Child widget");
+ child->setFocus();
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowActive(widget.get()));
+
+ activeCount = focusObjectChangedSpy.size();
+ widget.reset();
+ // we might get more than one signal emission
+ QVERIFY(focusObjectChangedSpy.size() > activeCount);
+ QCOMPARE(focusObjectChangedSpy.last().last().value<QObject*>(), nullptr);
+}
+
+class CreateDestroyWidget : public QWidget
+{
+public:
+ using QWidget::create;
+ using QWidget::destroy;
+};
+
+void tst_QWidget_window::cleanupOnDestruction()
+{
+ CreateDestroyWidget widget;
+ QWidget child(&widget);
+
+ QWidget grandChild(&child);
+ // Ensure there's not a 1:1 native window hierarhcy that we could
+ // recurse during QWidget::destroy(), triggering the issue that
+ // we were failing to clean up when not destroyed via QWidget.
+ grandChild.setAttribute(Qt::WA_DontCreateNativeAncestors);
+ grandChild.winId();
+
+ widget.destroy();
+ widget.create();
+
+ widget.show();
+}
+
QTEST_MAIN(tst_QWidget_window)
#include "tst_qwidget_window.moc"
diff --git a/tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt b/tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt
index 58dae2d076..fb5409464d 100644
--- a/tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qwidgetaction.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetaction Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidgetaction LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qwidgetaction
SOURCES
tst_qwidgetaction.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
diff --git a/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp b/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp
index 1b43961182..a06e072b71 100644
--- a/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp
+++ b/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -247,7 +222,7 @@ void tst_QWidgetAction::customWidget()
tb1.addAction(action);
QList<QWidget *> combos = action->createdWidgets();
- QCOMPARE(combos.count(), 1);
+ QCOMPARE(combos.size(), 1);
QPointer<QComboBox> combo1 = qobject_cast<QComboBox *>(combos.at(0));
QVERIFY(combo1);
@@ -255,7 +230,7 @@ void tst_QWidgetAction::customWidget()
tb2.addAction(action);
combos = action->createdWidgets();
- QCOMPARE(combos.count(), 2);
+ QCOMPARE(combos.size(), 2);
QCOMPARE(combos.at(0), combo1.data());
QPointer<QComboBox> combo2 = qobject_cast<QComboBox *>(combos.at(1));
diff --git a/tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt b/tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt
index 3d8c3bbf4b..431a584a60 100644
--- a/tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qwidgetmetatype.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetmetatype Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidgetmetatype LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qwidgetmetatype
SOURCES
tst_qwidgetmetatype.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp b/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp
index 425380a99e..885c26a128 100644
--- a/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp
+++ b/tests/auto/widgets/kernel/qwidgetmetatype/tst_qwidgetmetatype.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/kernel/qwidgetrepaintmanager/CMakeLists.txt b/tests/auto/widgets/kernel/qwidgetrepaintmanager/CMakeLists.txt
new file mode 100644
index 0000000000..ae91af064c
--- /dev/null
+++ b/tests/auto/widgets/kernel/qwidgetrepaintmanager/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidgetrepaintmanager LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qwidgetrepaintmanager
+ SOURCES
+ tst_qwidgetrepaintmanager.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::TestPrivate
+ Qt::Widgets
+ Qt::WidgetsPrivate
+)
diff --git a/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp
new file mode 100644
index 0000000000..9059a9262e
--- /dev/null
+++ b/tests/auto/widgets/kernel/qwidgetrepaintmanager/tst_qwidgetrepaintmanager.cpp
@@ -0,0 +1,831 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+
+#include <QTest>
+#include <QPainter>
+#include <QScrollArea>
+#include <QScrollBar>
+#include <QApplication>
+
+#include <private/qhighdpiscaling_p.h>
+#include <private/qwidget_p.h>
+#include <private/qwidgetrepaintmanager_p.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformbackingstore.h>
+#include <private/qguiapplication_p.h>
+
+//#define MANUAL_DEBUG
+
+class TestWidget : public QWidget
+{
+public:
+ TestWidget(QWidget *parent = nullptr)
+ : QWidget(parent)
+ {
+ }
+
+ QSize sizeHint() const override
+ {
+ const int screenWidth = QGuiApplication::primaryScreen()->geometry().width();
+ const int width = qMax(200, 100 * ((screenWidth + 500) / 1000));
+ return isWindow() ? QSize(width, width) : QSize(width - 40, width - 40);
+ }
+
+ void initialShow()
+ {
+ show();
+ if (isWindow()) {
+ QVERIFY(QTest::qWaitForWindowExposed(this));
+ QVERIFY(waitForPainted());
+ }
+ paintedRegions = {};
+ }
+
+ bool waitForPainted(int timeout = 5000)
+ {
+ int remaining = timeout;
+ QDeadlineTimer deadline(remaining, Qt::PreciseTimer);
+ if (!QTest::qWaitFor([this]{ return !paintedRegions.isEmpty(); }, timeout))
+ return false;
+
+ // In case of multiple paint events:
+ // Process events and wait until all have been consumed,
+ // i.e. paintedRegions no longer changes.
+ QRegion reg;
+ while (remaining > 0 && reg != paintedRegions) {
+ reg = paintedRegions;
+ QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
+ if (reg == paintedRegions)
+ return true;
+
+ remaining = int(deadline.remainingTime());
+ }
+ return false;
+ }
+
+ QRegion takePaintedRegions()
+ {
+ QRegion result = paintedRegions;
+ paintedRegions = {};
+ return result;
+ }
+ QRegion paintedRegions;
+
+ bool event(QEvent *event) override
+ {
+ const auto type = event->type();
+ if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
+ return true;
+ if (type == QEvent::UpdateRequest)
+ ++updateRequests;
+ return QWidget::event(event);
+ }
+ int updateRequests = 0;
+
+protected:
+ void paintEvent(QPaintEvent *event) override
+ {
+ paintedRegions += event->region();
+ QPainter painter(this);
+ const QBrush patternBrush = isWindow() ? QBrush(Qt::blue, Qt::VerPattern)
+ : QBrush(Qt::red, Qt::HorPattern);
+ painter.fillRect(rect(), patternBrush);
+ }
+};
+
+class OpaqueWidget : public QWidget
+{
+public:
+ OpaqueWidget(const QColor &col, QWidget *parent = nullptr)
+ : QWidget(parent), fillColor(col)
+ {
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ }
+
+ bool event(QEvent *event) override
+ {
+ const auto type = event->type();
+ if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
+ return true;
+ return QWidget::event(event);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *e) override
+ {
+ Q_UNUSED(e);
+ QPainter painter(this);
+ fillColor.setBlue(paintCount % 255);
+ painter.fillRect(e->rect(), fillColor);
+#ifdef MANUAL_DEBUG
+ ++paintCount;
+ painter.drawText(rect(), Qt::AlignCenter, QString::number(paintCount));
+#endif
+ }
+
+private:
+ QColor fillColor;
+ int paintCount = 0;
+};
+
+class Draggable : public OpaqueWidget
+{
+public:
+ Draggable(QWidget *parent = nullptr)
+ : OpaqueWidget(Qt::white, parent)
+ {
+ }
+
+ Draggable(const QColor &col, QWidget *parent = nullptr)
+ : OpaqueWidget(col, parent)
+ {
+ left = new OpaqueWidget(Qt::gray, this);
+ top = new OpaqueWidget(Qt::gray, this);
+ right = new OpaqueWidget(Qt::gray, this);
+ bottom = new OpaqueWidget(Qt::gray, this);
+ }
+
+ QSize sizeHint() const override {
+ return QSize(100, 100);
+ }
+
+protected:
+ void resizeEvent(QResizeEvent *) override
+ {
+ if (!left)
+ return;
+ left->setGeometry(0, 0, 10, height());
+ top->setGeometry(10, 0, width() - 10, 10);
+ right->setGeometry(width() - 10, 10, 10, height() - 10);
+ bottom->setGeometry(10, height() - 10, width() - 10, 10);
+ }
+
+ void mousePressEvent(QMouseEvent *e) override
+ {
+ lastPos = e->position().toPoint();
+ }
+ void mouseMoveEvent(QMouseEvent *e) override
+ {
+ QPoint pos = geometry().topLeft();
+ pos += e->position().toPoint() - lastPos;
+ move(pos);
+ }
+ void mouseReleaseEvent(QMouseEvent *) override
+ {
+ lastPos = {};
+ }
+
+private:
+ OpaqueWidget *left = nullptr;
+ OpaqueWidget *top = nullptr;
+ OpaqueWidget *right = nullptr;
+ OpaqueWidget *bottom = nullptr;
+ QPoint lastPos;
+};
+
+class TestScene : public QWidget
+{
+public:
+ TestScene()
+ {
+ setObjectName("scene");
+
+ // opaque because it has an opaque background color and autoFillBackground is set
+ area = new QWidget(this);
+ area->setObjectName("area");
+ area->setAutoFillBackground(true);
+ QPalette palette;
+ palette.setColor(QPalette::Window, QColor::fromRgb(0, 0, 0));
+ area->setPalette(palette);
+
+ // all these children set WA_OpaquePaintEvent
+ redChild = new Draggable(Qt::red, area);
+ redChild->setObjectName("redChild");
+
+ greenChild = new Draggable(Qt::green, area);
+ greenChild->setObjectName("greenChild");
+
+ yellowChild = new Draggable(Qt::yellow, this);
+ yellowChild->setObjectName("yellowChild");
+
+ nakedChild = new Draggable(this);
+ nakedChild->move(300, 0);
+ nakedChild->setObjectName("nakedChild");
+
+ bar = new OpaqueWidget(Qt::darkGray, this);
+ bar->setObjectName("bar");
+ }
+
+ QWidget *area;
+ QWidget *redChild;
+ QWidget *greenChild;
+ QWidget *yellowChild;
+ QWidget *nakedChild;
+ QWidget *bar;
+
+ QSize sizeHint() const override { return QSize(400, 400); }
+
+ bool event(QEvent *event) override
+ {
+ const auto type = event->type();
+ if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
+ return true;
+ return QWidget::event(event);
+ }
+
+protected:
+ void resizeEvent(QResizeEvent *) override
+ {
+ area->setGeometry(50, 50, width() - 100, height() - 100);
+ bar->setGeometry(width() / 2 - 25, height() / 2, 50, height() / 2);
+ }
+};
+
+class tst_QWidgetRepaintManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWidgetRepaintManager();
+
+public slots:
+ void initTestCase();
+ void cleanup();
+
+private slots:
+ void basic();
+ void children();
+ void opaqueChildren();
+ void staticContents();
+ void scroll();
+ void paintOnScreenUpdates();
+
+#if defined(QT_BUILD_INTERNAL)
+ void scrollWithOverlap();
+ void overlappedRegion();
+ void fastMove();
+ void moveAccross();
+ void moveInOutOverlapped();
+
+protected:
+ /*
+ This helper compares the widget as rendered into the backingstore with the widget
+ as rendered via QWidget::grab. The latter always produces a fully rendered image,
+ so differences indicate bugs in QWidgetRepaintManager's or QWidget's painting code.
+ */
+ bool compareWidget(QWidget *w)
+ {
+ QBackingStore *backingStore = w->window()->backingStore();
+ Q_ASSERT(backingStore && backingStore->handle());
+ QPlatformBackingStore *platformBackingStore = backingStore->handle();
+
+ if (!waitForFlush(w)) {
+ qWarning() << "Widget" << w << "failed to flush";
+ return false;
+ }
+
+ QImage backingstoreContent = platformBackingStore->toImage();
+ if (!w->isWindow()) {
+ const qreal dpr = w->devicePixelRatioF();
+ const QPointF offset = w->mapTo(w->window(), QPointF(0, 0)) * dpr;
+ backingstoreContent = backingstoreContent.copy(offset.x(), offset.y(), w->width() * dpr, w->height() * dpr);
+ }
+ const QImage widgetRender = w->grab().toImage().convertToFormat(backingstoreContent.format());
+
+ const bool result = backingstoreContent == widgetRender;
+
+#ifdef MANUAL_DEBUG
+ if (!result) {
+ backingstoreContent.save(QString("/tmp/backingstore_%1_%2.png").arg(QTest::currentTestFunction(), QTest::currentDataTag()));
+ widgetRender.save(QString("/tmp/grab_%1_%2.png").arg(QTest::currentTestFunction(), QTest::currentDataTag()));
+ }
+#endif
+ return result;
+ };
+
+ QRegion dirtyRegion(QWidget *widget) const
+ {
+ return QWidgetPrivate::get(widget)->dirty;
+ }
+ bool waitForFlush(QWidget *widget) const
+ {
+ if (!widget)
+ return true;
+
+ auto *repaintManager = QWidgetPrivate::get(widget->window())->maybeRepaintManager();
+
+ if (!repaintManager)
+ return true;
+
+ return QTest::qWaitFor([repaintManager]{ return !repaintManager->isDirty(); } );
+ };
+#endif // QT_BUILD_INTERNAL
+
+
+private:
+ const int m_fuzz;
+ bool m_implementsScroll = false;
+};
+
+tst_QWidgetRepaintManager::tst_QWidgetRepaintManager() :
+ m_fuzz(int(QHighDpiScaling::factor(QGuiApplication::primaryScreen())))
+{
+}
+
+void tst_QWidgetRepaintManager::initTestCase()
+{
+ QWidget widget;
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ m_implementsScroll = widget.backingStore()->handle()->scroll(QRegion(widget.rect()), 1, 1);
+ qInfo() << QGuiApplication::platformName() << "QPA backend implements scroll:" << m_implementsScroll;
+}
+
+void tst_QWidgetRepaintManager::cleanup()
+{
+ QVERIFY(QApplication::topLevelWidgets().isEmpty());
+}
+
+void tst_QWidgetRepaintManager::basic()
+{
+ TestWidget widget;
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
+
+ widget.update();
+ QVERIFY(widget.waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
+
+ widget.repaint();
+ QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
+}
+
+/*!
+ Children cannot assumed to be fully opaque, so the parent will repaint when the
+ child repaints.
+*/
+void tst_QWidgetRepaintManager::children()
+{
+ if (QStringList{"android"}.contains(QGuiApplication::platformName()))
+ QSKIP("This test fails on Android");
+
+ TestWidget widget;
+ widget.initialShow();
+
+ TestWidget *child1 = new TestWidget(&widget);
+ child1->move(20, 20);
+ child1->show();
+ QVERIFY(QTest::qWaitForWindowExposed(child1));
+ QVERIFY(child1->waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion(child1->geometry()));
+ QCOMPARE(child1->takePaintedRegions(), QRegion(child1->rect()));
+
+ child1->move(20, 30);
+ QVERIFY(widget.waitForPainted());
+ // both the old and the new area covered by child1 need to be repainted
+ QCOMPARE(widget.takePaintedRegions(), QRegion(20, 20, child1->width(), child1->height() + 10));
+ QCOMPARE(child1->takePaintedRegions(), QRegion(child1->rect()));
+
+ TestWidget *child2 = new TestWidget(&widget);
+ child2->move(30, 30);
+ child2->raise();
+ child2->show();
+
+ QVERIFY(child2->waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion(child2->geometry()));
+ QCOMPARE(child1->takePaintedRegions(), QRegion(10, 0, child2->width() - 10, child2->height()));
+ QCOMPARE(child2->takePaintedRegions(), QRegion(child2->rect()));
+
+ child1->hide();
+ QVERIFY(widget.waitForPainted());
+ QCOMPARE(widget.paintedRegions, QRegion(child1->geometry()));
+}
+
+void tst_QWidgetRepaintManager::opaqueChildren()
+{
+ if (QStringList{"android"}.contains(QGuiApplication::platformName()))
+ QSKIP("This test fails on Android");
+
+ TestWidget widget;
+ widget.initialShow();
+
+ TestWidget *child1 = new TestWidget(&widget);
+ child1->move(20, 20);
+ child1->setAttribute(Qt::WA_OpaquePaintEvent);
+ child1->show();
+
+ QVERIFY(child1->waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion());
+ QCOMPARE(child1->takePaintedRegions(), child1->rect());
+
+ child1->move(20, 30);
+ QVERIFY(widget.waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion(20, 20, child1->width(), 10));
+ if (!m_implementsScroll)
+ QEXPECT_FAIL("", "child1 shouldn't get painted, we can just move the area of the backingstore", Continue);
+ QCOMPARE(child1->takePaintedRegions(), QRegion());
+}
+
+/*!
+ When resizing to be larger, a widget with Qt::WA_StaticContents set
+ should only repaint the newly revealed areas.
+*/
+void tst_QWidgetRepaintManager::staticContents()
+{
+ const auto *integration = QGuiApplicationPrivate::platformIntegration();
+ if (!integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents))
+ QSKIP("Platform does not support static backingstore content");
+
+ TestWidget widget;
+ widget.setAttribute(Qt::WA_StaticContents);
+ widget.initialShow();
+
+ // Trigger resize via QWindow (similar to QWSI code path)
+ QVERIFY(widget.windowHandle());
+ QSize oldSize = widget.size();
+ widget.windowHandle()->resize(widget.width(), widget.height() + 10);
+ QVERIFY(widget.waitForPainted());
+ QCOMPARE(widget.takePaintedRegions(), QRegion(0, oldSize.width(), widget.width(), 10));
+
+ // Trigger resize via QWidget
+ oldSize = widget.size();
+ widget.resize(widget.width() + 10, widget.height());
+ QVERIFY(widget.waitForPainted());
+ QEXPECT_FAIL("", "QWidgetPrivate::setGeometry_sys wrongly triggers full update", Continue);
+ QCOMPARE(widget.takePaintedRegions(), QRegion(oldSize.width(), 0, 10, widget.height()));
+}
+
+/*!
+ Scrolling a widget.
+*/
+void tst_QWidgetRepaintManager::scroll()
+{
+ if (QStringList{"android"}.contains(QGuiApplication::platformName()))
+ QSKIP("This test fails on Android");
+
+ TestWidget widget;
+ widget.initialShow();
+
+ widget.scroll(10, 0);
+ QVERIFY(widget.waitForPainted());
+ if (!m_implementsScroll)
+ QEXPECT_FAIL("", "This should just repaint the newly exposed region", Continue);
+ QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, 10, widget.height()));
+
+ TestWidget *child = new TestWidget(&widget);
+ child->move(20, 20);
+ child->initialShow();
+
+ // a potentially semi-transparent child scrolling needs a full repaint
+ child->scroll(10, 0);
+ QVERIFY(child->waitForPainted());
+ QCOMPARE(child->takePaintedRegions(), child->rect());
+ QCOMPARE(widget.takePaintedRegions(), child->geometry());
+
+ // a explicitly opaque child scrolling only needs the child to repaint newly exposed regions
+ child->setAttribute(Qt::WA_OpaquePaintEvent);
+ child->scroll(10, 0);
+ QVERIFY(child->waitForPainted());
+ if (!m_implementsScroll)
+ QEXPECT_FAIL("", "This should just repaint the newly exposed region", Continue);
+ QCOMPARE(child->takePaintedRegions(), QRegion(0, 0, 10, child->height()));
+ QCOMPARE(widget.takePaintedRegions(), QRegion());
+}
+
+class PaintOnScreenWidget : public TestWidget
+{
+public:
+ using TestWidget::TestWidget;
+
+ // Explicit override to prevent noPaintOnScreen on Windows
+ QPaintEngine *paintEngine() const override
+ {
+ return nullptr;
+ }
+};
+
+void tst_QWidgetRepaintManager::paintOnScreenUpdates()
+{
+ {
+ TestWidget topLevel;
+ topLevel.setObjectName("TopLevel");
+ topLevel.resize(500, 500);
+ TestWidget renderToTextureWidget(&topLevel);
+ renderToTextureWidget.setObjectName("RenderToTexture");
+ renderToTextureWidget.setGeometry(0, 0, 200, 200);
+ QWidgetPrivate::get(&renderToTextureWidget)->setRenderToTexture();
+
+ PaintOnScreenWidget paintOnScreenWidget(&topLevel);
+ paintOnScreenWidget.setObjectName("PaintOnScreen");
+ paintOnScreenWidget.setGeometry(200, 200, 300, 300);
+
+ topLevel.initialShow();
+
+ // Updating before toggling WA_PaintOnScreen should work fine
+ paintOnScreenWidget.update();
+ paintOnScreenWidget.waitForPainted();
+ QVERIFY(paintOnScreenWidget.waitForPainted());
+
+#ifdef Q_OS_ANDROID
+ QEXPECT_FAIL("", "This test fails on Android", Abort);
+#endif
+ QCOMPARE(paintOnScreenWidget.takePaintedRegions(), paintOnScreenWidget.rect());
+
+ renderToTextureWidget.update();
+ QVERIFY(renderToTextureWidget.waitForPainted());
+ QCOMPARE(renderToTextureWidget.takePaintedRegions(), renderToTextureWidget.rect());
+
+ // Then toggle WA_PaintOnScreen
+ paintOnScreenWidget.setAttribute(Qt::WA_PaintOnScreen);
+
+ // The render-to-texture widget updates fine
+ renderToTextureWidget.update();
+ QVERIFY(renderToTextureWidget.waitForPainted());
+ QCOMPARE(renderToTextureWidget.takePaintedRegions(), renderToTextureWidget.rect());
+
+ // Updating the paint-on-screen texture widget will not result
+ // in a paint event, but should result in an update request.
+ paintOnScreenWidget.updateRequests = 0;
+ paintOnScreenWidget.update();
+ QVERIFY(QTest::qWaitFor([&]{ return paintOnScreenWidget.updateRequests > 0; }));
+
+ // And should not prevent the render-to-texture widget from receiving updates
+ renderToTextureWidget.update();
+ QVERIFY(renderToTextureWidget.waitForPainted());
+ QCOMPARE(renderToTextureWidget.takePaintedRegions(), renderToTextureWidget.rect());
+ }
+
+ {
+ TestWidget paintOnScreenTopLevel;
+ paintOnScreenTopLevel.setObjectName("PaintOnScreenTopLevel");
+ paintOnScreenTopLevel.setAttribute(Qt::WA_PaintOnScreen);
+
+ paintOnScreenTopLevel.initialShow();
+
+ paintOnScreenTopLevel.updateRequests = 0;
+ paintOnScreenTopLevel.update();
+ QVERIFY(QTest::qWaitFor([&]{ return paintOnScreenTopLevel.updateRequests > 0; }));
+
+ // Turn off paint on screen and make it a render-to-texture widget.
+ // This will lead us into a QWidgetRepaintManager::markDirty() code
+ // path that checks updateRequestSent, which is still set from the
+ // update above since paint-on-screen handling doesn't reset it.
+ paintOnScreenTopLevel.setAttribute(Qt::WA_PaintOnScreen, false);
+ QWidgetPrivate::get(&paintOnScreenTopLevel)->setRenderToTexture();
+ paintOnScreenTopLevel.update();
+ QVERIFY(QTest::qWaitFor([&]{ return paintOnScreenTopLevel.updateRequests > 1; }));
+ }
+}
+
+#if defined(QT_BUILD_INTERNAL)
+
+/*!
+ Verify that overlapping children are repainted correctly when
+ a widget is moved (via a scroll area) for such a distance that
+ none of the old area is still visible. QTBUG-26269
+*/
+void tst_QWidgetRepaintManager::scrollWithOverlap()
+{
+ if (QStringList{"android"}.contains(QGuiApplication::platformName()))
+ QSKIP("This test fails on Android");
+
+ class MainWindow : public QWidget
+ {
+ public:
+ MainWindow(QWidget *parent = 0)
+ : QWidget(parent, Qt::WindowStaysOnTopHint)
+ {
+ m_scrollArea = new QScrollArea(this);
+ m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ QWidget *w = new QWidget;
+ w->setPalette(QPalette(Qt::gray));
+ w->setAutoFillBackground(true);
+ m_scrollArea->setWidget(w);
+ m_scrollArea->resize(500, 100);
+ w->resize(5000, 600);
+
+ m_topWidget = new QWidget(this);
+ m_topWidget->setPalette(QPalette(Qt::red));
+ m_topWidget->setAutoFillBackground(true);
+ m_topWidget->resize(300, 200);
+
+ resize(600, 300);
+ }
+
+ void resizeEvent(QResizeEvent *e) override
+ {
+ QWidget::resizeEvent(e);
+ // move scroll area and top widget to the center of the main window
+ scrollArea()->move((width() - scrollArea()->width()) / 2, (height() - scrollArea()->height()) / 2);
+ topWidget()->move((width() - topWidget()->width()) / 2, (height() - topWidget()->height()) / 2);
+ }
+
+
+ inline QScrollArea *scrollArea() const { return m_scrollArea; }
+ inline QWidget *topWidget() const { return m_topWidget; }
+
+ private:
+ QScrollArea *m_scrollArea;
+ QWidget *m_topWidget;
+ };
+
+ MainWindow w;
+ w.show();
+
+ QVERIFY(QTest::qWaitForWindowActive(&w));
+
+ bool result = compareWidget(w.topWidget());
+ // if this fails already, then the system we test on can't compare screenshots from grabbed widgets,
+ // and we have to skip this test. Possible reasons are differences in surface formats or DPI, or
+ // unrelated bugs in QPlatformBackingStore::toImage or QWidget::grab.
+ if (!result)
+ QSKIP("Cannot compare QWidget::grab with QScreen::grabWindow on this machine");
+
+ // scroll the horizontal slider to the right side
+ {
+ w.scrollArea()->horizontalScrollBar()->setValue(w.scrollArea()->horizontalScrollBar()->maximum());
+ QVERIFY(compareWidget(w.topWidget()));
+ }
+
+ // scroll the vertical slider down
+ {
+ w.scrollArea()->verticalScrollBar()->setValue(w.scrollArea()->verticalScrollBar()->maximum());
+ QVERIFY(compareWidget(w.topWidget()));
+ }
+
+ // hide the top widget
+ {
+ w.topWidget()->hide();
+ QVERIFY(compareWidget(w.scrollArea()->viewport()));
+ }
+
+ // scroll the horizontal slider to the left side
+ {
+ w.scrollArea()->horizontalScrollBar()->setValue(w.scrollArea()->horizontalScrollBar()->minimum());
+ QVERIFY(compareWidget(w.scrollArea()->viewport()));
+ }
+
+ // scroll the vertical slider up
+ {
+ w.scrollArea()->verticalScrollBar()->setValue(w.scrollArea()->verticalScrollBar()->minimum());
+ QVERIFY(compareWidget(w.scrollArea()->viewport()));
+ }
+}
+
+/*!
+ This tests QWidgetPrivate::overlappedRegion, which however is only used in the
+ QWidgetRepaintManager, so the test is here.
+*/
+void tst_QWidgetRepaintManager::overlappedRegion()
+{
+ TestScene scene;
+
+ if (scene.screen()->availableSize().width() < scene.sizeHint().width()
+ || scene.screen()->availableSize().height() < scene.sizeHint().height()) {
+ QSKIP("The screen on this system is too small for this test");
+ }
+
+ scene.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&scene));
+
+ auto overlappedRegion = [](QWidget *widget, bool breakAfterFirst = false){
+ auto *priv = QWidgetPrivate::get(widget);
+ // overlappedRegion works on parent coordinates (crect, i.e. QWidget::geometry)
+ return priv->overlappedRegion(widget->geometry(), breakAfterFirst);
+ };
+
+ // the yellow child is not overlapped
+ QVERIFY(overlappedRegion(scene.yellowChild).isEmpty());
+ // the green child is partially overlapped by the yellow child, which
+ // is at position -50, -50 relative to the green child (and 100x100 large)
+ QRegion overlap = overlappedRegion(scene.greenChild);
+ QVERIFY(!overlap.isEmpty());
+ QCOMPARE(overlap, QRegion(QRect(-50, -50, 100, 100)));
+ // the red child is completely obscured by the green child, and partially
+ // obscured by the yellow child. How exactly this is divided into rects is
+ // irrelevant for the test.
+ overlap = overlappedRegion(scene.redChild);
+ QVERIFY(!overlap.isEmpty());
+ QCOMPARE(overlap.boundingRect(), QRect(-50, -50, 150, 150));
+
+ // moving the red child out of obscurity
+ scene.redChild->move(100, 0);
+ overlap = overlappedRegion(scene.redChild);
+ QTRY_VERIFY(overlap.isEmpty());
+
+ // moving the red child down so it's partially behind the bar
+ scene.redChild->move(100, 100);
+ overlap = overlappedRegion(scene.redChild);
+ QTRY_VERIFY(!overlap.isEmpty());
+
+ // moving the yellow child so it is partially overlapped by the bar
+ scene.yellowChild->move(200, 200);
+ overlap = overlappedRegion(scene.yellowChild);
+ QTRY_VERIFY(!overlap.isEmpty());
+}
+
+void tst_QWidgetRepaintManager::fastMove()
+{
+ TestScene scene;
+ scene.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&scene));
+
+ QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
+ QVERIFY(repaintManager->dirtyRegion().isEmpty());
+
+ // moving yellow; nothing obscured
+ scene.yellowChild->move(QPoint(25, 0));
+ QVERIFY(repaintManager->dirtyRegion().isEmpty()); // fast move
+ if (m_implementsScroll) {
+ QCOMPARE(repaintManager->dirtyWidgetList(), QList<QWidget *>() << &scene);
+ QVERIFY(dirtyRegion(scene.yellowChild).isEmpty());
+ } else {
+ QCOMPARE(repaintManager->dirtyWidgetList(), QList<QWidget *>() << scene.yellowChild << &scene);
+ QCOMPARE(dirtyRegion(scene.yellowChild), QRect(0, 0, 100, 100));
+ }
+ QCOMPARE(dirtyRegion(&scene), QRect(0, 0, 25, 100));
+ QTRY_VERIFY(dirtyRegion(&scene).isEmpty());
+ QVERIFY(compareWidget(&scene));
+}
+
+void tst_QWidgetRepaintManager::moveAccross()
+{
+ TestScene scene;
+ scene.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&scene));
+
+ QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
+ QVERIFY(repaintManager->dirtyRegion().isEmpty());
+
+ for (int i = 0; i < 4; ++i) {
+ scene.greenChild->move(scene.greenChild->pos() + QPoint(25, 0));
+ waitForFlush(&scene);
+ }
+ QVERIFY(compareWidget(&scene));
+
+ for (int i = 0; i < 16; ++i) {
+ scene.redChild->move(scene.redChild->pos() + QPoint(25, 0));
+ waitForFlush(&scene);
+ }
+ QVERIFY(compareWidget(&scene));
+
+ for (int i = 0; i < qMin(scene.area->width(), scene.area->height()); i += 25) {
+ scene.yellowChild->move(scene.yellowChild->pos() + QPoint(25, 25));
+ waitForFlush(&scene);
+ }
+ QVERIFY(compareWidget(&scene));
+}
+
+void tst_QWidgetRepaintManager::moveInOutOverlapped()
+{
+ TestScene scene;
+ scene.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&scene));
+
+ QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
+ QVERIFY(repaintManager->dirtyRegion().isEmpty());
+
+ // yellow out
+ scene.yellowChild->move(QPoint(-100, 0));
+ QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid dest rect
+ QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
+ QVERIFY(waitForFlush(&scene));
+ QVERIFY(compareWidget(&scene));
+
+ // yellow in, obscured by bar
+ scene.yellowChild->move(QPoint(scene.width() / 2, scene.height() / 2));
+ QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid source rect
+ QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
+ QVERIFY(waitForFlush(&scene));
+ QVERIFY(compareWidget(&scene));
+
+ // green out
+ scene.greenChild->move(QPoint(-100, 0));
+ QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid dest rect
+ QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
+ QVERIFY(waitForFlush(&scene));
+ QVERIFY(compareWidget(&scene));
+
+ // green back in, obscured by bar
+ scene.greenChild->move(QPoint(scene.area->width() / 2 - 50, scene.area->height() / 2 - 50));
+ QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid source rect
+ QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
+ QVERIFY(waitForFlush(&scene));
+ QVERIFY(compareWidget(&scene));
+
+ // red back under green
+ scene.redChild->move(scene.greenChild->pos());
+ QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // destination rect obscured
+ QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
+ QVERIFY(waitForFlush(&scene));
+ QVERIFY(compareWidget(&scene));
+}
+#endif //# defined(QT_BUILD_INTERNAL)
+
+QTEST_MAIN(tst_QWidgetRepaintManager)
+#include "tst_qwidgetrepaintmanager.moc"
diff --git a/tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt b/tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt
index f387be7306..bb3c1e2ad6 100644
--- a/tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt
@@ -1,15 +1,22 @@
-# Generated from qwidgetsvariant.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetsvariant Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwidgetsvariant LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qwidgetsvariant
SOURCES
tst_qwidgetsvariant.cpp
INCLUDE_DIRECTORIES
../../../other/qvariant_common
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qwidgetsvariant/tst_qwidgetsvariant.cpp b/tests/auto/widgets/kernel/qwidgetsvariant/tst_qwidgetsvariant.cpp
index d33f734af0..0a03fb9e1d 100644
--- a/tests/auto/widgets/kernel/qwidgetsvariant/tst_qwidgetsvariant.cpp
+++ b/tests/auto/widgets/kernel/qwidgetsvariant/tst_qwidgetsvariant.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt b/tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt
index 63a3f9632d..787505972f 100644
--- a/tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt
+++ b/tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qwindowcontainer.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwindowcontainer Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qwindowcontainer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qwindowcontainer
SOURCES
tst_qwindowcontainer.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Widgets
)
diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
index 9dead3d3ea..52aaf094b4 100644
--- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
+++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -32,12 +7,14 @@
#include <qapplication.h>
#include <qwindow.h>
#include <qwidget.h>
+#include <qlineedit.h>
#include <qdockwidget.h>
#include <qmainwindow.h>
#include <qscreen.h>
#include <qscopedpointer.h>
#include <qevent.h>
+#include <qboxlayout.h>
class Window : public QWindow
@@ -71,16 +48,20 @@ public:
private slots:
void testShow();
void testPositionAndSize();
+ void testSizeHints();
void testExposeObscure();
void testOwnership();
void testBehindTheScenesDeletion();
void testUnparenting();
+ void testReparenting();
void testUnparentReparent();
void testActivation();
void testAncestorChange();
void testDockWidget();
void testNativeContainerParent();
void testPlatformSurfaceEvent();
+ void embedWidgetWindow();
+ void testFocus();
void cleanup();
private:
@@ -132,7 +113,29 @@ void tst_QWindowContainer::testPositionAndSize()
QCOMPARE(window->height(), container->height());
}
+void tst_QWindowContainer::testSizeHints()
+{
+ QScopedPointer<QWidget> tlw(new QWidget);
+ QWindow *window = new QWindow();
+ window->setMinimumSize(QSize(200, 200));
+ window->setGeometry(m_availableGeometry.x() + 300, m_availableGeometry.y() + 400, 500, 600);
+
+ QScopedPointer<QWidget> container(QWidget::createWindowContainer(window));
+ container->setWindowTitle(QTest::currentTestFunction());
+
+ QVBoxLayout *vbox = new QVBoxLayout(tlw.data());
+ vbox->addWidget(container.data());
+ vbox->setContentsMargins(0, 0, 0, 0);
+ // Size hints should work regardless of visibility
+ QCOMPARE(container->minimumSizeHint(), window->minimumSize());
+ QCOMPARE(vbox->minimumSize(), window->minimumSize());
+
+ // Respect dynamic updates
+ window->setMinimumSize(QSize(210, 210));
+ QCOMPARE(container->minimumSizeHint(), window->minimumSize());
+ QCOMPARE(vbox->minimumSize(), window->minimumSize());
+}
void tst_QWindowContainer::testExposeObscure()
{
@@ -231,12 +234,12 @@ void tst_QWindowContainer::testActivation()
void tst_QWindowContainer::testUnparenting()
{
- QWindow *window = new QWindow();
+ QPointer<QWindow> window(new QWindow());
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window));
container->setWindowTitle(QTest::currentTestFunction());
container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100);
- window->setParent(0);
+ window->setParent(nullptr);
container->show();
@@ -244,6 +247,26 @@ void tst_QWindowContainer::testUnparenting()
// Window should not be made visible by container..
QVERIFY(!window->isVisible());
+
+ container.reset();
+ QVERIFY(window);
+ delete window;
+}
+
+void tst_QWindowContainer::testReparenting()
+{
+ QPointer<QWindow> window1(new QWindow());
+ QScopedPointer<QWindow> window2(new QWindow());
+ QScopedPointer<QWidget> container(QWidget::createWindowContainer(window1));
+
+ window1->setParent(window2.data());
+
+ // Not deleted with container
+ container.reset();
+ QVERIFY(window1);
+ // but deleted with new parent
+ window2.reset();
+ QVERIFY(!window1);
}
void tst_QWindowContainer::testUnparentReparent()
@@ -414,6 +437,99 @@ void tst_QWindowContainer::testPlatformSurfaceEvent()
QVERIFY(ok);
}
+void tst_QWindowContainer::embedWidgetWindow()
+{
+ {
+ QWidget parent;
+ QWidget *widget = new QWidget;
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(widget));
+ QVERIFY(widget->windowHandle());
+ QPointer<QWindow> widgetWindow = widget->windowHandle();
+ auto *container = QWidget::createWindowContainer(widgetWindow, &parent);
+ QCOMPARE(container, widget);
+ QCOMPARE(widget->parent(), &parent);
+ delete widget;
+ QTRY_VERIFY(widgetWindow.isNull());
+ }
+
+ QPointer<QWidget> widget = new QWidget;
+ QPointer<QWindow> widgetWindow;
+ {
+ QWidget parent;
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(widget));
+ QVERIFY(widget->windowHandle());
+ widgetWindow = widget->windowHandle();
+ auto *container = QWidget::createWindowContainer(widgetWindow, &parent);
+ QCOMPARE(container, widget);
+ QCOMPARE(widget->parent(), &parent);
+ }
+ QTRY_VERIFY(widget.isNull());
+ QTRY_VERIFY(widgetWindow.isNull());
+
+}
+
+void tst_QWindowContainer::testFocus()
+{
+ QWidget root;
+ root.setGeometry(m_availableGeometry);
+
+ QLineEdit *lineEdit = new QLineEdit(&root);
+ lineEdit->setGeometry(0, 0, m_availableGeometry.width() * 0.1, 17);
+ lineEdit->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
+
+ QWindow *embedded = new QWindow();
+ QWidget *container = QWidget::createWindowContainer(embedded, &root);
+ container->setGeometry(0, lineEdit->height() + 10, m_availableGeometry.width() * 0.2, m_availableGeometry.height() - (lineEdit->height() + 10));
+ container->setFocusPolicy(Qt::StrongFocus);
+
+ root.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
+ lineEdit->setFocus();
+ QTRY_VERIFY(lineEdit->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+
+ // embedded window gets focused because of mouse click
+ QPoint embeddedCenter = container->rect().center();
+ QTest::mousePress(root.windowHandle(), Qt::LeftButton, {}, embeddedCenter);
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+
+ QTest::mouseClick(lineEdit, Qt::LeftButton, {});
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+ QVERIFY(lineEdit->hasFocus());
+
+ // embedded window gets focused because of Tab key event
+ QTest::keyClick(root.windowHandle(), Qt::Key_Tab);
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+ // A key tab event sent to the root window should cause
+ // the nextInFocusChain of the window container to get focused
+ QTest::keyClick(root.windowHandle(), Qt::Key_Tab);
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
+ QCOMPARE(QApplication::focusWidget(), lineEdit);
+ QVERIFY(lineEdit->hasFocus());
+
+ // embedded window gets focused programmatically
+ embedded->requestActivate();
+ QVERIFY(QTest::qWaitForWindowFocused(embedded));
+ QVERIFY(container->hasFocus());
+ QCOMPARE(QGuiApplication::focusWindow(), embedded);
+ QCOMPARE(QApplication::focusWidget(), container);
+ QVERIFY(!lineEdit->hasFocus());
+}
+
QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc"