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"