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"