From 3e0677b78ee27ae96e7a5dfabdd0d9d1baeb3999 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sat, 14 Jun 2025 22:06:17 +0200 Subject: [PATCH] Use synchrone component loading instead of asynchrone to avoid concurrent bug --- .../quicksettingsmodel.cpp | 114 ++++++++---------- .../quicksettingsplugin/quicksettingsmodel.h | 4 +- 2 files changed, 54 insertions(+), 64 deletions(-) diff --git a/components/quicksettingsplugin/quicksettingsmodel.cpp b/components/quicksettingsplugin/quicksettingsmodel.cpp index 197a19ac..f81ce9f1 100644 --- a/components/quicksettingsplugin/quicksettingsmodel.cpp +++ b/components/quicksettingsplugin/quicksettingsmodel.cpp @@ -82,6 +82,50 @@ QVariant QuickSettingsModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(obj); } +QuickSetting *QuickSettingsModel::loadQuickSettingComponent(KPluginMetaData metaData) +{ + // Load KPackage + const KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("KPackage/GenericQML", QFileInfo(metaData.fileName()).path()); + if (!package.isValid()) { + return nullptr; + } + + // Create translation context + QQmlEngine *engine = qmlEngine(this); + KLocalizedContext *i18nContext = new KLocalizedContext(engine); + i18nContext->setTranslationDomain(QLatin1String("plasma_") + metaData.pluginId()); + engine->rootContext()->setContextObject(i18nContext); + + // Create component synchronously + QQmlComponent component(engine, package.fileUrl("mainscript")); + if (component.isError()) { + qWarning() << "Unable to load quick setting element:" << metaData.pluginId(); + for (auto error : component.errors()) { + qWarning() << error; + } + return nullptr; + } + + // Create object + QObject *object = component.create(engine->rootContext()); + if (!object) { + qWarning() << "Unable to create quick setting element:" << metaData.pluginId(); + return nullptr; + } + + auto createdSetting = qobject_cast(object); + if (createdSetting && createdSetting->isAvailable()) { + // Connect availability signal + connect(createdSetting, &QuickSetting::availableChanged, this, [this, metaData, createdSetting]() { + availabilityChanged(metaData, createdSetting); + }); + return createdSetting; + } else { + object->deleteLater(); + return nullptr; + } +} + void QuickSettingsModel::loadQuickSettings() { if (!m_loaded) { @@ -96,10 +140,12 @@ void QuickSettingsModel::loadQuickSettings() m_quickSettings.clear(); m_quickSettingsMetaData.clear(); - // Loop through enabled quick settings and start loading them + // Loop through enabled quick settings and load them synchronously for (const auto &metaData : m_savedQuickSettings->enabledQuickSettingsModel()->list()) { - // false - Ensure row insertion signals aren't emitted (since we are resetting the model) - loadQuickSetting(metaData, false); + if (auto *setting = loadQuickSettingComponent(metaData)) { + m_quickSettings.append(setting); + m_quickSettingsMetaData.append(metaData); + } } endResetModel(); @@ -112,31 +158,8 @@ void QuickSettingsModel::loadQuickSetting(KPluginMetaData metaData, bool emitIns return; } - // Load KPackage - const KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("KPackage/GenericQML", QFileInfo(metaData.fileName()).path()); - if (!package.isValid()) { - return; - } - - // Create translation context - QQmlEngine *engine = qmlEngine(this); - KLocalizedContext *i18nContext = new KLocalizedContext(engine); - i18nContext->setTranslationDomain(QLatin1String("plasma_") + metaData.pluginId()); - engine->rootContext()->setContextObject(i18nContext); - - QQmlComponent *component = new QQmlComponent(engine, this); - - // Load QML from KPackage async - component->loadUrl(package.fileUrl("mainscript"), QQmlComponent::Asynchronous); - - if (component->isLoading()) { - // Listen to load completion - connect(component, &QQmlComponent::statusChanged, this, [this, metaData, component, engine]() { - afterQuickSettingLoad(engine, metaData, component, true); - }); - } else { - // Only emit insertion signal if we aren't resetting the model - afterQuickSettingLoad(engine, metaData, component, emitInsertSignal); + if (auto *setting = loadQuickSettingComponent(metaData)) { + insertQuickSettingToModel(metaData, setting, emitInsertSignal); } } @@ -151,41 +174,6 @@ void QuickSettingsModel::removeQuickSetting(int index) } } -void QuickSettingsModel::afterQuickSettingLoad(QQmlEngine *engine, KPluginMetaData metaData, QQmlComponent *component, bool emitInsertSignal) -{ - // Create quicksetting component - QObject *object = component->create(engine->rootContext()); - if (!object) { - qWarning() << "Unable to load quick setting element:" << metaData.pluginId(); - component->deleteLater(); - return; - } - - if (component->isError()) { - // Print errors - qWarning() << "Unable to load quick setting element:" << metaData.pluginId(); - for (auto error : component->errors()) { - qWarning() << error; - } - - component->deleteLater(); - } else if (component->isReady()) { - component->deleteLater(); - - auto createdSetting = qobject_cast(object); - - // Connect availability signal to insert/remove quicksetting into model - connect(createdSetting, &QuickSetting::availableChanged, this, [this, metaData, createdSetting]() { - availabilityChanged(metaData, createdSetting); - }); - - // Add quicksetting to model if available - if (createdSetting->isAvailable()) { - insertQuickSettingToModel(metaData, createdSetting, emitInsertSignal); - } - } -} - void QuickSettingsModel::insertQuickSettingToModel(KPluginMetaData metaData, QuickSetting *quickSetting, bool emitInsertSignal) { // Insert into correct position based on the saved quick settings order diff --git a/components/quicksettingsplugin/quicksettingsmodel.h b/components/quicksettingsplugin/quicksettingsmodel.h index 064bb3b0..7ac19eba 100644 --- a/components/quicksettingsplugin/quicksettingsmodel.h +++ b/components/quicksettingsplugin/quicksettingsmodel.h @@ -12,9 +12,11 @@ #include "savedquicksettings.h" #include "savedquicksettingsmodel.h" +#include #include #include #include +#include class QuickSettingsModel : public QAbstractListModel, public QQmlParserStatus { @@ -44,8 +46,8 @@ private: void loadQuickSetting(KPluginMetaData metaData, bool emitInsertSignal); void removeQuickSetting(int index); - void afterQuickSettingLoad(QQmlEngine *engine, KPluginMetaData metaData, QQmlComponent *component, bool emitInsertSignal); void insertQuickSettingToModel(KPluginMetaData metaData, QuickSetting *quickSetting, bool emitInsertSignal); + QuickSetting *loadQuickSettingComponent(KPluginMetaData metaData); bool m_loaded{false};