Warning, file /frameworks/kwindowsystem/autotests/netwininfotestwm.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 "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 Q_DECLARE_METATYPE(NET::State) 0018 Q_DECLARE_METATYPE(NET::States) 0019 Q_DECLARE_METATYPE(NET::Actions) 0020 0021 using Property = UniqueCPointer<xcb_get_property_reply_t>; 0022 0023 // clang-format off 0024 #define INFO NETWinInfo info(m_connection, m_testWindow, m_rootWindow, NET::WMAllProperties, NET::WM2AllProperties, NET::WindowManager); 0025 0026 #define ATOM(name) \ 0027 KXUtils::Atom atom(connection(), QByteArrayLiteral(#name)); 0028 0029 #define UTF8 KXUtils::Atom utf8String(connection(), QByteArrayLiteral("UTF8_STRING")); 0030 0031 #define GETPROP(type, length, formatSize) \ 0032 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, m_testWindow, \ 0033 atom, type, 0, length); \ 0034 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); \ 0035 QVERIFY(reply); \ 0036 QCOMPARE(reply->format, uint8_t(formatSize)); \ 0037 QCOMPARE(reply->value_len, uint32_t(length)); 0038 0039 #define VERIFYDELETED(t) \ 0040 xcb_get_property_cookie_t cookieDeleted = xcb_get_property_unchecked(connection(), false, m_testWindow, \ 0041 atom, t, 0, 1); \ 0042 Property replyDeleted(xcb_get_property_reply(connection(), cookieDeleted, nullptr)); \ 0043 QVERIFY(replyDeleted); \ 0044 QVERIFY(replyDeleted->type == XCB_ATOM_NONE); 0045 0046 class NetWinInfoTestWM : public QObject 0047 { 0048 Q_OBJECT 0049 private Q_SLOTS: 0050 void initTestCase(); 0051 void cleanupTestCase(); 0052 void init(); 0053 void cleanup(); 0054 0055 void testState_data(); 0056 void testState(); 0057 void testVisibleName(); 0058 void testVisibleIconName(); 0059 void testDesktop_data(); 0060 void testDesktop(); 0061 void testOpacity_data(); 0062 void testOpacity(); 0063 void testAllowedActions_data(); 0064 void testAllowedActions(); 0065 void testFrameExtents(); 0066 void testFrameExtentsKDE(); 0067 void testFrameOverlap(); 0068 void testFullscreenMonitors(); 0069 0070 private: 0071 bool hasAtomFlag(const xcb_atom_t *atoms, int atomsLenght, const QByteArray &actionName); 0072 void testStrut(xcb_atom_t atom, NETStrut(NETWinInfo:: *getter)(void)const, void (NETWinInfo:: *setter)(NETStrut), NET::Property property, NET::Property2 property2 = NET::Property2(0)); 0073 void waitForPropertyChange(NETWinInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2 = NET::Property2(0)); 0074 xcb_connection_t *connection() 0075 { 0076 return m_connection; 0077 } 0078 xcb_connection_t *m_connection; 0079 QVector<xcb_connection_t*> m_connections; 0080 std::unique_ptr<QProcess> m_xvfb; 0081 xcb_window_t m_rootWindow; 0082 xcb_window_t m_testWindow; 0083 QByteArray m_displayNumber; 0084 }; 0085 0086 void NetWinInfoTestWM::initTestCase() 0087 { 0088 } 0089 0090 void NetWinInfoTestWM::cleanupTestCase() 0091 { 0092 // close connection 0093 while (!m_connections.isEmpty()) { 0094 xcb_disconnect(m_connections.takeFirst()); 0095 } 0096 } 0097 0098 void NetWinInfoTestWM::init() 0099 { 0100 // first reset just to be sure 0101 m_connection = nullptr; 0102 m_rootWindow = XCB_WINDOW_NONE; 0103 m_testWindow = XCB_WINDOW_NONE; 0104 0105 const QString xfvbExec = QStandardPaths::findExecutable(QStringLiteral("Xvfb")); 0106 QVERIFY(!xfvbExec.isEmpty()); 0107 0108 // start Xvfb 0109 m_xvfb.reset(new QProcess); 0110 0111 // use pipe to pass fd to Xvfb to get back the display id 0112 int pipeFds[2]; 0113 QVERIFY(pipe(pipeFds) == 0); 0114 m_xvfb->start(QStringLiteral("Xvfb"), QStringList{ QStringLiteral("-displayfd"), QString::number(pipeFds[1]) }); 0115 QVERIFY(m_xvfb->waitForStarted()); 0116 QCOMPARE(m_xvfb->state(), QProcess::Running); 0117 0118 // reads from pipe, closes write side 0119 close(pipeFds[1]); 0120 0121 QFile readPipe; 0122 QVERIFY(readPipe.open(pipeFds[0], QIODevice::ReadOnly, QFileDevice::AutoCloseHandle)); 0123 QByteArray displayNumber = readPipe.readLine(); 0124 readPipe.close(); 0125 0126 displayNumber.prepend(QByteArray(":")); 0127 displayNumber.remove(displayNumber.size() -1, 1); 0128 m_displayNumber = displayNumber; 0129 0130 // create X connection 0131 int screen = 0; 0132 m_connection = xcb_connect(displayNumber.constData(), &screen); 0133 QVERIFY(m_connection); 0134 QVERIFY(!xcb_connection_has_error(m_connection)); 0135 m_rootWindow = KXUtils::rootWindow(m_connection, screen); 0136 0137 // create test window 0138 m_testWindow = xcb_generate_id(m_connection); 0139 uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE}; 0140 xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_testWindow, 0141 m_rootWindow, 0142 0, 0, 100, 100, 0, XCB_COPY_FROM_PARENT, 0143 XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values); 0144 // and map it 0145 xcb_map_window(m_connection, m_testWindow); 0146 } 0147 0148 void NetWinInfoTestWM::cleanup() 0149 { 0150 // destroy test window 0151 xcb_unmap_window(m_connection, m_testWindow); 0152 xcb_destroy_window(m_connection, m_testWindow); 0153 m_testWindow = XCB_WINDOW_NONE; 0154 0155 // delay till clenupTestCase as otherwise xcb reuses the same memory address 0156 m_connections << connection(); 0157 // kill Xvfb 0158 m_xvfb->terminate(); 0159 m_xvfb->waitForFinished(); 0160 } 0161 0162 void NetWinInfoTestWM::waitForPropertyChange(NETWinInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2) 0163 { 0164 while (true) { 0165 UniqueCPointer<xcb_generic_event_t> event(xcb_wait_for_event(connection())); 0166 if (!event) { 0167 break; 0168 } 0169 if ((event->response_type & ~0x80) != XCB_PROPERTY_NOTIFY) { 0170 continue; 0171 } 0172 xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event.get()); 0173 if (pe->window != m_testWindow) { 0174 continue; 0175 } 0176 if (pe->atom != atom) { 0177 continue; 0178 } 0179 NET::Properties dirty; 0180 NET::Properties2 dirty2; 0181 info->event(event.get(), &dirty, &dirty2); 0182 if (prop != 0) { 0183 QVERIFY(dirty & prop); 0184 } 0185 if (prop2 != 0) { 0186 QVERIFY(dirty2 & prop2); 0187 } 0188 if (!prop) { 0189 QCOMPARE(dirty, NET::Properties()); 0190 } 0191 if (!prop2) { 0192 QCOMPARE(dirty2, NET::Properties2()); 0193 } 0194 break; 0195 } 0196 } 0197 0198 bool NetWinInfoTestWM::hasAtomFlag(const xcb_atom_t *atoms, int atomsLength, const QByteArray &actionName) 0199 { 0200 KXUtils::Atom atom(connection(), actionName); 0201 if (atom == XCB_ATOM_NONE) { 0202 qDebug() << "get atom failed"; 0203 return false; 0204 } 0205 for (int i = 0; i < atomsLength; ++i) { 0206 if (atoms[i] == atom) { 0207 return true; 0208 } 0209 } 0210 return false; 0211 } 0212 0213 void NetWinInfoTestWM::testAllowedActions_data() 0214 { 0215 QTest::addColumn<NET::Actions>("actions"); 0216 QTest::addColumn<QVector<QByteArray> >("names"); 0217 0218 const QByteArray move = QByteArrayLiteral("_NET_WM_ACTION_MOVE"); 0219 const QByteArray resize = QByteArrayLiteral("_NET_WM_ACTION_RESIZE"); 0220 const QByteArray minimize = QByteArrayLiteral("_NET_WM_ACTION_MINIMIZE"); 0221 const QByteArray shade = QByteArrayLiteral("_NET_WM_ACTION_SHADE"); 0222 const QByteArray stick = QByteArrayLiteral("_NET_WM_ACTION_STICK"); 0223 const QByteArray maxVert = QByteArrayLiteral("_NET_WM_ACTION_MAXIMIZE_VERT"); 0224 const QByteArray maxHoriz = QByteArrayLiteral("_NET_WM_ACTION_MAXIMIZE_HORZ"); 0225 const QByteArray fullscreen = QByteArrayLiteral("_NET_WM_ACTION_FULLSCREEN"); 0226 const QByteArray desktop = QByteArrayLiteral("_NET_WM_ACTION_CHANGE_DESKTOP"); 0227 const QByteArray close = QByteArrayLiteral("_NET_WM_ACTION_CLOSE"); 0228 0229 QTest::newRow("move") << NET::Actions(NET::ActionMove) << (QVector<QByteArray>() << move); 0230 QTest::newRow("resize") << NET::Actions(NET::ActionResize) << (QVector<QByteArray>() << resize); 0231 QTest::newRow("minimize") << NET::Actions(NET::ActionMinimize) << (QVector<QByteArray>() << minimize); 0232 QTest::newRow("shade") << NET::Actions(NET::ActionShade) << (QVector<QByteArray>() << shade); 0233 QTest::newRow("stick") << NET::Actions(NET::ActionStick) << (QVector<QByteArray>() << stick); 0234 QTest::newRow("maxVert") << NET::Actions(NET::ActionMaxVert) << (QVector<QByteArray>() << maxVert); 0235 QTest::newRow("maxHoriz") << NET::Actions(NET::ActionMaxHoriz) << (QVector<QByteArray>() << maxHoriz); 0236 QTest::newRow("fullscreen") << NET::Actions(NET::ActionFullScreen) << (QVector<QByteArray>() << fullscreen); 0237 QTest::newRow("desktop") << NET::Actions(NET::ActionChangeDesktop) << (QVector<QByteArray>() << desktop); 0238 QTest::newRow("close") << NET::Actions(NET::ActionClose) << (QVector<QByteArray>() << close); 0239 0240 QTest::newRow("none") << NET::Actions() << QVector<QByteArray>(); 0241 0242 QTest::newRow("all") << NET::Actions(NET::ActionMove | 0243 NET::ActionResize | 0244 NET::ActionMinimize | 0245 NET::ActionShade | 0246 NET::ActionStick | 0247 NET::ActionMaxVert | 0248 NET::ActionMaxHoriz | 0249 NET::ActionFullScreen | 0250 NET::ActionChangeDesktop | 0251 NET::ActionClose) 0252 << (QVector<QByteArray>() << move << resize << minimize << shade << 0253 stick << maxVert << maxHoriz << 0254 fullscreen << desktop << close); 0255 } 0256 0257 void NetWinInfoTestWM::testAllowedActions() 0258 { 0259 QVERIFY(connection()); 0260 ATOM(_NET_WM_ALLOWED_ACTIONS) 0261 INFO 0262 0263 QCOMPARE(info.allowedActions(), NET::Actions()); 0264 QFETCH(NET::Actions, actions); 0265 info.setAllowedActions(actions); 0266 QCOMPARE(info.allowedActions(), actions); 0267 0268 // compare with the X property 0269 QFETCH(QVector<QByteArray>, names); 0270 QVERIFY(atom != XCB_ATOM_NONE); 0271 GETPROP(XCB_ATOM_ATOM, names.size(), 32) 0272 xcb_atom_t *atoms = reinterpret_cast<xcb_atom_t *>(xcb_get_property_value(reply.get())); 0273 for (int i = 0; i < names.size(); ++i) { 0274 QVERIFY(hasAtomFlag(atoms, names.size(), names.at(i))); 0275 } 0276 0277 // and wait for our event 0278 waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2AllowedActions); 0279 QCOMPARE(info.allowedActions(), actions); 0280 } 0281 0282 void NetWinInfoTestWM::testDesktop_data() 0283 { 0284 QTest::addColumn<int>("desktop"); 0285 QTest::addColumn<uint32_t>("propertyDesktop"); 0286 0287 QTest::newRow("1") << 1 << uint32_t(0); 0288 QTest::newRow("4") << 4 << uint32_t(3); 0289 QTest::newRow("on all") << int(NET::OnAllDesktops) << uint32_t(~0); 0290 } 0291 0292 void NetWinInfoTestWM::testDesktop() 0293 { 0294 QVERIFY(connection()); 0295 ATOM(_NET_WM_DESKTOP) 0296 INFO 0297 0298 QCOMPARE(info.desktop(), 0); 0299 QFETCH(int, desktop); 0300 info.setDesktop(desktop); 0301 QCOMPARE(info.desktop(), desktop); 0302 0303 // compare with the X property 0304 QVERIFY(atom != XCB_ATOM_NONE); 0305 GETPROP(XCB_ATOM_CARDINAL, 1, 32) 0306 QTEST(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], "propertyDesktop"); 0307 0308 // and wait for our event 0309 waitForPropertyChange(&info, atom, NET::WMDesktop); 0310 QCOMPARE(info.desktop(), desktop); 0311 0312 // delete it 0313 info.setDesktop(0); 0314 QCOMPARE(info.desktop(), 0); 0315 VERIFYDELETED(XCB_ATOM_CARDINAL) 0316 0317 // and wait for our event 0318 waitForPropertyChange(&info, atom, NET::WMDesktop); 0319 QCOMPARE(info.desktop(), 0); 0320 } 0321 0322 void NetWinInfoTestWM::testStrut(xcb_atom_t atom, NETStrut(NETWinInfo:: *getter)(void)const, void (NETWinInfo:: *setter)(NETStrut), NET::Property property, NET::Property2 property2) 0323 { 0324 INFO 0325 0326 NETStrut extents = (info.*getter)(); 0327 QCOMPARE(extents.bottom, 0); 0328 QCOMPARE(extents.left, 0); 0329 QCOMPARE(extents.right, 0); 0330 QCOMPARE(extents.top, 0); 0331 0332 NETStrut newExtents; 0333 newExtents.bottom = 10; 0334 newExtents.left = 20; 0335 newExtents.right = 30; 0336 newExtents.top = 40; 0337 (info.*setter)(newExtents); 0338 extents = (info.*getter)(); 0339 QCOMPARE(extents.bottom, newExtents.bottom); 0340 QCOMPARE(extents.left, newExtents.left); 0341 QCOMPARE(extents.right, newExtents.right); 0342 QCOMPARE(extents.top, newExtents.top); 0343 0344 // compare with the X property 0345 QVERIFY(atom != XCB_ATOM_NONE); 0346 GETPROP(XCB_ATOM_CARDINAL, 4, 32) 0347 uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get())); 0348 QCOMPARE(data[0], uint32_t(newExtents.left)); 0349 QCOMPARE(data[1], uint32_t(newExtents.right)); 0350 QCOMPARE(data[2], uint32_t(newExtents.top)); 0351 QCOMPARE(data[3], uint32_t(newExtents.bottom)); 0352 0353 // and wait for our event 0354 waitForPropertyChange(&info, atom, property, property2); 0355 extents = (info.*getter)(); 0356 QCOMPARE(extents.bottom, newExtents.bottom); 0357 QCOMPARE(extents.left, newExtents.left); 0358 QCOMPARE(extents.right, newExtents.right); 0359 QCOMPARE(extents.top, newExtents.top); 0360 } 0361 0362 void NetWinInfoTestWM::testFrameExtents() 0363 { 0364 QVERIFY(connection()); 0365 ATOM(_NET_FRAME_EXTENTS) 0366 testStrut(atom, &NETWinInfo::frameExtents, &NETWinInfo::setFrameExtents, NET::WMFrameExtents); 0367 } 0368 0369 void NetWinInfoTestWM::testFrameExtentsKDE() 0370 { 0371 // same as testFrameExtents just with a different atom name 0372 QVERIFY(connection()); 0373 ATOM(_KDE_NET_WM_FRAME_STRUT) 0374 testStrut(atom, &NETWinInfo::frameExtents, &NETWinInfo::setFrameExtents, NET::WMFrameExtents); 0375 } 0376 0377 void NetWinInfoTestWM::testFrameOverlap() 0378 { 0379 QVERIFY(connection()); 0380 ATOM(_NET_WM_FRAME_OVERLAP) 0381 testStrut(atom, &NETWinInfo::frameOverlap, &NETWinInfo::setFrameOverlap, NET::Property(0), NET::WM2FrameOverlap); 0382 } 0383 0384 void NetWinInfoTestWM::testOpacity_data() 0385 { 0386 QTest::addColumn<uint32_t>("opacity"); 0387 0388 QTest::newRow("0 %") << uint32_t(0); 0389 QTest::newRow("50 %") << uint32_t(0x0000ffff); 0390 QTest::newRow("100 %") << uint32_t(0xffffffff); 0391 } 0392 0393 void NetWinInfoTestWM::testOpacity() 0394 { 0395 QVERIFY(connection()); 0396 ATOM(_NET_WM_WINDOW_OPACITY) 0397 INFO 0398 0399 QCOMPARE(info.opacity(), static_cast<unsigned long>(0xffffffffU)); 0400 QFETCH(uint32_t, opacity); 0401 info.setOpacity(opacity); 0402 QCOMPARE(info.opacity(), static_cast<unsigned long>(opacity)); 0403 0404 // compare with the X property 0405 QVERIFY(atom != XCB_ATOM_NONE); 0406 GETPROP(XCB_ATOM_CARDINAL, 1, 32) 0407 QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], opacity); 0408 0409 // and wait for our event 0410 waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2Opacity); 0411 QCOMPARE(info.opacity(), static_cast<unsigned long>(opacity)); 0412 } 0413 0414 void NetWinInfoTestWM::testState_data() 0415 { 0416 QTest::addColumn<NET::States>("states"); 0417 QTest::addColumn<QVector<QByteArray> >("names"); 0418 0419 const QByteArray modal = QByteArrayLiteral("_NET_WM_STATE_MODAL"); 0420 const QByteArray sticky = QByteArrayLiteral("_NET_WM_STATE_STICKY"); 0421 const QByteArray maxVert = QByteArrayLiteral("_NET_WM_STATE_MAXIMIZED_VERT"); 0422 const QByteArray maxHoriz = QByteArrayLiteral("_NET_WM_STATE_MAXIMIZED_HORZ"); 0423 const QByteArray shaded = QByteArrayLiteral("_NET_WM_STATE_SHADED"); 0424 const QByteArray skipTaskbar = QByteArrayLiteral("_NET_WM_STATE_SKIP_TASKBAR"); 0425 const QByteArray skipSwitcher = QByteArrayLiteral("_KDE_NET_WM_STATE_SKIP_SWITCHER"); 0426 const QByteArray keepAbove = QByteArrayLiteral("_NET_WM_STATE_ABOVE"); 0427 const QByteArray staysOnTop = QByteArrayLiteral("_NET_WM_STATE_STAYS_ON_TOP"); 0428 const QByteArray skipPager = QByteArrayLiteral("_NET_WM_STATE_SKIP_PAGER"); 0429 const QByteArray hidden = QByteArrayLiteral("_NET_WM_STATE_HIDDEN"); 0430 const QByteArray fullScreen = QByteArrayLiteral("_NET_WM_STATE_FULLSCREEN"); 0431 const QByteArray keepBelow = QByteArrayLiteral("_NET_WM_STATE_BELOW"); 0432 const QByteArray demandsAttention = QByteArrayLiteral("_NET_WM_STATE_DEMANDS_ATTENTION"); 0433 const QByteArray focused = QByteArrayLiteral("_NET_WM_STATE_FOCUSED"); 0434 0435 QTest::newRow("modal") << NET::States(NET::Modal) << (QVector<QByteArray>() << modal); 0436 QTest::newRow("sticky") << NET::States(NET::Sticky) << (QVector<QByteArray>() << sticky); 0437 QTest::newRow("maxVert") << NET::States(NET::MaxVert) << (QVector<QByteArray>() << maxVert); 0438 QTest::newRow("maxHoriz") << NET::States(NET::MaxHoriz) << (QVector<QByteArray>() << maxHoriz); 0439 QTest::newRow("shaded") << NET::States(NET::Shaded) << (QVector<QByteArray>() << shaded); 0440 QTest::newRow("skipTaskbar") << NET::States(NET::SkipTaskbar) << (QVector<QByteArray>() << skipTaskbar); 0441 QTest::newRow("keepAbove") << NET::States(NET::KeepAbove) << (QVector<QByteArray>() << keepAbove << staysOnTop); 0442 QTest::newRow("skipPager") << NET::States(NET::SkipPager) << (QVector<QByteArray>() << skipPager); 0443 QTest::newRow("hidden") << NET::States(NET::Hidden) << (QVector<QByteArray>() << hidden); 0444 QTest::newRow("fullScreen") << NET::States(NET::FullScreen) << (QVector<QByteArray>() << fullScreen); 0445 QTest::newRow("keepBelow") << NET::States(NET::KeepBelow) << (QVector<QByteArray>() << keepBelow); 0446 QTest::newRow("demandsAttention") << NET::States(NET::DemandsAttention) << (QVector<QByteArray>() << demandsAttention); 0447 QTest::newRow("skipSwitcher") << NET::States(NET::SkipSwitcher) << (QVector<QByteArray>() << skipSwitcher); 0448 QTest::newRow("focused") << NET::States(NET::Focused) << (QVector<QByteArray>() << focused); 0449 0450 // TODO: it's possible to be keep above and below at the same time?!? 0451 QTest::newRow("all") << NET::States(NET::Modal | 0452 NET::Sticky | 0453 NET::Max | 0454 NET::Shaded | 0455 NET::SkipTaskbar | 0456 NET::SkipPager | 0457 NET::KeepAbove | 0458 NET::KeepBelow | 0459 NET::Hidden | 0460 NET::FullScreen | 0461 NET::DemandsAttention | 0462 NET::SkipSwitcher | 0463 NET::Focused) 0464 << (QVector<QByteArray>() << modal << sticky << maxVert << maxHoriz 0465 << shaded << skipTaskbar << keepAbove 0466 << skipPager << hidden << fullScreen 0467 << keepBelow << demandsAttention << staysOnTop << skipSwitcher << focused); 0468 } 0469 0470 void NetWinInfoTestWM::testState() 0471 { 0472 QVERIFY(connection()); 0473 ATOM(_NET_WM_STATE) 0474 INFO 0475 0476 QCOMPARE(info.state(), NET::States()); 0477 QFETCH(NET::States, states); 0478 info.setState(states, NET::States()); 0479 QCOMPARE(info.state(), states); 0480 0481 // compare with the X property 0482 QFETCH(QVector<QByteArray>, names); 0483 QVERIFY(atom != XCB_ATOM_NONE); 0484 GETPROP(XCB_ATOM_ATOM, names.size(), 32) 0485 xcb_atom_t *atoms = reinterpret_cast<xcb_atom_t *>(xcb_get_property_value(reply.get())); 0486 for (int i = 0; i < names.size(); ++i) { 0487 QVERIFY(hasAtomFlag(atoms, names.size(), names.at(i))); 0488 } 0489 0490 // and wait for our event 0491 waitForPropertyChange(&info, atom, NET::WMState); 0492 QCOMPARE(info.state(), states); 0493 } 0494 0495 void NetWinInfoTestWM::testVisibleIconName() 0496 { 0497 QVERIFY(connection()); 0498 ATOM(_NET_WM_VISIBLE_ICON_NAME) 0499 UTF8 0500 INFO 0501 0502 QVERIFY(!info.visibleIconName()); 0503 info.setVisibleIconName("foo"); 0504 QCOMPARE(info.visibleIconName(), "foo"); 0505 0506 // compare with the X property 0507 QVERIFY(atom != XCB_ATOM_NONE); 0508 QVERIFY(utf8String != XCB_ATOM_NONE); 0509 GETPROP(utf8String, 3, 8) 0510 QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo"); 0511 0512 // and wait for our event 0513 waitForPropertyChange(&info, atom, NET::WMVisibleIconName); 0514 QCOMPARE(info.visibleIconName(), "foo"); 0515 0516 // delete the string 0517 info.setVisibleIconName(""); 0518 QCOMPARE(info.visibleIconName(), ""); 0519 VERIFYDELETED(utf8String) 0520 // and wait for our event 0521 waitForPropertyChange(&info, atom, NET::WMVisibleIconName); 0522 QVERIFY(!info.visibleIconName()); 0523 0524 // set again, to ensure we don't leak on tear down 0525 info.setVisibleIconName("bar"); 0526 xcb_flush(connection()); 0527 waitForPropertyChange(&info, atom, NET::WMVisibleIconName); 0528 QCOMPARE(info.visibleIconName(), "bar"); 0529 } 0530 0531 void NetWinInfoTestWM::testVisibleName() 0532 { 0533 QVERIFY(connection()); 0534 ATOM(_NET_WM_VISIBLE_NAME) 0535 UTF8 0536 INFO 0537 0538 QVERIFY(!info.visibleName()); 0539 info.setVisibleName("foo"); 0540 QCOMPARE(info.visibleName(), "foo"); 0541 0542 // compare with the X property 0543 QVERIFY(atom != XCB_ATOM_NONE); 0544 QVERIFY(utf8String != XCB_ATOM_NONE); 0545 GETPROP(utf8String, 3, 8) 0546 QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo"); 0547 0548 // and wait for our event 0549 waitForPropertyChange(&info, atom, NET::WMVisibleName); 0550 QCOMPARE(info.visibleName(), "foo"); 0551 0552 // delete the string 0553 info.setVisibleName(""); 0554 QCOMPARE(info.visibleName(), ""); 0555 VERIFYDELETED(utf8String) 0556 0557 // and wait for our event 0558 waitForPropertyChange(&info, atom, NET::WMVisibleName); 0559 QVERIFY(!info.visibleName()); 0560 0561 // set again, to ensure we don't leak on tear down 0562 info.setVisibleName("bar"); 0563 xcb_flush(connection()); 0564 waitForPropertyChange(&info, atom, NET::WMVisibleName); 0565 QCOMPARE(info.visibleName(), "bar"); 0566 } 0567 0568 class MockWinInfo : public NETWinInfo 0569 { 0570 public: 0571 MockWinInfo(xcb_connection_t *connection, xcb_window_t window, xcb_window_t rootWindow) 0572 : NETWinInfo(connection, window, rootWindow, NET::WMAllProperties, NET::WM2AllProperties, NET::WindowManager) 0573 { 0574 } 0575 0576 protected: 0577 void changeFullscreenMonitors(NETFullscreenMonitors topology) override 0578 { 0579 setFullscreenMonitors(topology); 0580 } 0581 }; 0582 0583 void NetWinInfoTestWM::testFullscreenMonitors() 0584 { 0585 // test case for BUG 391960 0586 QVERIFY(connection()); 0587 const uint32_t maskValues[] = { 0588 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | 0589 XCB_EVENT_MASK_KEY_PRESS | 0590 XCB_EVENT_MASK_PROPERTY_CHANGE | 0591 XCB_EVENT_MASK_COLOR_MAP_CHANGE | 0592 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | 0593 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | 0594 XCB_EVENT_MASK_FOCUS_CHANGE | // For NotifyDetailNone 0595 XCB_EVENT_MASK_EXPOSURE 0596 }; 0597 UniqueCPointer<xcb_generic_error_t> redirectCheck(xcb_request_check(connection(), xcb_change_window_attributes_checked(connection(), 0598 m_rootWindow, XCB_CW_EVENT_MASK, maskValues))); 0599 QVERIFY(!redirectCheck); 0600 0601 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_WM_FULLSCREEN_MONITORS")); 0602 0603 // create client connection 0604 auto clientConnection = xcb_connect(m_displayNumber.constData(), nullptr); 0605 QVERIFY(clientConnection); 0606 QVERIFY(!xcb_connection_has_error(clientConnection)); 0607 0608 NETWinInfo clientInfo(clientConnection, m_testWindow, m_rootWindow, NET::WMAllProperties, NET::WM2AllProperties); 0609 NETFullscreenMonitors topology; 0610 topology.top = 1; 0611 topology.bottom = 2; 0612 topology.left = 3; 0613 topology.right = 4; 0614 clientInfo.setFullscreenMonitors(topology); 0615 xcb_flush(clientConnection); 0616 0617 MockWinInfo info(connection(), m_testWindow, m_rootWindow); 0618 0619 while (true) { 0620 UniqueCPointer<xcb_generic_event_t> event(xcb_wait_for_event(connection())); 0621 if (!event) { 0622 break; 0623 } 0624 if ((event->response_type & ~0x80) != XCB_CLIENT_MESSAGE) { 0625 continue; 0626 } 0627 0628 NET::Properties dirtyProtocols; 0629 NET::Properties2 dirtyProtocols2; 0630 QCOMPARE(info.fullscreenMonitors().isSet(), false); 0631 info.event(event.get(), &dirtyProtocols, &dirtyProtocols2); 0632 QCOMPARE(info.fullscreenMonitors().isSet(), true); 0633 break; 0634 } 0635 xcb_flush(connection()); 0636 // now the property should be updated 0637 waitForPropertyChange(&info, atom, NET::Property(0), NET::WM2FullscreenMonitors); 0638 0639 QCOMPARE(info.fullscreenMonitors().top, 1); 0640 QCOMPARE(info.fullscreenMonitors().bottom, 2); 0641 QCOMPARE(info.fullscreenMonitors().left, 3); 0642 QCOMPARE(info.fullscreenMonitors().right, 4); 0643 0644 xcb_disconnect(clientConnection); 0645 } 0646 0647 QTEST_GUILESS_MAIN(NetWinInfoTestWM) 0648 0649 #include "netwininfotestwm.moc"