diff --git a/changelog/next.md b/changelog/next.md index 237b788..b6dacca 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -20,3 +20,4 @@ - Fixed `PwNodePeakMonitor` crashing when sampling a stream with mismatched channels from the node. - Fixed unsetting `PopupAnchor.item` causing a crash. - Fixed hiding the last `PanelWindow` on screen causing a crash under X11. +- Fixed crashes when `ScriptModel.values` is set while processing previously set values. diff --git a/src/core/scriptmodel.cpp b/src/core/scriptmodel.cpp index fae65dd..7bd930e 100644 --- a/src/core/scriptmodel.cpp +++ b/src/core/scriptmodel.cpp @@ -16,7 +16,7 @@ bool ScriptModel::updateValuesUnique(const QList& newValues) { auto anyChanges = false; - this->hasActiveIterators = true; + this->isModifying = true; this->mValues.reserve(newValues.size()); auto iter = this->mValues.begin(); @@ -158,12 +158,24 @@ bool ScriptModel::updateValuesUnique(const QList& newValues) { } } - this->hasActiveIterators = false; + this->isModifying = false; + + if (this->stagedValues.has_value()) { + auto values = *this->stagedValues; + this->stagedValues.reset(); + anyChanges |= this->updateValuesUnique(values); + } return anyChanges; } void ScriptModel::setValues(const QList& newValues) { + // Re-entrant modification waits for the original modification to complete to avoid mishandled duplicates. + if (this->isModifying) { + this->stagedValues = newValues; + return; + } + auto changed = this->updateValuesUnique(newValues); if (changed) emit this->valuesChanged(); } diff --git a/src/core/scriptmodel.hpp b/src/core/scriptmodel.hpp index b3254fb..06758d8 100644 --- a/src/core/scriptmodel.hpp +++ b/src/core/scriptmodel.hpp @@ -85,7 +85,7 @@ public: [[nodiscard]] QList values() const { auto values = this->mValues; // If not detached, the QML engine will invalidate iterators in updateValuesUnique. - if (this->hasActiveIterators) values.detach(); + if (this->isModifying) values.detach(); return values; } @@ -105,7 +105,8 @@ signals: private: QList mValues; QString cmpKey; - bool hasActiveIterators = false; + bool isModifying = false; + std::optional> stagedValues; bool updateValuesUnique(const QList& newValues); };