File indexing completed on 2024-05-05 17:42:25

0001 /* This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 2000, 2006 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
0004     SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0005     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #include "kfontsettingsdata.h"
0011 #include <QApplication>
0012 #include <QCoreApplication>
0013 #include <QDBusConnection>
0014 #include <QDBusMessage>
0015 #include <QDBusReply>
0016 #include <QString>
0017 #include <QVariant>
0018 #include <qpa/qwindowsysteminterface.h>
0019 
0020 #include <KSandbox>
0021 #include <kconfiggroup.h>
0022 
0023 KFontSettingsData::KFontSettingsData()
0024     : QObject(nullptr)
0025     , mUsePortal(KSandbox::isInside())
0026     , mKdeGlobals(KSharedConfig::openConfig())
0027 {
0028     QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection);
0029 
0030     for (int i = 0; i < FontTypesCount; ++i) {
0031         mFonts[i] = nullptr;
0032     }
0033 }
0034 
0035 KFontSettingsData::~KFontSettingsData()
0036 {
0037     for (int i = 0; i < FontTypesCount; ++i) {
0038         delete mFonts[i];
0039     }
0040 }
0041 
0042 // NOTE: keep in sync with plasma-desktop/kcms/fonts/fonts.cpp
0043 static const char GeneralId[] = "General";
0044 static const char DefaultFont[] = "Noto Sans";
0045 
0046 static const KFontData DefaultFontData[KFontSettingsData::FontTypesCount] = {
0047     {GeneralId, "font", DefaultFont, 10, QFont::Normal, QFont::SansSerif, "Regular"},
0048     {GeneralId, "fixed", "Hack", 10, QFont::Normal, QFont::Monospace, "Regular"},
0049     {GeneralId, "toolBarFont", DefaultFont, 10, QFont::Normal, QFont::SansSerif, "Regular"},
0050     {GeneralId, "menuFont", DefaultFont, 10, QFont::Normal, QFont::SansSerif, "Regular"},
0051     {"WM", "activeFont", DefaultFont, 10, QFont::Normal, QFont::SansSerif, "Regular"},
0052     {GeneralId, "taskbarFont", DefaultFont, 10, QFont::Normal, QFont::SansSerif, "Regular"},
0053     {GeneralId, "smallestReadableFont", DefaultFont, 8, QFont::Normal, QFont::SansSerif, "Regular"},
0054 };
0055 
0056 QFont *KFontSettingsData::font(FontTypes fontType)
0057 {
0058     QFont *cachedFont = mFonts[fontType];
0059 
0060     if (!cachedFont) {
0061         const KFontData &fontData = DefaultFontData[fontType];
0062         cachedFont = new QFont(QLatin1String(fontData.FontName), fontData.Size, fontData.Weight);
0063         cachedFont->setStyleHint(fontData.StyleHint);
0064 
0065         const QString fontInfo = readConfigValue(QLatin1String(fontData.ConfigGroupKey), QLatin1String(fontData.ConfigKey));
0066 
0067         // If we have serialized information for this font, restore it
0068         // NOTE: We are not using KConfig directly because we can't call QFont::QFont from here
0069         if (!fontInfo.isEmpty()) {
0070             cachedFont->fromString(fontInfo);
0071         }
0072         // Don't set default font style names, as it prevents different font weights from being used (the QFont::Normal weight should work)
0073 
0074         mFonts[fontType] = cachedFont;
0075     }
0076 
0077     return cachedFont;
0078 }
0079 
0080 void KFontSettingsData::dropFontSettingsCache()
0081 {
0082     mKdeGlobals->reparseConfiguration();
0083     for (int i = 0; i < FontTypesCount; ++i) {
0084         delete mFonts[i];
0085         mFonts[i] = nullptr;
0086     }
0087 
0088     QWindowSystemInterface::handleThemeChange(nullptr);
0089 
0090     if (qobject_cast<QApplication *>(QCoreApplication::instance())) {
0091         QApplication::setFont(*font(KFontSettingsData::GeneralFont));
0092     } else {
0093         QGuiApplication::setFont(*font(KFontSettingsData::GeneralFont));
0094     }
0095 }
0096 
0097 void KFontSettingsData::delayedDBusConnects()
0098 {
0099     QDBusConnection::sessionBus().connect(QString(),
0100                                           QStringLiteral("/KDEPlatformTheme"),
0101                                           QStringLiteral("org.kde.KDEPlatformTheme"),
0102                                           QStringLiteral("refreshFonts"),
0103                                           this,
0104                                           SLOT(dropFontSettingsCache()));
0105 
0106     if (mUsePortal) {
0107         QDBusConnection::sessionBus().connect(QString(),
0108                                               QStringLiteral("/org/freedesktop/portal/desktop"),
0109                                               QStringLiteral("org.freedesktop.portal.Settings"),
0110                                               QStringLiteral("SettingChanged"),
0111                                               this,
0112                                               SLOT(slotPortalSettingChanged(QString, QString, QDBusVariant)));
0113     }
0114 }
0115 
0116 void KFontSettingsData::slotPortalSettingChanged(const QString &group, const QString &key, const QDBusVariant &value)
0117 {
0118     Q_UNUSED(value);
0119 
0120     if (group == QLatin1String("org.kde.kdeglobals.General") && key == QLatin1String("font")) {
0121         dropFontSettingsCache();
0122     }
0123 }
0124 
0125 QString KFontSettingsData::readConfigValue(const QString &group, const QString &key, const QString &defaultValue) const
0126 {
0127     if (mUsePortal) {
0128         const QString settingName = QStringLiteral("org.kde.kdeglobals.%1").arg(group);
0129         QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.portal.Desktop"),
0130                                                               QStringLiteral("/org/freedesktop/portal/desktop"),
0131                                                               QStringLiteral("org.freedesktop.portal.Settings"),
0132                                                               QStringLiteral("Read"));
0133         message << settingName << key;
0134 
0135         // FIXME: async?
0136         QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(message);
0137         if (reply.isValid()) {
0138             QDBusVariant result = qvariant_cast<QDBusVariant>(reply.value());
0139             const QString resultStr = result.variant().toString();
0140 
0141             if (!resultStr.isEmpty()) {
0142                 return resultStr;
0143             }
0144         }
0145     }
0146 
0147     const KConfigGroup configGroup(mKdeGlobals, group);
0148     return configGroup.readEntry(key, defaultValue);
0149 }