-
Notifications
You must be signed in to change notification settings - Fork 15
fix: Refactor DConfig wrapper class generation for thread safety and … #178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Dami-star The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
deepin pr auto review这是一个对dconfig2cpp工具的代码重构,主要改进了代码结构和线程安全性。以下是我的分析:
建议:
总的来说,这次重构显著提高了代码的质量、安全性和可维护性。 |
…lifecycle management Problem: - Single-threaded design with weak state machine (Invalid -> Succeed/Failed) - No proper handling of object destruction during initialization - Signal emissions in worker thread context (incorrect thread context) - Fragile destructor unable to handle all cleanup scenarios Solution: 1. Introduce Data layer separation (TreelandUserConfigData + TreelandUserConfig) - Clear separation between internal data management and public API - Enables safer object lifecycle management 2. Enhance state machine (3-state -> 5-state model) - Add Initializing and Destroyed states - Use atomic CAS operations for thread-safe state transitions - States: Invalid -> Initializing -> (Succeed | Failed | Destroyed) 3. Improve async initialization and cleanup - Use QPointer for safe backref checks (prevent use-after-free) - Support 4 destruction paths: normal/failed/quick/mid-initialization - Atomic state transitions with proper signal emission guards 4. Separate thread responsibilities - updateValue(): Worker thread reads config values - updateProperty(): Main thread updates properties and emits signals - Use QMetaObject::invokeMethod for correct thread context Improvements: - Thread safety: Complete atomic operations coverage - Memory safety: QPointer guards prevent dangling pointers - Code clarity: Layered architecture with clear responsibilities - Backward compatibility: API unchanged
|
V25 实际使用的是dtk6core的dconfig2cpp吧 |
这个dtk6core的代码是从dtkcore项目用机器人同步过来的,dtk6core只是用来打包, |
ok |
--- treelandconfig-old.hpp 2026-01-07 15:43:28.000000000 +0800
+++ treelandconfig-new.hpp 2026-01-07 14:35:13.000000000 +0800
@@ -1,7 +1,7 @@
/**
* This file is generated by dconfig2cpp.
* Command line arguments: /usr/libexec/dtk6/DCore/bin/dconfig2cpp -o /home/uos/treeland/treeland/build/src/treelandconfig.hpp -c TreelandConfig /home/uos/treeland/treeland/misc/dconfig/org.deepin.dde.treeland.json
- * Generation time: 2026-01-07T15:43:28
+ * Generation time: 2026-01-07T14:35:13
* JSON file version: 1.0
*
* WARNING: DO NOT MODIFY THIS FILE MANUALLY.
@@ -23,8 +23,58 @@
#include <DSGApplication>
#include <DConfig>
+class TreelandConfig;
+
+class TreelandConfigData : public QObject {
+public:
+ enum class Status {
+ Invalid = 0,
+ Initializing = 1,
+ Succeed = 2,
+ Failed = 3,
+ Destroyed = 4
+ };
+
+ explicit TreelandConfigData(QObject *parent = nullptr)
+ : QObject(parent) {}
+
+ void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config);
+ void updateValue(const QString &key, const QVariant &fallback = QVariant());
+ void updateProperty(const QString &key, const QVariant &value);
+
+ inline void markPropertySet(const int index, bool on = true) {
+ if (index < 32) {
+ if (on)
+ m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0));
+ else
+ m_propertySetStatus0.fetchAndAndOrdered(~(1 << (index - 0)));
+ return;
+ }
+ Q_UNREACHABLE();
+ }
+
+ inline bool testPropertySet(const int index) const {
+ if (index < 32) {
+ return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0)));
+ }
+ Q_UNREACHABLE();
+ }
+
+ QAtomicPointer<DTK_CORE_NAMESPACE::DConfig> m_config = nullptr;
+ QAtomicInteger<int> m_status = static_cast<int>(Status::Invalid);
+ QPointer<TreelandConfig> m_userConfig = nullptr;
+ QAtomicInteger<quint32> m_propertySetStatus0 = 0;
+
+ // Property storage
+ bool p_enablePrelaunchSplash { false };
+ bool p_forceSoftwareCursor { false };
+ qlonglong p_prelaunchSplashTimeoutMs { 5000 };
+};
+
class TreelandConfig : public QObject {
Q_OBJECT
+public:
+ using Data = TreelandConfigData;
Q_PROPERTY(bool enablePrelaunchSplash READ enablePrelaunchSplash WRITE setEnablePrelaunchSplash NOTIFY enablePrelaunchSplashChanged RESET resetEnablePrelaunchSplash)
Q_PROPERTY(bool forceSoftwareCursor READ forceSoftwareCursor WRITE setForceSoftwareCursor NOTIFY forceSoftwareCursorChanged RESET resetForceSoftwareCursor)
@@ -37,15 +87,25 @@
explicit TreelandConfig(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend,
const QString &name, const QString &appId, const QString &subpath,
bool isGeneric, QObject *parent)
- : QObject(nullptr) {
+ : QObject(parent), m_data(new Data) {
+ m_data->m_userConfig = this;
+
if (!thread->isRunning()) {
qWarning() << QLatin1String("Warning: The provided thread is not running.");
}
Q_ASSERT(QThread::currentThread() != thread);
auto worker = new QObject();
worker->moveToThread(thread);
- QPointer<QObject> watcher(parent);
- QMetaObject::invokeMethod(worker, [=, this]() {
+ auto data = m_data;
+
+ QMetaObject::invokeMethod(worker, [=]() {
+ // Atomically transition from Invalid to Initializing
+ if (!data->m_status.testAndSetOrdered(static_cast<int>(Data::Status::Invalid),
+ static_cast<int>(Data::Status::Initializing))) {
+ worker->deleteLater();
+ return;
+ }
+
DTK_CORE_NAMESPACE::DConfig *config = nullptr;
if (isGeneric) {
if (backend) {
@@ -70,20 +130,37 @@
}
}
}
- if (!config) {
+
+ if (!config || !config->isValid()) {
qWarning() << QLatin1String("Failed to create DConfig instance.");
+
+ if (data->m_status.testAndSetOrdered(static_cast<int>(Data::Status::Initializing),
+ static_cast<int>(Data::Status::Failed))) {
+ // Successfully transitioned to Failed - notify main thread
+ QMetaObject::invokeMethod(data, [data]() {
+ if (data->m_userConfig)
+ Q_EMIT data->m_userConfig->configInitializeFailed();
+ });
+ }
+
worker->deleteLater();
+ if (config)
+ delete config;
+
return;
}
+
config->moveToThread(QThread::currentThread());
- initializeInConfigThread(config);
- if (watcher != parent) {
- // delete this if watcher is changed to nullptr.
- deleteLater();
- } else if (!this->parent() && parent) {
- // !parent() means that parent is not changed.
- this->setParent(watcher);
- }
+
+ // Initialize through Data class
+ data->initializeInConfigThread(config);
+
+ QObject::connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, data, [data](const QString &key) { data->updateValue(key); }, Qt::DirectConnection);
+ QObject::connect(config, &QObject::destroyed, data, &QObject::deleteLater);
+ QMetaObject::invokeMethod(data, [data, config]() {
+ if (data->m_userConfig)
+ Q_EMIT data->m_userConfig->configInitializeSucceed(config);
+ });
worker->deleteLater();
});
}
@@ -103,261 +180,196 @@
{ return new TreelandConfig(thread, nullptr, name, {}, subpath, true, parent); }
static TreelandConfig* createGenericByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())
{ return new TreelandConfig(thread, backend, name, {}, subpath, true, parent); }
- ~TreelandConfig() {
- if (m_config.loadRelaxed()) {
- m_config.loadRelaxed()->deleteLater();
- m_config.storeRelaxed(nullptr);
- }
- }
- Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const {
- return m_config.loadRelaxed();
- }
-
- Q_INVOKABLE bool isInitializeSucceed() const {
- return m_status.loadRelaxed() == static_cast<int>(Status::Succeed);
- }
+ ~TreelandConfig() {
+ int oldStatus = m_data->m_status.fetchAndStoreOrdered(static_cast<int>(Data::Status::Destroyed));
+ m_data->m_userConfig = nullptr;
- Q_INVOKABLE bool isInitializeFailed() const {
- return m_status.loadRelaxed() == static_cast<int>(Status::Failed);
+ if (oldStatus == static_cast<int>(Data::Status::Succeed)) {
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ config->deleteLater();
+ // m_data will be deleted by config->destroyed connection
+ } else {
+ m_data->deleteLater();
+ }
+ } else if (oldStatus == static_cast<int>(Data::Status::Failed) || oldStatus == static_cast<int>(Data::Status::Invalid)) {
+ m_data->deleteLater();
+ }
+ // If Initializing, worker thread handles m_data deletion when it sees Destroyed status
}
- Q_INVOKABLE bool isInitializing() const {
- return m_status.loadRelaxed() == static_cast<int>(Status::Invalid);
- }
+ Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { return m_data->m_config.loadRelaxed(); }
+ Q_INVOKABLE bool isInitializeSucceed() const { return m_data->m_status.loadRelaxed() == static_cast<int>(Data::Status::Succeed); }
+ Q_INVOKABLE bool isInitializeFailed() const { return m_data->m_status.loadRelaxed() == static_cast<int>(Data::Status::Failed); }
+ Q_INVOKABLE bool isInitializing() const { return m_data->m_status.loadRelaxed() == static_cast<int>(Data::Status::Initializing); }
- Q_INVOKABLE QStringList keyList() const {
- return { QStringLiteral("enablePrelaunchSplash"),
- QStringLiteral("forceSoftwareCursor"),
- QStringLiteral("prelaunchSplashTimeoutMs")};
- }
+ Q_INVOKABLE QStringList keyList() const { return { QStringLiteral("enablePrelaunchSplash"), QStringLiteral("forceSoftwareCursor"), QStringLiteral("prelaunchSplashTimeoutMs") }; }
Q_INVOKABLE bool isDefaultValue(const QString &key) const {
- if (key == QStringLiteral("enablePrelaunchSplash"))
- return enablePrelaunchSplashIsDefaultValue();
- if (key == QStringLiteral("forceSoftwareCursor"))
- return forceSoftwareCursorIsDefaultValue();
- if (key == QStringLiteral("prelaunchSplashTimeoutMs"))
- return prelaunchSplashTimeoutMsIsDefaultValue();
+ if (key == QStringLiteral("enablePrelaunchSplash")) return enablePrelaunchSplashIsDefaultValue();
+ if (key == QStringLiteral("forceSoftwareCursor")) return forceSoftwareCursorIsDefaultValue();
+ if (key == QStringLiteral("prelaunchSplashTimeoutMs")) return prelaunchSplashTimeoutMsIsDefaultValue();
return false;
}
- bool enablePrelaunchSplash() const {
- return p_enablePrelaunchSplash;
- }
- void setEnablePrelaunchSplash(const bool &value) {
- auto oldValue = p_enablePrelaunchSplash;
- p_enablePrelaunchSplash = value;
- markPropertySet(0);
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this, value]() {
- m_config.loadRelaxed()->setValue(QStringLiteral("enablePrelaunchSplash"), value);
- });
- }
- if (p_enablePrelaunchSplash != oldValue) {
- Q_EMIT enablePrelaunchSplashChanged();
- Q_EMIT valueChanged(QStringLiteral("enablePrelaunchSplash"), value);
+ bool enablePrelaunchSplash() const { return m_data->p_enablePrelaunchSplash; }
+ void setEnablePrelaunchSplash(const bool &v) {
+ if (m_data->p_enablePrelaunchSplash == v && m_data->testPropertySet(0)) return;
+ m_data->p_enablePrelaunchSplash = v;
+ m_data->markPropertySet(0);
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config, v]() { config->setValue(QStringLiteral("enablePrelaunchSplash"), v); });
}
+ Q_EMIT enablePrelaunchSplashChanged();
+ Q_EMIT valueChanged(QStringLiteral("enablePrelaunchSplash"), v);
}
void resetEnablePrelaunchSplash() {
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this]() {
- m_config.loadRelaxed()->reset(QStringLiteral("enablePrelaunchSplash"));
- });
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config]() { config->reset(QStringLiteral("enablePrelaunchSplash")); });
}
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- QBindable<bool> bindableEnablePrelaunchSplash() {
- return QBindable<bool>(this, "enablePrelaunchSplash");
- }
-#endif
- Q_INVOKABLE bool enablePrelaunchSplashIsDefaultValue() const {
- return !testPropertySet(0);
- }
- bool forceSoftwareCursor() const {
- return p_forceSoftwareCursor;
- }
- void setForceSoftwareCursor(const bool &value) {
- auto oldValue = p_forceSoftwareCursor;
- p_forceSoftwareCursor = value;
- markPropertySet(1);
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this, value]() {
- m_config.loadRelaxed()->setValue(QStringLiteral("forceSoftwareCursor"), value);
- });
- }
- if (p_forceSoftwareCursor != oldValue) {
- Q_EMIT forceSoftwareCursorChanged();
- Q_EMIT valueChanged(QStringLiteral("forceSoftwareCursor"), value);
+ Q_INVOKABLE bool enablePrelaunchSplashIsDefaultValue() const { return !m_data->testPropertySet(0); }
+ bool forceSoftwareCursor() const { return m_data->p_forceSoftwareCursor; }
+ void setForceSoftwareCursor(const bool &v) {
+ if (m_data->p_forceSoftwareCursor == v && m_data->testPropertySet(1)) return;
+ m_data->p_forceSoftwareCursor = v;
+ m_data->markPropertySet(1);
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config, v]() { config->setValue(QStringLiteral("forceSoftwareCursor"), v); });
}
+ Q_EMIT forceSoftwareCursorChanged();
+ Q_EMIT valueChanged(QStringLiteral("forceSoftwareCursor"), v);
}
void resetForceSoftwareCursor() {
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this]() {
- m_config.loadRelaxed()->reset(QStringLiteral("forceSoftwareCursor"));
- });
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config]() { config->reset(QStringLiteral("forceSoftwareCursor")); });
}
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- QBindable<bool> bindableForceSoftwareCursor() {
- return QBindable<bool>(this, "forceSoftwareCursor");
- }
-#endif
- Q_INVOKABLE bool forceSoftwareCursorIsDefaultValue() const {
- return !testPropertySet(1);
- }
- qlonglong prelaunchSplashTimeoutMs() const {
- return p_prelaunchSplashTimeoutMs;
- }
- void setPrelaunchSplashTimeoutMs(const qlonglong &value) {
- auto oldValue = p_prelaunchSplashTimeoutMs;
- p_prelaunchSplashTimeoutMs = value;
- markPropertySet(2);
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this, value]() {
- m_config.loadRelaxed()->setValue(QStringLiteral("prelaunchSplashTimeoutMs"), value);
- });
- }
- if (p_prelaunchSplashTimeoutMs != oldValue) {
- Q_EMIT prelaunchSplashTimeoutMsChanged();
- Q_EMIT valueChanged(QStringLiteral("prelaunchSplashTimeoutMs"), value);
+ Q_INVOKABLE bool forceSoftwareCursorIsDefaultValue() const { return !m_data->testPropertySet(1); }
+ qlonglong prelaunchSplashTimeoutMs() const { return m_data->p_prelaunchSplashTimeoutMs; }
+ void setPrelaunchSplashTimeoutMs(const qlonglong &v) {
+ if (m_data->p_prelaunchSplashTimeoutMs == v && m_data->testPropertySet(2)) return;
+ m_data->p_prelaunchSplashTimeoutMs = v;
+ m_data->markPropertySet(2);
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config, v]() { config->setValue(QStringLiteral("prelaunchSplashTimeoutMs"), v); });
}
+ Q_EMIT prelaunchSplashTimeoutMsChanged();
+ Q_EMIT valueChanged(QStringLiteral("prelaunchSplashTimeoutMs"), v);
}
void resetPrelaunchSplashTimeoutMs() {
- if (auto config = m_config.loadRelaxed()) {
- QMetaObject::invokeMethod(config, [this]() {
- m_config.loadRelaxed()->reset(QStringLiteral("prelaunchSplashTimeoutMs"));
- });
+ if (auto config = m_data->m_config.loadRelaxed()) {
+ QMetaObject::invokeMethod(config, [config]() { config->reset(QStringLiteral("prelaunchSplashTimeoutMs")); });
}
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- QBindable<qlonglong> bindablePrelaunchSplashTimeoutMs() {
- return QBindable<qlonglong>(this, "prelaunchSplashTimeoutMs");
- }
-#endif
- Q_INVOKABLE bool prelaunchSplashTimeoutMsIsDefaultValue() const {
- return !testPropertySet(2);
- }
+ Q_INVOKABLE bool prelaunchSplashTimeoutMsIsDefaultValue() const { return !m_data->testPropertySet(2); }
+
Q_SIGNALS:
- void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config);
+ void configInitializeFailed();
void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config);
void valueChanged(const QString &key, const QVariant &value);
-
void enablePrelaunchSplashChanged();
void forceSoftwareCursorChanged();
void prelaunchSplashTimeoutMsChanged();
-private:
- void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {
- Q_ASSERT(!m_config.loadRelaxed());
- m_config.storeRelaxed(config);
- if (!config->isValid()) {
- m_status.storeRelaxed(static_cast<int>(Status::Failed));
- Q_EMIT configInitializeFailed(config);
- return;
- }
-
- if (testPropertySet(0)) {
- config->setValue(QStringLiteral("enablePrelaunchSplash"), QVariant::fromValue(p_enablePrelaunchSplash));
- } else {
- updateValue(QStringLiteral("enablePrelaunchSplash"), QVariant::fromValue(p_enablePrelaunchSplash));
- }
- if (testPropertySet(1)) {
- config->setValue(QStringLiteral("forceSoftwareCursor"), QVariant::fromValue(p_forceSoftwareCursor));
- } else {
- updateValue(QStringLiteral("forceSoftwareCursor"), QVariant::fromValue(p_forceSoftwareCursor));
- }
- if (testPropertySet(2)) {
- config->setValue(QStringLiteral("prelaunchSplashTimeoutMs"), QVariant::fromValue(p_prelaunchSplashTimeoutMs));
- } else {
- updateValue(QStringLiteral("prelaunchSplashTimeoutMs"), QVariant::fromValue(p_prelaunchSplashTimeoutMs));
- }
- if (!m_config.loadRelaxed())
- return;
- connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) {
- updateValue(key);
- }, Qt::DirectConnection);
+private:
+ Data *m_data;
+};
- m_status.storeRelaxed(static_cast<int>(Status::Succeed));
- Q_EMIT configInitializeSucceed(config);
+inline void TreelandConfigData::initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {
+ Q_ASSERT(!m_config.loadRelaxed());
+ m_config.storeRelaxed(config);
+ if (testPropertySet(0)) config->setValue(QStringLiteral("enablePrelaunchSplash"), QVariant::fromValue(p_enablePrelaunchSplash));
+ else updateValue(QStringLiteral("enablePrelaunchSplash"), QVariant::fromValue(p_enablePrelaunchSplash));
+ if (testPropertySet(1)) config->setValue(QStringLiteral("forceSoftwareCursor"), QVariant::fromValue(p_forceSoftwareCursor));
+ else updateValue(QStringLiteral("forceSoftwareCursor"), QVariant::fromValue(p_forceSoftwareCursor));
+ if (testPropertySet(2)) config->setValue(QStringLiteral("prelaunchSplashTimeoutMs"), QVariant::fromValue(p_prelaunchSplashTimeoutMs));
+ else updateValue(QStringLiteral("prelaunchSplashTimeoutMs"), QVariant::fromValue(p_prelaunchSplashTimeoutMs));
+ // Transition from Initializing to Succeed
+ if (!m_status.testAndSetOrdered(static_cast<int>(Status::Initializing), static_cast<int>(Status::Succeed))) {
+ if (m_status.loadRelaxed() == static_cast<int>(Status::Destroyed)) {
+ config->deleteLater();
+ deleteLater();
+ }
+ return;
+ }}
+
+inline void TreelandConfigData::updateValue(const QString &key, const QVariant &fallback) {
+ auto config = m_config.loadRelaxed();
+ if (!config) return;
+ const QVariant &v = config->value(key, fallback);
+ if (key == QStringLiteral("enablePrelaunchSplash")) {
+ markPropertySet(0, !config->isDefaultValue(key));
+ // Safe capture using QPointer to handle object destruction
+ QPointer<TreelandConfigData> safeThis(this);
+ QMetaObject::invokeMethod(this, [safeThis, key, v]() {
+ if (safeThis) safeThis->updateProperty(key, v);
+ });
+ return;
}
- void updateValue(const QString &key, const QVariant &fallback = QVariant()) {
- if (!m_config.loadRelaxed())
- return;
- Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread());
- const QVariant &value = m_config.loadRelaxed()->value(key, fallback);
- if (key == QStringLiteral("enablePrelaunchSplash")) {
- markPropertySet(0, !m_config.loadRelaxed()->isDefaultValue(key));
- auto newValue = qvariant_cast<bool>(value);
- QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
- Q_ASSERT(QThread::currentThread() == this->thread());
- if (p_enablePrelaunchSplash != newValue) {
- p_enablePrelaunchSplash = newValue;
- Q_EMIT enablePrelaunchSplashChanged();
- Q_EMIT valueChanged(key, value);
- }
- });
- return;
- }
- if (key == QStringLiteral("forceSoftwareCursor")) {
- markPropertySet(1, !m_config.loadRelaxed()->isDefaultValue(key));
- auto newValue = qvariant_cast<bool>(value);
- QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
- Q_ASSERT(QThread::currentThread() == this->thread());
- if (p_forceSoftwareCursor != newValue) {
- p_forceSoftwareCursor = newValue;
- Q_EMIT forceSoftwareCursorChanged();
- Q_EMIT valueChanged(key, value);
- }
- });
- return;
- }
- if (key == QStringLiteral("prelaunchSplashTimeoutMs")) {
- markPropertySet(2, !m_config.loadRelaxed()->isDefaultValue(key));
- auto newValue = qvariant_cast<qlonglong>(value);
- QMetaObject::invokeMethod(this, [this, newValue, key, value]() {
- Q_ASSERT(QThread::currentThread() == this->thread());
- if (p_prelaunchSplashTimeoutMs != newValue) {
- p_prelaunchSplashTimeoutMs = newValue;
- Q_EMIT prelaunchSplashTimeoutMsChanged();
- Q_EMIT valueChanged(key, value);
+ if (key == QStringLiteral("forceSoftwareCursor")) {
+ markPropertySet(1, !config->isDefaultValue(key));
+ // Safe capture using QPointer to handle object destruction
+ QPointer<TreelandConfigData> safeThis(this);
+ QMetaObject::invokeMethod(this, [safeThis, key, v]() {
+ if (safeThis) safeThis->updateProperty(key, v);
+ });
+ return;
+ }
+ if (key == QStringLiteral("prelaunchSplashTimeoutMs")) {
+ markPropertySet(2, !config->isDefaultValue(key));
+ // Safe capture using QPointer to handle object destruction
+ QPointer<TreelandConfigData> safeThis(this);
+ QMetaObject::invokeMethod(this, [safeThis, key, v]() {
+ if (safeThis) safeThis->updateProperty(key, v);
+ });
+ return;
+ }
+}
+
+inline void TreelandConfigData::updateProperty(const QString &key, const QVariant &v) {
+ if (key == QStringLiteral("enablePrelaunchSplash")) {
+ bool nv = qvariant_cast<bool>(v);
+ if (p_enablePrelaunchSplash != nv) {
+ p_enablePrelaunchSplash = nv;
+ if (m_userConfig) {
+ auto uc = m_userConfig;
+ if (uc) {
+ Q_EMIT uc.data()->enablePrelaunchSplashChanged();
+ Q_EMIT uc.data()->valueChanged(key, v);
}
- });
- return;
+ }
}
+ return;
}
- inline void markPropertySet(const int index, bool on = true) {
- if (index < 32) {
- if (on)
- m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0));
- else
- m_propertySetStatus0.fetchAndAndOrdered(~(1 << (index - 0)));
- return;
+ if (key == QStringLiteral("forceSoftwareCursor")) {
+ bool nv = qvariant_cast<bool>(v);
+ if (p_forceSoftwareCursor != nv) {
+ p_forceSoftwareCursor = nv;
+ if (m_userConfig) {
+ auto uc = m_userConfig;
+ if (uc) {
+ Q_EMIT uc.data()->forceSoftwareCursorChanged();
+ Q_EMIT uc.data()->valueChanged(key, v);
+ }
+ }
}
- Q_UNREACHABLE();
+ return;
}
- inline bool testPropertySet(const int index) const {
- if (index < 32) {
- return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0)));
+ if (key == QStringLiteral("prelaunchSplashTimeoutMs")) {
+ qlonglong nv = qvariant_cast<qlonglong>(v);
+ if (p_prelaunchSplashTimeoutMs != nv) {
+ p_prelaunchSplashTimeoutMs = nv;
+ if (m_userConfig) {
+ auto uc = m_userConfig;
+ if (uc) {
+ Q_EMIT uc.data()->prelaunchSplashTimeoutMsChanged();
+ Q_EMIT uc.data()->valueChanged(key, v);
+ }
+ }
}
- Q_UNREACHABLE();
+ return;
}
+}
- QAtomicPointer<DTK_CORE_NAMESPACE::DConfig> m_config = nullptr;
-
-public:
- enum class Status {
- Invalid = 0,
- Succeed = 1,
- Failed = 2
- };
-private:
- QAtomicInteger<int> m_status = static_cast<int>(Status::Invalid);
-
- bool p_enablePrelaunchSplash { false };
- bool p_forceSoftwareCursor { false };
- qlonglong p_prelaunchSplashTimeoutMs { 5000 };
- QAtomicInteger<quint32> m_propertySetStatus0 = 0;
-};
-
-#endif // TREELANDCONFIG_H
+#endif
|
…lifecycle management
Problem:
Solution:
Introduce Data layer separation (TreelandUserConfigData + TreelandUserConfig)
Enhance state machine (3-state -> 5-state model)
Improve async initialization and cleanup
Separate thread responsibilities
Improvements: