File indexing completed on 2024-04-28 16:55:48
0001 /* 0002 * SPDX-FileCopyrightText: 2018-2019 Red Hat Inc 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 * 0006 * SPDX-FileCopyrightText: 2018-2019 Jan Grulich <jgrulich@redhat.com> 0007 */ 0008 0009 #include "settings.h" 0010 #include "settings_debug.h" 0011 0012 #include <QApplication> 0013 0014 #include <QDBusConnection> 0015 #include <QDBusContext> 0016 #include <QDBusMessage> 0017 #include <QDBusMetaType> 0018 0019 #include <QPalette> 0020 0021 #include "dbushelpers.h" 0022 #include <KConfigCore/KConfigGroup> 0023 0024 /* accent-color */ 0025 struct AccentColorArray { 0026 double r = 0.0; // 0-1 0027 double g = 0.0; // 0-1 0028 double b = 0.0; // 0-1 0029 0030 operator QVariant() const 0031 { 0032 return QVariant::fromValue(*this); 0033 } 0034 }; 0035 Q_DECLARE_METATYPE(AccentColorArray) 0036 0037 QDBusArgument &operator<<(QDBusArgument &argument, const AccentColorArray &item) 0038 { 0039 argument.beginStructure(); 0040 argument << item.r << item.g << item.b; 0041 argument.endStructure(); 0042 return argument; 0043 } 0044 0045 const QDBusArgument &operator>>(const QDBusArgument &argument, AccentColorArray &item) 0046 { 0047 argument.beginStructure(); 0048 argument >> item.r >> item.g >> item.b; 0049 argument.endStructure(); 0050 return argument; 0051 } 0052 0053 static bool groupMatches(const QString &group, const QStringList &patterns) 0054 { 0055 for (const QString &pattern : patterns) { 0056 if (pattern.isEmpty()) { 0057 return true; 0058 } 0059 0060 if (pattern == group) { 0061 return true; 0062 } 0063 0064 if (pattern.endsWith(QLatin1Char('*')) && group.startsWith(pattern.left(pattern.length() - 1))) { 0065 return true; 0066 } 0067 } 0068 0069 return false; 0070 } 0071 0072 SettingsPortal::SettingsPortal(QObject *parent) 0073 : QDBusAbstractAdaptor(parent) 0074 { 0075 qDBusRegisterMetaType<VariantMapMap>(); 0076 qDBusRegisterMetaType<AccentColorArray>(); 0077 0078 m_kdeglobals = KSharedConfig::openConfig(); 0079 0080 QDBusConnection::sessionBus().connect(QString(), 0081 QStringLiteral("/KDEPlatformTheme"), 0082 QStringLiteral("org.kde.KDEPlatformTheme"), 0083 QStringLiteral("refreshFonts"), 0084 this, 0085 SLOT(fontChanged())); 0086 QDBusConnection::sessionBus().connect(QString(), 0087 QStringLiteral("/KGlobalSettings"), 0088 QStringLiteral("org.kde.KGlobalSettings"), 0089 QStringLiteral("notifyChange"), 0090 this, 0091 SLOT(globalSettingChanged(int, int))); 0092 QDBusConnection::sessionBus() 0093 .connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), this, SLOT(toolbarStyleChanged())); 0094 } 0095 0096 SettingsPortal::~SettingsPortal() 0097 { 0098 } 0099 0100 void SettingsPortal::ReadAll(const QStringList &groups) 0101 { 0102 qCDebug(XdgDesktopPortalKdeSettings) << "ReadAll called with parameters:"; 0103 qCDebug(XdgDesktopPortalKdeSettings) << " groups: " << groups; 0104 0105 // FIXME this is super ugly, but I was unable to make it properly return VariantMapMap 0106 QObject *obj = QObject::parent(); 0107 0108 if (!obj) { 0109 qCWarning(XdgDesktopPortalKdeSettings) << "Failed to get dbus context"; 0110 return; 0111 } 0112 0113 void *ptr = obj->qt_metacast("QDBusContext"); 0114 QDBusContext *q_ptr = reinterpret_cast<QDBusContext *>(ptr); 0115 0116 if (!q_ptr) { 0117 qCWarning(XdgDesktopPortalKdeSettings) << "Failed to get dbus context"; 0118 return; 0119 } 0120 0121 VariantMapMap result; 0122 0123 if (groupMatches(QStringLiteral("org.freedesktop.appearance"), groups)) { 0124 QVariantMap appearanceSettings; 0125 appearanceSettings.insert(QStringLiteral("color-scheme"), readFdoColorScheme().variant()); 0126 appearanceSettings.insert(QStringLiteral("accent-color"), readAccentColor().variant()); 0127 0128 result.insert(QStringLiteral("org.freedesktop.appearance"), appearanceSettings); 0129 } 0130 0131 const auto groupList = m_kdeglobals->groupList(); 0132 for (const QString &settingGroupName : groupList) { 0133 // NOTE: use org.kde.kdeglobals prefix 0134 0135 QString uniqueGroupName = QStringLiteral("org.kde.kdeglobals.") + settingGroupName; 0136 0137 if (!groupMatches(uniqueGroupName, groups)) { 0138 continue; 0139 } 0140 0141 QVariantMap map; 0142 KConfigGroup configGroup(m_kdeglobals, settingGroupName); 0143 0144 const auto keyList = configGroup.keyList(); 0145 for (const QString &key : keyList) { 0146 map.insert(key, configGroup.readEntry(key)); 0147 } 0148 0149 result.insert(uniqueGroupName, map); 0150 } 0151 0152 QDBusMessage message = q_ptr->message(); 0153 QDBusMessage reply = message.createReply(QVariant::fromValue(result)); 0154 QDBusConnection::sessionBus().send(reply); 0155 } 0156 0157 void SettingsPortal::Read(const QString &group, const QString &key) 0158 { 0159 qCDebug(XdgDesktopPortalKdeSettings) << "Read called with parameters:"; 0160 qCDebug(XdgDesktopPortalKdeSettings) << " group: " << group; 0161 qCDebug(XdgDesktopPortalKdeSettings) << " key: " << key; 0162 0163 // FIXME this is super ugly, but I was unable to make it properly return VariantMapMap 0164 QObject *obj = QObject::parent(); 0165 0166 if (!obj) { 0167 qCWarning(XdgDesktopPortalKdeSettings) << "Failed to get dbus context"; 0168 return; 0169 } 0170 0171 void *ptr = obj->qt_metacast("QDBusContext"); 0172 QDBusContext *q_ptr = reinterpret_cast<QDBusContext *>(ptr); 0173 0174 if (!q_ptr) { 0175 qCWarning(XdgDesktopPortalKdeSettings) << "Failed to get dbus context"; 0176 return; 0177 } 0178 0179 QDBusMessage reply; 0180 QDBusMessage message = q_ptr->message(); 0181 0182 if (group == QLatin1String("org.freedesktop.appearance")) { 0183 if (key == QLatin1String("color-scheme")) { 0184 reply = message.createReply(QVariant::fromValue(readFdoColorScheme())); 0185 QDBusConnection::sessionBus().send(reply); 0186 return; 0187 } else if (key == QLatin1String("accent-color")) { 0188 reply = message.createReply(QVariant::fromValue(readAccentColor())); 0189 QDBusConnection::sessionBus().send(reply); 0190 return; 0191 } 0192 } 0193 // All other namespaces start with this prefix 0194 else if (!group.startsWith(QStringLiteral("org.kde.kdeglobals"))) { 0195 qCWarning(XdgDesktopPortalKdeSettings) << "Namespace " << group << " is not supported"; 0196 reply = message.createErrorReply(QDBusError::UnknownProperty, QStringLiteral("Namespace is not supported")); 0197 QDBusConnection::sessionBus().send(reply); 0198 return; 0199 } 0200 0201 QDBusVariant result = readProperty(group, key); 0202 if (result.variant().isNull()) { 0203 reply = message.createErrorReply(QDBusError::UnknownProperty, QStringLiteral("Property doesn't exist")); 0204 } else { 0205 reply = message.createReply(QVariant::fromValue(result)); 0206 } 0207 0208 QDBusConnection::sessionBus().send(reply); 0209 } 0210 0211 void SettingsPortal::fontChanged() 0212 { 0213 Q_EMIT SettingChanged(QStringLiteral("org.kde.kdeglobals.General"), 0214 QStringLiteral("font"), 0215 readProperty(QStringLiteral("org.kde.kdeglobals.General"), QStringLiteral("font"))); 0216 } 0217 0218 void SettingsPortal::globalSettingChanged(int type, int arg) 0219 { 0220 m_kdeglobals->reparseConfiguration(); 0221 0222 // Mostly based on plasma-integration needs 0223 switch (type) { 0224 case PaletteChanged: 0225 // Plasma-integration will be loading whole palette again, there is no reason to try to identify 0226 // particular categories or colors 0227 Q_EMIT SettingChanged(QStringLiteral("org.kde.kdeglobals.General"), 0228 QStringLiteral("ColorScheme"), 0229 readProperty(QStringLiteral("org.kde.kdeglobals.General"), QStringLiteral("ColorScheme"))); 0230 0231 Q_EMIT SettingChanged(QStringLiteral("org.freedesktop.appearance"), QStringLiteral("color-scheme"), readFdoColorScheme()); 0232 0233 // https://github.com/flatpak/xdg-desktop-portal/pull/815 0234 Q_EMIT SettingChanged(QStringLiteral("org.freedesktop.appearance"), QStringLiteral("accent-color"), readAccentColor()); 0235 break; 0236 case FontChanged: 0237 fontChanged(); 0238 break; 0239 case StyleChanged: 0240 Q_EMIT SettingChanged(QStringLiteral("org.kde.kdeglobals.KDE"), 0241 QStringLiteral("widgetStyle"), 0242 readProperty(QStringLiteral("org.kde.kdeglobals.KDE"), QStringLiteral("widgetStyle"))); 0243 break; 0244 case SettingsChanged: { 0245 SettingsCategory category = static_cast<SettingsCategory>(arg); 0246 if (category == SETTINGS_QT || category == SETTINGS_MOUSE) { 0247 // TODO 0248 } else if (category == SETTINGS_STYLE) { 0249 // TODO 0250 } 0251 break; 0252 } 0253 case IconChanged: 0254 // we will get notified about each category, but it probably makes sense to send this signal just once 0255 if (arg == 0) { // KIconLoader::Desktop 0256 Q_EMIT SettingChanged(QStringLiteral("org.kde.kdeglobals.Icons"), 0257 QStringLiteral("Theme"), 0258 readProperty(QStringLiteral("org.kde.kdeglobals.Icons"), QStringLiteral("Theme"))); 0259 } 0260 break; 0261 case CursorChanged: 0262 // TODO 0263 break; 0264 case ToolbarStyleChanged: 0265 toolbarStyleChanged(); 0266 break; 0267 default: 0268 break; 0269 } 0270 } 0271 0272 void SettingsPortal::toolbarStyleChanged() 0273 { 0274 Q_EMIT SettingChanged(QStringLiteral("org.kde.kdeglobals.Toolbar style"), 0275 QStringLiteral("ToolButtonStyle"), 0276 readProperty(QStringLiteral("org.kde.kdeglobals.Toolbar style"), QStringLiteral("ToolButtonStyle"))); 0277 } 0278 0279 QDBusVariant SettingsPortal::readProperty(const QString &group, const QString &key) 0280 { 0281 QString groupName = group.right(group.length() - QStringLiteral("org.kde.kdeglobals.").length()); 0282 0283 if (!m_kdeglobals->hasGroup(groupName)) { 0284 qCWarning(XdgDesktopPortalKdeSettings) << "Group " << group << " doesn't exist"; 0285 return QDBusVariant(); 0286 } 0287 0288 KConfigGroup configGroup(m_kdeglobals, groupName); 0289 0290 if (!configGroup.hasKey(key)) { 0291 qCWarning(XdgDesktopPortalKdeSettings) << "Key " << key << " doesn't exist"; 0292 return QDBusVariant(); 0293 } 0294 0295 return QDBusVariant(configGroup.readEntry(key)); 0296 } 0297 0298 QDBusVariant SettingsPortal::readFdoColorScheme() 0299 { 0300 const QPalette palette = QApplication::palette(); 0301 const int windowBackgroundGray = qGray(palette.window().color().rgb()); 0302 0303 uint result = 0; // no preference 0304 0305 if (windowBackgroundGray < 192) { 0306 result = 1; // prefer dark 0307 } else { 0308 result = 2; // prefer light 0309 } 0310 0311 return QDBusVariant(result); 0312 } 0313 0314 QDBusVariant SettingsPortal::readAccentColor() const 0315 { 0316 const QColor accentColor = qGuiApp->palette().highlight().color(); 0317 return QDBusVariant(AccentColorArray{accentColor.redF(), accentColor.greenF(), accentColor.blueF()}); 0318 }