Warning, file /frameworks/kwindowsystem/autotests/kwindowsystemx11test.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kwindowsystem.h" 0008 #include "kx11extras.h" 0009 #include "nettesthelper.h" 0010 #include "netwm.h" 0011 0012 #include <QSignalSpy> 0013 #include <QWidget> 0014 #include <private/qtx11extras_p.h> 0015 0016 #include <qtest_widgets.h> 0017 Q_DECLARE_METATYPE(WId) 0018 Q_DECLARE_METATYPE(NET::Properties) 0019 Q_DECLARE_METATYPE(NET::Properties2) 0020 Q_DECLARE_METATYPE(const unsigned long *) 0021 0022 class KWindowSystemX11Test : public QObject 0023 { 0024 Q_OBJECT 0025 private Q_SLOTS: 0026 void initTestCase(); 0027 // needs to be first test, would fail if run after others (X11) 0028 void testActiveWindowChanged(); 0029 void testWindowAdded(); 0030 void testWindowRemoved(); 0031 void testDesktopChanged(); 0032 void testNumberOfDesktopsChanged(); 0033 void testDesktopNamesChanged(); 0034 void testShowingDesktopChanged(); 0035 void testSetShowingDesktop(); 0036 void testWorkAreaChanged(); 0037 void testWindowTitleChanged(); 0038 void testMinimizeWindow(); 0039 void testPlatformX11(); 0040 }; 0041 0042 void KWindowSystemX11Test::initTestCase() 0043 { 0044 QCoreApplication::setAttribute(Qt::AA_ForceRasterWidgets); 0045 } 0046 0047 void KWindowSystemX11Test::testActiveWindowChanged() 0048 { 0049 qRegisterMetaType<WId>("WId"); 0050 QSignalSpy spy(KX11Extras::self(), &KX11Extras::activeWindowChanged); 0051 0052 std::unique_ptr<QWidget> widget(new QWidget); 0053 widget->show(); 0054 0055 QVERIFY(spy.wait()); 0056 QCOMPARE(spy.count(), 1); 0057 QCOMPARE(spy.first().at(0).toULongLong(), widget->winId()); 0058 QCOMPARE(KX11Extras::activeWindow(), widget->winId()); 0059 } 0060 0061 void KWindowSystemX11Test::testWindowAdded() 0062 { 0063 qRegisterMetaType<WId>("WId"); 0064 QSignalSpy spy(KX11Extras::self(), &KX11Extras::windowAdded); 0065 QSignalSpy stackingOrderSpy(KX11Extras::self(), &KX11Extras::stackingOrderChanged); 0066 std::unique_ptr<QWidget> widget(new QWidget); 0067 widget->show(); 0068 QVERIFY(QTest::qWaitForWindowExposed(widget.get())); 0069 QVERIFY(spy.count() > 0); 0070 bool hasWId = false; 0071 for (auto it = spy.constBegin(); it != spy.constEnd(); ++it) { 0072 if ((*it).isEmpty()) { 0073 continue; 0074 } 0075 QCOMPARE((*it).count(), 1); 0076 hasWId = (*it).at(0).toULongLong() == widget->winId(); 0077 if (hasWId) { 0078 break; 0079 } 0080 } 0081 QVERIFY(hasWId); 0082 QVERIFY(KX11Extras::hasWId(widget->winId())); 0083 QVERIFY(!stackingOrderSpy.isEmpty()); 0084 } 0085 0086 void KWindowSystemX11Test::testWindowRemoved() 0087 { 0088 qRegisterMetaType<WId>("WId"); 0089 std::unique_ptr<QWidget> widget(new QWidget); 0090 widget->show(); 0091 QVERIFY(QTest::qWaitForWindowExposed(widget.get())); 0092 QVERIFY(KX11Extras::hasWId(widget->winId())); 0093 0094 QSignalSpy spy(KX11Extras::self(), &KX11Extras::windowRemoved); 0095 widget->hide(); 0096 spy.wait(1000); 0097 QCOMPARE(spy.first().at(0).toULongLong(), widget->winId()); 0098 QVERIFY(!KX11Extras::hasWId(widget->winId())); 0099 } 0100 0101 void KWindowSystemX11Test::testDesktopChanged() 0102 { 0103 // This test requires a running NETWM-compliant window manager 0104 if (KX11Extras::numberOfDesktops() == 1) { 0105 QSKIP("At least two virtual desktops are required to test desktop changed"); 0106 } 0107 const int current = KX11Extras::currentDesktop(); 0108 0109 QSignalSpy spy(KX11Extras::self(), &KX11Extras::currentDesktopChanged); 0110 int newDesktop = current + 1; 0111 if (newDesktop > KX11Extras::numberOfDesktops()) { 0112 newDesktop = 1; 0113 } 0114 KX11Extras::setCurrentDesktop(newDesktop); 0115 QVERIFY(spy.wait()); 0116 QCOMPARE(KX11Extras::currentDesktop(), newDesktop); 0117 QCOMPARE(spy.count(), 1); 0118 QCOMPARE(spy.first().at(0).toInt(), newDesktop); 0119 spy.clear(); 0120 0121 // setting to current desktop should not change anything 0122 KX11Extras::setCurrentDesktop(newDesktop); 0123 0124 // set back for clean state 0125 KX11Extras::setCurrentDesktop(current); 0126 QVERIFY(spy.wait()); 0127 QCOMPARE(KX11Extras::currentDesktop(), current); 0128 QCOMPARE(spy.count(), 1); 0129 QCOMPARE(spy.first().at(0).toInt(), current); 0130 } 0131 0132 void KWindowSystemX11Test::testNumberOfDesktopsChanged() 0133 { 0134 // This test requires a running NETWM-compliant window manager 0135 const int oldNumber = KX11Extras::numberOfDesktops(); 0136 QSignalSpy spy(KX11Extras::self(), &KX11Extras::numberOfDesktopsChanged); 0137 0138 // KWin has arbitrary max number of 20 desktops, so don't fail the test if we use +1 0139 const int newNumber = oldNumber < 20 ? oldNumber + 1 : oldNumber - 1; 0140 0141 NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops, NET::Properties2()); 0142 info.setNumberOfDesktops(newNumber); 0143 0144 QVERIFY(spy.wait()); 0145 QCOMPARE(KX11Extras::numberOfDesktops(), newNumber); 0146 QCOMPARE(spy.count(), 1); 0147 QCOMPARE(spy.first().at(0).toInt(), newNumber); 0148 spy.clear(); 0149 0150 // setting to same number should not change 0151 info.setNumberOfDesktops(newNumber); 0152 0153 // set back for clean state 0154 info.setNumberOfDesktops(oldNumber); 0155 QVERIFY(spy.wait()); 0156 QCOMPARE(KX11Extras::numberOfDesktops(), oldNumber); 0157 QCOMPARE(spy.count(), 1); 0158 QCOMPARE(spy.first().at(0).toInt(), oldNumber); 0159 } 0160 0161 void KWindowSystemX11Test::testDesktopNamesChanged() 0162 { 0163 // This test requires a running NETWM-compliant window manager 0164 const QString origName = KX11Extras::desktopName(KX11Extras::currentDesktop()); 0165 QSignalSpy spy(KX11Extras::self(), &KX11Extras::desktopNamesChanged); 0166 0167 const QString testName = QStringLiteral("testFooBar"); 0168 0169 KX11Extras::setDesktopName(KX11Extras::currentDesktop(), testName); 0170 QVERIFY(spy.wait()); 0171 QCOMPARE(KX11Extras::desktopName(KX11Extras::currentDesktop()), testName); 0172 QCOMPARE(spy.count(), 1); 0173 spy.clear(); 0174 0175 QX11Info::setAppTime(QX11Info::getTimestamp()); 0176 0177 // setting back to clean state 0178 KX11Extras::setDesktopName(KX11Extras::currentDesktop(), origName); 0179 QVERIFY(spy.wait()); 0180 QCOMPARE(KX11Extras::desktopName(KX11Extras::currentDesktop()), origName); 0181 QCOMPARE(spy.count(), 1); 0182 } 0183 0184 void KWindowSystemX11Test::testShowingDesktopChanged() 0185 { 0186 QX11Info::setAppTime(QX11Info::getTimestamp()); 0187 const bool showingDesktop = KWindowSystem::showingDesktop(); 0188 0189 QSignalSpy spy(KWindowSystem::self(), &KWindowSystem::showingDesktopChanged); 0190 0191 NETRootInfo info(QX11Info::connection(), NET::Properties(), NET::WM2ShowingDesktop); 0192 info.setShowingDesktop(!showingDesktop); 0193 0194 QVERIFY(spy.wait()); 0195 QCOMPARE(spy.count(), 1); 0196 QCOMPARE(spy.first().at(0).toBool(), !showingDesktop); 0197 QCOMPARE(KWindowSystem::showingDesktop(), !showingDesktop); 0198 spy.clear(); 0199 0200 QX11Info::setAppTime(QX11Info::getTimestamp()); 0201 0202 // setting again should not change 0203 info.setShowingDesktop(!showingDesktop); 0204 0205 // setting back to clean state 0206 info.setShowingDesktop(showingDesktop); 0207 QVERIFY(spy.wait(100)); 0208 QCOMPARE(spy.count(), 1); 0209 QCOMPARE(spy.first().at(0).toBool(), showingDesktop); 0210 QCOMPARE(KWindowSystem::showingDesktop(), showingDesktop); 0211 } 0212 0213 void KWindowSystemX11Test::testSetShowingDesktop() 0214 { 0215 QSignalSpy spy(KWindowSystem::self(), &KWindowSystem::showingDesktopChanged); 0216 const bool showingDesktop = KWindowSystem::showingDesktop(); 0217 0218 // setting the same state shouldn't change it 0219 QX11Info::setAppTime(QX11Info::getTimestamp()); 0220 KWindowSystem::setShowingDesktop(showingDesktop); 0221 QCOMPARE(spy.wait(), false); // spy.wait() waits for 5s 0222 QCOMPARE(KWindowSystem::showingDesktop(), showingDesktop); 0223 spy.clear(); 0224 0225 // set opposite state 0226 QX11Info::setAppTime(QX11Info::getTimestamp()); 0227 KWindowSystem::setShowingDesktop(!showingDesktop); 0228 QVERIFY(spy.wait()); 0229 QCOMPARE(KWindowSystem::showingDesktop(), !showingDesktop); 0230 spy.clear(); 0231 0232 // setting back to clean state 0233 QX11Info::setAppTime(QX11Info::getTimestamp()); 0234 KWindowSystem::setShowingDesktop(showingDesktop); 0235 QVERIFY(spy.wait()); 0236 QCOMPARE(KWindowSystem::showingDesktop(), showingDesktop); 0237 spy.clear(); 0238 } 0239 0240 void KWindowSystemX11Test::testWorkAreaChanged() 0241 { 0242 // if there are multiple screens this test can fail as workarea is not multi screen aware 0243 QSignalSpy spy(KX11Extras::self(), &KX11Extras::workAreaChanged); 0244 QSignalSpy strutSpy(KX11Extras::self(), &KX11Extras::strutChanged); 0245 0246 QWidget widget; 0247 widget.setGeometry(0, 0, 100, 10); 0248 widget.show(); 0249 0250 KX11Extras::setExtendedStrut(widget.winId(), 10, 0, 10, 0, 0, 0, 100, 0, 100, 0, 0, 0); 0251 QVERIFY(spy.wait()); 0252 QVERIFY(!spy.isEmpty()); 0253 QVERIFY(!strutSpy.isEmpty()); 0254 } 0255 0256 void KWindowSystemX11Test::testWindowTitleChanged() 0257 { 0258 qRegisterMetaType<WId>("WId"); 0259 qRegisterMetaType<NET::Properties>("NET::Properties"); 0260 qRegisterMetaType<NET::Properties2>("NET::Properties2"); 0261 qRegisterMetaType<const unsigned long *>("const ulong*"); 0262 QWidget widget; 0263 widget.setWindowTitle(QStringLiteral("foo")); 0264 widget.show(); 0265 QVERIFY(QTest::qWaitForWindowExposed(&widget)); 0266 0267 // wait till the window is mapped, etc. 0268 QTest::qWait(200); 0269 0270 QSignalSpy propertiesChangedSpy(KX11Extras::self(), &KX11Extras::windowChanged); 0271 QVERIFY(propertiesChangedSpy.isValid()); 0272 0273 widget.setWindowTitle(QStringLiteral("bar")); 0274 QX11Info::setAppTime(QX11Info::getTimestamp()); 0275 0276 int counter = 0; 0277 bool gotWMName = false; 0278 while (propertiesChangedSpy.wait() && counter < 10) { 0279 for (auto it = propertiesChangedSpy.constBegin(); it != propertiesChangedSpy.constEnd(); ++it) { 0280 if ((*it).isEmpty()) { 0281 continue; 0282 } 0283 if ((*it).at(0).toULongLong() == widget.winId()) { 0284 NET::Properties props = (*it).at(1).value<NET::Properties>(); 0285 if (props.testFlag(NET::WMName)) { 0286 gotWMName = true; 0287 } 0288 } 0289 } 0290 if (gotWMName) { 0291 break; 0292 } 0293 propertiesChangedSpy.clear(); 0294 counter++; 0295 } 0296 QVERIFY(gotWMName); 0297 0298 // now let's verify the info in KWindowInfo 0299 // we wait a little bit more as openbox is updating the visible name 0300 QTest::qWait(500); 0301 KWindowInfo info(widget.winId(), NET::WMName | NET::WMVisibleName | NET::WMVisibleIconName | NET::WMIconName, NET::Properties2()); 0302 QVERIFY(info.valid()); 0303 const QString expectedName = QStringLiteral("bar"); 0304 QCOMPARE(info.name(), expectedName); 0305 QCOMPARE(info.visibleName(), expectedName); 0306 QCOMPARE(info.visibleIconName(), expectedName); 0307 QCOMPARE(info.iconName(), expectedName); 0308 } 0309 0310 void KWindowSystemX11Test::testMinimizeWindow() 0311 { 0312 NETRootInfo rootInfo(QX11Info::connection(), NET::Supported | NET::SupportingWMCheck); 0313 if (qstrcmp(rootInfo.wmName(), "Openbox") != 0 && qstrcmp(rootInfo.wmName(), "KWin") != 0) { 0314 QSKIP("Test minimize window might not be supported on the used window manager."); 0315 } 0316 QWidget widget; 0317 widget.show(); 0318 QVERIFY(QTest::qWaitForWindowExposed(&widget)); 0319 0320 KWindowInfo info(widget.winId(), NET::WMState | NET::XAWMState); 0321 QVERIFY(!info.isMinimized()); 0322 0323 KX11Extras::minimizeWindow(widget.winId()); 0324 // create a roundtrip, updating minimized state is done by the window manager and wait a short time 0325 QX11Info::setAppTime(QX11Info::getTimestamp()); 0326 QTest::qWait(200); 0327 0328 KWindowInfo info2(widget.winId(), NET::WMState | NET::XAWMState); 0329 QVERIFY(info2.isMinimized()); 0330 0331 KX11Extras::unminimizeWindow(widget.winId()); 0332 // create a roundtrip, updating minimized state is done by the window manager and wait a short time 0333 QX11Info::setAppTime(QX11Info::getTimestamp()); 0334 QTest::qWait(200); 0335 0336 KWindowInfo info3(widget.winId(), NET::WMState | NET::XAWMState); 0337 QVERIFY(!info3.isMinimized()); 0338 } 0339 0340 void KWindowSystemX11Test::testPlatformX11() 0341 { 0342 QCOMPARE(KWindowSystem::platform(), KWindowSystem::Platform::X11); 0343 QCOMPARE(KWindowSystem::isPlatformX11(), true); 0344 QCOMPARE(KWindowSystem::isPlatformWayland(), false); 0345 } 0346 0347 QTEST_MAIN(KWindowSystemX11Test) 0348 0349 #include "kwindowsystemx11test.moc"