Skip to content

Conversation

@Dami-star
Copy link

…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

@deepin-ci-robot
Copy link
Contributor

[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.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@deepin-ci-robot
Copy link
Contributor

deepin pr auto review

这是一个对dconfig2cpp工具的代码重构,主要改进了代码结构和线程安全性。以下是我的分析:

  1. 代码质量改进:
  • 将数据存储和管理逻辑分离到Data类中,使代码结构更清晰
  • 添加了详细的注释分隔不同功能区域
  • 统一了代码格式和缩进
  • 改进了字符串拼接方式,使用更简洁的语法
  1. 线程安全性增强:
  • 使用QAtomicPointer和QAtomicInteger确保原子操作
  • 添加了状态管理(Invalid/Initializing/Succeed/Failed/Destroyed)
  • 使用QPointer防止在异步操作中访问已销毁的对象
  • 改进了线程间的通信机制
  1. 性能优化:
  • 使用位运算来存储属性设置状态,节省内存
  • 减少了不必要的属性更新和信号发射
  • 优化了属性值的比较和更新逻辑
  1. 安全性改进:
  • 添加了更多的空指针检查
  • 改进了对象生命周期管理
  • 增加了对并发访问的保护
  • 使用Q_UNREACHABLE()标记不应该到达的代码路径
  1. 其他改进:
  • 添加了Qt 6的QBindable支持
  • 改进了错误处理和状态转换
  • 优化了配置初始化流程
  • 增加了对配置文件版本的支持

建议:

  1. 可以考虑添加更多的单元测试来验证线程安全性
  2. 可以添加更多的日志记录以便调试
  3. 可以考虑使用智能指针来进一步简化内存管理
  4. 可以添加更多的错误处理和恢复机制

总的来说,这次重构显著提高了代码的质量、安全性和可维护性。

@18202781743
Copy link
Contributor

这个代码提交到https://github.com/linuxdeepin/dtkcore

…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
@Dami-star
Copy link
Author

这个代码提交到https://github.com/linuxdeepin/dtkcore

V25 实际使用的是dtk6core的dconfig2cpp吧

@18202781743
Copy link
Contributor

这个代码提交到https://github.com/linuxdeepin/dtkcore

V25 实际使用的是dtk6core的dconfig2cpp吧

这个dtk6core的代码是从dtkcore项目用机器人同步过来的,dtk6core只是用来打包,

@Dami-star
Copy link
Author

这个代码提交到https://github.com/linuxdeepin/dtkcore

V25 实际使用的是dtk6core的dconfig2cpp吧

这个dtk6core的代码是从dtkcore项目用机器人同步过来的,dtk6core只是用来打包,

ok

@Dami-star
Copy link
Author

Dami-star commented Jan 7, 2026

--- 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

@Dami-star
Copy link
Author

linuxdeepin/dtkcore#531

@Dami-star Dami-star closed this Jan 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants