Warning, file /plasma/plasma-workspace/kcms/wallpaper/wallpapermodule.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #include "wallpapermodule.h" 0002 0003 #include "config-workspace.h" 0004 #include "defaultwallpaper.h" 0005 #include "kcm_wallpaper_debug.h" 0006 #include "qdbusinterface.h" 0007 #include "qdbusreply.h" 0008 #include <defaultwallpaper.h> 0009 #include <outputorderwatcher.h> 0010 0011 #include <KPackage/Package> 0012 #include <KPackage/PackageLoader> 0013 #include <Plasma/Corona> 0014 #include <Plasma/PluginLoader> 0015 0016 #include <KConfig> 0017 #include <KConfigGroup> 0018 #include <KConfigLoader> 0019 #include <KConfigPropertyMap> 0020 #include <KLocalizedString> 0021 #include <KPluginFactory> 0022 #include <plasmaactivities/consumer.h> 0023 0024 #include <QAbstractItemModel> 0025 #include <QApplication> 0026 #include <QDBusArgument> 0027 #include <QDBusConnection> 0028 #include <QDBusMetaType> 0029 #include <QFile> 0030 #include <QQmlEngine> 0031 #include <QQuickItem> 0032 #include <QQuickWindow> 0033 #include <QScreen> 0034 #include <QWindow> 0035 0036 K_PLUGIN_CLASS_WITH_JSON(WallpaperModule, "kcm_wallpaper.json") 0037 0038 Q_DECLARE_METATYPE(QColor) 0039 0040 QDBusArgument &operator<<(QDBusArgument &argument, const QColor &color) 0041 { 0042 argument.beginStructure(); 0043 argument << color.rgba(); 0044 argument.endStructure(); 0045 return argument; 0046 } 0047 0048 const QDBusArgument &operator>>(const QDBusArgument &argument, QColor &color) 0049 { 0050 argument.beginStructure(); 0051 QRgb rgba; 0052 argument >> rgba; 0053 argument.endStructure(); 0054 color = QColor::fromRgba(rgba); 0055 return argument; 0056 } 0057 0058 WallpaperModule::WallpaperModule(QObject *parent, const KPluginMetaData &data) 0059 : KQuickConfigModule(parent, data) 0060 , m_config(KSharedConfig::openConfig(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/plasma-org.kde.plasma.desktop-appletsrc", 0061 KConfig::OpenFlag::SimpleConfig)) 0062 , m_activityConsumer(new KActivities::Consumer(this)) 0063 { 0064 qDBusRegisterMetaType<QColor>(); 0065 0066 KActivities::Consumer c(this); 0067 0068 connect(m_activityConsumer, &KActivities::Consumer::currentActivityChanged, this, &WallpaperModule::setCurrentActivity); 0069 0070 constexpr const char *uri = "org.kde.plasma.kcm.wallpaper"; 0071 0072 qmlRegisterAnonymousType<QScreen>(uri, 1); 0073 qmlRegisterAnonymousType<KConfigPropertyMap>(uri, 1); 0074 // Only register types once 0075 [[maybe_unused]] static int configModelRegisterResult = qmlRegisterType<PlasmaQuick::ConfigModel>("org.kde.plasma.configuration", 2, 0, "ConfigModel"); 0076 0077 m_outputOrderWatcher = OutputOrderWatcher::instance(this); 0078 connect(m_outputOrderWatcher, &OutputOrderWatcher::outputOrderChanged, this, [this](const QStringList &outputOrder) { 0079 if (!outputOrder.contains(m_selectedScreen->name())) { 0080 // current screen was removed 0081 m_selectedScreen = mainUi()->window()->screen(); 0082 Q_EMIT selectedScreenChanged(); 0083 } 0084 onScreenChanged(); 0085 }); 0086 0087 connect(this, &KQuickConfigModule::mainUiReady, this, [this]() { 0088 connect( 0089 mainUi(), 0090 &QQuickItem::windowChanged, 0091 this, 0092 [this]() { 0093 m_selectedScreen = mainUi()->window()->screen(); 0094 Q_EMIT selectedScreenChanged(); 0095 onScreenChanged(); 0096 }, 0097 Qt::ConnectionType::SingleShotConnection); 0098 }); 0099 0100 const bool connected = QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.plasmashell"), 0101 QStringLiteral("/PlasmaShell"), 0102 QStringLiteral("org.kde.PlasmaShell"), 0103 QStringLiteral("wallpaperChanged"), 0104 this, 0105 SLOT(onWallpaperChanged(uint))); 0106 if (!connected) { 0107 qCFatal(KCM_WALLPAPER_DEBUG) << "Could not connect to dbus service org.kde.plasmashell"; 0108 } 0109 0110 setButtons(Apply | Default); 0111 0112 m_screens = qApp->screens(); 0113 connect(qApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) { 0114 m_screens.removeAll(screen); 0115 Q_EMIT screensChanged(); 0116 }); 0117 connect(qApp, &QGuiApplication::screenAdded, this, [this](QScreen *screen) { 0118 m_screens << screen; 0119 Q_EMIT screensChanged(); 0120 }); 0121 } 0122 0123 void WallpaperModule::onScreenChanged() 0124 { 0125 if (m_activityId.isEmpty() || m_activityId == QUuid().toString()) { 0126 return; 0127 } 0128 0129 if (m_selectedScreen == nullptr) { 0130 return; 0131 } 0132 0133 const auto outputOrder = m_outputOrderWatcher->outputOrder(); 0134 if (outputOrder.isEmpty()) { 0135 return; 0136 } 0137 int screenId = screenIdFromName(m_selectedScreen->name()); 0138 Q_ASSERT(screenId != -1); 0139 0140 auto containmentsGroup = m_config->group(QStringLiteral("Containments")); 0141 0142 for (const auto &contIndex : containmentsGroup.groupList()) { 0143 const auto contConfig = containmentsGroup.group(contIndex); 0144 if (m_activityId != contConfig.readEntry("activityId")) { 0145 continue; 0146 } 0147 0148 auto lastScreenIdx = contConfig.readEntry("lastScreen", -1); 0149 if (lastScreenIdx < 0) { 0150 continue; 0151 } 0152 0153 if (lastScreenIdx == screenId) { 0154 m_containmentIdx = contIndex; 0155 break; 0156 } 0157 } 0158 Q_ASSERT(m_containmentIdx != ""); 0159 0160 auto containmentConfigGroup = containmentsGroup.group(m_containmentIdx); 0161 m_loadedWallpaperplugin = containmentConfigGroup.readEntry("wallpaperplugin"); 0162 0163 auto previousConfig = m_wallpaperConfiguration; 0164 setWallpaperPluginConfiguration(m_loadedWallpaperplugin); 0165 0166 setRepresentsDefaults(isDefault()); 0167 setNeedsSave(false); 0168 0169 if (m_loadedWallpaperplugin != m_currentWallpaperPlugin) { 0170 m_currentWallpaperPlugin = m_loadedWallpaperplugin; 0171 Q_EMIT currentWallpaperPluginChanged(); 0172 } else { 0173 Q_EMIT wallpaperConfigurationChanged(); 0174 } 0175 0176 delete previousConfig; 0177 } 0178 0179 int WallpaperModule::screenIdFromName(const QString &screenName) const 0180 { 0181 int screenId = -1; 0182 int idx = 0; 0183 const auto outputOrder = m_outputOrderWatcher->outputOrder(); 0184 for (const auto &output : outputOrder) { 0185 if (output == screenName) { 0186 screenId = idx; 0187 break; 0188 } 0189 ++idx; 0190 } 0191 0192 return screenId; 0193 } 0194 0195 void WallpaperModule::setWallpaperPluginConfiguration(const QString &wallpaperplugin, bool loadDefaults) 0196 { 0197 auto wallpaperConfig = m_config->group(QStringLiteral("Containments")).group(m_containmentIdx).group(QStringLiteral("Wallpaper")).group(wallpaperplugin); 0198 m_wallpaperConfigGeneral = wallpaperConfig.group(QStringLiteral("General")); 0199 0200 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Wallpaper")); 0201 pkg.setDefaultPackageRoot(QStringLiteral(PLASMA_RELATIVE_DATA_INSTALL_DIR "/wallpapers")); 0202 pkg.setPath(wallpaperplugin); 0203 QFile file(pkg.filePath("config", QStringLiteral("main.xml"))); 0204 0205 m_configLoader = new KConfigLoader(wallpaperConfig, &file, this); 0206 if (loadDefaults) { 0207 m_configLoader->setDefaults(); 0208 } 0209 m_wallpaperConfiguration = new KConfigPropertyMap(m_configLoader, this); 0210 0211 // set the default wallpaper value 0212 m_defaultWallpaper = DefaultWallpaper::defaultWallpaperPackage().path(); 0213 m_wallpaperConfiguration->insert(QStringLiteral("ImageDefault"), m_defaultWallpaper); 0214 0215 // set the default Image value if necessary 0216 if (m_wallpaperConfiguration->value(QStringLiteral("Image")).isNull()) { 0217 m_wallpaperConfiguration->insert(QStringLiteral("Image"), m_defaultWallpaper); 0218 } 0219 0220 connect(m_wallpaperConfiguration, &QQmlPropertyMap::valueChanged, this, [this](const QString & /* key */, const QVariant & /* value */) { 0221 setRepresentsDefaults(isDefault()); 0222 setNeedsSave(m_configLoader->isSaveNeeded() || m_loadedWallpaperplugin != m_currentWallpaperPlugin); 0223 }); 0224 } 0225 0226 class WallpaperConfigModel : public PlasmaQuick::ConfigModel 0227 { 0228 Q_OBJECT 0229 0230 public: 0231 WallpaperConfigModel(QObject *parent); 0232 public Q_SLOTS: 0233 void repopulate(); 0234 }; 0235 0236 void WallpaperModule::onWallpaperChanged(uint screenIdx) 0237 { 0238 m_config->markAsClean(); 0239 m_config->reparseConfiguration(); 0240 0241 int screen = screenIdFromName(m_selectedScreen->name()); 0242 if (screen >= 0 && screenIdx == uint(screen)) { 0243 onScreenChanged(); 0244 } 0245 } 0246 0247 void WallpaperModule::setCurrentActivity(const QString &activityId) 0248 { 0249 if (m_activityId != activityId) { 0250 m_activityId = activityId; 0251 onScreenChanged(); 0252 } 0253 } 0254 0255 bool WallpaperModule::isDefault() const 0256 { 0257 if (m_currentWallpaperPlugin != QStringLiteral("org.kde.image")) { 0258 return false; 0259 } 0260 for (const auto &item : m_configLoader->items()) { 0261 if (!item->isDefault()) { 0262 if (item->name() == QStringLiteral("Image") && item->property() == m_defaultWallpaper) { 0263 continue; 0264 } 0265 if (item->name() == QStringLiteral("SlidePaths")) { 0266 continue; 0267 } 0268 return false; 0269 } 0270 } 0271 return true; 0272 } 0273 0274 void WallpaperModule::defaults() 0275 { 0276 KQuickConfigModule::defaults(); 0277 0278 if (m_currentWallpaperPlugin != QStringLiteral("org.kde.image")) { 0279 setCurrentWallpaperPlugin(QStringLiteral("org.kde.image")); 0280 Q_EMIT currentWallpaperPluginChanged(); 0281 } 0282 0283 auto previousConfig = m_wallpaperConfiguration; 0284 disconnect(previousConfig, nullptr); 0285 0286 setWallpaperPluginConfiguration(m_currentWallpaperPlugin, true); 0287 m_wallpaperConfiguration->insert(QStringLiteral("Image"), m_defaultWallpaper); 0288 0289 setRepresentsDefaults(isDefault()); 0290 setNeedsSave(m_configLoader->isSaveNeeded() || m_loadedWallpaperplugin != m_currentWallpaperPlugin); 0291 0292 Q_EMIT wallpaperConfigurationChanged(); 0293 0294 delete previousConfig; 0295 } 0296 0297 void WallpaperModule::load() 0298 { 0299 KQuickConfigModule::load(); 0300 onScreenChanged(); 0301 } 0302 0303 void WallpaperModule::save() 0304 { 0305 KQuickConfigModule::save(); 0306 auto iface = new QDBusInterface("org.kde.plasmashell", "/PlasmaShell", "org.kde.PlasmaShell", QDBusConnection::sessionBus(), this); 0307 if (!iface->isValid()) { 0308 qCWarning(KCM_WALLPAPER_DEBUG) << qPrintable(QDBusConnection::sessionBus().lastError().message()); 0309 return; 0310 } 0311 0312 QList<uint> screenIds; 0313 0314 if (m_allScreens) { 0315 uint idx = 0; 0316 const auto outputOrder = m_outputOrderWatcher->outputOrder(); 0317 for (const auto &output : outputOrder) { 0318 screenIds.append(idx); 0319 ++idx; 0320 } 0321 } else { 0322 int screenId = screenIdFromName(m_selectedScreen->name()); 0323 if (screenId == -1) { 0324 qCWarning(KCM_WALLPAPER_DEBUG) << "Screen not found"; 0325 return; 0326 } 0327 screenIds.append(uint(screenId)); 0328 } 0329 0330 QVariantMap params; 0331 for (const auto &key : m_wallpaperConfiguration->keys()) { 0332 params.insert(key, m_wallpaperConfiguration->value(key)); 0333 } 0334 0335 if (m_currentWallpaperPlugin == QLatin1String("org.kde.image")) { 0336 params.remove(QStringLiteral("PreviewImage")); 0337 } 0338 0339 for (const uint screenId : screenIds) { 0340 const QDBusReply<void> response = iface->call(QStringLiteral("setWallpaper"), m_currentWallpaperPlugin, params, screenId); 0341 if (!response.isValid()) { 0342 qCWarning(KCM_WALLPAPER_DEBUG) << "failed to set wallpaper:" << response.error(); 0343 } 0344 } 0345 0346 setRepresentsDefaults(isDefault()); 0347 Q_EMIT settingsSaved(); 0348 } 0349 0350 QQmlPropertyMap *WallpaperModule::wallpaperConfiguration() const 0351 { 0352 return m_wallpaperConfiguration; 0353 } 0354 0355 QString WallpaperModule::currentWallpaperPlugin() const 0356 { 0357 return m_currentWallpaperPlugin; 0358 } 0359 0360 bool WallpaperModule::allScreens() const 0361 { 0362 return m_allScreens; 0363 } 0364 0365 void WallpaperModule::setAllScreens(const bool allScreens) 0366 { 0367 if (allScreens != m_allScreens) { 0368 m_allScreens = allScreens; 0369 setNeedsSave(m_allScreens || m_configLoader->isSaveNeeded() || m_loadedWallpaperplugin != m_currentWallpaperPlugin); 0370 Q_EMIT allScreensChanged(); 0371 } 0372 } 0373 0374 QList<QScreen *> WallpaperModule::screens() const 0375 { 0376 return m_screens; 0377 } 0378 0379 QScreen *WallpaperModule::selectedScreen() const 0380 { 0381 return m_selectedScreen; 0382 } 0383 0384 void WallpaperModule::setSelectedScreen(const QString &screenName) 0385 { 0386 const auto screens = qApp->screens(); 0387 auto it = std::find_if(screens.constBegin(), screens.cend(), [screenName](const QScreen *screen) { 0388 return screen->name() == screenName; 0389 }); 0390 if (it != screens.cend() && m_selectedScreen != *it) { 0391 m_selectedScreen = *it; 0392 Q_EMIT selectedScreenChanged(); 0393 0394 onScreenChanged(); 0395 } 0396 } 0397 0398 QString WallpaperModule::wallpaperPluginSource() 0399 { 0400 if (m_currentWallpaperPlugin.isEmpty()) { 0401 return QString(); 0402 } 0403 0404 const auto model = wallpaperConfigModel(); 0405 const auto wallpaperPluginCount = model->count(); 0406 for (int i = 0; i < wallpaperPluginCount; ++i) { 0407 if (model->data(model->index(i), PlasmaQuick::ConfigModel::PluginNameRole) == m_currentWallpaperPlugin) { 0408 return model->data(model->index(i), PlasmaQuick::ConfigModel::SourceRole).toString(); 0409 } 0410 } 0411 0412 return QString(); 0413 } 0414 0415 void WallpaperModule::setCurrentWallpaperPlugin(const QString &wallpaperPlugin) 0416 { 0417 if (wallpaperPlugin == m_currentWallpaperPlugin) { 0418 return; 0419 } 0420 0421 m_currentWallpaperPlugin = wallpaperPlugin; 0422 auto previousConfig = m_wallpaperConfiguration; 0423 disconnect(previousConfig, nullptr); 0424 0425 setWallpaperPluginConfiguration(m_currentWallpaperPlugin); 0426 0427 setNeedsSave(needsSave() || m_loadedWallpaperplugin != m_currentWallpaperPlugin); 0428 0429 Q_EMIT currentWallpaperPluginChanged(); 0430 0431 delete previousConfig; 0432 } 0433 0434 PlasmaQuick::ConfigModel *WallpaperModule::wallpaperConfigModel() 0435 { 0436 if (!m_wallpaperConfigModel) { 0437 m_wallpaperConfigModel = new WallpaperConfigModel(this); 0438 QDBusConnection::sessionBus().connect(QString(), 0439 QStringLiteral("/KPackage/Plasma/Wallpaper"), 0440 QStringLiteral("org.kde.plasma.kpackage"), 0441 QStringLiteral("packageInstalled"), 0442 m_wallpaperConfigModel, 0443 SLOT(repopulate())); 0444 QDBusConnection::sessionBus().connect(QString(), 0445 QStringLiteral("/KPackage/Plasma/Wallpaper"), 0446 QStringLiteral("org.kde.plasma.kpackage"), 0447 QStringLiteral("packageUpdated"), 0448 m_wallpaperConfigModel, 0449 SLOT(repopulate())); 0450 QDBusConnection::sessionBus().connect(QString(), 0451 QStringLiteral("/KPackage/Plasma/Wallpaper"), 0452 QStringLiteral("org.kde.plasma.kpackage"), 0453 QStringLiteral("packageUninstalled"), 0454 m_wallpaperConfigModel, 0455 SLOT(repopulate())); 0456 } 0457 return m_wallpaperConfigModel; 0458 } 0459 0460 WallpaperConfigModel::WallpaperConfigModel(QObject *parent) 0461 : PlasmaQuick::ConfigModel(parent) 0462 { 0463 repopulate(); 0464 } 0465 0466 void WallpaperConfigModel::repopulate() 0467 { 0468 clear(); 0469 for (const KPluginMetaData &m : KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/Wallpaper"))) { 0470 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Wallpaper"), m.pluginId()); 0471 if (!pkg.isValid()) { 0472 continue; 0473 } 0474 appendCategory(pkg.metadata().iconName(), pkg.metadata().name(), pkg.fileUrl("ui", QStringLiteral("config.qml")).toString(), m.pluginId()); 0475 } 0476 } 0477 0478 #include "wallpapermodule.moc"