File indexing completed on 2024-04-14 03:56:55

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 "nettesthelper.h"
0008 #include <netwm.h>
0009 
0010 #include <QProcess>
0011 #include <QStandardPaths>
0012 #include <qtest_widgets.h>
0013 
0014 // system
0015 #include <unistd.h>
0016 
0017 using Property = UniqueCPointer<xcb_get_property_reply_t>;
0018 
0019 // clang-format off
0020 #define INFO NETWinInfo info(m_connection, m_testWindow, m_rootWindow, NET::WMAllProperties, NET::WM2AllProperties, NET::Client);
0021 
0022 #define ATOM(name) \
0023     KXUtils::Atom atom(connection(), QByteArrayLiteral(#name));
0024 
0025 #define UTF8 KXUtils::Atom utf8String(connection(), QByteArrayLiteral("UTF8_STRING"));
0026 
0027 #define GETPROP(type, length, formatSize) \
0028     xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, m_testWindow, \
0029                                        atom, type, 0, length); \
0030     Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); \
0031     QVERIFY(reply); \
0032     QCOMPARE(reply->format, uint8_t(formatSize)); \
0033     QCOMPARE(reply->value_len, uint32_t(length));
0034 
0035 #define VERIFYDELETED(t) \
0036     xcb_get_property_cookie_t cookieDeleted = xcb_get_property_unchecked(connection(), false, m_testWindow, \
0037             atom, t, 0, 1); \
0038     Property replyDeleted(xcb_get_property_reply(connection(), cookieDeleted, nullptr)); \
0039     QVERIFY(replyDeleted); \
0040     QVERIFY(replyDeleted->type == XCB_ATOM_NONE);
0041 
0042 class NetWinInfoTestClient : public QObject
0043 {
0044     Q_OBJECT
0045 private Q_SLOTS:
0046     void initTestCase();
0047     void cleanupTestCase();
0048     void init();
0049     void cleanup();
0050 
0051     void testBlockCompositing();
0052     void testUserTime();
0053     void testStartupId();
0054     void testDesktopFileName();
0055     void testAppMenuObjectPath();
0056     void testAppMenuServiceName();
0057     void testHandledIcons_data();
0058     void testHandledIcons();
0059     void testPid();
0060     void testName();
0061     void testIconName();
0062     void testExtendedStrut();
0063     void testIconGeometry();
0064     void testWindowType_data();
0065     void testWindowType();
0066 
0067     void testActivities_data();
0068     void testActivities();
0069     void testWindowRole();
0070     void testWindowClass();
0071     void testClientMachine();
0072     void testGroupLeader();
0073     void testUrgency_data();
0074     void testUrgency();
0075     void testInput_data();
0076     void testInput();
0077     void testInitialMappingState_data();
0078     void testInitialMappingState();
0079     void testIconPixmap_data();
0080     void testIconPixmap();
0081     void testTransientFor();
0082     void testProtocols_data();
0083     void testProtocols();
0084     void testOpaqueRegion_data();
0085     void testOpaqueRegion();
0086 
0087 private:
0088     void performNameTest(xcb_atom_t atom, const char *(NETWinInfo:: *getter)(void)const, void (NETWinInfo:: *setter)(const char *), NET::Property property);
0089     void waitForPropertyChange(NETWinInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2 = NET::Property2(0));
0090     xcb_connection_t *connection()
0091     {
0092         return m_connection;
0093     }
0094     xcb_connection_t *m_connection;
0095     QList<xcb_connection_t*> m_connections;
0096     std::unique_ptr<QProcess> m_xvfb;
0097     xcb_window_t m_rootWindow;
0098     xcb_window_t m_testWindow;
0099 };
0100 
0101 void NetWinInfoTestClient::initTestCase()
0102 {
0103 }
0104 
0105 void NetWinInfoTestClient::cleanupTestCase()
0106 {
0107     // close connection
0108     while (!m_connections.isEmpty()) {
0109         xcb_disconnect(m_connections.takeFirst());
0110     }
0111 }
0112 
0113 void NetWinInfoTestClient::init()
0114 {
0115     // first reset just to be sure
0116     m_connection = nullptr;
0117     m_rootWindow = XCB_WINDOW_NONE;
0118     m_testWindow = XCB_WINDOW_NONE;
0119 
0120     const QString xfvbExec = QStandardPaths::findExecutable(QStringLiteral("Xvfb"));
0121     QVERIFY(!xfvbExec.isEmpty());
0122 
0123     // start Xvfb
0124     m_xvfb.reset(new QProcess);
0125     // use pipe to pass fd to Xvfb to get back the display id
0126     int pipeFds[2];
0127     QVERIFY(pipe(pipeFds) == 0);
0128     m_xvfb->start(QStringLiteral("Xvfb"), QStringList{ QStringLiteral("-displayfd"), QString::number(pipeFds[1]) });
0129     QVERIFY(m_xvfb->waitForStarted());
0130     QCOMPARE(m_xvfb->state(), QProcess::Running);
0131 
0132     // reads from pipe, closes write side
0133     close(pipeFds[1]);
0134 
0135     QFile readPipe;
0136     QVERIFY(readPipe.open(pipeFds[0], QIODevice::ReadOnly, QFileDevice::AutoCloseHandle));
0137     QByteArray displayNumber = readPipe.readLine();
0138     readPipe.close();
0139 
0140     displayNumber.prepend(QByteArray(":"));
0141     displayNumber.remove(displayNumber.size() -1, 1);
0142 
0143     // create X connection
0144     int screen = 0;
0145     m_connection = xcb_connect(displayNumber.constData(), &screen);
0146     QVERIFY(m_connection);
0147     QVERIFY(!xcb_connection_has_error(m_connection));
0148     m_rootWindow = KXUtils::rootWindow(m_connection, screen);
0149 
0150     // create test window
0151     m_testWindow = xcb_generate_id(m_connection);
0152     uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE};
0153     xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_testWindow,
0154                       m_rootWindow,
0155                       0, 0, 100, 100, 0, XCB_COPY_FROM_PARENT,
0156                       XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
0157     // and map it
0158     xcb_map_window(m_connection, m_testWindow);
0159 }
0160 
0161 void NetWinInfoTestClient::cleanup()
0162 {
0163     // destroy test window
0164     xcb_unmap_window(m_connection, m_testWindow);
0165     xcb_destroy_window(m_connection, m_testWindow);
0166     m_testWindow = XCB_WINDOW_NONE;
0167 
0168     // delay till clenupTestCase as otherwise xcb reuses the same memory address
0169     m_connections << connection();
0170     // kill Xvfb
0171     m_xvfb->terminate();
0172     m_xvfb->waitForFinished();
0173 }
0174 
0175 void NetWinInfoTestClient::waitForPropertyChange(NETWinInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2)
0176 {
0177     while (true) {
0178         UniqueCPointer<xcb_generic_event_t> event(xcb_wait_for_event(connection()));
0179         if (!event) {
0180             break;
0181         }
0182         if ((event->response_type & ~0x80) != XCB_PROPERTY_NOTIFY) {
0183             continue;
0184         }
0185         xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event.get());
0186         if (pe->window != m_testWindow) {
0187             continue;
0188         }
0189         if (pe->atom != atom) {
0190             continue;
0191         }
0192         NET::Properties dirty;
0193         NET::Properties2 dirty2;
0194         info->event(event.get(), &dirty, &dirty2);
0195         if (prop != 0) {
0196             QVERIFY(dirty & prop);
0197         }
0198         if (prop2 != 0) {
0199             QVERIFY(dirty2 & prop2);
0200         }
0201         if (!prop) {
0202             QCOMPARE(dirty, NET::Properties());
0203         }
0204         if (!prop2) {
0205             QCOMPARE(dirty2, NET::Properties2());
0206         }
0207         break;
0208     }
0209 }
0210 
0211 void NetWinInfoTestClient::testBlockCompositing()
0212 {
0213     QVERIFY(connection());
0214     ATOM(_KDE_NET_WM_BLOCK_COMPOSITING)
0215     INFO
0216 
0217     QVERIFY(!info.isBlockingCompositing());
0218     info.setBlockingCompositing(true);
0219     QVERIFY(info.isBlockingCompositing());
0220 
0221     // compare with the X property
0222     QVERIFY(atom != XCB_ATOM_NONE);
0223     GETPROP(XCB_ATOM_CARDINAL, 1, 32)
0224     QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], uint32_t(1));
0225 
0226     // and wait for our event
0227     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2BlockCompositing);
0228     QVERIFY(info.isBlockingCompositing());
0229 
0230     // setting false should delete the property again
0231     info.setBlockingCompositing(false);
0232     QVERIFY(!info.isBlockingCompositing());
0233     VERIFYDELETED(XCB_ATOM_CARDINAL)
0234 
0235     // and wait for our event
0236     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2BlockCompositing);
0237     QVERIFY(!info.isBlockingCompositing());
0238 }
0239 
0240 void NetWinInfoTestClient::testUserTime()
0241 {
0242     QVERIFY(connection());
0243     ATOM(_NET_WM_USER_TIME)
0244     INFO
0245 
0246     QCOMPARE(info.userTime(), uint32_t(-1));
0247     info.setUserTime(500);
0248     QCOMPARE(info.userTime(), uint32_t(500));
0249 
0250     // compare with the X property
0251     QVERIFY(atom != XCB_ATOM_NONE);
0252     GETPROP(XCB_ATOM_CARDINAL, 1, 32)
0253     QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], uint32_t(500));
0254 
0255     // and wait for our event
0256     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2UserTime);
0257     QCOMPARE(info.userTime(), uint32_t(500));
0258 }
0259 
0260 void NetWinInfoTestClient::testStartupId()
0261 {
0262     QVERIFY(connection());
0263     ATOM(_NET_STARTUP_ID)
0264     UTF8
0265     INFO
0266 
0267     QVERIFY(!info.startupId());
0268     info.setStartupId("foo");
0269     QCOMPARE(info.startupId(), "foo");
0270 
0271     // compare with the X property
0272     QVERIFY(atom != XCB_ATOM_NONE);
0273     QVERIFY(utf8String != XCB_ATOM_NONE);
0274     GETPROP(utf8String, 3, 8)
0275     QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo");
0276 
0277     // and wait for our event
0278     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2StartupId);
0279     QCOMPARE(info.startupId(), "foo");
0280 }
0281 
0282 void NetWinInfoTestClient::testAppMenuObjectPath()
0283 {
0284     ATOM(_KDE_NET_WM_APPMENU_OBJECT_PATH)
0285     INFO
0286 
0287     QVERIFY(!info.appMenuObjectPath());
0288 
0289     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0290                         atom, XCB_ATOM_STRING, 8, 3, "foo");
0291     xcb_flush(connection());
0292 
0293     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2AppMenuObjectPath);
0294     QCOMPARE(info.appMenuObjectPath(), "foo");
0295 }
0296 
0297 void NetWinInfoTestClient::testAppMenuServiceName()
0298 {
0299     ATOM(_KDE_NET_WM_APPMENU_SERVICE_NAME)
0300     INFO
0301 
0302     QVERIFY(!info.appMenuServiceName());
0303 
0304     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0305                         atom, XCB_ATOM_STRING, 8, 3, "foo");
0306     xcb_flush(connection());
0307 
0308     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2AppMenuServiceName);
0309     QCOMPARE(info.appMenuServiceName(), "foo");
0310 }
0311 
0312 void NetWinInfoTestClient::testDesktopFileName()
0313 {
0314     QVERIFY(connection());
0315     ATOM(_KDE_NET_WM_DESKTOP_FILE)
0316     UTF8
0317     INFO
0318 
0319     QVERIFY(!info.desktopFileName());
0320     info.setDesktopFileName("foo");
0321     QCOMPARE(info.desktopFileName(), "foo");
0322 
0323     // compare with the X property
0324     QVERIFY(atom != XCB_ATOM_NONE);
0325     QVERIFY(utf8String != XCB_ATOM_NONE);
0326     GETPROP(utf8String, 3, 8)
0327     QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo");
0328 
0329     // and wait for our event
0330     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2DesktopFileName);
0331     QCOMPARE(info.desktopFileName(), "foo");
0332 }
0333 
0334 void NetWinInfoTestClient::testHandledIcons_data()
0335 {
0336     QTest::addColumn<bool>("handled");
0337     QTest::addColumn<uint32_t>("value");
0338 
0339     QTest::newRow("enabled") << true << uint32_t(1);
0340     QTest::newRow("disabled") << false << uint32_t(0);
0341 }
0342 
0343 void NetWinInfoTestClient::testHandledIcons()
0344 {
0345     QVERIFY(connection());
0346     ATOM(_NET_WM_HANDLED_ICONS)
0347     INFO
0348 
0349     QVERIFY(!info.handledIcons());
0350     QFETCH(bool, handled);
0351     info.setHandledIcons(handled);
0352     QCOMPARE(info.handledIcons(), handled);
0353 
0354     // compare with the X property
0355     QVERIFY(atom != XCB_ATOM_NONE);
0356     GETPROP(XCB_ATOM_CARDINAL, 1, 32)
0357     QTEST(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], "value");
0358 
0359     // and wait for our event
0360     waitForPropertyChange(&info, atom, NET::WMHandledIcons);
0361     QCOMPARE(info.handledIcons(), handled);
0362 }
0363 
0364 void NetWinInfoTestClient::testPid()
0365 {
0366     QVERIFY(connection());
0367     ATOM(_NET_WM_PID)
0368     INFO
0369 
0370     QCOMPARE(info.pid(), 0);
0371     info.setPid(m_xvfb->processId());
0372     QCOMPARE(info.pid(), m_xvfb->processId());
0373 
0374     // compare with the X property
0375     QVERIFY(atom != XCB_ATOM_NONE);
0376     GETPROP(XCB_ATOM_CARDINAL, 1, 32)
0377     QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], uint32_t(m_xvfb->processId()));
0378 
0379     // and wait for our event
0380     waitForPropertyChange(&info, atom, NET::WMPid);
0381     QCOMPARE(info.pid(), m_xvfb->processId());
0382 }
0383 
0384 void NetWinInfoTestClient::performNameTest(xcb_atom_t atom, const char *(NETWinInfo:: *getter)(void)const, void (NETWinInfo:: *setter)(const char *), NET::Property property)
0385 {
0386     UTF8
0387     INFO
0388 
0389     QVERIFY(!(info.*getter)());
0390     (info.*setter)("foo");
0391     QCOMPARE((info.*getter)(), "foo");
0392 
0393     // compare with the X property
0394     QVERIFY(atom != XCB_ATOM_NONE);
0395     QVERIFY(utf8String != XCB_ATOM_NONE);
0396     GETPROP(utf8String, 3, 8)
0397     QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo");
0398 
0399     // and wait for our event
0400     waitForPropertyChange(&info, atom, property);
0401     QCOMPARE((info.*getter)(), "foo");
0402 
0403     // delete the string
0404     (info.*setter)("");
0405     QCOMPARE((info.*getter)(), "");
0406     VERIFYDELETED(utf8String)
0407 
0408     // and wait for our event
0409     waitForPropertyChange(&info, atom, property);
0410     QVERIFY(!(info.*getter)());
0411 
0412     // set it again, to ensure that we don't leak on tear-down
0413     (info.*setter)("bar");
0414     QCOMPARE((info.*getter)(), "bar");
0415     xcb_flush(connection());
0416     waitForPropertyChange(&info, atom, property);
0417     QCOMPARE((info.*getter)(), "bar");
0418 }
0419 
0420 void NetWinInfoTestClient::testIconName()
0421 {
0422     QVERIFY(connection());
0423     ATOM(_NET_WM_ICON_NAME)
0424     performNameTest(atom, &NETWinInfo::iconName, &NETWinInfo::setIconName, NET::WMIconName);
0425 }
0426 
0427 void NetWinInfoTestClient::testName()
0428 {
0429     QVERIFY(connection());
0430     ATOM(_NET_WM_NAME)
0431     performNameTest(atom, &NETWinInfo::name, &NETWinInfo::setName, NET::WMName);
0432 }
0433 
0434 void NetWinInfoTestClient::testExtendedStrut()
0435 {
0436     QVERIFY(connection());
0437     ATOM(_NET_WM_STRUT_PARTIAL)
0438     INFO
0439 
0440     NETExtendedStrut extents = info.extendedStrut();
0441     QCOMPARE(extents.left_width, 0);
0442     QCOMPARE(extents.right_width, 0);
0443     QCOMPARE(extents.top_width, 0);
0444     QCOMPARE(extents.bottom_width, 0);
0445     QCOMPARE(extents.left_start, 0);
0446     QCOMPARE(extents.left_end, 0);
0447     QCOMPARE(extents.right_start, 0);
0448     QCOMPARE(extents.right_end, 0);
0449     QCOMPARE(extents.top_start, 0);
0450     QCOMPARE(extents.top_end, 0);
0451     QCOMPARE(extents.bottom_start, 0);
0452     QCOMPARE(extents.bottom_end, 0);
0453 
0454     NETExtendedStrut newExtents;
0455     newExtents.left_width   = 10;
0456     newExtents.right_width  = 20;
0457     newExtents.top_width    = 30;
0458     newExtents.bottom_width = 40;
0459     newExtents.left_start   = 50;
0460     newExtents.left_end     = 60;
0461     newExtents.right_start  = 70;
0462     newExtents.right_end    = 80;
0463     newExtents.top_start    = 90;
0464     newExtents.top_end      = 91;
0465     newExtents.bottom_start = 92;
0466     newExtents.bottom_end   = 93;
0467     info.setExtendedStrut(newExtents);
0468     extents = info.extendedStrut();
0469     QCOMPARE(extents.left_width,   newExtents.left_width);
0470     QCOMPARE(extents.right_width,  newExtents.right_width);
0471     QCOMPARE(extents.top_width,    newExtents.top_width);
0472     QCOMPARE(extents.bottom_width, newExtents.bottom_width);
0473     QCOMPARE(extents.left_start,   newExtents.left_start);
0474     QCOMPARE(extents.left_end,     newExtents.left_end);
0475     QCOMPARE(extents.right_start,  newExtents.right_start);
0476     QCOMPARE(extents.right_end,    newExtents.right_end);
0477     QCOMPARE(extents.top_start,    newExtents.top_start);
0478     QCOMPARE(extents.top_end,      newExtents.top_end);
0479     QCOMPARE(extents.bottom_start, newExtents.bottom_start);
0480     QCOMPARE(extents.bottom_end,   newExtents.bottom_end);
0481 
0482     // compare with the X property
0483     QVERIFY(atom != XCB_ATOM_NONE);
0484     GETPROP(XCB_ATOM_CARDINAL, 12, 32)
0485     uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()));
0486     QCOMPARE(data[ 0], uint32_t(newExtents.left_width));
0487     QCOMPARE(data[ 1], uint32_t(newExtents.right_width));
0488     QCOMPARE(data[ 2], uint32_t(newExtents.top_width));
0489     QCOMPARE(data[ 3], uint32_t(newExtents.bottom_width));
0490     QCOMPARE(data[ 4], uint32_t(newExtents.left_start));
0491     QCOMPARE(data[ 5], uint32_t(newExtents.left_end));
0492     QCOMPARE(data[ 6], uint32_t(newExtents.right_start));
0493     QCOMPARE(data[ 7], uint32_t(newExtents.right_end));
0494     QCOMPARE(data[ 8], uint32_t(newExtents.top_start));
0495     QCOMPARE(data[ 9], uint32_t(newExtents.top_end));
0496     QCOMPARE(data[10], uint32_t(newExtents.bottom_start));
0497     QCOMPARE(data[11], uint32_t(newExtents.bottom_end));
0498 
0499     // and wait for our event
0500     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2ExtendedStrut);
0501     extents = info.extendedStrut();
0502     QCOMPARE(extents.left_width,   newExtents.left_width);
0503     QCOMPARE(extents.right_width,  newExtents.right_width);
0504     QCOMPARE(extents.top_width,    newExtents.top_width);
0505     QCOMPARE(extents.bottom_width, newExtents.bottom_width);
0506     QCOMPARE(extents.left_start,   newExtents.left_start);
0507     QCOMPARE(extents.left_end,     newExtents.left_end);
0508     QCOMPARE(extents.right_start,  newExtents.right_start);
0509     QCOMPARE(extents.right_end,    newExtents.right_end);
0510     QCOMPARE(extents.top_start,    newExtents.top_start);
0511     QCOMPARE(extents.top_end,      newExtents.top_end);
0512     QCOMPARE(extents.bottom_start, newExtents.bottom_start);
0513     QCOMPARE(extents.bottom_end,   newExtents.bottom_end);
0514 }
0515 
0516 void NetWinInfoTestClient::testIconGeometry()
0517 {
0518     QVERIFY(connection());
0519     ATOM(_NET_WM_ICON_GEOMETRY)
0520     INFO
0521 
0522     NETRect geo = info.iconGeometry();
0523     QCOMPARE(geo.pos.x, 0);
0524     QCOMPARE(geo.pos.y, 0);
0525     QCOMPARE(geo.size.width, 0);
0526     QCOMPARE(geo.size.height, 0);
0527 
0528     NETRect newGeo;
0529     newGeo.pos.x       = 10;
0530     newGeo.pos.y       = 20;
0531     newGeo.size.width  = 30;
0532     newGeo.size.height = 40;
0533     info.setIconGeometry(newGeo);
0534     geo = info.iconGeometry();
0535     QCOMPARE(geo.pos.x,       newGeo.pos.x);
0536     QCOMPARE(geo.pos.y,       newGeo.pos.y);
0537     QCOMPARE(geo.size.width,  newGeo.size.width);
0538     QCOMPARE(geo.size.height, newGeo.size.height);
0539 
0540     // compare with the X property
0541     QVERIFY(atom != XCB_ATOM_NONE);
0542     GETPROP(XCB_ATOM_CARDINAL, 4, 32)
0543     uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()));
0544     QCOMPARE(data[0], uint32_t(newGeo.pos.x));
0545     QCOMPARE(data[1], uint32_t(newGeo.pos.y));
0546     QCOMPARE(data[2], uint32_t(newGeo.size.width));
0547     QCOMPARE(data[3], uint32_t(newGeo.size.height));
0548 
0549     // and wait for our event
0550     waitForPropertyChange(&info, atom, NET::WMIconGeometry);
0551     geo = info.iconGeometry();
0552     QCOMPARE(geo.pos.x,       newGeo.pos.x);
0553     QCOMPARE(geo.pos.y,       newGeo.pos.y);
0554     QCOMPARE(geo.size.width,  newGeo.size.width);
0555     QCOMPARE(geo.size.height, newGeo.size.height);
0556 }
0557 
0558 Q_DECLARE_METATYPE(NET::WindowType)
0559 void NetWinInfoTestClient::testWindowType_data()
0560 {
0561     QTest::addColumn<NET::WindowType>("type");
0562     QTest::addColumn<int>("length");
0563     QTest::addColumn<QByteArray>("typeAtom");
0564     QTest::addColumn<QByteArray>("secondaryTypeAtom");
0565 
0566     QTest::newRow("override")     << NET::Override     << 2 << QByteArrayLiteral("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE")  << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_NORMAL");
0567     QTest::newRow("TopMenu")      << NET::TopMenu      << 2 << QByteArrayLiteral("_KDE_NET_WM_WINDOW_TYPE_TOPMENU")   << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DOCK");
0568     QTest::newRow("Utility")      << NET::Utility      << 2 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_UTILITY")       << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DIALOG");
0569     QTest::newRow("Splash")       << NET::Splash       << 2 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_SPLASH")        << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DOCK");
0570     // TODO: this should be 2
0571     QTest::newRow("DropdownMenu") << NET::DropdownMenu << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU") << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_MENU");
0572     // TODO: this should be 2
0573     QTest::newRow("PopupMenu")    << NET::PopupMenu    << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_POPUP_MENU")    << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_MENU");
0574     // TODO: this should be 2
0575     QTest::newRow("Notification") << NET::Notification << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_NOTIFICATION")  << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_UTILITY");
0576     QTest::newRow("Dialog")       << NET::Dialog       << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DIALOG")   << QByteArray();
0577     QTest::newRow("Menu")         << NET::Menu         << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_MENU")     << QByteArray();
0578     QTest::newRow("Toolbar")      << NET::Toolbar      << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_TOOLBAR")  << QByteArray();
0579     QTest::newRow("Dock")         << NET::Dock         << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DOCK")     << QByteArray();
0580     QTest::newRow("Desktop")      << NET::Desktop      << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DESKTOP")  << QByteArray();
0581     QTest::newRow("Tooltip")      << NET::Tooltip      << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_TOOLTIP")  << QByteArray();
0582     QTest::newRow("ComboBox")     << NET::ComboBox     << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_COMBO")    << QByteArray();
0583     QTest::newRow("DNDIcon")      << NET::DNDIcon      << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_DND")      << QByteArray();
0584     QTest::newRow("Normal")       << NET::Normal       << 1 << QByteArrayLiteral("_NET_WM_WINDOW_TYPE_NORMAL")   << QByteArray();
0585     QTest::newRow("OnScreenDisplay") << NET::OnScreenDisplay << 1 << QByteArrayLiteral("_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY") << QByteArray();
0586     QTest::newRow("CriticalNotification") << NET::CriticalNotification << 1 << QByteArrayLiteral("_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION") << QByteArray();
0587     QTest::newRow("AppletPopup")  << NET::AppletPopup  << 1 << QByteArrayLiteral("_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP") << QByteArray();
0588 }
0589 
0590 void NetWinInfoTestClient::testWindowType()
0591 {
0592     QVERIFY(connection());
0593     ATOM(_NET_WM_WINDOW_TYPE)
0594     INFO
0595 
0596     QVERIFY(info.hasWindowType());
0597     QVERIFY(!info.hasNETSupport());
0598     QCOMPARE(info.windowType(NET::AllTypesMask), NET::Unknown);
0599     QFETCH(NET::WindowType, type);
0600     info.setWindowType(type);
0601     // it does not update the internal type!
0602     QCOMPARE(info.windowType(NET::AllTypesMask), NET::Unknown);
0603     QFETCH(int, length);
0604     QFETCH(QByteArray, typeAtom);
0605 
0606     // compare the X property
0607     KXUtils::Atom type1(connection(), typeAtom);
0608     QVERIFY(atom != XCB_ATOM_NONE);
0609     GETPROP(XCB_ATOM_ATOM, length, 32)
0610     xcb_atom_t *atoms = reinterpret_cast<xcb_atom_t *>(xcb_get_property_value(reply.get()));
0611     QCOMPARE(atoms[0], xcb_atom_t(type1));
0612     if (reply->value_len > 1) {
0613         QFETCH(QByteArray, secondaryTypeAtom);
0614         KXUtils::Atom type2(connection(), secondaryTypeAtom);
0615         QVERIFY(type2 != XCB_ATOM_NONE);
0616         QCOMPARE(atoms[1], xcb_atom_t(type2));
0617     }
0618 
0619     waitForPropertyChange(&info, atom, NET::WMWindowType);
0620     QCOMPARE(info.windowType(NET::AllTypesMask), type);
0621     QVERIFY(info.hasNETSupport());
0622 }
0623 
0624 void NetWinInfoTestClient::testClientMachine()
0625 {
0626     QVERIFY(connection());
0627     INFO
0628 
0629     QVERIFY(!info.clientMachine());
0630 
0631     // client machine needs to be changed using xcb
0632     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0633                         XCB_ATOM_WM_CLIENT_MACHINE, XCB_ATOM_STRING, 8, 9, "localhost");
0634     xcb_flush(connection());
0635 
0636     // only updated after event
0637     waitForPropertyChange(&info, XCB_ATOM_WM_CLIENT_MACHINE, NET::Property(0), NET::WM2ClientMachine);
0638     QCOMPARE(info.clientMachine(), "localhost");
0639 }
0640 
0641 void NetWinInfoTestClient::testGroupLeader()
0642 {
0643     QVERIFY(connection());
0644     INFO
0645 
0646     QVERIFY(info.groupLeader() == XCB_WINDOW_NONE);
0647 
0648     // group leader needs to be changed through wm hints
0649     uint32_t values[] = {
0650         1 << 6, /* WindowGroupHint*/
0651         1, /* Input */
0652         1, /* Normal State */
0653         XCB_NONE, /* icon pixmap */
0654         XCB_NONE, /* icon window */
0655         XCB_NONE, /* icon x */
0656         XCB_NONE, /* icon y */
0657         XCB_NONE, /* icon mask */
0658         m_rootWindow /* group leader */
0659     };
0660     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0661                         XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, 9, values);
0662     xcb_flush(connection());
0663 
0664     // only updated after event
0665     waitForPropertyChange(&info, XCB_ATOM_WM_HINTS, NET::Property(0), NET::WM2GroupLeader);
0666     QCOMPARE(info.groupLeader(), m_rootWindow);
0667 }
0668 
0669 void NetWinInfoTestClient::testUrgency_data()
0670 {
0671     QTest::addColumn<quint32>("flags");
0672     QTest::addColumn<bool>("expected");
0673 
0674     QTest::newRow("urgency") << quint32(1 << 8) << true;
0675     QTest::newRow("none") << quint32(0) << false;
0676     QTest::newRow("group_urgency") << quint32((1 << 6) | (1 << 8)) << true;
0677     QTest::newRow("input") << quint32(1) << false;
0678 }
0679 
0680 void NetWinInfoTestClient::testUrgency()
0681 {
0682     QVERIFY(connection());
0683     INFO
0684 
0685     QVERIFY(!info.urgency());
0686     QFETCH(quint32, flags);
0687 
0688     // group leader needs to be changed through wm hints
0689     uint32_t values[] = {
0690         flags,
0691         1, /* Input */
0692         1, /* Normal State */
0693         XCB_NONE, /* icon pixmap */
0694         XCB_NONE, /* icon window */
0695         XCB_NONE, /* icon x */
0696         XCB_NONE, /* icon y */
0697         XCB_NONE, /* icon mask */
0698         XCB_NONE /* group leader */
0699     };
0700     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0701                         XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, 9, values);
0702     xcb_flush(connection());
0703 
0704     // only updated after event
0705     waitForPropertyChange(&info, XCB_ATOM_WM_HINTS, NET::Property(0), NET::WM2Urgency);
0706     QTEST(info.urgency(), "expected");
0707 }
0708 
0709 void NetWinInfoTestClient::testInput_data()
0710 {
0711     QTest::addColumn<quint32>("flags");
0712     QTest::addColumn<quint32>("input");
0713     QTest::addColumn<bool>("expected");
0714 
0715     QTest::newRow("flag_input")      << quint32(1) << quint32(1) << true;
0716     QTest::newRow("flag_noinput")    << quint32(1) << quint32(0) << false;
0717     QTest::newRow("noflag_input")    << quint32(0) << quint32(1) << true;
0718     QTest::newRow("noflag_noinput")  << quint32(0) << quint32(0) << true;
0719     QTest::newRow("flag_with_other_input")   << quint32(1 | 1 << 8) << quint32(1) << true;
0720     QTest::newRow("flag_with_other_noinput") << quint32(1 | 1 << 8) << quint32(0) << false;
0721 }
0722 
0723 void NetWinInfoTestClient::testInput()
0724 {
0725     QVERIFY(connection());
0726     INFO
0727 
0728     QVERIFY(info.input());
0729     QFETCH(quint32, flags);
0730     QFETCH(quint32, input);
0731 
0732     // group leader needs to be changed through wm hints
0733     uint32_t values[] = {
0734         flags,
0735         input, /* Input */
0736         1, /* Normal State */
0737         XCB_NONE, /* icon pixmap */
0738         XCB_NONE, /* icon window */
0739         XCB_NONE, /* icon x */
0740         XCB_NONE, /* icon y */
0741         XCB_NONE, /* icon mask */
0742         XCB_NONE /* group leader */
0743     };
0744     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0745                         XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, 9, values);
0746     xcb_flush(connection());
0747 
0748     // only updated after event
0749     waitForPropertyChange(&info, XCB_ATOM_WM_HINTS, NET::Property(0), NET::WM2Urgency);
0750     QTEST(info.input(), "expected");
0751 }
0752 
0753 Q_DECLARE_METATYPE(NET::MappingState)
0754 
0755 void NetWinInfoTestClient::testInitialMappingState_data()
0756 {
0757     QTest::addColumn<quint32>("flags");
0758     QTest::addColumn<quint32>("state");
0759     QTest::addColumn<NET::MappingState>("expected");
0760 
0761     QTest::newRow("flag-iconic") << quint32(2) << quint32(3) << NET::Iconic;
0762     QTest::newRow("flag-normal") << quint32(2) << quint32(1) << NET::Visible;
0763     QTest::newRow("flag-invalid") << quint32(2) << quint32(8) << NET::Withdrawn;
0764     QTest::newRow("noflag-iconic") << quint32(256) << quint32(3) << NET::Withdrawn;
0765     QTest::newRow("noflag-normal") << quint32(256) << quint32(1) << NET::Withdrawn;
0766 }
0767 
0768 void NetWinInfoTestClient::testInitialMappingState()
0769 {
0770     QVERIFY(connection());
0771     INFO
0772 
0773     QCOMPARE(info.initialMappingState(), NET::Withdrawn);
0774     QFETCH(quint32, flags);
0775     QFETCH(quint32, state);
0776 
0777     // group leader needs to be changed through wm hints
0778     uint32_t values[] = {
0779         flags,
0780         1, /* Input */
0781         state, /* Normal State */
0782         XCB_NONE, /* icon pixmap */
0783         XCB_NONE, /* icon window */
0784         XCB_NONE, /* icon x */
0785         XCB_NONE, /* icon y */
0786         XCB_NONE, /* icon mask */
0787         XCB_NONE /* group leader */
0788     };
0789     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0790                         XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, 9, values);
0791     xcb_flush(connection());
0792 
0793     // only updated after event
0794     waitForPropertyChange(&info, XCB_ATOM_WM_HINTS, NET::Property(0), NET::WM2InitialMappingState);
0795     QTEST(info.initialMappingState(), "expected");
0796 }
0797 
0798 void NetWinInfoTestClient::testIconPixmap_data()
0799 {
0800     QTest::addColumn<quint32>("flags");
0801     QTest::addColumn<quint32>("icon");
0802     QTest::addColumn<quint32>("mask");
0803     QTest::addColumn<quint32>("expectedPixmap");
0804     QTest::addColumn<quint32>("expectedMask");
0805 
0806     QTest::newRow("invalid-flags") << 1u << 2u << 3u << 0u << 0u;
0807     QTest::newRow("pixmap-flags") << 4u << 2u << 3u << 2u << 0u;
0808     QTest::newRow("mask-flags") << 32u << 2u << 3u << 0u << 3u;
0809     QTest::newRow("pixmap-mask-flags") << 36u << 2u << 3u << 2u << 3u;
0810 }
0811 
0812 void NetWinInfoTestClient::testIconPixmap()
0813 {
0814     QVERIFY(connection());
0815     INFO
0816 
0817     QCOMPARE(info.icccmIconPixmap(), 0u);
0818     QCOMPARE(info.icccmIconPixmapMask(), 0u);
0819     QFETCH(quint32, flags);
0820     QFETCH(quint32, icon);
0821     QFETCH(quint32, mask);
0822 
0823     // icon pixmap needs to be changed through wm hints
0824     uint32_t values[] = {
0825         flags,
0826         1, /* Input */
0827         XCB_NONE, /* Normal State */
0828         icon,     /* icon pixmap */
0829         XCB_NONE, /* icon window */
0830         XCB_NONE, /* icon x */
0831         XCB_NONE, /* icon y */
0832         mask,     /* icon mask */
0833         XCB_NONE  /* group leader */
0834     };
0835     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0836                         XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, 9, values);
0837     xcb_flush(connection());
0838     // only updated after event
0839     waitForPropertyChange(&info, XCB_ATOM_WM_HINTS, NET::Property(0), NET::WM2IconPixmap);
0840     QTEST(info.icccmIconPixmap(), "expectedPixmap");
0841     QTEST(info.icccmIconPixmapMask(), "expectedMask");
0842 }
0843 
0844 void NetWinInfoTestClient::testTransientFor()
0845 {
0846     QVERIFY(connection());
0847     INFO
0848 
0849     QVERIFY(info.transientFor() == XCB_WINDOW_NONE);
0850     // transient for needs to be changed using xcb
0851     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0852                         XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1, &m_rootWindow);
0853     xcb_flush(connection());
0854 
0855     // only updated after event
0856     waitForPropertyChange(&info, XCB_ATOM_WM_TRANSIENT_FOR, NET::Property(0), NET::WM2TransientFor);
0857     QCOMPARE(info.transientFor(), m_rootWindow);
0858 }
0859 
0860 void NetWinInfoTestClient::testWindowClass()
0861 {
0862     QVERIFY(connection());
0863     INFO
0864 
0865     QVERIFY(!info.windowClassClass());
0866     QVERIFY(!info.windowClassName());
0867 
0868     // window class needs to be changed using xcb
0869     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0870                         XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, 7, "foo\0bar");
0871     xcb_flush(connection());
0872 
0873     // only updated after event
0874     waitForPropertyChange(&info, XCB_ATOM_WM_CLASS, NET::Property(0), NET::WM2WindowClass);
0875     QCOMPARE(info.windowClassName(), "foo");
0876     QCOMPARE(info.windowClassClass(), "bar");
0877 }
0878 
0879 void NetWinInfoTestClient::testWindowRole()
0880 {
0881     QVERIFY(connection());
0882     ATOM(WM_WINDOW_ROLE)
0883     INFO
0884 
0885     QVERIFY(!info.windowRole());
0886 
0887     // window role needs to be changed using xcb
0888     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow,
0889                         atom, XCB_ATOM_STRING, 8, 3, "bar");
0890     xcb_flush(connection());
0891 
0892     // only updated after event
0893     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2WindowRole);
0894     QCOMPARE(info.windowRole(), "bar");
0895 }
0896 
0897 void NetWinInfoTestClient::testActivities_data()
0898 {
0899     QTest::addColumn<QByteArray>("activities");
0900     QTest::addColumn<QByteArray>("expectedActivities");
0901 
0902     const QByteArray testActivities = QByteArrayLiteral("foo,bar");
0903     const QByteArray allActivities = QByteArrayLiteral(KDE_ALL_ACTIVITIES_UUID);
0904 
0905     QTest::newRow("activities") << testActivities << testActivities;
0906     QTest::newRow("empty") << QByteArray() << allActivities;
0907     QTest::newRow("\\0") << QByteArrayLiteral("\0") << allActivities;
0908 }
0909 
0910 void NetWinInfoTestClient::testActivities()
0911 {
0912     QVERIFY(connection());
0913     ATOM(_KDE_NET_WM_ACTIVITIES)
0914     INFO
0915 
0916     QVERIFY(!info.activities());
0917     QFETCH(QByteArray, activities);
0918 
0919     // activities needs to be changed using xcb
0920     info.setActivities(activities.isNull() ? nullptr : activities.constData());
0921     xcb_flush(connection());
0922 
0923     // only updated after event
0924     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2Activities);
0925     QTEST(QByteArray(info.activities()), "expectedActivities");
0926 }
0927 
0928 Q_DECLARE_METATYPE(NET::Protocols)
0929 void NetWinInfoTestClient::testProtocols_data()
0930 {
0931     QTest::addColumn<NET::Protocols>("protocols");
0932     QTest::addColumn<bool>("takeFocus");
0933     QTest::addColumn<bool>("deleteWindow");
0934     QTest::addColumn<bool>("ping");
0935     QTest::addColumn<bool>("sync");
0936     QTest::addColumn<bool>("context");
0937 
0938     const NET::Protocol t = NET::TakeFocusProtocol;
0939     const NET::Protocol d = NET::DeleteWindowProtocol;
0940     const NET::Protocol p = NET::PingProtocol;
0941     const NET::Protocol s = NET::SyncRequestProtocol;
0942     const NET::Protocol c = NET::ContextHelpProtocol;
0943 
0944     QTest::newRow("none") << NET::Protocols(NET::NoProtocol) << false << false << false << false << false;
0945 
0946     QTest::newRow("t") << NET::Protocols(t) << true << false << false << false << false;
0947     QTest::newRow("d") << NET::Protocols(d) << false << true << false << false << false;
0948     QTest::newRow("p") << NET::Protocols(p) << false << false << true << false << false;
0949     QTest::newRow("s") << NET::Protocols(s) << false << false << false << true << false;
0950     QTest::newRow("c") << NET::Protocols(c) << false << false << false << false << true;
0951 
0952     // all two combinations with t
0953     QTest::newRow("t/d") << NET::Protocols(t | d) << true << true  << false << false << false;
0954     QTest::newRow("t/p") << NET::Protocols(t | p) << true << false << true  << false << false;
0955     QTest::newRow("t/s") << NET::Protocols(t | s) << true << false << false << true  << false;
0956     QTest::newRow("t/c") << NET::Protocols(t | c) << true << false << false << false << true;
0957     // all two combinations with d
0958     QTest::newRow("d/p") << NET::Protocols(d | p) << false << true << true  << false << false;
0959     QTest::newRow("d/s") << NET::Protocols(d | s) << false << true << false << true  << false;
0960     QTest::newRow("d/c") << NET::Protocols(d | c) << false << true << false << false << true;
0961     // all two combinations with p
0962     QTest::newRow("p/s") << NET::Protocols(p | s) << false << false << true << true  << false;
0963     QTest::newRow("p/c") << NET::Protocols(p | c) << false << false << true << false << true;
0964     // and remaining two combination
0965     QTest::newRow("s/c") << NET::Protocols(s | c) << false << false << false << true << true;
0966 
0967     // all three combinations with t
0968     QTest::newRow("t/d/p") << NET::Protocols(t | d | p) << true << true  << true  << false << false;
0969     QTest::newRow("t/d/s") << NET::Protocols(t | d | s) << true << true  << false << true  << false;
0970     QTest::newRow("t/d/c") << NET::Protocols(t | d | c) << true << true  << false << false << true;
0971     QTest::newRow("t/p/s") << NET::Protocols(t | p | s) << true << false << true  << true  << false;
0972     QTest::newRow("t/p/c") << NET::Protocols(t | p | c) << true << false << true  << false << true;
0973     QTest::newRow("t/s/c") << NET::Protocols(t | s | c) << true << false << false << true  << true;
0974     // all three combinations with d
0975     QTest::newRow("d/p/s") << NET::Protocols(d | p | s) << false << true << true  << true  << false;
0976     QTest::newRow("d/p/c") << NET::Protocols(d | p | c) << false << true << true  << false << true;
0977     QTest::newRow("d/s/c") << NET::Protocols(d | s | c) << false << true << false << true  << true;
0978     // and remaining
0979     QTest::newRow("p/s/c") << NET::Protocols(p | s | c) << false << false << true << true << true;
0980 
0981     QTest::newRow("t/d/p/s") << NET::Protocols(t | d | p | s) << true  << true  << true  << true  << false;
0982     QTest::newRow("t/d/p/c") << NET::Protocols(t | d | p | c) << true  << true  << true  << false << true;
0983     QTest::newRow("t/d/s/c") << NET::Protocols(t | d | s | c) << true  << true  << false << true  << true;
0984     QTest::newRow("t/p/s/c") << NET::Protocols(t | p | s | c) << true  << false << true  << true  << true;
0985     QTest::newRow("d/p/s/c") << NET::Protocols(d | p | s | c) << false << true  << true  << true  << true;
0986 
0987     QTest::newRow("all") << NET::Protocols(t | d | p | s | c) << true << true << true << true << true;
0988 }
0989 
0990 void NetWinInfoTestClient::testProtocols()
0991 {
0992     QVERIFY(connection());
0993     ATOM(WM_PROTOCOLS)
0994     KXUtils::Atom takeFocus(connection(), QByteArrayLiteral("WM_TAKE_FOCUS"));
0995     KXUtils::Atom deleteWindow(connection(), QByteArrayLiteral("WM_DELETE_WINDOW"));
0996     KXUtils::Atom ping(connection(), QByteArrayLiteral("_NET_WM_PING"));
0997     KXUtils::Atom syncRequest(connection(), QByteArrayLiteral("_NET_WM_SYNC_REQUEST"));
0998     KXUtils::Atom contextHelp(connection(), QByteArrayLiteral("_NET_WM_CONTEXT_HELP"));
0999     INFO
1000 
1001     QVERIFY(!info.supportsProtocol(NET::TakeFocusProtocol));
1002     QVERIFY(!info.supportsProtocol(NET::DeleteWindowProtocol));
1003     QVERIFY(!info.supportsProtocol(NET::PingProtocol));
1004     QVERIFY(!info.supportsProtocol(NET::SyncRequestProtocol));
1005     QVERIFY(!info.supportsProtocol(NET::ContextHelpProtocol));
1006     QCOMPARE(info.protocols(), NET::Protocols(NET::NoProtocol));
1007 
1008     QList<xcb_atom_t> props;
1009     QFETCH(NET::Protocols, protocols);
1010     if (protocols.testFlag(NET::TakeFocusProtocol)) {
1011         props << takeFocus;
1012     }
1013     if (protocols.testFlag(NET::DeleteWindowProtocol)) {
1014         props << deleteWindow;
1015     }
1016     if (protocols.testFlag(NET::PingProtocol)) {
1017         props << ping;
1018     }
1019     if (protocols.testFlag(NET::SyncRequestProtocol)) {
1020         props << syncRequest;
1021     }
1022     if (protocols.testFlag(NET::ContextHelpProtocol)) {
1023         props << contextHelp;
1024     }
1025 
1026     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow, atom, XCB_ATOM_ATOM, 32, props.size(), props.constData());
1027     xcb_flush(connection());
1028 
1029     // only updated after event
1030     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2Protocols);
1031     QCOMPARE(info.protocols(), protocols);
1032     QTEST(info.supportsProtocol(NET::TakeFocusProtocol), "takeFocus");
1033     QTEST(info.supportsProtocol(NET::DeleteWindowProtocol), "deleteWindow");
1034     QTEST(info.supportsProtocol(NET::PingProtocol), "ping");
1035     QTEST(info.supportsProtocol(NET::SyncRequestProtocol), "sync");
1036     QTEST(info.supportsProtocol(NET::ContextHelpProtocol), "context");
1037 
1038     xcb_delete_property(connection(), m_testWindow, atom);
1039     xcb_flush(connection());
1040     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2Protocols);
1041     QVERIFY(!info.supportsProtocol(NET::TakeFocusProtocol));
1042     QVERIFY(!info.supportsProtocol(NET::DeleteWindowProtocol));
1043     QVERIFY(!info.supportsProtocol(NET::PingProtocol));
1044     QVERIFY(!info.supportsProtocol(NET::SyncRequestProtocol));
1045     QVERIFY(!info.supportsProtocol(NET::ContextHelpProtocol));
1046     QCOMPARE(info.protocols(), NET::Protocols(NET::NoProtocol));
1047 }
1048 
1049 void NetWinInfoTestClient::testOpaqueRegion_data()
1050 {
1051     QTest::addColumn<QList<QRect> >("geometries");
1052 
1053     QTest::newRow("none") << QList<QRect>();
1054     QTest::newRow("empty") << QList<QRect>({QRect(0, 0, 0, 0)});
1055     QTest::newRow("one rect") << QList<QRect>({QRect(10, 20, 30, 40)});
1056     QTest::newRow("two rect") << QList<QRect>({QRect(10, 20, 30, 40), QRect(1, 2, 4, 5)});
1057     QTest::newRow("multiple") << QList<QRect>({QRect(10, 20, 30, 40),
1058                                                  QRect(1, 2, 4, 5),
1059                                                  QRect(100, 0, 200, 400),
1060                                                  QRect(1, 2, 4, 5)});
1061 }
1062 
1063 void NetWinInfoTestClient::testOpaqueRegion()
1064 {
1065     QVERIFY(connection());
1066     ATOM(_NET_WM_OPAQUE_REGION)
1067     INFO
1068 
1069     QCOMPARE(info.opaqueRegion().size(), std::size_t(0));
1070 
1071     QFETCH(QList<QRect>, geometries);
1072     QList<qint32> data;
1073     for (auto it = geometries.constBegin(); it != geometries.constEnd(); ++it) {
1074         const QRect &r = *it;
1075         data << r.x();
1076         data << r.y();
1077         data << r.width();
1078         data << r.height();
1079     }
1080 
1081     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, m_testWindow, atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData());
1082     xcb_flush(connection());
1083 
1084     // only updated after event
1085     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2OpaqueRegion);
1086     const auto opaqueRegion = info.opaqueRegion();
1087     QCOMPARE(opaqueRegion.size(), std::size_t(geometries.size()));
1088 
1089     for (std::size_t i = 0; i < opaqueRegion.size(); ++i) {
1090         auto r1 = opaqueRegion.at(i);
1091         auto r2 = geometries.at(i);
1092         QCOMPARE(r1.pos.x, r2.x());
1093         QCOMPARE(r1.pos.y, r2.y());
1094         QCOMPARE(r1.size.width, r2.width());
1095         QCOMPARE(r1.size.height, r2.height());
1096     }
1097 
1098     xcb_delete_property(connection(), m_testWindow, atom);
1099     xcb_flush(connection());
1100     waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2OpaqueRegion);
1101     QCOMPARE(info.opaqueRegion().size(), std::size_t(0));
1102 }
1103 
1104 QTEST_GUILESS_MAIN(NetWinInfoTestClient)
1105 
1106 #include "netwininfotestclient.moc"