Warning, file /frameworks/kwindowsystem/autotests/netrootinfotestwm.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 using Property = UniqueCPointer<xcb_get_property_reply_t>; 0018 0019 Q_DECLARE_METATYPE(NET::Orientation) 0020 Q_DECLARE_METATYPE(NET::DesktopLayoutCorner) 0021 0022 static const char *s_wmName = "netrootinfotest"; 0023 0024 class NetRootInfoTestWM : public QObject 0025 { 0026 Q_OBJECT 0027 private Q_SLOTS: 0028 void initTestCase(); 0029 void cleanupTestCase(); 0030 void init(); 0031 void cleanup(); 0032 0033 void testCtor(); 0034 void testSupported(); 0035 void testClientList(); 0036 void testClientListStacking(); 0037 void testNumberOfDesktops(); 0038 void testCurrentDesktop(); 0039 void testDesktopNames(); 0040 void testDesktopLayout_data(); 0041 void testDesktopLayout(); 0042 void testDesktopGeometry(); 0043 void testDesktopViewports(); 0044 void testShowingDesktop_data(); 0045 void testShowingDesktop(); 0046 void testWorkArea(); 0047 void testActiveWindow(); 0048 void testVirtualRoots(); 0049 void testDontCrashMapViewports(); 0050 0051 private: 0052 void waitForPropertyChange(NETRootInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2 = NET::Property2(0)); 0053 xcb_connection_t *connection() 0054 { 0055 return m_connection; 0056 } 0057 xcb_connection_t *m_connection; 0058 QVector<xcb_connection_t *> m_connections; 0059 std::unique_ptr<QProcess> m_xvfb; 0060 xcb_window_t m_supportWindow; 0061 xcb_window_t m_rootWindow; 0062 }; 0063 0064 void NetRootInfoTestWM::cleanupTestCase() 0065 { 0066 while (!m_connections.isEmpty()) { 0067 xcb_disconnect(m_connections.takeFirst()); 0068 } 0069 } 0070 0071 void NetRootInfoTestWM::initTestCase() 0072 { 0073 } 0074 0075 void NetRootInfoTestWM::init() 0076 { 0077 // first reset just to be sure 0078 m_connection = nullptr; 0079 m_supportWindow = XCB_WINDOW_NONE; 0080 // start Xvfb 0081 const QString xfvbExec = QStandardPaths::findExecutable(QStringLiteral("Xvfb")); 0082 QVERIFY(!xfvbExec.isEmpty()); 0083 0084 m_xvfb.reset(new QProcess); 0085 // use pipe to pass fd to Xvfb to get back the display id 0086 int pipeFds[2]; 0087 QVERIFY(pipe(pipeFds) == 0); 0088 m_xvfb->start(xfvbExec, QStringList{QStringLiteral("-displayfd"), QString::number(pipeFds[1])}); 0089 QVERIFY(m_xvfb->waitForStarted()); 0090 QCOMPARE(m_xvfb->state(), QProcess::Running); 0091 0092 // reads from pipe, closes write side 0093 close(pipeFds[1]); 0094 0095 QFile readPipe; 0096 QVERIFY(readPipe.open(pipeFds[0], QIODevice::ReadOnly, QFileDevice::AutoCloseHandle)); 0097 QByteArray displayNumber = readPipe.readLine(); 0098 readPipe.close(); 0099 0100 displayNumber.prepend(QByteArray(":")); 0101 displayNumber.remove(displayNumber.size() - 1, 1); 0102 0103 // create X connection 0104 int screen = 0; 0105 m_connection = xcb_connect(displayNumber.constData(), &screen); 0106 QVERIFY(m_connection); 0107 QVERIFY(!xcb_connection_has_error(m_connection)); 0108 m_rootWindow = KXUtils::rootWindow(m_connection, screen); 0109 uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE}; 0110 xcb_change_window_attributes(m_connection, m_rootWindow, XCB_CW_EVENT_MASK, values); 0111 0112 // create support window 0113 values[0] = true; 0114 m_supportWindow = xcb_generate_id(m_connection); 0115 xcb_create_window(m_connection, 0116 XCB_COPY_FROM_PARENT, 0117 m_supportWindow, 0118 m_rootWindow, 0119 0, 0120 0, 0121 1, 0122 1, 0123 0, 0124 XCB_COPY_FROM_PARENT, 0125 XCB_COPY_FROM_PARENT, 0126 XCB_CW_OVERRIDE_REDIRECT, 0127 values); 0128 const uint32_t lowerValues[] = {XCB_STACK_MODE_BELOW}; 0129 // we need to do the lower window with a roundtrip, otherwise NETRootInfo is not functioning 0130 UniqueCPointer<xcb_generic_error_t> error( 0131 xcb_request_check(m_connection, xcb_configure_window_checked(m_connection, m_supportWindow, XCB_CONFIG_WINDOW_STACK_MODE, lowerValues))); 0132 QVERIFY(!error); 0133 } 0134 0135 void NetRootInfoTestWM::cleanup() 0136 { 0137 // destroy support window 0138 xcb_destroy_window(connection(), m_supportWindow); 0139 m_supportWindow = XCB_WINDOW_NONE; 0140 0141 // close connection 0142 // delay till clenupTestCase as otherwise xcb reuses the same memory address 0143 m_connections << connection(); 0144 // kill Xvfb 0145 m_xvfb->terminate(); 0146 m_xvfb->waitForFinished(); 0147 m_xvfb.reset(); 0148 } 0149 0150 void NetRootInfoTestWM::waitForPropertyChange(NETRootInfo *info, xcb_atom_t atom, NET::Property prop, NET::Property2 prop2) 0151 { 0152 while (true) { 0153 UniqueCPointer<xcb_generic_event_t> event(xcb_wait_for_event(connection())); 0154 if (!event) { 0155 break; 0156 } 0157 if ((event->response_type & ~0x80) != XCB_PROPERTY_NOTIFY) { 0158 continue; 0159 } 0160 xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event.get()); 0161 if (pe->window != m_rootWindow) { 0162 continue; 0163 } 0164 if (pe->atom != atom) { 0165 continue; 0166 } 0167 NET::Properties dirty; 0168 NET::Properties2 dirty2; 0169 info->event(event.get(), &dirty, &dirty2); 0170 if (prop != 0) { 0171 QVERIFY(dirty & prop); 0172 } 0173 if (prop2 != 0) { 0174 QVERIFY(dirty2 & prop2); 0175 } 0176 if (!prop) { 0177 QCOMPARE(dirty, NET::Properties()); 0178 } 0179 if (!prop2) { 0180 QCOMPARE(dirty2, NET::Properties2()); 0181 } 0182 break; 0183 } 0184 } 0185 0186 void NetRootInfoTestWM::testCtor() 0187 { 0188 QVERIFY(connection()); 0189 NETRootInfo 0190 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0191 QCOMPARE(rootInfo.xcbConnection(), connection()); 0192 QCOMPARE(rootInfo.rootWindow(), m_rootWindow); 0193 QCOMPARE(rootInfo.supportWindow(), m_supportWindow); 0194 QCOMPARE(rootInfo.wmName(), s_wmName); 0195 QCOMPARE(rootInfo.supportedProperties(), NET::WMAllProperties); 0196 QCOMPARE(rootInfo.supportedProperties2(), NET::WM2AllProperties); 0197 QCOMPARE(rootInfo.supportedActions(), NET::Actions(~0u)); 0198 QCOMPARE(rootInfo.supportedStates(), NET::States(~0u)); 0199 QCOMPARE(rootInfo.supportedWindowTypes(), NET::AllTypesMask); 0200 0201 QCOMPARE(rootInfo.passedProperties(), NET::WMAllProperties); 0202 QCOMPARE(rootInfo.passedProperties2(), NET::WM2AllProperties); 0203 QCOMPARE(rootInfo.passedActions(), NET::Actions(~0u)); 0204 QCOMPARE(rootInfo.passedStates(), NET::States(~0u)); 0205 QCOMPARE(rootInfo.passedWindowTypes(), NET::AllTypesMask); 0206 } 0207 0208 void NetRootInfoTestWM::testSupported() 0209 { 0210 KXUtils::Atom supported(connection(), QByteArrayLiteral("_NET_SUPPORTED")); 0211 KXUtils::Atom wmCheck(connection(), QByteArrayLiteral("_NET_SUPPORTING_WM_CHECK")); 0212 KXUtils::Atom wmName(connection(), QByteArrayLiteral("_NET_WM_NAME")); 0213 KXUtils::Atom utf8String(connection(), QByteArrayLiteral("UTF8_STRING")); 0214 QVERIFY(connection()); 0215 NETRootInfo 0216 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0217 int count = 0; 0218 for (int i = 0; i < 34; ++i) { 0219 if (i == 12) { 0220 continue; 0221 } 0222 QVERIFY(rootInfo.isSupported(NET::Property(1 << i))); 0223 count++; 0224 } 0225 for (int i = 0; i < 22; ++i) { 0226 QVERIFY(rootInfo.isSupported(NET::Property2(1 << i))); 0227 count++; 0228 } 0229 0230 QVERIFY(rootInfo.isSupported(NET::WM2GTKShowWindowMenu)); 0231 count++; 0232 0233 for (int i = 0; i < 17; ++i) { 0234 QVERIFY(rootInfo.isSupported(NET::WindowTypeMask(1 << i))); 0235 count++; 0236 } 0237 for (int i = 0; i < 13; ++i) { 0238 QVERIFY(rootInfo.isSupported(NET::State(1 << i))); 0239 count++; 0240 } 0241 for (int i = 0; i < 10; ++i) { 0242 QVERIFY(rootInfo.isSupported(NET::Action(1 << i))); 0243 count++; 0244 } 0245 // NET::WMFrameExtents has two properties 0246 count += 1; 0247 // XAWState, WMGeometry, WM2TransientFor, WM2GroupLeader, WM2WindowClass, WM2WindowRole, WM2ClientMachine 0248 count -= 7; 0249 // WM2BlockCompositing has 3 properties 0250 count += 2; 0251 // Add _GTK_FRAME_EXTENTS 0252 ++count; 0253 0254 QVERIFY(supported != XCB_ATOM_NONE); 0255 QVERIFY(utf8String != XCB_ATOM_NONE); 0256 QVERIFY(wmCheck != XCB_ATOM_NONE); 0257 QVERIFY(wmName != XCB_ATOM_NONE); 0258 0259 // we should have got some events 0260 waitForPropertyChange(&rootInfo, supported, NET::Supported); 0261 waitForPropertyChange(&rootInfo, wmCheck, NET::SupportingWMCheck); 0262 0263 // get the cookies of the things to check 0264 xcb_get_property_cookie_t supportedCookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), supported, XCB_ATOM_ATOM, 0, 101); 0265 xcb_get_property_cookie_t wmCheckRootCookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), wmCheck, XCB_ATOM_WINDOW, 0, 1); 0266 xcb_get_property_cookie_t wmCheckSupportWinCookie = xcb_get_property_unchecked(connection(), false, m_supportWindow, wmCheck, XCB_ATOM_WINDOW, 0, 1); 0267 xcb_get_property_cookie_t wmNameCookie = xcb_get_property_unchecked(connection(), false, m_supportWindow, wmName, utf8String, 0, 16); 0268 0269 Property supportedReply(xcb_get_property_reply(connection(), supportedCookie, nullptr)); 0270 QVERIFY(supportedReply); 0271 QCOMPARE(supportedReply->format, uint8_t(32)); 0272 QCOMPARE(supportedReply->value_len, uint32_t(count)); 0273 // TODO: check that the correct atoms are set? 0274 Property wmCheckRootReply(xcb_get_property_reply(connection(), wmCheckRootCookie, nullptr)); 0275 QVERIFY(wmCheckRootReply); 0276 QCOMPARE(wmCheckRootReply->format, uint8_t(32)); 0277 QCOMPARE(wmCheckRootReply->value_len, uint32_t(1)); 0278 QCOMPARE(reinterpret_cast<xcb_window_t *>(xcb_get_property_value(wmCheckRootReply.get()))[0], m_supportWindow); 0279 0280 Property wmCheckSupportReply(xcb_get_property_reply(connection(), wmCheckSupportWinCookie, nullptr)); 0281 QVERIFY(wmCheckSupportReply); 0282 QCOMPARE(wmCheckSupportReply->format, uint8_t(32)); 0283 QCOMPARE(wmCheckSupportReply->value_len, uint32_t(1)); 0284 QCOMPARE(reinterpret_cast<xcb_window_t *>(xcb_get_property_value(wmCheckSupportReply.get()))[0], m_supportWindow); 0285 0286 Property wmNameReply(xcb_get_property_reply(connection(), wmNameCookie, nullptr)); 0287 QVERIFY(wmNameReply); 0288 QCOMPARE(wmNameReply->format, uint8_t(8)); 0289 QCOMPARE(wmNameReply->value_len, uint32_t(15)); 0290 QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(wmNameReply.get())), s_wmName); 0291 0292 // disable some supported 0293 rootInfo.setSupported(NET::WMFrameExtents, false); 0294 rootInfo.setSupported(NET::WM2KDETemporaryRules, false); 0295 rootInfo.setSupported(NET::ActionChangeDesktop, false); 0296 rootInfo.setSupported(NET::FullScreen, false); 0297 QVERIFY(rootInfo.isSupported(NET::ToolbarMask)); 0298 QVERIFY(rootInfo.isSupported(NET::OnScreenDisplayMask)); 0299 QVERIFY(rootInfo.isSupported(NET::DockMask)); 0300 rootInfo.setSupported(NET::ToolbarMask, false); 0301 rootInfo.setSupported(NET::OnScreenDisplayMask, false); 0302 0303 QVERIFY(!rootInfo.isSupported(NET::WMFrameExtents)); 0304 QVERIFY(!rootInfo.isSupported(NET::WM2KDETemporaryRules)); 0305 QVERIFY(!rootInfo.isSupported(NET::ActionChangeDesktop)); 0306 QVERIFY(!rootInfo.isSupported(NET::FullScreen)); 0307 QVERIFY(!rootInfo.isSupported(NET::ToolbarMask)); 0308 QVERIFY(!rootInfo.isSupported(NET::OnScreenDisplayMask)); 0309 QVERIFY(rootInfo.isSupported(NET::DockMask)); 0310 0311 // lets get supported again 0312 supportedCookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), supported, XCB_ATOM_ATOM, 0, 90); 0313 supportedReply.reset(xcb_get_property_reply(connection(), supportedCookie, nullptr)); 0314 QVERIFY(supportedReply); 0315 QCOMPARE(supportedReply->format, uint8_t(32)); 0316 QCOMPARE(supportedReply->value_len, uint32_t(count - 7)); 0317 0318 for (int i = 0; i < 5; ++i) { 0319 // we should have got some events 0320 waitForPropertyChange(&rootInfo, supported, NET::Supported); 0321 waitForPropertyChange(&rootInfo, wmCheck, NET::SupportingWMCheck); 0322 } 0323 0324 // turn something off, just to get another event 0325 rootInfo.setSupported(NET::WM2BlockCompositing, false); 0326 // lets get supported again 0327 supportedCookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), supported, XCB_ATOM_ATOM, 0, 90); 0328 supportedReply.reset(xcb_get_property_reply(connection(), supportedCookie, nullptr)); 0329 QVERIFY(supportedReply); 0330 QCOMPARE(supportedReply->format, uint8_t(32)); 0331 QCOMPARE(supportedReply->value_len, uint32_t(count - 9)); 0332 NETRootInfo clientInfo(connection(), NET::Supported | NET::SupportingWMCheck); 0333 waitForPropertyChange(&clientInfo, supported, NET::Supported); 0334 waitForPropertyChange(&clientInfo, wmCheck, NET::SupportingWMCheck); 0335 } 0336 0337 void NetRootInfoTestWM::testClientList() 0338 { 0339 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_CLIENT_LIST")); 0340 QVERIFY(connection()); 0341 NETRootInfo 0342 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0343 QCOMPARE(rootInfo.clientListCount(), 0); 0344 QVERIFY(!rootInfo.clientList()); 0345 0346 xcb_window_t windows[] = {xcb_generate_id(connection()), 0347 xcb_generate_id(connection()), 0348 xcb_generate_id(connection()), 0349 xcb_generate_id(connection()), 0350 xcb_generate_id(connection())}; 0351 rootInfo.setClientList(windows, 5); 0352 QCOMPARE(rootInfo.clientListCount(), 5); 0353 const xcb_window_t *otherWins = rootInfo.clientList(); 0354 for (int i = 0; i < 5; ++i) { 0355 QCOMPARE(otherWins[i], windows[i]); 0356 } 0357 0358 // compare with the X property 0359 QVERIFY(atom != XCB_ATOM_NONE); 0360 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_WINDOW, 0, 5); 0361 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0362 QVERIFY(reply); 0363 QCOMPARE(reply->format, uint8_t(32)); 0364 QCOMPARE(reply->value_len, uint32_t(5)); 0365 const xcb_window_t *propWins = reinterpret_cast<xcb_window_t *>(xcb_get_property_value(reply.get())); 0366 for (int i = 0; i < 5; ++i) { 0367 QCOMPARE(propWins[i], windows[i]); 0368 } 0369 0370 // wait for our property 0371 NETRootInfo clientInfo(connection(), NET::Supported | NET::SupportingWMCheck | NET::ClientList); 0372 waitForPropertyChange(&clientInfo, atom, NET::ClientList); 0373 QCOMPARE(clientInfo.clientListCount(), 5); 0374 const xcb_window_t *otherWins2 = clientInfo.clientList(); 0375 for (int i = 0; i < 5; ++i) { 0376 QCOMPARE(otherWins2[i], windows[i]); 0377 } 0378 } 0379 0380 void NetRootInfoTestWM::testClientListStacking() 0381 { 0382 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_CLIENT_LIST_STACKING")); 0383 QVERIFY(connection()); 0384 NETRootInfo 0385 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0386 QCOMPARE(rootInfo.clientListStackingCount(), 0); 0387 QVERIFY(!rootInfo.clientListStacking()); 0388 0389 xcb_window_t windows[] = {xcb_generate_id(connection()), 0390 xcb_generate_id(connection()), 0391 xcb_generate_id(connection()), 0392 xcb_generate_id(connection()), 0393 xcb_generate_id(connection())}; 0394 rootInfo.setClientListStacking(windows, 5); 0395 QCOMPARE(rootInfo.clientListStackingCount(), 5); 0396 const xcb_window_t *otherWins = rootInfo.clientListStacking(); 0397 for (int i = 0; i < 5; ++i) { 0398 QCOMPARE(otherWins[i], windows[i]); 0399 } 0400 0401 // compare with the X property 0402 QVERIFY(atom != XCB_ATOM_NONE); 0403 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_WINDOW, 0, 5); 0404 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0405 QVERIFY(reply); 0406 QCOMPARE(reply->format, uint8_t(32)); 0407 QCOMPARE(reply->value_len, uint32_t(5)); 0408 const xcb_window_t *propWins = reinterpret_cast<xcb_window_t *>(xcb_get_property_value(reply.get())); 0409 for (int i = 0; i < 5; ++i) { 0410 QCOMPARE(propWins[i], windows[i]); 0411 } 0412 0413 // wait for our property 0414 waitForPropertyChange(&rootInfo, atom, NET::ClientListStacking); 0415 QCOMPARE(rootInfo.clientListStackingCount(), 5); 0416 const xcb_window_t *otherWins2 = rootInfo.clientListStacking(); 0417 for (int i = 0; i < 5; ++i) { 0418 QCOMPARE(otherWins2[i], windows[i]); 0419 } 0420 } 0421 0422 void NetRootInfoTestWM::testVirtualRoots() 0423 { 0424 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_VIRTUAL_ROOTS")); 0425 QVERIFY(connection()); 0426 NETRootInfo 0427 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0428 QCOMPARE(rootInfo.virtualRootsCount(), 0); 0429 QVERIFY(!rootInfo.virtualRoots()); 0430 0431 xcb_window_t windows[] = {xcb_generate_id(connection()), 0432 xcb_generate_id(connection()), 0433 xcb_generate_id(connection()), 0434 xcb_generate_id(connection()), 0435 xcb_generate_id(connection())}; 0436 rootInfo.setVirtualRoots(windows, 5); 0437 QCOMPARE(rootInfo.virtualRootsCount(), 5); 0438 const xcb_window_t *otherWins = rootInfo.virtualRoots(); 0439 for (int i = 0; i < 5; ++i) { 0440 QCOMPARE(otherWins[i], windows[i]); 0441 } 0442 0443 // compare with the X property 0444 QVERIFY(atom != XCB_ATOM_NONE); 0445 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_WINDOW, 0, 5); 0446 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0447 QVERIFY(reply); 0448 QCOMPARE(reply->format, uint8_t(32)); 0449 QCOMPARE(reply->value_len, uint32_t(5)); 0450 const xcb_window_t *propWins = reinterpret_cast<xcb_window_t *>(xcb_get_property_value(reply.get())); 0451 for (int i = 0; i < 5; ++i) { 0452 QCOMPARE(propWins[i], windows[i]); 0453 } 0454 0455 // wait for our property - reported to a Client NETRootInfo 0456 NETRootInfo clientInfo(connection(), NET::VirtualRoots); 0457 waitForPropertyChange(&clientInfo, atom, NET::VirtualRoots); 0458 QCOMPARE(rootInfo.virtualRootsCount(), 5); 0459 const xcb_window_t *otherWins2 = rootInfo.virtualRoots(); 0460 for (int i = 0; i < 5; ++i) { 0461 QCOMPARE(otherWins2[i], windows[i]); 0462 } 0463 } 0464 0465 void NetRootInfoTestWM::testNumberOfDesktops() 0466 { 0467 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_NUMBER_OF_DESKTOPS")); 0468 QVERIFY(connection()); 0469 NETRootInfo 0470 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0471 QCOMPARE(rootInfo.numberOfDesktops(), 1); 0472 rootInfo.setNumberOfDesktops(4); 0473 QCOMPARE(rootInfo.numberOfDesktops(), 4); 0474 0475 // compare with the X property 0476 QVERIFY(atom != XCB_ATOM_NONE); 0477 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 1); 0478 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0479 QVERIFY(reply); 0480 QCOMPARE(reply->format, uint8_t(32)); 0481 QCOMPARE(reply->value_len, uint32_t(1)); 0482 QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], uint32_t(4)); 0483 0484 // wait for our property 0485 waitForPropertyChange(&rootInfo, atom, NET::NumberOfDesktops); 0486 QCOMPARE(rootInfo.numberOfDesktops(), 4); 0487 } 0488 0489 void NetRootInfoTestWM::testCurrentDesktop() 0490 { 0491 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_CURRENT_DESKTOP")); 0492 // TODO: verify that current desktop cannot be higher than number of desktops 0493 QVERIFY(connection()); 0494 NETRootInfo 0495 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0496 QCOMPARE(rootInfo.currentDesktop(), 1); 0497 rootInfo.setCurrentDesktop(5); 0498 QCOMPARE(rootInfo.currentDesktop(), 5); 0499 0500 // compare with the X property 0501 QVERIFY(atom != XCB_ATOM_NONE); 0502 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 1); 0503 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0504 QVERIFY(reply); 0505 QCOMPARE(reply->format, uint8_t(32)); 0506 QCOMPARE(reply->value_len, uint32_t(1)); 0507 // note: API starts counting at 1, but property starts counting at 5, because of that subtracting one 0508 QCOMPARE(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], uint32_t(5 - 1)); 0509 0510 // wait for our property 0511 waitForPropertyChange(&rootInfo, atom, NET::CurrentDesktop); 0512 QCOMPARE(rootInfo.currentDesktop(), 5); 0513 } 0514 0515 void NetRootInfoTestWM::testDesktopNames() 0516 { 0517 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_DESKTOP_NAMES")); 0518 KXUtils::Atom utf8String(connection(), QByteArrayLiteral("UTF8_STRING")); 0519 QVERIFY(connection()); 0520 NETRootInfo 0521 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0522 QVERIFY(!rootInfo.desktopName(0)); 0523 QVERIFY(!rootInfo.desktopName(1)); 0524 QVERIFY(!rootInfo.desktopName(2)); 0525 rootInfo.setDesktopName(1, "foo"); 0526 rootInfo.setDesktopName(2, "bar"); 0527 rootInfo.setNumberOfDesktops(2); 0528 QCOMPARE(rootInfo.desktopName(1), "foo"); 0529 QCOMPARE(rootInfo.desktopName(2), "bar"); 0530 0531 // compare with the X property 0532 QVERIFY(atom != XCB_ATOM_NONE); 0533 QVERIFY(utf8String != XCB_ATOM_NONE); 0534 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, utf8String, 0, 10000); 0535 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0536 QVERIFY(reply); 0537 QCOMPARE(reply->format, uint8_t(8)); 0538 QCOMPARE(reply->value_len, uint32_t(8)); 0539 QCOMPARE(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), "foo\0bar"); 0540 0541 // wait for our property 0542 waitForPropertyChange(&rootInfo, atom, NET::DesktopNames); 0543 QCOMPARE(rootInfo.desktopName(1), "foo"); 0544 QCOMPARE(rootInfo.desktopName(2), "bar"); 0545 // there should be two events 0546 waitForPropertyChange(&rootInfo, atom, NET::DesktopNames); 0547 QCOMPARE(rootInfo.desktopName(1), "foo"); 0548 QCOMPARE(rootInfo.desktopName(2), "bar"); 0549 } 0550 0551 void NetRootInfoTestWM::testActiveWindow() 0552 { 0553 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_ACTIVE_WINDOW")); 0554 QVERIFY(connection()); 0555 NETRootInfo 0556 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0557 QVERIFY(rootInfo.activeWindow() == XCB_WINDOW_NONE); 0558 // rootinfo doesn't verify whether our window is a window, so we just generate an ID 0559 xcb_window_t activeWindow = xcb_generate_id(connection()); 0560 rootInfo.setActiveWindow(activeWindow); 0561 QCOMPARE(rootInfo.activeWindow(), activeWindow); 0562 0563 // compare with the X property 0564 QVERIFY(atom != XCB_ATOM_NONE); 0565 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_WINDOW, 0, 1); 0566 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0567 QVERIFY(reply); 0568 QCOMPARE(reply->format, uint8_t(32)); 0569 QCOMPARE(reply->value_len, uint32_t(1)); 0570 QCOMPARE(reinterpret_cast<xcb_window_t *>(xcb_get_property_value(reply.get()))[0], activeWindow); 0571 0572 // wait for our property 0573 waitForPropertyChange(&rootInfo, atom, NET::ActiveWindow); 0574 QCOMPARE(rootInfo.activeWindow(), activeWindow); 0575 } 0576 0577 void NetRootInfoTestWM::testDesktopGeometry() 0578 { 0579 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_DESKTOP_GEOMETRY")); 0580 QVERIFY(connection()); 0581 NETRootInfo 0582 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0583 QCOMPARE(rootInfo.desktopGeometry().width, 0); 0584 QCOMPARE(rootInfo.desktopGeometry().height, 0); 0585 0586 NETSize size; 0587 size.width = 1000; 0588 size.height = 800; 0589 rootInfo.setDesktopGeometry(size); 0590 QCOMPARE(rootInfo.desktopGeometry().width, size.width); 0591 QCOMPARE(rootInfo.desktopGeometry().height, size.height); 0592 0593 // compare with the X property 0594 QVERIFY(atom != XCB_ATOM_NONE); 0595 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 2); 0596 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0597 QVERIFY(reply); 0598 QCOMPARE(reply->format, uint8_t(32)); 0599 QCOMPARE(reply->value_len, uint32_t(2)); 0600 uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get())); 0601 QCOMPARE(data[0], uint32_t(size.width)); 0602 QCOMPARE(data[1], uint32_t(size.height)); 0603 0604 // wait for our property 0605 waitForPropertyChange(&rootInfo, atom, NET::DesktopGeometry); 0606 QCOMPARE(rootInfo.desktopGeometry().width, size.width); 0607 QCOMPARE(rootInfo.desktopGeometry().height, size.height); 0608 } 0609 0610 void NetRootInfoTestWM::testDesktopLayout_data() 0611 { 0612 QTest::addColumn<NET::Orientation>("orientation"); 0613 QTest::addColumn<QSize>("columnsRows"); 0614 QTest::addColumn<NET::DesktopLayoutCorner>("corner"); 0615 0616 QTest::newRow("h/1/1/tl") << NET::OrientationHorizontal << QSize(1, 1) << NET::DesktopLayoutCornerTopLeft; 0617 QTest::newRow("h/1/0/tr") << NET::OrientationHorizontal << QSize(1, 0) << NET::DesktopLayoutCornerTopRight; 0618 QTest::newRow("h/0/1/bl") << NET::OrientationHorizontal << QSize(0, 1) << NET::DesktopLayoutCornerBottomLeft; 0619 QTest::newRow("h/1/2/br") << NET::OrientationHorizontal << QSize(1, 2) << NET::DesktopLayoutCornerBottomRight; 0620 QTest::newRow("v/3/2/tl") << NET::OrientationVertical << QSize(3, 2) << NET::DesktopLayoutCornerTopLeft; 0621 QTest::newRow("v/5/4/tr") << NET::OrientationVertical << QSize(5, 4) << NET::DesktopLayoutCornerTopRight; 0622 QTest::newRow("v/2/1/bl") << NET::OrientationVertical << QSize(2, 1) << NET::DesktopLayoutCornerBottomLeft; 0623 QTest::newRow("v/3/2/br") << NET::OrientationVertical << QSize(3, 2) << NET::DesktopLayoutCornerBottomRight; 0624 } 0625 0626 void NetRootInfoTestWM::testDesktopLayout() 0627 { 0628 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_DESKTOP_LAYOUT")); 0629 QVERIFY(connection()); 0630 NETRootInfo 0631 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0632 QFETCH(NET::Orientation, orientation); 0633 QFETCH(QSize, columnsRows); 0634 QFETCH(NET::DesktopLayoutCorner, corner); 0635 0636 rootInfo.setDesktopLayout(orientation, columnsRows.width(), columnsRows.height(), corner); 0637 QCOMPARE(rootInfo.desktopLayoutOrientation(), orientation); 0638 QCOMPARE(rootInfo.desktopLayoutColumnsRows(), columnsRows); 0639 QCOMPARE(rootInfo.desktopLayoutCorner(), corner); 0640 0641 // compare with the X property 0642 QVERIFY(atom != XCB_ATOM_NONE); 0643 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 4); 0644 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0645 QVERIFY(reply); 0646 QCOMPARE(reply->format, uint8_t(32)); 0647 QCOMPARE(reply->value_len, uint32_t(4)); 0648 uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get())); 0649 QCOMPARE(data[0], uint32_t(orientation)); 0650 QCOMPARE(data[1], uint32_t(columnsRows.width())); 0651 QCOMPARE(data[2], uint32_t(columnsRows.height())); 0652 QCOMPARE(data[3], uint32_t(corner)); 0653 0654 // wait for our property 0655 waitForPropertyChange(&rootInfo, atom, NET::Property(0), NET::WM2DesktopLayout); 0656 QCOMPARE(rootInfo.desktopLayoutOrientation(), orientation); 0657 QCOMPARE(rootInfo.desktopLayoutColumnsRows(), columnsRows); 0658 QCOMPARE(rootInfo.desktopLayoutCorner(), corner); 0659 0660 NETRootInfo info2(connection(), NET::WMAllProperties, NET::WM2AllProperties); 0661 QCOMPARE(info2.desktopLayoutColumnsRows(), columnsRows); 0662 } 0663 0664 void NetRootInfoTestWM::testDesktopViewports() 0665 { 0666 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_DESKTOP_VIEWPORT")); 0667 QVERIFY(connection()); 0668 NETRootInfo 0669 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0670 // we need to know the number of desktops, therefore setting it 0671 rootInfo.setNumberOfDesktops(4); 0672 NETPoint desktopOne; 0673 desktopOne.x = 100; 0674 desktopOne.y = 50; 0675 NETPoint desktopTwo; 0676 desktopTwo.x = 200; 0677 desktopTwo.y = 100; 0678 rootInfo.setDesktopViewport(1, desktopOne); 0679 rootInfo.setDesktopViewport(2, desktopTwo); 0680 0681 const NETPoint compareZero = rootInfo.desktopViewport(0); 0682 QCOMPARE(compareZero.x, 0); 0683 QCOMPARE(compareZero.y, 0); 0684 const NETPoint compareOne = rootInfo.desktopViewport(1); 0685 QCOMPARE(compareOne.x, desktopOne.x); 0686 QCOMPARE(compareOne.y, desktopOne.y); 0687 const NETPoint compareTwo = rootInfo.desktopViewport(2); 0688 QCOMPARE(compareTwo.x, desktopTwo.x); 0689 QCOMPARE(compareTwo.y, desktopTwo.y); 0690 const NETPoint compareThree = rootInfo.desktopViewport(3); 0691 QCOMPARE(compareThree.x, 0); 0692 QCOMPARE(compareThree.y, 0); 0693 0694 // compare with the X property 0695 QVERIFY(atom != XCB_ATOM_NONE); 0696 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 8); 0697 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0698 QVERIFY(reply); 0699 QCOMPARE(reply->format, uint8_t(32)); 0700 QCOMPARE(reply->value_len, uint32_t(8)); 0701 uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get())); 0702 QCOMPARE(data[0], uint32_t(desktopOne.x)); 0703 QCOMPARE(data[1], uint32_t(desktopOne.y)); 0704 QCOMPARE(data[2], uint32_t(desktopTwo.x)); 0705 QCOMPARE(data[3], uint32_t(desktopTwo.y)); 0706 QCOMPARE(data[4], uint32_t(0)); 0707 QCOMPARE(data[5], uint32_t(0)); 0708 QCOMPARE(data[6], uint32_t(0)); 0709 QCOMPARE(data[7], uint32_t(0)); 0710 0711 // wait for our property - two events 0712 waitForPropertyChange(&rootInfo, atom, NET::DesktopViewport); 0713 waitForPropertyChange(&rootInfo, atom, NET::DesktopViewport); 0714 const NETPoint compareOne2 = rootInfo.desktopViewport(1); 0715 QCOMPARE(compareOne2.x, desktopOne.x); 0716 QCOMPARE(compareOne2.y, desktopOne.y); 0717 const NETPoint compareTwo2 = rootInfo.desktopViewport(2); 0718 QCOMPARE(compareTwo2.x, desktopTwo.x); 0719 QCOMPARE(compareTwo2.y, desktopTwo.y); 0720 const NETPoint compareThree2 = rootInfo.desktopViewport(3); 0721 QCOMPARE(compareThree2.x, 0); 0722 QCOMPARE(compareThree2.y, 0); 0723 } 0724 0725 void NetRootInfoTestWM::testShowingDesktop_data() 0726 { 0727 QTest::addColumn<bool>("set"); 0728 QTest::addColumn<uint32_t>("setValue"); 0729 0730 QTest::newRow("true") << true << uint32_t(1); 0731 QTest::newRow("false") << false << uint32_t(0); 0732 } 0733 0734 void NetRootInfoTestWM::testShowingDesktop() 0735 { 0736 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_SHOWING_DESKTOP")); 0737 QVERIFY(connection()); 0738 NETRootInfo 0739 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0740 QFETCH(bool, set); 0741 rootInfo.setShowingDesktop(set); 0742 QCOMPARE(rootInfo.showingDesktop(), set); 0743 0744 // compare with the X property 0745 QVERIFY(atom != XCB_ATOM_NONE); 0746 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 1); 0747 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0748 QVERIFY(reply); 0749 QCOMPARE(reply->format, uint8_t(32)); 0750 QCOMPARE(reply->value_len, uint32_t(1)); 0751 QTEST(reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get()))[0], "setValue"); 0752 0753 // wait for our property 0754 waitForPropertyChange(&rootInfo, atom, NET::Property(0), NET::WM2ShowingDesktop); 0755 QCOMPARE(rootInfo.showingDesktop(), set); 0756 } 0757 0758 void NetRootInfoTestWM::testWorkArea() 0759 { 0760 KXUtils::Atom atom(connection(), QByteArrayLiteral("_NET_WORKAREA")); 0761 QVERIFY(connection()); 0762 NETRootInfo 0763 rootInfo(connection(), m_supportWindow, s_wmName, NET::WMAllProperties, NET::AllTypesMask, NET::States(~0u), NET::WM2AllProperties, NET::Actions(~0u)); 0764 // we need to know the number of desktops, therefore setting it 0765 rootInfo.setNumberOfDesktops(4); 0766 NETRect desktopOne; 0767 desktopOne.pos.x = 10; 0768 desktopOne.pos.y = 5; 0769 desktopOne.size.width = 1000; 0770 desktopOne.size.height = 800; 0771 NETRect desktopTwo; 0772 desktopTwo.pos.x = 20; 0773 desktopTwo.pos.y = 10; 0774 desktopTwo.size.width = 800; 0775 desktopTwo.size.height = 750; 0776 rootInfo.setWorkArea(1, desktopOne); 0777 rootInfo.setWorkArea(2, desktopTwo); 0778 0779 const NETRect compareZero = rootInfo.workArea(0); 0780 QCOMPARE(compareZero.pos.x, 0); 0781 QCOMPARE(compareZero.pos.y, 0); 0782 QCOMPARE(compareZero.size.width, 0); 0783 QCOMPARE(compareZero.size.height, 0); 0784 const NETRect compareOne = rootInfo.workArea(1); 0785 QCOMPARE(compareOne.pos.x, desktopOne.pos.x); 0786 QCOMPARE(compareOne.pos.y, desktopOne.pos.y); 0787 QCOMPARE(compareOne.size.width, desktopOne.size.width); 0788 QCOMPARE(compareOne.size.height, desktopOne.size.height); 0789 const NETRect compareTwo = rootInfo.workArea(2); 0790 QCOMPARE(compareTwo.pos.x, desktopTwo.pos.x); 0791 QCOMPARE(compareTwo.pos.y, desktopTwo.pos.y); 0792 QCOMPARE(compareTwo.size.width, desktopTwo.size.width); 0793 QCOMPARE(compareTwo.size.height, desktopTwo.size.height); 0794 const NETRect compareThree = rootInfo.workArea(3); 0795 QCOMPARE(compareThree.pos.x, 0); 0796 QCOMPARE(compareThree.pos.y, 0); 0797 QCOMPARE(compareThree.size.width, 0); 0798 QCOMPARE(compareThree.size.height, 0); 0799 0800 // compare with the X property 0801 QVERIFY(atom != XCB_ATOM_NONE); 0802 xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(connection(), false, rootInfo.rootWindow(), atom, XCB_ATOM_CARDINAL, 0, 16); 0803 Property reply(xcb_get_property_reply(connection(), cookie, nullptr)); 0804 QVERIFY(reply); 0805 QCOMPARE(reply->format, uint8_t(32)); 0806 QCOMPARE(reply->value_len, uint32_t(16)); 0807 uint32_t *data = reinterpret_cast<uint32_t *>(xcb_get_property_value(reply.get())); 0808 QCOMPARE(data[0], uint32_t(desktopOne.pos.x)); 0809 QCOMPARE(data[1], uint32_t(desktopOne.pos.y)); 0810 QCOMPARE(data[2], uint32_t(desktopOne.size.width)); 0811 QCOMPARE(data[3], uint32_t(desktopOne.size.height)); 0812 QCOMPARE(data[4], uint32_t(desktopTwo.pos.x)); 0813 QCOMPARE(data[5], uint32_t(desktopTwo.pos.y)); 0814 QCOMPARE(data[6], uint32_t(desktopTwo.size.width)); 0815 QCOMPARE(data[7], uint32_t(desktopTwo.size.height)); 0816 QCOMPARE(data[8], uint32_t(0)); 0817 QCOMPARE(data[9], uint32_t(0)); 0818 QCOMPARE(data[10], uint32_t(0)); 0819 QCOMPARE(data[11], uint32_t(0)); 0820 QCOMPARE(data[12], uint32_t(0)); 0821 QCOMPARE(data[13], uint32_t(0)); 0822 QCOMPARE(data[14], uint32_t(0)); 0823 QCOMPARE(data[15], uint32_t(0)); 0824 0825 // wait for our property - two events 0826 waitForPropertyChange(&rootInfo, atom, NET::WorkArea); 0827 waitForPropertyChange(&rootInfo, atom, NET::WorkArea); 0828 const NETRect compareOne2 = rootInfo.workArea(1); 0829 QCOMPARE(compareOne2.pos.x, desktopOne.pos.x); 0830 QCOMPARE(compareOne2.pos.y, desktopOne.pos.y); 0831 QCOMPARE(compareOne2.size.width, desktopOne.size.width); 0832 QCOMPARE(compareOne2.size.height, desktopOne.size.height); 0833 const NETRect compareTwo2 = rootInfo.workArea(2); 0834 QCOMPARE(compareTwo2.pos.x, desktopTwo.pos.x); 0835 QCOMPARE(compareTwo2.pos.y, desktopTwo.pos.y); 0836 QCOMPARE(compareTwo2.size.width, desktopTwo.size.width); 0837 QCOMPARE(compareTwo2.size.height, desktopTwo.size.height); 0838 const NETRect compareThree2 = rootInfo.workArea(3); 0839 QCOMPARE(compareThree2.pos.x, 0); 0840 QCOMPARE(compareThree2.pos.y, 0); 0841 QCOMPARE(compareThree2.size.width, 0); 0842 QCOMPARE(compareThree2.size.height, 0); 0843 } 0844 0845 void NetRootInfoTestWM::testDontCrashMapViewports() 0846 { 0847 QProcess p; 0848 const QString processName = QFINDTESTDATA("dontcrashmapviewport"); 0849 QVERIFY(!processName.isEmpty()); 0850 0851 p.start(processName, QStringList()); 0852 QVERIFY(p.waitForFinished()); 0853 QCOMPARE(p.exitStatus(), QProcess::NormalExit); 0854 QCOMPARE(p.exitCode(), 0); 0855 } 0856 0857 QTEST_GUILESS_MAIN(NetRootInfoTestWM) 0858 0859 #include "netrootinfotestwm.moc"