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

0001 /*  This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 2013 Kevin Ottens <ervin+bluesystems@kde.org>
0003     SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0004     SPDX-FileCopyrightText: 2013 Alejandro Fiestas Olivares <afiestas@kde.org>
0005     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008 */
0009 
0010 #include "khintssettings.h"
0011 
0012 #include <QApplication>
0013 #include <QDebug>
0014 #include <QDialogButtonBox>
0015 #include <QDir>
0016 #include <QFileInfo>
0017 #include <QGuiApplication>
0018 #include <QMainWindow>
0019 #include <QPalette>
0020 #include <QScreen>
0021 #include <QStandardPaths>
0022 #include <QString>
0023 #include <QTemporaryFile>
0024 #include <QToolBar>
0025 #include <QToolButton>
0026 
0027 #include <QDBusArgument>
0028 #include <QDBusConnection>
0029 #include <QDBusInterface>
0030 
0031 #include <KSandbox>
0032 #include <kcolorscheme.h>
0033 #include <kconfiggroup.h>
0034 #include <kiconloader.h>
0035 
0036 #include <config-platformtheme.h>
0037 #ifdef UNIT_TEST
0038 #undef HAVE_X11
0039 #define HAVE_X11 0
0040 #endif
0041 #if HAVE_X11
0042 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0043 #include <private/qtx11extras_p.h>
0044 #else
0045 #include <QX11Info>
0046 #endif
0047 #include <X11/Xcursor/Xcursor.h>
0048 #endif
0049 
0050 static const QString defaultLookAndFeelPackage = QStringLiteral("org.kde.breeze.desktop");
0051 
0052 const QDBusArgument &operator>>(const QDBusArgument &argument, QMap<QString, QVariantMap> &map)
0053 {
0054     argument.beginMap();
0055     map.clear();
0056 
0057     while (!argument.atEnd()) {
0058         QString key;
0059         QVariantMap value;
0060         argument.beginMapEntry();
0061         argument >> key >> value;
0062         argument.endMapEntry();
0063         map.insert(key, value);
0064     }
0065 
0066     argument.endMap();
0067     return argument;
0068 }
0069 
0070 KHintsSettings::KHintsSettings(const KSharedConfig::Ptr &kdeglobals)
0071     : QObject(nullptr)
0072     , mKdeGlobals(kdeglobals)
0073     , mUsePortal(KSandbox::isInside())
0074 {
0075     if (!mKdeGlobals) {
0076         mKdeGlobals = KSharedConfig::openConfig();
0077     }
0078     KConfigGroup cg(mKdeGlobals, "KDE");
0079 
0080     if (mUsePortal) {
0081         updatePortalSetting();
0082     }
0083 
0084     const auto cursorBlinkRate = readConfigValue(cg, QStringLiteral("CursorBlinkRate"), 1000).toInt();
0085     m_hints[QPlatformTheme::CursorFlashTime] = cursorBlinkRate > 0 ? qBound(200, cursorBlinkRate, 2000) : 0; // 0 => no blinking
0086     m_hints[QPlatformTheme::MouseDoubleClickInterval] = readConfigValue(cg, QStringLiteral("DoubleClickInterval"), 400);
0087     m_hints[QPlatformTheme::StartDragDistance] = readConfigValue(cg, QStringLiteral("StartDragDist"), 10);
0088     m_hints[QPlatformTheme::StartDragTime] = readConfigValue(cg, QStringLiteral("StartDragTime"), 500);
0089 
0090     KConfigGroup cgToolbar(mKdeGlobals, "Toolbar style");
0091     m_hints[QPlatformTheme::ToolButtonStyle] = toolButtonStyle(cgToolbar);
0092 
0093     KConfigGroup cgToolbarIcon(mKdeGlobals, "MainToolbarIcons");
0094     m_hints[QPlatformTheme::ToolBarIconSize] = readConfigValue(cgToolbarIcon, QStringLiteral("Size"), 22);
0095 
0096     m_hints[QPlatformTheme::ItemViewActivateItemOnSingleClick] = readConfigValue(cg, QStringLiteral("SingleClick"), true);
0097 
0098     m_hints[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("breeze"));
0099 
0100     m_hints[QPlatformTheme::SystemIconFallbackThemeName] = QStringLiteral("hicolor");
0101     m_hints[QPlatformTheme::IconThemeSearchPaths] = xdgIconThemePaths();
0102 
0103     QStringList styleNames{
0104         QStringLiteral(BREEZE_STYLE_NAME),
0105         QStringLiteral("oxygen"),
0106         QStringLiteral("fusion"),
0107         QStringLiteral("windows"),
0108     };
0109     const QString configuredStyle = readConfigValue(cg, QStringLiteral("widgetStyle"), QString()).toString();
0110     if (!configuredStyle.isEmpty()) {
0111         styleNames.removeOne(configuredStyle);
0112         styleNames.prepend(configuredStyle);
0113     }
0114     const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString();
0115     if (!lnfStyle.isEmpty()) {
0116         styleNames.removeOne(lnfStyle);
0117         styleNames.prepend(lnfStyle);
0118     }
0119     m_hints[QPlatformTheme::StyleNames] = styleNames;
0120 
0121     m_hints[QPlatformTheme::DialogButtonBoxLayout] = QDialogButtonBox::KdeLayout;
0122     m_hints[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = readConfigValue(cg, QStringLiteral("ShowIconsOnPushButtons"), true);
0123     m_hints[QPlatformTheme::UseFullScreenForPopupMenu] = true;
0124     m_hints[QPlatformTheme::KeyboardScheme] = QPlatformTheme::KdeKeyboardScheme;
0125 
0126     int uiEffectsFlags = readConfigValue(cg, QStringLiteral("GraphicEffectsLevel"), 0) != 0 ? QPlatformTheme::GeneralUiEffect : 0;
0127     uiEffectsFlags |= QPlatformTheme::HoverEffect;
0128     m_hints[QPlatformTheme::UiEffects] = uiEffectsFlags;
0129 
0130     m_hints[QPlatformTheme::IconPixmapSizes] = QVariant::fromValue(QList<int>() << 512 << 256 << 128 << 64 << 32 << 22 << 16 << 8);
0131 
0132     m_hints[QPlatformTheme::WheelScrollLines] = readConfigValue(cg, QStringLiteral("WheelScrollLines"), 3);
0133     if (qobject_cast<QApplication *>(QCoreApplication::instance())) {
0134         QApplication::setWheelScrollLines(readConfigValue(cg, QStringLiteral("WheelScrollLines"), 3).toInt());
0135     }
0136 
0137     updateShowIconsInMenuItems(cg);
0138 
0139     m_hints[QPlatformTheme::ShowShortcutsInContextMenus] = true;
0140 
0141     QMetaObject::invokeMethod(this, "delayedDBusConnects", Qt::QueuedConnection);
0142     QMetaObject::invokeMethod(this, "setupIconLoader", Qt::QueuedConnection);
0143 
0144     loadPalettes();
0145 }
0146 
0147 KHintsSettings::~KHintsSettings()
0148 {
0149     qDeleteAll(m_palettes);
0150 }
0151 
0152 QVariant KHintsSettings::readConfigValue(const QString &group, const QString &key, const QVariant &defaultValue)
0153 {
0154     KConfigGroup userCg(mKdeGlobals, group);
0155     return readConfigValue(userCg, key, defaultValue);
0156 }
0157 
0158 QVariant KHintsSettings::readConfigValue(const KConfigGroup &cg, const QString &key, const QVariant &defaultValue) const
0159 {
0160     if (mUsePortal) {
0161         const QString settingName = QStringLiteral("org.kde.kdeglobals.%1").arg(cg.name());
0162         auto groupIt = mKdeGlobalsPortal.constFind(settingName);
0163         if (groupIt != mKdeGlobalsPortal.constEnd()) {
0164             auto valueIt = groupIt.value().constFind(key);
0165             if (valueIt != groupIt.value().constEnd()) {
0166                 return valueIt.value();
0167             }
0168         }
0169     }
0170 
0171     return cg.readEntry(key, defaultValue);
0172 }
0173 
0174 QStringList KHintsSettings::xdgIconThemePaths() const
0175 {
0176     QStringList paths;
0177 
0178     // make sure we have ~/.local/share/icons in paths if it exists
0179     paths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory);
0180 
0181     const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons"));
0182     if (homeIconDir.isDir()) {
0183         paths << homeIconDir.absoluteFilePath();
0184     }
0185 
0186     return paths;
0187 }
0188 
0189 void KHintsSettings::delayedDBusConnects()
0190 {
0191     QDBusConnection::sessionBus()
0192         .connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), this, SLOT(toolbarStyleChanged()));
0193     QDBusConnection::sessionBus().connect(QString(),
0194                                           QStringLiteral("/KGlobalSettings"),
0195                                           QStringLiteral("org.kde.KGlobalSettings"),
0196                                           QStringLiteral("notifyChange"),
0197                                           this,
0198                                           SLOT(slotNotifyChange(int, int)));
0199     if (mUsePortal) {
0200         QDBusConnection::sessionBus().connect(QString(),
0201                                               QStringLiteral("/org/freedesktop/portal/desktop"),
0202                                               QStringLiteral("org.freedesktop.portal.Settings"),
0203                                               QStringLiteral("SettingChanged"),
0204                                               this,
0205                                               SLOT(slotPortalSettingChanged(QString, QString, QDBusVariant)));
0206     }
0207 }
0208 
0209 void KHintsSettings::setupIconLoader()
0210 {
0211     connect(KIconLoader::global(), &KIconLoader::iconChanged, this, &KHintsSettings::iconChanged);
0212 }
0213 
0214 void KHintsSettings::toolbarStyleChanged()
0215 {
0216     mKdeGlobals->reparseConfiguration();
0217     KConfigGroup cg(mKdeGlobals, "Toolbar style");
0218 
0219     m_hints[QPlatformTheme::ToolButtonStyle] = toolButtonStyle(cg);
0220     // from gtksymbol.cpp
0221     QWidgetList widgets = QApplication::allWidgets();
0222     for (int i = 0; i < widgets.size(); ++i) {
0223         QWidget *widget = widgets.at(i);
0224         if (qobject_cast<QToolButton *>(widget)) {
0225             QEvent event(QEvent::StyleChange);
0226             QApplication::sendEvent(widget, &event);
0227         }
0228     }
0229 }
0230 
0231 void KHintsSettings::slotNotifyChange(int type, int arg)
0232 {
0233     mKdeGlobals->reparseConfiguration();
0234     KConfigGroup cg(mKdeGlobals, "KDE");
0235 
0236     switch (type) {
0237     case PaletteChanged: {
0238         // Don't change the palette if the application has a custom one set
0239         if (!qApp->property("KDE_COLOR_SCHEME_PATH").toString().isEmpty()) {
0240             break;
0241         }
0242         loadPalettes();
0243 
0244         // QApplication::setPalette and QGuiApplication::setPalette are different functions
0245         // and non virtual. Call the correct one
0246         if (qobject_cast<QApplication *>(QCoreApplication::instance())) {
0247             QPalette palette = *m_palettes[QPlatformTheme::SystemPalette];
0248             QApplication::setPalette(palette);
0249             // QTBUG QGuiApplication::paletteChanged() signal is only emitted by QGuiApplication
0250             // so things like SystemPalette QtQuick item that use it won't notice a palette
0251             // change when a QApplication which causes e.g. QML System Settings modules to not update
0252             Q_EMIT qApp->paletteChanged(palette);
0253         } else if (qobject_cast<QGuiApplication *>(QCoreApplication::instance())) {
0254             QGuiApplication::setPalette(*m_palettes[QPlatformTheme::SystemPalette]);
0255         }
0256         break;
0257     }
0258     case SettingsChanged: {
0259         SettingsCategory category = static_cast<SettingsCategory>(arg);
0260         if (category == SETTINGS_QT || category == SETTINGS_MOUSE) {
0261             updateQtSettings(cg);
0262         } else if (category == SETTINGS_STYLE) {
0263             m_hints[QPlatformTheme::DialogButtonBoxButtonsHaveIcons] = cg.readEntry("ShowIconsOnPushButtons", true);
0264             m_hints[QPlatformTheme::UiEffects] = cg.readEntry("GraphicEffectsLevel", 0) != 0 ? QPlatformTheme::GeneralUiEffect : 0;
0265 
0266             updateShowIconsInMenuItems(cg);
0267         }
0268         break;
0269     }
0270     case ToolbarStyleChanged: {
0271         toolbarStyleChanged();
0272         break;
0273     }
0274     case IconChanged:
0275         iconChanged(arg); // Once the KCM is ported to use IconChanged, this should not be needed
0276         break;
0277     case CursorChanged:
0278         updateCursorTheme();
0279         break;
0280     case StyleChanged: {
0281         QApplication *app = qobject_cast<QApplication *>(QCoreApplication::instance());
0282         if (!app) {
0283             return;
0284         }
0285 
0286         // HOTFIX here. Hardcoded default value is duplicated and may be inconsistent with the one actually defined in kcm_style kcfg
0287         const QString theme = readConfigValue(cg, QStringLiteral("widgetStyle"), QStringLiteral(BREEZE_STYLE_NAME)).toString();
0288 
0289         QStringList styleNames;
0290         if (theme != QStringLiteral(BREEZE_STYLE_NAME)) {
0291             styleNames << theme;
0292         }
0293         styleNames << QStringLiteral(BREEZE_STYLE_NAME) << QStringLiteral("oxygen") << QStringLiteral("fusion") << QStringLiteral("windows");
0294         const QString lnfStyle = readConfigValue(QStringLiteral("KDE"), QStringLiteral("widgetStyle"), QString()).toString();
0295         if (!lnfStyle.isEmpty() && !styleNames.contains(lnfStyle)) {
0296             styleNames.prepend(lnfStyle);
0297         }
0298         m_hints[QPlatformTheme::StyleNames] = styleNames;
0299 
0300         app->setStyle(theme);
0301         loadPalettes();
0302         break;
0303     }
0304     default:
0305         qWarning() << "Unknown type of change in KGlobalSettings::slotNotifyChange: " << type;
0306     }
0307 }
0308 
0309 void KHintsSettings::slotPortalSettingChanged(const QString &group, const QString &key, const QDBusVariant &value)
0310 {
0311     if (group == QLatin1String("org.kde.kdeglobals.General") && key == QLatin1String("ColorScheme")) {
0312         // For colors obtain complete configuration again
0313         updatePortalSetting();
0314         slotNotifyChange(PaletteChanged, 0);
0315     } else if (group == QLatin1String("org.kde.kdeglobals.KDE") && key == QLatin1String("widgetStyle")) {
0316         mKdeGlobalsPortal[group][key] = value.variant().toString();
0317         slotNotifyChange(StyleChanged, 0);
0318     } else if (group == QLatin1String("org.kde.kdeglobals.Icons") && key == QLatin1String("Theme")) {
0319         mKdeGlobalsPortal[group][key] = value.variant().toString();
0320         // Change icons for each group
0321         for (int i = 0; i <= 5; ++i) {
0322             iconChanged(i);
0323         }
0324     } else if (group == QLatin1String("org.kde.kdeglobals.Toolbar style") && key == QLatin1String("ToolButtonStyle")) {
0325         mKdeGlobalsPortal[group][key] = value.variant().toString();
0326         toolbarStyleChanged();
0327     }
0328 }
0329 
0330 void KHintsSettings::iconChanged(int group)
0331 {
0332     KIconLoader::Group iconGroup = (KIconLoader::Group)group;
0333     if (iconGroup != KIconLoader::MainToolbar) {
0334         m_hints[QPlatformTheme::SystemIconThemeName] = readConfigValue(QStringLiteral("Icons"), QStringLiteral("Theme"), QStringLiteral("breeze"));
0335         return;
0336     }
0337 
0338     const int currentSize = KIconLoader::global()->currentSize(KIconLoader::MainToolbar);
0339     if (m_hints[QPlatformTheme::ToolBarIconSize] == currentSize) {
0340         return;
0341     }
0342 
0343     m_hints[QPlatformTheme::ToolBarIconSize] = currentSize;
0344 
0345     // If we are not a QApplication, means that we are a QGuiApplication, then we do nothing.
0346     if (!qobject_cast<QApplication *>(QCoreApplication::instance())) {
0347         return;
0348     }
0349 
0350     const QWidgetList widgets = QApplication::allWidgets();
0351     for (QWidget *widget : widgets) {
0352         if (qobject_cast<QToolBar *>(widget) || qobject_cast<QMainWindow *>(widget)) {
0353             QEvent event(QEvent::StyleChange);
0354             QApplication::sendEvent(widget, &event);
0355         }
0356     }
0357 }
0358 
0359 void KHintsSettings::updateQtSettings(KConfigGroup &cg)
0360 {
0361     int flash = qBound(200, cg.readEntry("CursorBlinkRate", 1000), 2000);
0362     m_hints[QPlatformTheme::CursorFlashTime] = flash;
0363 
0364     int doubleClickInterval = cg.readEntry("DoubleClickInterval", 400);
0365     m_hints[QPlatformTheme::MouseDoubleClickInterval] = doubleClickInterval;
0366 
0367     int startDragDistance = cg.readEntry("StartDragDist", 10);
0368     m_hints[QPlatformTheme::StartDragDistance] = startDragDistance;
0369 
0370     int startDragTime = cg.readEntry("StartDragTime", 500);
0371     m_hints[QPlatformTheme::StartDragTime] = startDragTime;
0372 
0373     m_hints[QPlatformTheme::ItemViewActivateItemOnSingleClick] = cg.readEntry("SingleClick", true);
0374 
0375     updateShowIconsInMenuItems(cg);
0376 
0377     int wheelScrollLines = cg.readEntry("WheelScrollLines", 3);
0378     m_hints[QPlatformTheme::WheelScrollLines] = wheelScrollLines;
0379     QApplication *app = qobject_cast<QApplication *>(QCoreApplication::instance());
0380     if (app) {
0381         QApplication::setWheelScrollLines(cg.readEntry("WheelScrollLines", 3));
0382     }
0383 }
0384 
0385 void KHintsSettings::updateShowIconsInMenuItems(KConfigGroup &cg)
0386 {
0387     bool showIcons = readConfigValue(cg, QStringLiteral("ShowIconsInMenuItems"), true).toBool();
0388     QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons);
0389 }
0390 
0391 Qt::ToolButtonStyle KHintsSettings::toolButtonStyle(const KConfigGroup &cg)
0392 {
0393     const QString buttonStyle = readConfigValue(cg, QStringLiteral("ToolButtonStyle"), QStringLiteral("TextBesideIcon")).toString().toLower();
0394     return buttonStyle == QLatin1String("textbesideicon") ? Qt::ToolButtonTextBesideIcon
0395         : buttonStyle == QLatin1String("icontextright")   ? Qt::ToolButtonTextBesideIcon
0396         : buttonStyle == QLatin1String("textundericon")   ? Qt::ToolButtonTextUnderIcon
0397         : buttonStyle == QLatin1String("icontextbottom")  ? Qt::ToolButtonTextUnderIcon
0398         : buttonStyle == QLatin1String("textonly")        ? Qt::ToolButtonTextOnly
0399                                                           : Qt::ToolButtonIconOnly;
0400 }
0401 
0402 void KHintsSettings::loadPalettes()
0403 {
0404     qDeleteAll(m_palettes);
0405     m_palettes.clear();
0406 
0407     if (mUsePortal && mKdeGlobalsPortal.contains(QStringLiteral("org.kde.kdeglobals.Colors:View"))) {
0408         // Construct a temporary KConfig file containing color setting so we can create a KColorScheme from it
0409         QTemporaryFile file;
0410         file.open();
0411 
0412         KSharedConfigPtr tempConfig = KSharedConfig::openConfig(file.fileName(), KConfig::SimpleConfig);
0413         for (auto groupIt = mKdeGlobalsPortal.constBegin(); groupIt != mKdeGlobalsPortal.constEnd(); ++groupIt) {
0414             if (groupIt.key().startsWith(QStringLiteral("org.kde.kdeglobals.Colors:"))) {
0415                 KConfigGroup tempGroup(tempConfig, groupIt.key().right(groupIt.key().length() - QStringLiteral("org.kde.kdeglobals.").length()));
0416                 for (auto valueIt = groupIt.value().constBegin(); valueIt != groupIt.value().constEnd(); ++valueIt) {
0417                     tempGroup.writeEntry(valueIt.key(), valueIt.value());
0418                 }
0419             }
0420         }
0421         m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(tempConfig));
0422     } else if (mKdeGlobals->hasGroup("Colors:View")) {
0423         m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(mKdeGlobals));
0424     } else {
0425         KConfigGroup cg(mKdeGlobals, "KDE");
0426         const QString looknfeel = readConfigValue(cg, QStringLiteral("LookAndFeelPackage"), defaultLookAndFeelPackage).toString();
0427         QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0428                                               QStringLiteral("plasma/look-and-feel/") + looknfeel + QStringLiteral("/contents/colors"));
0429         if (!path.isEmpty()) {
0430             m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path)));
0431             return;
0432         }
0433 
0434         const QString scheme = readConfigValue(QStringLiteral("General"), QStringLiteral("ColorScheme"), QStringLiteral("BreezeLight")).toString();
0435         path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/") + scheme + QStringLiteral(".colors"));
0436 
0437         if (path.isEmpty()) {
0438             qWarning() << "Could not find color scheme" << scheme << "falling back to BreezeLight";
0439             path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes/BreezeLight.colors"));
0440         }
0441 
0442         m_palettes[QPlatformTheme::SystemPalette] = new QPalette(KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path)));
0443     }
0444 }
0445 
0446 void KHintsSettings::updateCursorTheme()
0447 {
0448 #if HAVE_X11
0449     if (QX11Info::isPlatformX11()) {
0450         KConfig config(QStringLiteral("kcminputrc"));
0451         KConfigGroup g(&config, "Mouse");
0452 
0453         int size = g.readEntry("cursorSize", 24);
0454         const QString theme = g.readEntry("cursorTheme", QString());
0455         // Note that in X11R7.1 and earlier, calling XcursorSetTheme()
0456         // with a NULL theme would cause Xcursor to use "default", but
0457         // in 7.2 and later it will cause it to revert to the theme that
0458         // was configured when the application was started.
0459         XcursorSetTheme(QX11Info::display(), theme.isNull() ? "default" : QFile::encodeName(theme).constData());
0460         XcursorSetDefaultSize(QX11Info::display(), size);
0461     }
0462 #endif
0463 }
0464 
0465 void KHintsSettings::updatePortalSetting()
0466 {
0467     mKdeGlobalsPortal.clear();
0468 
0469     QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.portal.Desktop"),
0470                                                           QStringLiteral("/org/freedesktop/portal/desktop"),
0471                                                           QStringLiteral("org.freedesktop.portal.Settings"),
0472                                                           QStringLiteral("ReadAll"));
0473     message << QStringList{QStringLiteral("org.kde.kdeglobals.*")};
0474 
0475     // FIXME: async?
0476     QDBusMessage resultMessage = QDBusConnection::sessionBus().call(message);
0477     if (resultMessage.type() == QDBusMessage::ReplyMessage) {
0478         QDBusArgument dbusArgument = resultMessage.arguments().at(0).value<QDBusArgument>();
0479         dbusArgument >> mKdeGlobalsPortal;
0480     }
0481 }