Warning, file /plasma/plasma-workspace/kcms/style/kcmstyle.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KCMStyle 0003 SPDX-FileCopyrightText: 2002 Karol Szwed <gallium@kde.org> 0004 SPDX-FileCopyrightText: 2002 Daniel Molkentin <molkentin@kde.org> 0005 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org> 0006 SPDX-FileCopyrightText: 2009 Davide Bettio <davide.bettio@kdemail.net> 0007 SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@broulik.de> 0008 SPDX-FileCopyrightText: 2019 Cyril Rossi <cyril.rossi@enioka.com> 0009 0010 SPDX-FileCopyrightText: 2007 Paolo Capriotti <p.capriotti@gmail.com> 0011 SPDX-FileCopyrightText: 2007 Ivan Cukic <ivan.cukic+kde@gmail.com> 0012 SPDX-FileCopyrightText: 2008 Petri Damsten <damu@iki.fi> 0013 SPDX-FileCopyrightText: 2000 TrollTech AS. 0014 0015 SPDX-License-Identifier: GPL-2.0-only 0016 */ 0017 0018 #include "kcmstyle.h" 0019 #include "kcm_style_debug.h" 0020 0021 #include "../kcms-common_p.h" 0022 #include "styleconfdialog.h" 0023 0024 #include <KConfigGroup> 0025 #include <KLocalizedString> 0026 #include <KPluginFactory> 0027 #include <KToolBar> 0028 0029 #include <QDBusPendingCallWatcher> 0030 #include <QDBusPendingReply> 0031 #include <QLibrary> 0032 #include <QMetaEnum> 0033 #include <QQuickItem> 0034 #include <QQuickRenderControl> 0035 #include <QQuickWindow> 0036 #include <QStyleFactory> 0037 #include <QWidget> 0038 #include <QWindow> 0039 0040 #include "krdb.h" 0041 0042 #include "kded_interface.h" 0043 0044 #include "previewitem.h" 0045 #include "styledata.h" 0046 0047 K_PLUGIN_FACTORY_WITH_JSON(KCMStyleFactory, "kcm_style.json", registerPlugin<KCMStyle>(); registerPlugin<StyleData>();) 0048 0049 extern "C" { 0050 Q_DECL_EXPORT void kcminit() 0051 { 0052 uint flags = KRdbExportQtSettings | KRdbExportQtColors | KRdbExportXftSettings | KRdbExportGtkTheme; 0053 KConfig _config(QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals); 0054 KConfigGroup config(&_config, "X11"); 0055 0056 // This key is written by the "colors" module. 0057 bool exportKDEColors = config.readEntry("exportKDEColors", true); 0058 if (exportKDEColors) { 0059 flags |= KRdbExportColors; 0060 } 0061 runRdb(flags); 0062 } 0063 } 0064 0065 KCMStyle::KCMStyle(QObject *parent, const KPluginMetaData &data, const QVariantList &args) 0066 : KQuickAddons::ManagedConfigModule(parent, data, args) 0067 , m_data(new StyleData(this)) 0068 , m_model(new StylesModel(this)) 0069 { 0070 const char *uri{"org.kde.private.kcms.style"}; 0071 0072 qmlRegisterUncreatableType<KCMStyle>(uri, 1, 0, "KCM", QStringLiteral("Cannot create instances of KCM")); 0073 qmlRegisterAnonymousType<StyleSettings>(uri, 1); 0074 qmlRegisterAnonymousType<StylesModel>(uri, 1); 0075 qmlRegisterType<PreviewItem>(uri, 1, 0, "PreviewItem"); 0076 0077 connect(m_model, &StylesModel::selectedStyleChanged, this, [this](const QString &style) { 0078 styleSettings()->setWidgetStyle(style); 0079 }); 0080 connect(styleSettings(), &StyleSettings::widgetStyleChanged, this, [this] { 0081 m_model->setSelectedStyle(styleSettings()->widgetStyle()); 0082 }); 0083 connect(styleSettings(), &StyleSettings::iconsOnButtonsChanged, this, [this] { 0084 m_effectsDirty = true; 0085 }); 0086 connect(styleSettings(), &StyleSettings::iconsInMenusChanged, this, [this] { 0087 m_effectsDirty = true; 0088 }); 0089 0090 m_gtkPage = new GtkPage(this); 0091 connect(m_gtkPage, &GtkPage::gtkThemeSettingsChanged, this, [this]() { 0092 settingsChanged(); 0093 }); 0094 } 0095 0096 KCMStyle::~KCMStyle() = default; 0097 0098 GtkPage *KCMStyle::gtkPage() const 0099 { 0100 return m_gtkPage; 0101 } 0102 0103 StylesModel *KCMStyle::model() const 0104 { 0105 return m_model; 0106 } 0107 0108 StyleSettings *KCMStyle::styleSettings() const 0109 { 0110 return m_data->settings(); 0111 } 0112 0113 KCMStyle::ToolBarStyle KCMStyle::mainToolBarStyle() const 0114 { 0115 return m_mainToolBarStyle; 0116 } 0117 0118 void KCMStyle::setMainToolBarStyle(ToolBarStyle style) 0119 { 0120 if (m_mainToolBarStyle != style) { 0121 m_mainToolBarStyle = style; 0122 Q_EMIT mainToolBarStyleChanged(); 0123 0124 const QMetaEnum toolBarStyleEnum = QMetaEnum::fromType<ToolBarStyle>(); 0125 styleSettings()->setToolButtonStyle(toolBarStyleEnum.valueToKey(m_mainToolBarStyle)); 0126 m_effectsDirty = true; 0127 } 0128 } 0129 0130 KCMStyle::ToolBarStyle KCMStyle::otherToolBarStyle() const 0131 { 0132 return m_otherToolBarStyle; 0133 } 0134 0135 void KCMStyle::setOtherToolBarStyle(ToolBarStyle style) 0136 { 0137 if (m_otherToolBarStyle != style) { 0138 m_otherToolBarStyle = style; 0139 Q_EMIT otherToolBarStyleChanged(); 0140 0141 const QMetaEnum toolBarStyleEnum = QMetaEnum::fromType<ToolBarStyle>(); 0142 styleSettings()->setToolButtonStyleOtherToolbars(toolBarStyleEnum.valueToKey(m_otherToolBarStyle)); 0143 m_effectsDirty = true; 0144 } 0145 } 0146 0147 void KCMStyle::configure(const QString &title, const QString &styleName, QQuickItem *ctx) 0148 { 0149 if (m_styleConfigDialog) { 0150 return; 0151 } 0152 0153 const QString configPage = m_model->styleConfigPage(styleName); 0154 if (configPage.isEmpty()) { 0155 return; 0156 } 0157 0158 QLibrary library(QPluginLoader(configPage).fileName()); 0159 if (!library.load()) { 0160 qCWarning(KCM_STYLE_DEBUG) << "Failed to load style config page" << configPage << library.errorString(); 0161 Q_EMIT showErrorMessage(i18n("There was an error loading the configuration dialog for this style.")); 0162 return; 0163 } 0164 0165 auto allocPtr = library.resolve("allocate_kstyle_config"); 0166 if (!allocPtr) { 0167 qCWarning(KCM_STYLE_DEBUG) << "Failed to resolve allocate_kstyle_config in" << configPage; 0168 Q_EMIT showErrorMessage(i18n("There was an error loading the configuration dialog for this style.")); 0169 return; 0170 } 0171 0172 m_styleConfigDialog = new StyleConfigDialog(nullptr /*this*/, title); 0173 m_styleConfigDialog->setAttribute(Qt::WA_DeleteOnClose); 0174 m_styleConfigDialog->setWindowModality(Qt::WindowModal); 0175 m_styleConfigDialog->winId(); // so it creates windowHandle 0176 0177 if (ctx && ctx->window()) { 0178 if (QWindow *actualWindow = QQuickRenderControl::renderWindowFor(ctx->window())) { 0179 m_styleConfigDialog->windowHandle()->setTransientParent(actualWindow); 0180 } 0181 } 0182 0183 typedef QWidget *(*factoryRoutine)(QWidget * parent); 0184 0185 // Get the factory, and make the widget. 0186 factoryRoutine factory = (factoryRoutine)(allocPtr); // Grmbl. So here I am on my 0187 //"never use C casts" moralizing streak, and I find that one can't go void* -> function ptr 0188 // even with a reinterpret_cast. 0189 0190 QWidget *pluginConfig = factory(m_styleConfigDialog.data()); 0191 0192 // Insert it in... 0193 m_styleConfigDialog->setMainWidget(pluginConfig); 0194 0195 //..and connect it to the wrapper 0196 connect(pluginConfig, SIGNAL(changed(bool)), m_styleConfigDialog.data(), SLOT(setDirty(bool))); 0197 connect(m_styleConfigDialog.data(), SIGNAL(defaults()), pluginConfig, SLOT(defaults())); 0198 connect(m_styleConfigDialog.data(), SIGNAL(save()), pluginConfig, SLOT(save())); 0199 0200 connect(m_styleConfigDialog.data(), &QDialog::accepted, this, [this, styleName] { 0201 if (!m_styleConfigDialog->isDirty()) { 0202 return; 0203 } 0204 0205 // Force re-rendering of the preview, to apply settings 0206 Q_EMIT styleReconfigured(styleName); 0207 0208 // For now, ask all KDE apps to recreate their styles to apply the setitngs 0209 notifyKcmChange(GlobalChangeType::StyleChanged); 0210 0211 // When user edited a style, assume they want to use it, too 0212 styleSettings()->setWidgetStyle(styleName); 0213 }); 0214 0215 m_styleConfigDialog->show(); 0216 } 0217 0218 bool KCMStyle::gtkConfigKdedModuleLoaded() const 0219 { 0220 return m_gtkConfigKdedModuleLoaded; 0221 } 0222 0223 void KCMStyle::checkGtkConfigKdedModuleLoaded() 0224 { 0225 org::kde::kded5 kdedInterface(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QDBusConnection::sessionBus()); 0226 auto call = kdedInterface.loadedModules(); 0227 auto *watcher = new QDBusPendingCallWatcher(call, this); 0228 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0229 QDBusPendingReply<QStringList> reply = *watcher; 0230 watcher->deleteLater(); 0231 0232 if (reply.isError()) { 0233 qCWarning(KCM_STYLE_DEBUG) << "Failed to check whether GTK Config KDED module is loaded" << reply.error().message(); 0234 return; 0235 } 0236 0237 const bool isLoaded = reply.value().contains(QLatin1String("gtkconfig")); 0238 if (m_gtkConfigKdedModuleLoaded != isLoaded) { 0239 m_gtkConfigKdedModuleLoaded = isLoaded; 0240 Q_EMIT gtkConfigKdedModuleLoadedChanged(); 0241 } 0242 }); 0243 } 0244 0245 void KCMStyle::load() 0246 { 0247 checkGtkConfigKdedModuleLoaded(); 0248 0249 m_gtkPage->load(); 0250 0251 ManagedConfigModule::load(); 0252 m_model->load(); 0253 m_previousStyle = styleSettings()->widgetStyle(); 0254 0255 loadSettingsToModel(); 0256 0257 m_effectsDirty = false; 0258 } 0259 0260 void KCMStyle::save() 0261 { 0262 m_gtkPage->save(); 0263 0264 // Check whether the new style can actually be loaded before saving it. 0265 // Otherwise apps will use the default style despite something else having been written to the config 0266 bool newStyleLoaded = false; 0267 if (styleSettings()->widgetStyle() != m_previousStyle) { 0268 std::unique_ptr<QStyle> newStyle(QStyleFactory::create(styleSettings()->widgetStyle())); 0269 if (newStyle) { 0270 newStyleLoaded = true; 0271 m_previousStyle = styleSettings()->widgetStyle(); 0272 } else { 0273 const QString styleDisplay = m_model->data(m_model->index(m_model->indexOfStyle(styleSettings()->widgetStyle()), 0), Qt::DisplayRole).toString(); 0274 Q_EMIT showErrorMessage(i18n("Failed to apply selected style '%1'.", styleDisplay)); 0275 0276 // Reset selected style back to current in case of failure 0277 styleSettings()->setWidgetStyle(m_previousStyle); 0278 } 0279 } 0280 0281 ManagedConfigModule::save(); 0282 0283 // Export the changes we made to qtrc, and update all qt-only 0284 // applications on the fly, ensuring that we still follow the user's 0285 // export fonts/colors settings. 0286 uint flags = KRdbExportQtSettings | KRdbExportGtkTheme; 0287 KConfig _kconfig(QStringLiteral("kcmdisplayrc"), KConfig::NoGlobals); 0288 KConfigGroup kconfig(&_kconfig, "X11"); 0289 bool exportKDEColors = kconfig.readEntry("exportKDEColors", true); 0290 if (exportKDEColors) { 0291 flags |= KRdbExportColors; 0292 } 0293 runRdb(flags); 0294 0295 // Now allow KDE apps to reconfigure themselves. 0296 if (newStyleLoaded) { 0297 notifyKcmChange(GlobalChangeType::StyleChanged); 0298 } 0299 0300 if (m_effectsDirty) { 0301 // This notifies listeners about: 0302 // - GraphicEffectsLevel' config entry, (e.g. to set QPlatformTheme::ThemeHint::UiEffects) 0303 // - ShowIconsOnPushButtons config entry, (e.g. to set QPlatformTheme::DialogButtonBoxButtonsHaveIcons) 0304 notifyKcmChange(GlobalChangeType::SettingsChanged, GlobalSettingsCategory::SETTINGS_STYLE); 0305 0306 // FIXME - Doesn't apply all settings correctly due to bugs in KApplication/KToolbar. 0307 // Is this ^ still an issue? 0308 KToolBar::emitToolbarStyleChanged(); 0309 } 0310 0311 m_effectsDirty = false; 0312 } 0313 0314 void KCMStyle::defaults() 0315 { 0316 m_gtkPage->defaults(); 0317 0318 // TODO the old code had a fallback chain but do we actually support not having Breeze for Plasma? 0319 // defaultStyle() -> oxygen -> plastique -> windows -> platinum -> motif 0320 0321 ManagedConfigModule::defaults(); 0322 0323 loadSettingsToModel(); 0324 } 0325 0326 void KCMStyle::loadSettingsToModel() 0327 { 0328 Q_EMIT styleSettings()->widgetStyleChanged(); 0329 0330 const QMetaEnum toolBarStyleEnum = QMetaEnum::fromType<ToolBarStyle>(); 0331 setMainToolBarStyle(static_cast<ToolBarStyle>(toolBarStyleEnum.keyToValue(qUtf8Printable(styleSettings()->toolButtonStyle())))); 0332 setOtherToolBarStyle(static_cast<ToolBarStyle>(toolBarStyleEnum.keyToValue(qUtf8Printable(styleSettings()->toolButtonStyleOtherToolbars())))); 0333 } 0334 0335 bool KCMStyle::isDefaults() const 0336 { 0337 return m_gtkPage->isDefaults(); 0338 } 0339 0340 bool KCMStyle::isSaveNeeded() const 0341 { 0342 return m_gtkPage->isSaveNeeded(); 0343 } 0344 0345 #include "kcmstyle.moc"