File indexing completed on 2024-05-12 05:38:09
0001 /* 0002 SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include <array> 0008 0009 #include <private/qtx11extras_p.h> 0010 0011 #include <KWindowInfo> 0012 #include <PlasmaActivities/Consumer> 0013 0014 #include <xcb/xcb.h> 0015 #include <xcb/xproto.h> 0016 0017 #include "common.h" 0018 #include "xwindowtasksmodel.h" 0019 0020 using namespace TaskManager; 0021 using MimeDataMap = QMap<QString, QByteArray>; 0022 0023 class XWindowTasksModelTest : public QObject 0024 { 0025 Q_OBJECT 0026 0027 private Q_SLOTS: 0028 void initTestCase(); 0029 void cleanupTestCase(); 0030 0031 void test_winIdFromMimeData_data(); 0032 void test_winIdFromMimeData(); 0033 void test_winIdsFromMimeData_data(); 0034 void test_winIdsFromMimeData(); 0035 0036 void test_openCloseWindow(); 0037 void test_modelData(); 0038 void test_isMinimized(); 0039 void test_fullscreen(); 0040 void test_geometry(); 0041 void test_stackingOrder(); 0042 void test_lastActivated(); 0043 void test_modelDataFromDesktopFile(); 0044 void test_windowState(); 0045 0046 void test_request(); 0047 0048 private: 0049 WId m_WId = 12345; 0050 QByteArray m_singleWId; 0051 QByteArray m_threeWIds; 0052 QByteArray m_negativeCountWIds; 0053 QByteArray m_insufficientWIds; 0054 0055 XWindowTasksModel m_model; 0056 }; 0057 0058 void XWindowTasksModelTest::initTestCase() 0059 { 0060 TestUtils::initTestCase(); 0061 if (!KWindowSystem::isPlatformX11()) { 0062 QSKIP("Test is not running on X11."); 0063 } 0064 0065 char *singleWIdData = new char[sizeof(WId)]; 0066 memcpy(singleWIdData, &m_WId, sizeof(WId)); 0067 m_singleWId = QByteArray(singleWIdData, sizeof(WId)); 0068 delete[] singleWIdData; 0069 0070 constexpr int count = 3; 0071 char *threeWIdsData = new char[sizeof(int) + sizeof(WId) * count]; 0072 memcpy(threeWIdsData, &count, sizeof(int)); 0073 for (int i = 0; i < count; ++i) { 0074 memcpy(threeWIdsData + sizeof(int) + sizeof(WId) * i, &m_WId, sizeof(WId)); 0075 } 0076 m_threeWIds = QByteArray(threeWIdsData, sizeof(int) + sizeof(WId) * count); 0077 delete[] threeWIdsData; 0078 0079 constexpr int negativeCount = -count; 0080 char *negativeWIdsData = new char[sizeof(int) + sizeof(WId) * count]; 0081 memcpy(negativeWIdsData, &negativeCount, sizeof(int)); 0082 for (int i = 0; i < count; ++i) { 0083 memcpy(negativeWIdsData + sizeof(int) + sizeof(WId) * i, &m_WId, sizeof(WId)); 0084 } 0085 m_negativeCountWIds = QByteArray(negativeWIdsData, sizeof(int) + sizeof(WId) * count); 0086 delete[] negativeWIdsData; 0087 0088 constexpr int insufficientCount = count - 1; 0089 char *insufficientWIdsData = new char[sizeof(int) + sizeof(WId) * insufficientCount]; 0090 memcpy(insufficientWIdsData, &count, sizeof(int)); 0091 for (int i = 0; i < insufficientCount; ++i) { 0092 memcpy(insufficientWIdsData + sizeof(int) + sizeof(WId) * i, &m_WId, sizeof(WId)); 0093 } 0094 m_insufficientWIds = QByteArray(insufficientWIdsData, sizeof(int) + sizeof(WId) * insufficientCount); 0095 delete[] insufficientWIdsData; 0096 0097 QGuiApplication::setQuitOnLastWindowClosed(false); 0098 0099 QStandardPaths::setTestModeEnabled(true); 0100 0101 const QString applicationDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + QStringLiteral("applications"); 0102 QDir dir; 0103 if (!dir.exists(applicationDir)) { 0104 dir.mkpath(applicationDir); 0105 } 0106 } 0107 0108 void XWindowTasksModelTest::cleanupTestCase() 0109 { 0110 TestUtils::cleanupTestCase(); 0111 } 0112 0113 void XWindowTasksModelTest::test_winIdFromMimeData_data() 0114 { 0115 QTest::addColumn<QString>("mimeType"); 0116 QTest::addColumn<QByteArray>("data"); 0117 QTest::addColumn<bool>("isOK"); 0118 0119 QTest::newRow("Valid WId") << QStringLiteral("windowsystem/winid") // XWindowTasksModel::Private::mimeType() 0120 << m_singleWId << true; 0121 QTest::newRow("Invalid WId") << QStringLiteral("windowsystem/winid") << QByteArray("\x06") << false; 0122 QTest::newRow("Invalid mimeType") << QStringLiteral("text/plain") << m_singleWId << false; 0123 } 0124 0125 void XWindowTasksModelTest::test_winIdFromMimeData() 0126 { 0127 QFETCH(QString, mimeType); 0128 QFETCH(QByteArray, data); 0129 QFETCH(bool, isOK); 0130 0131 QMimeData mimeData; 0132 mimeData.setData(mimeType, data); 0133 qDebug() << data << "data size:" << data.size(); 0134 0135 bool ok = !isOK; 0136 WId result = XWindowTasksModel::winIdFromMimeData(&mimeData, &ok); 0137 QCOMPARE(ok, isOK); 0138 if (isOK) { 0139 QCOMPARE(result, m_WId); 0140 } 0141 } 0142 0143 void XWindowTasksModelTest::test_winIdsFromMimeData_data() 0144 { 0145 QTest::addColumn<MimeDataMap>("mimeDataMap"); 0146 QTest::addColumn<bool>("isOK"); 0147 QTest::addColumn<int>("count"); 0148 0149 // if (!mimeData->hasFormat(Private::groupMimeType())) 0150 MimeDataMap data1; 0151 data1.insert(QStringLiteral("windowsystem/winid"), m_singleWId); 0152 QTest::newRow("Single WId") << data1 << true << data1.size(); 0153 0154 MimeDataMap data2; 0155 data2.insert(QStringLiteral("windowsystem/winid"), QByteArray("\x06")); 0156 QTest::newRow("Invalid WId") << data2 << false << 0; 0157 0158 MimeDataMap data3; 0159 data3.insert(QStringLiteral("windowsystem/multiple-winids"), m_threeWIds); 0160 QTest::newRow("Three WIds") << data3 << true << 3; 0161 0162 // if ((unsigned int)data.size() < sizeof(int) + sizeof(WId)) 0163 MimeDataMap data4; 0164 data4.insert(QStringLiteral("windowsystem/multiple-winids"), QByteArray("\x06")); 0165 data4.insert(QStringLiteral("windowsystem/winid"), m_singleWId); 0166 QTest::newRow("Invalid WIds") << data4 << false << 0; 0167 0168 // count < 1 0169 MimeDataMap data5; 0170 data5.insert(QStringLiteral("windowsystem/multiple-winids"), m_negativeCountWIds); 0171 QTest::newRow("Negative count WIds") << data5 << false << 0; 0172 0173 // (unsigned int)data.size() < sizeof(int) + sizeof(WId) * count 0174 MimeDataMap data6; 0175 data6.insert(QStringLiteral("windowsystem/multiple-winids"), m_insufficientWIds); 0176 QTest::newRow("Insufficient count WIds") << data6 << false << 0; 0177 } 0178 0179 void XWindowTasksModelTest::test_winIdsFromMimeData() 0180 { 0181 QFETCH(MimeDataMap, mimeDataMap); 0182 QFETCH(bool, isOK); 0183 QFETCH(int, count); 0184 0185 QMimeData mimeData; 0186 for (auto it = mimeDataMap.cbegin(); it != mimeDataMap.cend(); it = std::next(it)) { 0187 mimeData.setData(it.key(), it.value()); 0188 } 0189 0190 bool ok = !isOK; 0191 auto results = XWindowTasksModel::winIdsFromMimeData(&mimeData, &ok); 0192 QCOMPARE(ok, isOK); 0193 QCOMPARE(results.size(), count); 0194 if (count > 0) { 0195 const bool verified = std::all_of(results.cbegin(), results.cend(), [this](WId id) { 0196 return id == m_WId; 0197 }); 0198 QVERIFY(verified); 0199 } 0200 } 0201 0202 void XWindowTasksModelTest::test_openCloseWindow() 0203 { 0204 TestUtils::testOpenCloseWindow(m_model); 0205 } 0206 0207 void XWindowTasksModelTest::test_modelData() 0208 { 0209 const QString title = QStringLiteral("__testwindow__%1").arg(QDateTime::currentDateTime().toString()); 0210 QModelIndex index; 0211 auto window = TestUtils::createSingleWindow(m_model, title, index); 0212 0213 // See XWindowTasksModel::data for available roles 0214 { // BEGIN Icon 0215 QSignalSpy dataChangedSpy(&m_model, &XWindowTasksModel::dataChanged); 0216 qDebug() << "Start testing Qt::DecorationRole"; 0217 const QIcon oldWindowIcon = index.data(Qt::DecorationRole).value<QIcon>(); // X11 icon 0218 QVERIFY(!oldWindowIcon.isNull()); 0219 window->setIcon(QIcon(QFINDTESTDATA("data/windows/samplewidgetwindow.png"))); 0220 QVERIFY(dataChangedSpy.wait()); 0221 QVERIFY(dataChangedSpy.takeLast().at(2).value<QList<int>>().contains(Qt::DecorationRole)); 0222 0223 const QIcon newWindowIcon = index.data(Qt::DecorationRole).value<QIcon>(); 0224 QVERIFY(!newWindowIcon.isNull()); 0225 QVERIFY(oldWindowIcon.pixmap(KIconLoader::SizeLarge).toImage().pixelColor(KIconLoader::SizeLarge / 2, KIconLoader::SizeLarge / 2) 0226 != newWindowIcon.pixmap(KIconLoader::SizeLarge).toImage().pixelColor(KIconLoader::SizeLarge / 2, KIconLoader::SizeLarge / 2)); 0227 0228 window->setIcon(QIcon()); 0229 QVERIFY(dataChangedSpy.wait()); 0230 QVERIFY(dataChangedSpy.takeLast().at(2).value<QList<int>>().contains(Qt::DecorationRole)); 0231 } // END Icon 0232 0233 const NET::Properties windowInfoFlags = 0234 NET::WMState | NET::XAWMState | NET::WMDesktop | NET::WMVisibleName | NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMPid; 0235 const NET::Properties2 windowInfoFlags2 = NET::WM2DesktopFileName | NET::WM2Activities | NET::WM2WindowClass | NET::WM2AllowedActions 0236 | NET::WM2AppMenuObjectPath | NET::WM2AppMenuServiceName | NET::WM2GTKApplicationId; 0237 KWindowInfo info(window->winId(), windowInfoFlags, windowInfoFlags2); 0238 0239 QTRY_COMPARE(index.data(AbstractTasksModel::AppId).toString(), info.windowClassClass()); 0240 QTRY_COMPARE(index.data(AbstractTasksModel::AppName).toString(), info.windowClassClass()); 0241 QTRY_COMPARE(index.data(AbstractTasksModel::GenericName).toString(), QString()); 0242 QTRY_VERIFY(index.data(AbstractTasksModel::LauncherUrl).toUrl().toLocalFile().endsWith(info.windowClassClass())); 0243 QTRY_VERIFY(index.data(AbstractTasksModel::LauncherUrlWithoutIcon).toUrl().toLocalFile().endsWith(info.windowClassClass())); 0244 QTRY_COMPARE(index.data(AbstractTasksModel::WinIdList).toList().size(), 1); 0245 QTRY_COMPARE(index.data(AbstractTasksModel::MimeType).toString(), QStringLiteral("windowsystem/winid")); 0246 0247 { 0248 QMimeData mimeData; 0249 mimeData.setData(index.data(AbstractTasksModel::MimeType).toString(), index.data(AbstractTasksModel::MimeData).toByteArray()); 0250 bool ok = false; 0251 XWindowTasksModel::winIdFromMimeData(&mimeData, &ok); 0252 QVERIFY(ok); 0253 } 0254 0255 QTRY_VERIFY(index.data(AbstractTasksModel::IsWindow).toBool()); 0256 QTRY_VERIFY(index.data(AbstractTasksModel::IsActive).toBool()); 0257 0258 QTRY_VERIFY(index.data(AbstractTasksModel::IsClosable).toBool()); 0259 QTRY_VERIFY(index.data(AbstractTasksModel::IsMovable).toBool()); 0260 QTRY_VERIFY(index.data(AbstractTasksModel::IsResizable).toBool()); 0261 QTRY_VERIFY(index.data(AbstractTasksModel::IsMaximizable).toBool()); 0262 QTRY_VERIFY(!index.data(AbstractTasksModel::IsMaximized).toBool()); 0263 QTRY_VERIFY(index.data(AbstractTasksModel::IsMinimizable).toBool()); 0264 QTRY_VERIFY(!index.data(AbstractTasksModel::IsKeepAbove).toBool()); 0265 QTRY_VERIFY(!index.data(AbstractTasksModel::IsKeepBelow).toBool()); 0266 QTRY_VERIFY(index.data(AbstractTasksModel::IsFullScreenable).toBool()); 0267 QTRY_VERIFY(!index.data(AbstractTasksModel::IsFullScreen).toBool()); 0268 QTRY_VERIFY(index.data(AbstractTasksModel::IsShadeable).toBool()); 0269 QTRY_VERIFY(!index.data(AbstractTasksModel::IsShaded).toBool()); 0270 QTRY_VERIFY(index.data(AbstractTasksModel::IsVirtualDesktopsChangeable).toBool()); 0271 QTRY_VERIFY(!index.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()); 0272 0273 // Due to window decoration, the size of a window can't be determined accurately 0274 const QRect screenGeometry = index.data(AbstractTasksModel::ScreenGeometry).toRect(); 0275 QVERIFY(screenGeometry.width() > 0 && screenGeometry.height() > 0); 0276 0277 KActivities::Consumer activityConsumer; 0278 qDebug() << "Start testing AbstractTasksModel::Activities. Current activity number:" << activityConsumer.runningActivities().size(); 0279 if (activityConsumer.runningActivities().size() > 0) { 0280 QCOMPARE(index.data(AbstractTasksModel::Activities).toStringList(), info.activities()); 0281 } else { 0282 // In CI the window manager is openbox, so there could be no running activity. 0283 QCOMPARE(index.data(AbstractTasksModel::Activities).toStringList().size(), 0); 0284 } 0285 0286 QTRY_VERIFY(!index.data(AbstractTasksModel::IsDemandingAttention).toBool()); 0287 QTRY_VERIFY(!index.data(AbstractTasksModel::SkipTaskbar).toBool()); 0288 QTRY_VERIFY(!index.data(AbstractTasksModel::SkipPager).toBool()); 0289 QTRY_COMPARE(index.data(AbstractTasksModel::AppPid).toInt(), info.pid()); 0290 0291 QVERIFY(index.data(AbstractTasksModel::CanLaunchNewInstance).toBool()); 0292 } 0293 0294 void XWindowTasksModelTest::test_isMinimized() 0295 { 0296 const QString title = QStringLiteral("__testwindow__%1").arg(QDateTime::currentDateTime().toString()); 0297 QModelIndex index; 0298 auto window = TestUtils::createSingleWindow(m_model, title, index); 0299 0300 QTRY_VERIFY(!index.data(AbstractTasksModel::IsMinimized).toBool()); 0301 QTRY_VERIFY(!index.data(AbstractTasksModel::IsHidden).toBool()); 0302 0303 // Minimize the window 0304 QSignalSpy dataChangedSpy(&m_model, &XWindowTasksModel::dataChanged); 0305 window->showMinimized(); 0306 dataChangedSpy.wait(); 0307 // There can be more than one dataChanged signal being emitted due to caching 0308 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0309 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsMinimized); 0310 })); 0311 // The model doesn't notify data change stored under IsHidden role 0312 QTRY_VERIFY(std::none_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0313 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsHidden); 0314 })); 0315 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0316 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsActive); 0317 })); 0318 QTRY_VERIFY(index.data(AbstractTasksModel::IsMinimized).toBool()); 0319 QTRY_VERIFY(index.data(AbstractTasksModel::IsHidden).toBool()); 0320 QTRY_VERIFY(!index.data(AbstractTasksModel::IsActive).toBool()); 0321 0322 // Restore the window 0323 dataChangedSpy.clear(); 0324 window->showNormal(); 0325 window->raise(); 0326 window->requestActivate(); 0327 dataChangedSpy.wait(); 0328 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0329 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsMinimized); 0330 })); 0331 QVERIFY(std::none_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0332 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsHidden); 0333 })); 0334 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0335 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsActive); 0336 })); 0337 QTRY_VERIFY(!index.data(AbstractTasksModel::IsMinimized).toBool()); 0338 QTRY_VERIFY(!index.data(AbstractTasksModel::IsHidden).toBool()); 0339 QTRY_VERIFY(index.data(AbstractTasksModel::IsActive).toBool()); 0340 } 0341 0342 void XWindowTasksModelTest::test_fullscreen() 0343 { 0344 TestUtils::testFullscreen(m_model); 0345 } 0346 0347 void XWindowTasksModelTest::test_geometry() 0348 { 0349 TestUtils::testGeometry(m_model); 0350 } 0351 0352 void XWindowTasksModelTest::test_stackingOrder() 0353 { 0354 TestUtils::testStackingOrder(m_model); 0355 } 0356 0357 void XWindowTasksModelTest::test_lastActivated() 0358 // Re-activate the window to update the last activated time 0359 { 0360 const QString title = QStringLiteral("__testwindow__%1").arg(QDateTime::currentDateTime().toString()); 0361 QModelIndex index; 0362 auto window = TestUtils::createSingleWindow(m_model, title, index); 0363 0364 QSignalSpy dataChangedSpy(&m_model, &XWindowTasksModel::dataChanged); 0365 window->showMinimized(); 0366 dataChangedSpy.wait(); 0367 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0368 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::IsMinimized); 0369 })); 0370 QTRY_VERIFY(index.data(AbstractTasksModel::IsMinimized).toBool()); 0371 0372 window->showNormal(); 0373 window->raise(); 0374 window->requestActivate(); 0375 const QTime lastActivatedTime = QTime::currentTime(); 0376 dataChangedSpy.wait(); 0377 // There can be more than one dataChanged signal being emitted due to caching 0378 QTRY_VERIFY(!index.data(AbstractTasksModel::IsMinimized).toBool()); 0379 // The model doesn't notify data change stored under LastActivated role 0380 QTRY_VERIFY(std::none_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [](const QVariantList &list) { 0381 return list.at(2).value<QList<int>>().contains(AbstractTasksModel::LastActivated); 0382 })); 0383 qDebug() << lastActivatedTime.msecsSinceStartOfDay() << index.data(AbstractTasksModel::LastActivated).toTime().msecsSinceStartOfDay(); 0384 QVERIFY(std::abs(lastActivatedTime.msecsSinceStartOfDay() - index.data(AbstractTasksModel::LastActivated).toTime().msecsSinceStartOfDay()) < 1000); 0385 } 0386 0387 void XWindowTasksModelTest::test_modelDataFromDesktopFile() 0388 { 0389 TestUtils::testModelDataFromDesktopFile(m_model); 0390 } 0391 0392 void XWindowTasksModelTest::test_windowState() 0393 { 0394 QSignalSpy rowsInsertedSpy(&m_model, &XWindowTasksModel::rowsInserted); 0395 0396 const QString title = QStringLiteral("__testwindow__%1").arg(QDateTime::currentDateTime().toString()); 0397 QModelIndex index; 0398 auto window = TestUtils::createSingleWindow(m_model, title, index); 0399 0400 QSignalSpy dataChangedSpy(&m_model, &XWindowTasksModel::dataChanged); 0401 0402 // NETWinInfo only allows a window manager set window states 0403 std::array<std::string, 11> actions{ 0404 "_NET_WM_ACTION_MOVE", 0405 "_NET_WM_ACTION_RESIZE", 0406 "_NET_WM_ACTION_MINIMIZE", 0407 "_NET_WM_ACTION_SHADE", 0408 "_NET_WM_ACTION_STICK", 0409 "_NET_WM_ACTION_MAXIMIZE_VERT", 0410 "_NET_WM_ACTION_MAXIMIZE_HORZ", 0411 "_NET_WM_ACTION_FULLSCREEN", 0412 "_NET_WM_ACTION_CHANGE_DESKTOP", 0413 "_NET_WM_ACTION_CLOSE", 0414 "_NET_WM_ALLOWED_ACTIONS", 0415 }; 0416 xcb_atom_t atoms[11]; 0417 { 0418 xcb_intern_atom_cookie_t cookies[11]; 0419 for (std::size_t i = 0; i < actions.size(); ++i) { 0420 cookies[i] = xcb_intern_atom(QX11Info::connection(), false, actions[i].size(), actions[i].c_str()); 0421 } 0422 // Get the replies 0423 for (std::size_t i = 0; i < actions.size(); ++i) { 0424 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(QX11Info::connection(), cookies[i], nullptr); 0425 if (!reply) { 0426 continue; 0427 } 0428 atoms[i] = reply->atom; 0429 free(reply); 0430 } 0431 qDebug() << "XCB atom cached"; 0432 } 0433 0434 auto setAllowedActionsAndVerify = [&](AbstractTasksModel::AdditionalRoles role, NET::Actions allowedActions, bool &success) { 0435 qDebug() << "Start testing" << role; 0436 success = false; 0437 dataChangedSpy.clear(); 0438 QVERIFY(index.data(role).toBool()); 0439 0440 uint32_t data[50]; 0441 int count = 0; 0442 if (allowedActions & NET::ActionMove) { 0443 data[count++] = atoms[0]; 0444 } 0445 if (allowedActions & NET::ActionResize) { 0446 data[count++] = atoms[1]; 0447 } 0448 if (allowedActions & NET::ActionMinimize) { 0449 data[count++] = atoms[2]; 0450 } 0451 if (allowedActions & NET::ActionShade) { 0452 data[count++] = atoms[3]; 0453 } 0454 if (allowedActions & NET::ActionStick) { 0455 data[count++] = atoms[4]; 0456 } 0457 if (allowedActions & NET::ActionMaxVert) { 0458 data[count++] = atoms[5]; 0459 } 0460 if (allowedActions & NET::ActionMaxHoriz) { 0461 data[count++] = atoms[6]; 0462 } 0463 if (allowedActions & NET::ActionFullScreen) { 0464 data[count++] = atoms[7]; 0465 } 0466 if (allowedActions & NET::ActionChangeDesktop) { 0467 data[count++] = atoms[8]; 0468 } 0469 if (allowedActions & NET::ActionClose) { 0470 data[count++] = atoms[9]; 0471 } 0472 0473 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, window->winId(), atoms[10], XCB_ATOM_ATOM, 32, count, (const void *)data); 0474 xcb_flush(QX11Info::connection()); 0475 QCoreApplication::processEvents(); 0476 0477 QTRY_VERIFY(std::any_of(dataChangedSpy.cbegin(), dataChangedSpy.cend(), [role](const QVariantList &list) { 0478 return list.at(2).value<QList<int>>().contains(role); 0479 })); 0480 QVERIFY(!index.data(role).toBool()); 0481 success = true; 0482 }; 0483 0484 bool success = false; 0485 const auto fullFlags = NET::ActionMove | NET::ActionResize | NET::ActionMinimize | NET::ActionShade | NET::ActionStick | NET::ActionMaxVert 0486 | NET::ActionMaxHoriz | NET::ActionFullScreen | NET::ActionChangeDesktop | NET::ActionClose; 0487 0488 // Make the window not movable 0489 setAllowedActionsAndVerify(AbstractTasksModel::IsMovable, fullFlags & (~NET::ActionMove), success); 0490 QVERIFY(success); 0491 0492 // Make the window not resizable 0493 setAllowedActionsAndVerify(AbstractTasksModel::IsResizable, fullFlags & (~NET::ActionResize), success); 0494 QVERIFY(success); 0495 0496 // Make the window not maximizable 0497 setAllowedActionsAndVerify(AbstractTasksModel::IsMaximizable, fullFlags & (~NET::ActionMax), success); 0498 QVERIFY(success); 0499 0500 // Make the window not minimizable 0501 setAllowedActionsAndVerify(AbstractTasksModel::IsMinimizable, fullFlags & (~NET::ActionMinimize), success); 0502 QVERIFY(success); 0503 0504 // Make the window not fullscreenable 0505 setAllowedActionsAndVerify(AbstractTasksModel::IsFullScreenable, fullFlags & (~NET::ActionFullScreen), success); 0506 QVERIFY(success); 0507 0508 // Make the window not shadeable 0509 setAllowedActionsAndVerify(AbstractTasksModel::IsShadeable, fullFlags & (~NET::ActionShade), success); 0510 QVERIFY(success); 0511 0512 // Make the window not able to change virtual desktop 0513 setAllowedActionsAndVerify(AbstractTasksModel::IsVirtualDesktopsChangeable, fullFlags & (~NET::ActionChangeDesktop), success); 0514 QVERIFY(success); 0515 0516 // Make the window not closable 0517 setAllowedActionsAndVerify(AbstractTasksModel::IsClosable, fullFlags & (~NET::ActionClose), success); 0518 QVERIFY(success); 0519 } 0520 0521 void XWindowTasksModelTest::test_request() 0522 { 0523 TestUtils::testRequest(m_model); 0524 } 0525 0526 QTEST_MAIN(XWindowTasksModelTest) 0527 0528 #include "xwindowtasksmodeltest.moc"