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