File indexing completed on 2024-11-17 05:01:36
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 2013 Alejandro Fiestas Olivares <afiestas@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "../src/platformtheme/kdeplatformtheme.h" 0008 #include "../src/platformtheme/khintssettings.h" 0009 #include "kdeplatformtheme_config.h" 0010 #include <config-platformtheme.h> 0011 #undef HAVE_X11 0012 #define HAVE_X11 0 0013 0014 #include <QApplication> 0015 #include <QDialogButtonBox> 0016 #include <QDir> 0017 #include <QDrag> 0018 #include <QFile> 0019 #include <QIconEngine> 0020 #include <QMimeData> 0021 #include <QPalette> 0022 #include <QStandardPaths> 0023 #include <QString> 0024 #include <QTest> 0025 #include <QToolButton> 0026 #include <Qt> 0027 0028 #include <KWindowSystem> 0029 #include <QDBusConnection> 0030 #include <QDBusMessage> 0031 #include <QTimer> 0032 0033 #include <KIconTheme> 0034 #include <KWindowInfo> 0035 #include <kiconloader.h> 0036 0037 static void prepareEnvironment() 0038 { 0039 QStandardPaths::setTestModeEnabled(true); 0040 0041 QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 0042 0043 if (!QDir(configPath).mkpath(QStringLiteral("."))) { 0044 qFatal("Failed to create test configuration directory."); 0045 } 0046 0047 configPath.append("/kdeglobals"); 0048 0049 QFile::remove(configPath); 0050 if (!QFile::copy(CONFIGFILE, configPath)) { 0051 qFatal("Failed to copy kdeglobals required for tests."); 0052 } 0053 } 0054 0055 Q_CONSTRUCTOR_FUNCTION(prepareEnvironment) 0056 0057 class EventTest : public QObject 0058 { 0059 public: 0060 EventTest(QObject *tested, QEvent::Type type) 0061 : QObject() 0062 , gotEvent(false) 0063 , m_type(type) 0064 { 0065 tested->installEventFilter(this); 0066 } 0067 0068 bool eventFilter(QObject *, QEvent *e) override 0069 { 0070 if (e->type() == m_type) { 0071 gotEvent = true; 0072 } 0073 return false; 0074 } 0075 0076 bool gotEvent; 0077 QEvent::Type m_type; 0078 }; 0079 0080 class KdePlatformTheme_UnitTest : public QObject 0081 { 0082 Q_OBJECT 0083 public: 0084 KdePlatformTheme_UnitTest() 0085 { 0086 } 0087 0088 private: 0089 void sendNotifyChange(KHintsSettings::ChangeType type, int arg = -1) 0090 { 0091 QDBusMessage message = 0092 QDBusMessage::createSignal(QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange")); 0093 QList<QVariant> args; 0094 args.append(static_cast<int>(type)); 0095 if (arg >= 0) { 0096 args.append(arg); 0097 } 0098 message.setArguments(args); 0099 QDBusConnection::sessionBus().send(message); 0100 } 0101 0102 QEventLoop m_loop; 0103 QToolButton m_toolBtn; 0104 KdePlatformTheme *m_qpa; 0105 private Q_SLOTS: 0106 void initTestCase() 0107 { 0108 m_qpa = new KdePlatformTheme(); 0109 QDBusConnection::sessionBus().connect(QString(), 0110 QStringLiteral("/KGlobalSettings"), 0111 QStringLiteral("org.kde.KGlobalSettings"), 0112 QStringLiteral("notifyChange"), 0113 &m_loop, 0114 SLOT(quit())); 0115 } 0116 0117 void cleanupTestCase() 0118 { 0119 QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 0120 configPath.append("/kdeglobals"); 0121 0122 QFile::remove(configPath); 0123 } 0124 0125 void testPlatformHints() 0126 { 0127 QCOMPARE(qApp->cursorFlashTime(), 1042); 0128 QCOMPARE(qApp->doubleClickInterval(), 4343); 0129 QCOMPARE(qApp->startDragDistance(), 15); 0130 QCOMPARE(qApp->startDragTime(), 555); 0131 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ToolButtonStyle).toInt(), (int)Qt::ToolButtonTextOnly); 0132 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ToolBarIconSize).toInt(), 2); 0133 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ItemViewActivateItemOnSingleClick).toBool(), false); 0134 QCOMPARE(m_qpa->themeHint(QPlatformTheme::SystemIconThemeName).toString(), QLatin1String("non-existent-icon-theme")); 0135 QCOMPARE(m_qpa->themeHint(QPlatformTheme::SystemIconFallbackThemeName).toString(), QLatin1String("hicolor")); 0136 0137 QStringList iconThemeSearchPaths = m_qpa->themeHint(QPlatformTheme::IconThemeSearchPaths).toStringList(); 0138 foreach (const QString &iconPath, iconThemeSearchPaths) { 0139 QVERIFY(iconPath.endsWith(QLatin1String("/icons")) || iconPath.endsWith(QLatin1String("/.icons"))); 0140 QVERIFY(QFile::exists(iconPath)); 0141 } 0142 // there must be *some* icons in XDG_DATA_DIRS, right? 0143 QVERIFY(!iconThemeSearchPaths.isEmpty()); 0144 0145 QStringList styles; 0146 styles << QStringLiteral("non-existent-widget-style") << QStringLiteral("breeze") << QStringLiteral("oxygen") << QStringLiteral("fusion") 0147 << QStringLiteral("windows"); 0148 QCOMPARE(m_qpa->themeHint(QPlatformTheme::StyleNames).toStringList(), styles); 0149 QCOMPARE(m_qpa->themeHint(QPlatformTheme::DialogButtonBoxLayout).toInt(), (int)QDialogButtonBox::KdeLayout); 0150 QCOMPARE(m_qpa->themeHint(QPlatformTheme::DialogButtonBoxButtonsHaveIcons).toBool(), false); 0151 QCOMPARE(m_qpa->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool(), true); 0152 QCOMPARE(m_qpa->themeHint(QPlatformTheme::KeyboardScheme).toInt(), (int)QPlatformTheme::KdeKeyboardScheme); 0153 QCOMPARE(m_qpa->themeHint(QPlatformTheme::UiEffects).toInt(), 0); 0154 QCOMPARE(m_qpa->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int>>(), QList<int>() << 512 << 256 << 128 << 64 << 32 << 22 << 16 << 8); 0155 0156 QCOMPARE(qApp->wheelScrollLines(), 1234); 0157 QCOMPARE(qApp->testAttribute(Qt::AA_DontShowIconsInMenus), false); 0158 } 0159 0160 void testPlatformPalette() 0161 { 0162 const QPalette palette = qApp->palette(); 0163 QPalette::ColorGroup states[3] = {QPalette::Active, QPalette::Inactive, QPalette::Disabled}; 0164 QColor greenColor(QColor(0, 128, 0)); 0165 QBrush greenBrush(greenColor); 0166 for (int i = 0; i < 3; i++) { 0167 QCOMPARE(palette.brush(states[i], QPalette::ButtonText), greenBrush); 0168 QCOMPARE(palette.brush(states[i], QPalette::WindowText), greenBrush); 0169 QCOMPARE(palette.brush(states[i], QPalette::Window), greenBrush); 0170 QCOMPARE(palette.brush(states[i], QPalette::Base), greenBrush); 0171 QCOMPARE(palette.brush(states[i], QPalette::Text), greenBrush); 0172 QCOMPARE(palette.brush(states[i], QPalette::Button), greenBrush); 0173 QCOMPARE(palette.brush(states[i], QPalette::ButtonText), greenBrush); 0174 QCOMPARE(palette.brush(states[i], QPalette::Highlight), greenBrush); 0175 QCOMPARE(palette.brush(states[i], QPalette::HighlightedText), greenBrush); 0176 QCOMPARE(palette.brush(states[i], QPalette::ToolTipBase), greenBrush); 0177 QCOMPARE(palette.brush(states[i], QPalette::ToolTipText), greenBrush); 0178 0179 // KColorScheme applies modifications and we can't disable them, so I extracted 0180 // the values and blindly compare them. 0181 QCOMPARE(palette.color(states[i], QPalette::Light).green(), 162); 0182 QCOMPARE(palette.color(states[i], QPalette::Midlight).green(), 144); 0183 QCOMPARE(palette.color(states[i], QPalette::Mid).green(), 109); 0184 QCOMPARE(palette.color(states[i], QPalette::Dark).green(), 62); 0185 QCOMPARE(palette.color(states[i], QPalette::Shadow).green(), 43); 0186 0187 QCOMPARE(palette.brush(states[i], QPalette::AlternateBase), greenBrush); 0188 QCOMPARE(palette.brush(states[i], QPalette::Link), greenBrush); 0189 QCOMPARE(palette.brush(states[i], QPalette::LinkVisited), greenBrush); 0190 } 0191 } 0192 0193 void testPlatformIconEngine() 0194 { 0195 QIconEngine *engine = m_qpa->createIconEngine(QStringLiteral("test-icon")); 0196 QCOMPARE(engine->key(), QStringLiteral("KIconEngine")); 0197 } 0198 0199 void testPlatformIconEngineTheme() 0200 { 0201 // The current theme should be what we defined. 0202 KdePlatformTheme().createIconEngine(QStringLiteral("test-icon")); 0203 QCOMPARE(KIconLoader::global()->theme()->current(), QStringLiteral("non-existent-icon-theme")); 0204 } 0205 0206 void testPlatformIconChanges() 0207 { 0208 QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 0209 configPath.append("/kdeglobals"); 0210 QFile::remove(configPath); 0211 QFile::copy(CHANGED_CONFIGFILE, configPath); 0212 0213 QDBusConnection::sessionBus() 0214 .connect(QString(), QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged"), &m_loop, SLOT(quit())); 0215 0216 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged")); 0217 message.setArguments(QList<QVariant>() << int(KIconLoader::MainToolbar)); 0218 QDBusConnection::sessionBus().send(message); 0219 m_loop.exec(); 0220 0221 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ToolBarIconSize).toInt(), 11); 0222 } 0223 0224 void testPlatformHintChanges() 0225 { 0226 EventTest tester(&m_toolBtn, QEvent::StyleChange); 0227 sendNotifyChange(KHintsSettings::SettingsChanged, KHintsSettings::SETTINGS_QT); 0228 m_loop.exec(); 0229 0230 QCOMPARE(qApp->cursorFlashTime(), 1022); 0231 0232 sendNotifyChange(KHintsSettings::SettingsChanged, KHintsSettings::SETTINGS_MOUSE); 0233 m_loop.exec(); 0234 0235 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ItemViewActivateItemOnSingleClick).toBool(), true); 0236 QCOMPARE(qApp->doubleClickInterval(), 401); 0237 QCOMPARE(qApp->startDragDistance(), 35); 0238 QCOMPARE(qApp->startDragTime(), 501); 0239 0240 QCOMPARE(qApp->wheelScrollLines(), 122); 0241 QCOMPARE(qApp->testAttribute(Qt::AA_DontShowIconsInMenus), true); 0242 0243 sendNotifyChange(KHintsSettings::ToolbarStyleChanged, 2); 0244 m_loop.exec(); 0245 0246 QCOMPARE(m_qpa->themeHint(QPlatformTheme::ToolButtonStyle).toInt(), (int)Qt::ToolButtonTextUnderIcon); 0247 QCOMPARE(tester.gotEvent, true); 0248 0249 sendNotifyChange(KHintsSettings::StyleChanged, 2); 0250 m_loop.exec(); 0251 0252 QStringList styles; 0253 styles << QStringLiteral("another-non-existent-widget-style") << QStringLiteral("breeze") << QStringLiteral("oxygen") << QStringLiteral("fusion") 0254 << QStringLiteral("windows"); 0255 QCOMPARE(m_qpa->themeHint(QPlatformTheme::StyleNames).toStringList(), styles); 0256 0257 sendNotifyChange(KHintsSettings::SettingsChanged, KHintsSettings::SETTINGS_STYLE); 0258 m_loop.exec(); 0259 0260 QCOMPARE(m_qpa->themeHint(QPlatformTheme::DialogButtonBoxButtonsHaveIcons).toBool(), true); 0261 0262 sendNotifyChange(KHintsSettings::IconChanged, 4); 0263 m_loop.exec(); 0264 0265 QCOMPARE(m_qpa->themeHint(QPlatformTheme::SystemIconThemeName).toString(), QLatin1String("other-non-existent")); 0266 } 0267 0268 void testPlatformPaletteChanges() 0269 { 0270 EventTest tester(QGuiApplication::instance(), QEvent::ApplicationPaletteChange); 0271 sendNotifyChange(KHintsSettings::PaletteChanged, 0); 0272 m_loop.exec(); 0273 QCOMPARE(tester.gotEvent, true); 0274 0275 const QPalette *palette = m_qpa->palette(); 0276 QPalette::ColorGroup states[3] = {QPalette::Active, QPalette::Inactive, QPalette::Disabled}; 0277 QColor redColor(QColor(174, 11, 11)); 0278 QBrush redBrush(redColor); 0279 for (int i = 0; i < 3; i++) { 0280 QCOMPARE(palette->brush(states[i], QPalette::ButtonText), redBrush); 0281 QCOMPARE(palette->brush(states[i], QPalette::WindowText), redBrush); 0282 QCOMPARE(palette->brush(states[i], QPalette::Window), redBrush); 0283 QCOMPARE(palette->brush(states[i], QPalette::Base), redBrush); 0284 QCOMPARE(palette->brush(states[i], QPalette::Text), redBrush); 0285 QCOMPARE(palette->brush(states[i], QPalette::Button), redBrush); 0286 QCOMPARE(palette->brush(states[i], QPalette::ButtonText), redBrush); 0287 QCOMPARE(palette->brush(states[i], QPalette::Highlight), redBrush); 0288 QCOMPARE(palette->brush(states[i], QPalette::HighlightedText), redBrush); 0289 QCOMPARE(palette->brush(states[i], QPalette::ToolTipBase), redBrush); 0290 QCOMPARE(palette->brush(states[i], QPalette::ToolTipText), redBrush); 0291 0292 // KColorScheme applies modifications and we can't disable them, so I extracted 0293 // the values and blindly compare them. 0294 QCOMPARE(palette->color(states[i], QPalette::Light).red(), 230); 0295 QCOMPARE(palette->color(states[i], QPalette::Midlight).red(), 203); 0296 QCOMPARE(palette->color(states[i], QPalette::Mid).red(), 149); 0297 QCOMPARE(palette->color(states[i], QPalette::Dark).red(), 84); 0298 QCOMPARE(palette->color(states[i], QPalette::Shadow).red(), 60); 0299 0300 QCOMPARE(palette->brush(states[i], QPalette::AlternateBase), redBrush); 0301 QCOMPARE(palette->brush(states[i], QPalette::Link), redBrush); 0302 QCOMPARE(palette->brush(states[i], QPalette::LinkVisited), redBrush); 0303 } 0304 } 0305 0306 void dndWindowFlagsTest() 0307 { 0308 if (!KWindowSystem::isPlatformX11()) { 0309 QSKIP("This test requires xcb platform."); 0310 } 0311 0312 QDrag *drag = new QDrag(this); 0313 QMimeData *data = new QMimeData; 0314 data->setData("Text/Plain", "drag data"); 0315 drag->setMimeData(data); 0316 bool succeeded = false; 0317 QTimer::singleShot(1000, [&succeeded] { 0318 auto windows = QGuiApplication::allWindows(); 0319 auto it = std::find_if(windows.constBegin(), windows.constEnd(), [](QWindow *w) { 0320 return w->inherits("QShapedPixmapWindow"); 0321 }); 0322 if (it != windows.constEnd()) { 0323 KWindowInfo info((*it)->winId(), NET::WMWindowType); 0324 succeeded = info.windowType(NET::DNDIconMask) == NET::DNDIcon; 0325 } 0326 QTest::keyClick(windows.first(), Qt::Key_Escape); 0327 }); 0328 drag->exec(); 0329 QVERIFY(succeeded); 0330 } 0331 }; 0332 0333 QTEST_MAIN(KdePlatformTheme_UnitTest) 0334 0335 #include "kdeplatformtheme_unittest.moc"