[plasma/union] src: Convert StyleCache to base cache files on installed path
Arjen Hiemstra <[email protected]> Wed, 5 Aug 2026 10:33:23 +0000 (UTC)
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 31ae510fcbc62a5eb86ce6fc6456cea05618b9b8 by Arjen Hiemstra.
Committed on 05/08/2026 at 10:24.
Pushed by ahiemstra into branch 'master'.
Convert StyleCache to base cache files on installed path
Instead of using a combination of plugin + style ID, use the path of the
style (package) as identifier. This separates caches for different
installs of the same style, removing conflicts when one or the other is
a different version.
M +31 -48 src/StyleCache.cpp
M +5 -7 src/StyleCache_p.h
M +18 -49 src/StyleRegistry.cpp
https://invent.kde.org/plasma/union/-/commit/31ae510fcbc62a5eb86ce6fc6456cea05618b9b8
diff --git a/src/StyleCache.cpp b/src/StyleCache.cpp
index 4a5f48b0..16ec5cec 100644
--- a/src/StyleCache.cpp
+++ b/src/StyleCache.cpp
@@ -3,6 +3,7 @@
#include "StyleCache_p.h"
+#include <QCryptographicHash>
#include <QFile>
#include <QSaveFile>
#include <QStandardPaths>
@@ -27,38 +28,21 @@ static constexpr uint32_t CacheVersion = 6;
class StyleCache::Private
{
public:
- QHash<StyleId, fs::path> stylePaths;
+ fs::path cachePath(const fs::path &stylePath)
+ {
+ auto pathHash = QCryptographicHash::hash(stylePath.string(), QCryptographicHash::Sha256)
+ .toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)
+ .toStdString();
+ return storagePath / pathHash;
+ }
+
+ fs::path storagePath;
};
StyleCache::StyleCache()
: d(std::make_unique<Private>())
{
- auto cachePath = fs::path(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation).toStdString()) / "union";
- if (!enabled() || !fs::exists(cachePath)) {
- return;
- }
-
- for (const auto &pluginEntry : fs::directory_iterator(cachePath)) {
- if (!pluginEntry.is_directory()) {
- continue;
- }
-
- auto pluginName = pluginEntry.path().filename();
- for (const auto &styleEntry : fs::directory_iterator(pluginEntry.path())) {
- if (!styleEntry.is_regular_file()) {
- continue;
- }
-
- if (styleEntry.file_size() == 0) {
- continue;
- }
-
- auto styleName = styleEntry.path().stem();
-
- auto styleId = std::make_pair(pluginName.string(), styleName.string());
- d->stylePaths.insert(styleId, styleEntry.path());
- }
- }
+ d->storagePath = fs::path(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation).toStdString()) / "union";
}
StyleCache::~StyleCache() = default;
@@ -69,21 +53,21 @@ bool Union::StyleCache::enabled() const
return enabled;
}
-bool StyleCache::hasEntry(const StyleId &styleId) const
+bool StyleCache::hasEntry(const fs::path &path) const
{
- return d->stylePaths.contains(styleId);
+ return fs::exists(d->cachePath(path));
}
-std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
+std::unique_ptr<StylePrivate> StyleCache::load(const fs::path &path) const
{
if (!enabled()) {
- qCDebug(UNION_GENERAL) << "Ignoring cache for style" << styleId.second << "from plugin" << styleId.first << "because caching has been disabled";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "because caching has been disabled";
return nullptr;
}
- auto path = d->stylePaths.value(styleId);
- if (path.empty()) {
- qCDebug(UNION_GENERAL) << "Ignoring cache for style" << styleId.second << "from plugin" << styleId.first << "because no cache file could be found";
+ auto cachePath = d->cachePath(path);
+ if (!fs::exists(cachePath)) {
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "because no cache file could be found";
return nullptr;
}
@@ -92,7 +76,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
return nullptr;
}
- QFile cacheFile(path);
+ QFile cacheFile(cachePath);
if (!cacheFile.open(QIODevice::ReadOnly)) {
return nullptr;
}
@@ -104,7 +88,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
reader >> magic;
if (magic != CacheMagic) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "invalid magic value";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "invalid magic value";
return nullptr;
}
@@ -112,15 +96,15 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
reader >> version;
if (version != CacheVersion) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "version mismatch";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "version mismatch";
return nullptr;
}
auto result = std::make_unique<StylePrivate>();
reader >> result->path;
- if (result->pluginName.toStdString() != styleId.first || result->styleName.toStdString() != styleId.second) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "plugin/style name mismatch";
+ if (result->path != path) {
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "style path mismatch";
return nullptr;
}
@@ -128,7 +112,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
reader >> result->modificationTimes;
if (result->cachePaths.size() != result->modificationTimes.size()) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "mismatch between cache paths and modification times";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "mismatch between cache paths and modification times";
return nullptr;
}
@@ -136,7 +120,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
auto path = result->cachePaths.at(i);
if (!fs::exists(path)) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "original file no longer exists";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "original file no longer exists";
return nullptr;
}
@@ -144,7 +128,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
auto currentModificationTime = fs::last_write_time(path);
if (cachedModificationTime != currentModificationTime) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "file modification time mismatch";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "file modification time mismatch";
return nullptr;
}
}
@@ -159,7 +143,7 @@ std::unique_ptr<StylePrivate> StyleCache::load(const StyleId &styleId) const
}
if (reader.status() != QDataStream::Status::Ok) {
- qCDebug(UNION_GENERAL) << "Ignoring cache file" << path.string() << "restoring cached data failed";
+ qCDebug(UNION_GENERAL) << "Ignoring cache for style" << path.string() << "restoring cached data failed";
return nullptr;
}
@@ -176,15 +160,14 @@ bool Union::StyleCache::save(const StylePrivate *style) const
return false;
}
- auto path = fs::path(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation).toStdString()) / "union" / style->pluginName.toStdString();
- if (!fs::exists(path)) {
- if (!fs::create_directories(path)) {
- qCWarning(UNION_GENERAL) << "Could not create cache path" << path.string();
+ if (!fs::exists(d->storagePath)) {
+ if (!fs::create_directories(d->storagePath)) {
+ qCWarning(UNION_GENERAL) << "Could not create cache path" << d->storagePath.string();
return false;
}
}
- QSaveFile cacheFile(QString::fromStdString(path / (style->styleName.toStdString() + ".cache"s)));
+ QSaveFile cacheFile(QString::fromStdString(d->cachePath(style->path)));
if (!cacheFile.open(QIODevice::WriteOnly)) {
qCWarning(UNION_GENERAL) << "Could not open cache file" << qPrintable(cacheFile.fileName()) << "for writing";
return false;
diff --git a/src/StyleCache_p.h b/src/StyleCache_p.h
index 48abc7de..3f74888b 100644
--- a/src/StyleCache_p.h
+++ b/src/StyleCache_p.h
@@ -27,8 +27,6 @@ class StylePrivate;
class StyleCache
{
public:
- using StyleId = std::pair<std::string, std::string>;
-
StyleCache();
~StyleCache();
@@ -38,20 +36,20 @@ public:
// set.
bool enabled() const;
- // Does a cache entry exist for the given style ID.
+ // Does a cache entry exist for the given style package path.
//
- // Note that this is based on whether a cache file exists for the given ID.
+ // Note that this is based on whether a cache file exists for the given path.
// It does not verify that the cache file actually loads properly, so this
// may return true while load() still ends up returning nullptr.
- bool hasEntry(const StyleId &styleId) const;
+ bool hasEntry(const std::filesystem::path &path) const;
- // Load the cached data for the style with the given style ID.
+ // Load the cached data for the style with the given style package path.
//
// This will return nullptr when the cached data cannot be loaded. Cached
// data may not be loaded for a number of reasons, including changes to the
// underlying style files as well as changes to the code or structure of
// cache files.
- std::unique_ptr<StylePrivate> load(const StyleId &styleId) const;
+ std::unique_ptr<StylePrivate> load(const std::filesystem::path &path) const;
// Save the style data to a cache file.
//
diff --git a/src/StyleRegistry.cpp b/src/StyleRegistry.cpp
index 53ef8d1f..75b52040 100644
--- a/src/StyleRegistry.cpp
+++ b/src/StyleRegistry.cpp
@@ -41,55 +41,6 @@ public:
{
}
- Style::Ptr loadStyle(const QString &styleName, const QString &pluginName)
- {
- auto styleId = std::make_pair(pluginName.toStdString(), styleName.toStdString());
- if (styles.contains(styleId)) {
- return styles.value(styleId);
- }
-
- if (!styleCache) {
- return nullptr;
- }
-
- if (styleCache->hasEntry(styleId)) {
- auto data = styleCache->load(styleId);
- if (data) {
- auto style = std::make_shared<Style>(std::move(data));
- qCDebug(UNION_GENERAL) << "Loaded style" << styleName << "from cached data";
- styles.insert(styleId, style);
- return style;
- }
- }
-
- static const bool DisablePlugins = qEnvironmentVariableIsSet("UNION_DISABLE_INPUT_PLUGINS");
- if (DisablePlugins) {
- return nullptr;
- }
-
- auto plugin = InputPlugin::inputPlugin(pluginName);
- if (!plugin) {
- qCWarning(UNION_GENERAL) << "Requested style" << styleName << "from plugin" << pluginName << "but the plugin could not be found!";
- return nullptr;
- }
-
- auto style = plugin->createStyle(styleName);
- if (!style) {
- qCWarning(UNION_GENERAL) << "Requested style" << styleName << "from plugin" << pluginName << "but the style could not be found!";
- return nullptr;
- }
-
- if (!style->load()) {
- qCWarning(UNION_GENERAL) << "Requested style" << styleName << "from plugin" << pluginName << "but it failed to load!";
- return nullptr;
- }
-
- qCDebug(UNION_GENERAL) << "Loaded style" << styleName << "from plugin" << pluginName;
-
- styles.insert(styleId, style);
- return style;
- }
-
void loadPlatform()
{
const auto forcedPlatform = qEnvironmentVariable("UNION_FORCE_PLATFORM", QString{});
@@ -103,6 +54,11 @@ public:
const auto platformName = QGuiApplication::platformName();
const auto desktopNames = qEnvironmentVariable("XDG_CURRENT_DESKTOP", QString{}).split(u':');
+ if (platformName.isEmpty()) {
+ platform = std::make_shared<FallbackPlatformPlugin>();
+ return;
+ }
+
const auto plugins = platformRegistry->plugins();
for (const auto &plugin : plugins) {
const auto supportedPlatforms = plugin.metaData.value(u"union-supported-platforms").toArray().toVariantList();
@@ -198,12 +154,25 @@ std::shared_ptr<Style> StyleRegistry::style(const QString &styleId)
return itr.value();
}
+ if (!d->styleCache) {
+ return nullptr;
+ }
+
auto stylePackage = d->packageHandler->package(styleId);
if (!stylePackage.isValid()) {
qCWarning(UNION_GENERAL) << "Could not find style" << styleId;
return nullptr;
}
+ if (d->styleCache->hasEntry(stylePackage.path())) {
+ if (auto data = d->styleCache->load(stylePackage.path()); data) {
+ auto style = std::make_shared<Style>(std::move(data));
+ qCDebug(UNION_GENERAL) << "Loaded style" << styleId << "from cached data";
+ d->styles.insert(stylePackage.path(), style);
+ return style;
+ }
+ }
+
auto style = stylePackage.load();
if (!style) {
qCWarning(UNION_GENERAL) << "Style" << styleId << "failed to load";