Skip to content

refactor: optimize plugin loading and QML registration#3136

Open
caixr23 wants to merge 2 commits intolinuxdeepin:masterfrom
caixr23:master
Open

refactor: optimize plugin loading and QML registration#3136
caixr23 wants to merge 2 commits intolinuxdeepin:masterfrom
caixr23:master

Conversation

@caixr23
Copy link
Copy Markdown
Contributor

@caixr23 caixr23 commented Mar 31, 2026

This refactor improves plugin management by separating QML registration from plugin object creation. Key changes include:

  1. Added QML_ENGINE_PROPERTY constant for QML engine property name
  2. Modified DCC_FACTORY_CLASS macro to accept variadic arguments for QML registration
  3. Added dccObject() method in factory to handle QML type registration on main thread
  4. Created containsByName() method for more efficient module filtering
  5. Improved plugin loading sequence with proper thread management
  6. Moved all QML registration calls from constructors to factory's dccObject() method
  7. Removed unnecessary QML integration headers from model classes

The changes ensure QML type registration happens on the main thread while plugin objects are created in worker threads, preventing threading issues and improving performance.

Log: Optimized plugin loading process and QML registration

Influence:

  1. Test plugin loading and module display in control center
  2. Verify all QML components are properly registered and accessible
  3. Check module hiding functionality with wildcard patterns
  4. Test thread safety during plugin initialization
  5. Verify no regression in existing functionality

refactor: 优化插件加载和 QML 注册流程

本次重构改进了插件管理机制,将 QML 注册与插件对象创建分离。主要变更
包括:

  1. 添加 QML_ENGINE_PROPERTY 常量用于 QML 引擎属性名
  2. 修改 DCC_FACTORY_CLASS 宏支持可变参数用于 QML 注册
  3. 在工厂类中添加 dccObject() 方法处理主线程中的 QML 类型注册
  4. 创建 containsByName() 方法实现更高效的模块过滤
  5. 改进插件加载序列,优化线程管理
  6. 将所有 QML 注册调用从构造函数移至工厂的 dccObject() 方法
  7. 从模型类中移除不必要的 QML 集成头文件

这些变更确保 QML 类型注册在主线程执行,而插件对象在工作线程创建,避免线
程问题并提升性能。

Log: 优化插件加载过程和 QML 注册机制

Influence:

  1. 测试控制中心插件加载和模块显示
  2. 验证所有 QML 组件正确注册并可访问
  3. 检查通配符模式下的模块隐藏功能
  4. 测试插件初始化期间的线程安全性
  5. 验证现有功能无回归

PMS: BUG-309197

Summary by Sourcery

Refactor plugin loading and QML registration so that QML types are registered on the main thread via plugin factories while plugin data objects are created in worker threads, and improve module filtering and ownership handling during plugin initialization.

Bug Fixes:

  • Fix potential threading issues and crashes by ensuring QML type registration and related operations occur on the main thread instead of worker threads.
  • Prevent leaks and dangling objects in plugin creation by correctly parenting created QObjects and deleting unexpected types.
  • Resolve a possible null-parent issue in PrivacySecurityWorker by parenting ApplicationItem instances to the worker’s model.

Enhancements:

  • Extend the DCC_FACTORY_CLASS macro to accept variadic arguments and perform QML-related registration through the factory’s dccObject method instead of plugin constructors.
  • Introduce a QML_ENGINE_PROPERTY constant and propagate the QQmlEngine to plugin factories to centralize QML registration.
  • Adjust PluginManager’s loading sequence to store factories, move them to the main thread, and create or discard QML-facing objects safely with proper object ownership and context parenting.
  • Add DccManager static helpers for wildcard-capable module name matching and use them for hide-module filtering.
  • Clean up model and worker classes by removing direct QML integration macros and headers now that registration is handled centrally by factories.
  • Initialize display plugin members defensively to avoid use of uninitialized pointers.

This refactor improves plugin management by separating QML registration
from plugin object creation. Key changes include:
1. Added QML_ENGINE_PROPERTY constant for QML engine property name
2. Modified DCC_FACTORY_CLASS macro to accept variadic arguments for
QML registration
3. Added dccObject() method in factory to handle QML type registration
on main thread
4. Created containsByName() method for more efficient module filtering
5. Improved plugin loading sequence with proper thread management
6. Moved all QML registration calls from constructors to factory's
dccObject() method
7. Removed unnecessary QML integration headers from model classes

The changes ensure QML type registration happens on the main thread
while plugin objects are created in worker threads, preventing threading
issues and improving performance.

Log: Optimized plugin loading process and QML registration

Influence:
1. Test plugin loading and module display in control center
2. Verify all QML components are properly registered and accessible
3. Check module hiding functionality with wildcard patterns
4. Test thread safety during plugin initialization
5. Verify no regression in existing functionality

refactor: 优化插件加载和 QML 注册流程

本次重构改进了插件管理机制,将 QML 注册与插件对象创建分离。主要变更
包括:
1. 添加 QML_ENGINE_PROPERTY 常量用于 QML 引擎属性名
2. 修改 DCC_FACTORY_CLASS 宏支持可变参数用于 QML 注册
3. 在工厂类中添加 dccObject() 方法处理主线程中的 QML 类型注册
4. 创建 containsByName() 方法实现更高效的模块过滤
5. 改进插件加载序列,优化线程管理
6. 将所有 QML 注册调用从构造函数移至工厂的 dccObject() 方法
7. 从模型类中移除不必要的 QML 集成头文件

这些变更确保 QML 类型注册在主线程执行,而插件对象在工作线程创建,避免线
程问题并提升性能。

Log: 优化插件加载过程和 QML 注册机制

Influence:
1. 测试控制中心插件加载和模块显示
2. 验证所有 QML 组件正确注册并可访问
3. 检查通配符模式下的模块隐藏功能
4. 测试插件初始化期间的线程安全性
5. 验证现有功能无回归

PMS: BUG-309197
@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: caixr23

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

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 31, 2026

Reviewer's Guide

Refactors the plugin loading pipeline so that plugin instances are created in worker threads while all QML type registration is centralized in DccFactory::dccObject() and executed on the main thread, and introduces reusable helpers for module filtering by name.

Sequence diagram for the new plugin loading and QML registration process

sequenceDiagram
    actor User
    participant PluginManager
    participant ManagerThread
    participant LoadPluginTask
    participant WorkerThread
    participant DccFactory
    participant MainThread
    participant QQmlEngine
    participant PluginData
    participant PluginData.data
    participant PluginData.factory
    participant obj

    User->>PluginManager: requestLoadPlugin()
    PluginManager->>ManagerThread: schedule LoadPluginTask

    ManagerThread->>LoadPluginTask: start doLoadSo()
    activate LoadPluginTask

    LoadPluginTask->>WorkerThread: load plugin .so
    activate WorkerThread
    WorkerThread->>DccFactory: create()  // plugin instance in worker thread
    DccFactory-->>WorkerThread: QObject* data
    deactivate WorkerThread

    LoadPluginTask->>LoadPluginTask: store data in PluginData.data
    LoadPluginTask->>LoadPluginTask: store DccFactory in PluginData.factory
    LoadPluginTask-->>PluginManager: emit updatePluginStatus(DataEnd)
    deactivate LoadPluginTask

    PluginManager->>PluginManager: loadPlugin(plugin) // reacts to DataEnd
    PluginManager->>PluginData: move data to ManagerThread
    PluginManager->>PluginData.data: setParent(PluginManager)
    PluginManager->>QQmlEngine: engine()
    QQmlEngine-->>PluginManager: QQmlEngine*

    PluginManager->>PluginData.factory: setProperty(QML_ENGINE_PROPERTY, engine)
    PluginManager->>PluginData.factory: moveToThread(ManagerThread)

    PluginManager->>DccFactory: dccObject()
    activate DccFactory
    DccFactory->>DccFactory: executeQmlRegisters() // __VA_ARGS__ qmlRegisterType<...>()
    DccFactory-->>PluginManager: QObject* obj (optional DccObject)
    deactivate DccFactory

    PluginManager->>PluginManager: dynamic_cast to DccObject
    alt obj is DccObject
        PluginManager->>PluginData: store as soObj
    else obj not DccObject
        PluginManager->>obj: deleteLater()
    end

    PluginManager->>PluginManager: loadMain(plugin)
    PluginManager-->>User: plugin ready
Loading

Updated class diagram for DccFactory, PluginManager, and DccManager helpers

classDiagram
    class QObject
    class QThread
    class QQmlEngine

    namespace dccV25 {
        class DccObject
        class DccFactory
    }

    class DccFactory {
        <<interface>>
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
    }

    class BiometricAuthControllerDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class soundInteractionDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class SystemInfoInteractionDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class BluetoothInteractionDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class CommonInfoInteractionDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class PersonalizationInterfaceDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class PrivacySecurityExportDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class AccountsControllerDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class DefAppModelDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class TouchScreenModelDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class DatetimeModelDccFactory {
        +QObject* create(QObject* parent)
        +QObject* dccObject(QObject* parent)
        -executeQmlRegisters()
    }

    class soundInteraction {
        +SoundWorker* m_soundWork
        +SoundModel* m_soundModel
    }

    class PluginData {
        +QString name
        +dccV25::DccObject* mainObj
        +dccV25::DccObject* soObj
        +QObject* data
        +dccV25::DccFactory* factory
        +QThread* thread
        +uint status
    }

    class PluginManager {
        +void loadPlugin(PluginData* plugin)
        +void loadMetaData(PluginData* plugin)
        +void createMain(QQmlComponent* component)
        +QThread* thread()
        +QObject* parent()
        -void addMainObject(PluginData* plugin)
        -void loadMain(PluginData* plugin)
    }

    class DccManager {
        +const QSet~QString~& hideModule()
        +static bool isMatchByName(QString url, QString name)
        +static bool isMatch(QString url, const dccV25::DccObject* obj)
        +static bool isEqualByName(QString url, QString name)
        +static bool isEqual(QString url, const dccV25::DccObject* obj)
        +static bool containsByName(QSet~QString~ urls, QString name)
        +static bool contains(QSet~QString~ urls, const dccV25::DccObject* obj)
        -QStringList splitUrl(QString url, QString targetName)
        -dccV25::DccObject* findObject(QString url)
        -QVector~dccV25::DccObject*~ findObjects(QString url, bool one)
        -const dccV25::DccObject* findParent(const dccV25::DccObject* obj)
    }

    QObject <|-- DccFactory
    QObject <|-- dccV25.DccObject

    DccFactory <|-- BiometricAuthControllerDccFactory
    DccFactory <|-- soundInteractionDccFactory
    DccFactory <|-- SystemInfoInteractionDccFactory
    DccFactory <|-- BluetoothInteractionDccFactory
    DccFactory <|-- CommonInfoInteractionDccFactory
    DccFactory <|-- PersonalizationInterfaceDccFactory
    DccFactory <|-- PrivacySecurityExportDccFactory
    DccFactory <|-- AccountsControllerDccFactory
    DccFactory <|-- DefAppModelDccFactory
    DccFactory <|-- TouchScreenModelDccFactory
    DccFactory <|-- DatetimeModelDccFactory

    PluginManager "1" o-- "many" PluginData
    PluginData "1" --> "0..1" dccV25.DccObject : mainObj
    PluginData "1" --> "0..1" dccV25.DccObject : soObj
    PluginData "1" --> "0..1" QObject : data
    PluginData "1" --> "0..1" DccFactory : factory
    PluginData "1" --> "0..1" QThread : thread

    PluginManager ..> DccManager : uses hideModule()
    PluginManager ..> QQmlEngine : engine()
    PluginManager ..> DccFactory : dccObject()

    soundInteraction --> SoundWorker
    soundInteraction --> SoundModel
Loading

File-Level Changes

Change Details Files
Extend DccFactory and its macro to support centralized, main-thread-only QML registration for each plugin.
  • Introduce QML_ENGINE_PROPERTY constant for passing the QQmlEngine to factories via QObject property.
  • Change DccFactory::dccObject() to return QObject* and document that QML-related work is done on the main thread.
  • Refactor DCC_FACTORY_CLASS macro to accept variadic QML registration expressions, wrap them in a lambda called from dccObject(), and stop exporting the factory class symbol explicitly.
include/dccfactory.h
Rework plugin loading flow to separate SO loading, data object lifetime, and QML registration, while adding module name-based filter helpers.
  • Extend PluginData to store a DccFactory pointer instead of an eagerly created DccObject so QML registration can be deferred.
  • Update LoadPluginTask::doLoadSo() to only create the data object in the worker thread and keep the factory instance, moving both objects to the manager thread as appropriate.
  • In PluginManager::loadPlugin(), set CppOwnership for data objects, inject the QQmlEngine into the factory via QML_ENGINE_PROPERTY, invoke dccObject() on the manager thread, and manage any returned DccObject or temporary QObject.
  • Ensure QQmlContext lifetime is tied to the created main object and delete it on failure in createMain().
  • Replace direct hide-module checks with DccManager::containsByName() and expose static helpers isMatch*, isEqual*, contains* for name-based and object-based matching.
src/dde-control-center/pluginmanager.cpp
src/dde-control-center/dccmanager.h
src/dde-control-center/dccmanager.cpp
Move QML type registration out of plugin/model constructors into the factory macro for multiple plugins.
  • For biometric auth, sound, system info, bluetooth, common info, personalization, privacy, accounts, default apps, touchscreen, and datetime plugins, remove qmlRegisterType calls from constructors and pass equivalent registrations as variadic arguments to DCC_FACTORY_CLASS.
  • Clean up now-unneeded QML integration includes and QML_NAMED_ELEMENT/QML_SINGLETON annotations from several model classes (e.g., CommonInfoModel, BluetoothModel, PowerOperatorModel, SoundEffectsModel, SoundModel, SoundWorker, AccountsController).
  • Add missing QtQml/qqml.h includes where qmlRegisterType is now used in factory macros.
src/plugin-authentication/operation/biometricauthcontroller.cpp
src/plugin-sound/operation/soundInteraction.cpp
src/plugin-systeminfo/operation/systeminfointeraction.cpp
src/plugin-bluetooth/operation/bluetoothinteraction.cpp
src/plugin-commoninfo/operation/commoninfointeraction.cpp
src/plugin-personalization/operation/personalizationinterface.cpp
src/plugin-privacy/operation/privacysecurityexport.cpp
src/plugin-accounts/operation/accountscontroller.cpp
src/plugin-commoninfo/operation/commoninfomodel.h
src/plugin-bluetooth/operation/bluetoothmodel.h
src/plugin-defaultapp/operation/defappmodel.cpp
src/plugin-power/operation/poweroperatormodel.h
src/plugin-sound/operation/soundeffectsmodel.h
src/plugin-sound/operation/soundmodel.h
src/plugin-sound/operation/soundworker.h
src/plugin-touchscreen/operation/touchscreenmodel.cpp
src/plugin-datetime/operation/datetimemodel.cpp
src/plugin-accounts/operation/accountscontroller.h
src/plugin-mouse/operation/mousemodel.h
src/plugin-sound/operation/soundmodel.cpp
Tighten ownership and initialization details in specific components.
  • Initialize additional members (m_model, m_worker) in DisplayModulePrivate constructor for safety.
  • Change PrivacySecurityWorker::addAppItem() to parent ApplicationItem instances to m_model instead of leaving them unparented.
  • Minor SPDX copyright year range updates across several files.
src/plugin-display/operation/displaymodule.cpp
src/plugin-privacy/operation/privacysecurityworker.cpp
src/plugin-sound/operation/soundInteraction.cpp
src/plugin-authentication/operation/biometricauthcontroller.cpp
src/plugin-systeminfo/operation/systeminfointeraction.cpp
src/plugin-bluetooth/operation/bluetoothinteraction.cpp
src/plugin-commoninfo/operation/commoninfointeraction.cpp
src/plugin-personalization/operation/personalizationinterface.cpp
src/plugin-privacy/operation/privacysecurityexport.cpp
src/plugin-accounts/operation/accountscontroller.cpp
src/plugin-commoninfo/operation/commoninfomodel.h
src/plugin-bluetooth/operation/bluetoothmodel.h
src/plugin-defaultapp/operation/defappmodel.cpp
src/plugin-power/operation/poweroperatormodel.h
src/plugin-sound/operation/soundeffectsmodel.h
src/plugin-sound/operation/soundmodel.h
src/plugin-sound/operation/soundworker.h
src/plugin-touchscreen/operation/touchscreenmodel.cpp
src/plugin-datetime/operation/datetimemodel.cpp
src/plugin-accounts/operation/accountscontroller.h
src/plugin-mouse/operation/mousemodel.h
include/dccfactory.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • In dccfactory.h, the new QML_ENGINE_PROPERTY value is spelled "QmlEngin"; if this is meant to be a stable key (and especially if read elsewhere), consider correcting it to "QmlEngine" now to avoid hard‑to‑trace bugs later.
  • The new DCC_FACTORY_CLASS macro dropped Q_DECL_EXPORT from the factory class declaration; please confirm this isn’t required for plugin symbol visibility on your platforms, and reintroduce it if necessary to avoid runtime plugin loading issues.
  • In the DCC_FACTORY_CLASS implementation, dccObject(QObject * = nullptr) ignores the parent argument and always returns nullptr; if future factory implementations are expected to allocate and return a QObject, consider wiring the parent through and/or documenting that the macro-generated version is intended only for QML registration side effects.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `dccfactory.h`, the new `QML_ENGINE_PROPERTY` value is spelled `"QmlEngin"`; if this is meant to be a stable key (and especially if read elsewhere), consider correcting it to `"QmlEngine"` now to avoid hard‑to‑trace bugs later.
- The new `DCC_FACTORY_CLASS` macro dropped `Q_DECL_EXPORT` from the factory class declaration; please confirm this isn’t required for plugin symbol visibility on your platforms, and reintroduce it if necessary to avoid runtime plugin loading issues.
- In the `DCC_FACTORY_CLASS` implementation, `dccObject(QObject * = nullptr)` ignores the parent argument and always returns `nullptr`; if future factory implementations are expected to allocate and return a `QObject`, consider wiring the parent through and/or documenting that the macro-generated version is intended only for QML registration side effects.

## Individual Comments

### Comment 1
<location path="include/dccfactory.h" line_range="11" />
<code_context>

 namespace dccV25 {
 #define DccFactory_iid "org.deepin.dde.dcc-factory/v1.0"
+#define QML_ENGINE_PROPERTY "QmlEngin"
 class DccObject;

</code_context>
<issue_to_address>
**issue (bug_risk):** The QML_ENGINE_PROPERTY string looks misspelled, which risks mismatches wherever it is read.

The macro value is "QmlEngin" (missing the final 'e'). Any code expecting "QmlEngine" will fail to read this property. Please either correct the spelling or verify that all existing usages intentionally match this exact string.
</issue_to_address>

### Comment 2
<location path="include/dccfactory.h" line_range="29-38" />
<code_context>
+#define DCC_FACTORY_CLASS(classname, ...)                   \
</code_context>
<issue_to_address>
**suggestion:** The variadic macro relies on call sites passing `__VA_ARGS__` as statements; some current usages instead use comma expressions.

Inside `dccObject`, `__VA_ARGS__` is injected directly into a lambda body, but some call sites use semicolon-terminated statements while others (e.g. `soundInteraction`, `SystemInfoInteraction`, `CommonInfoInteraction`) use comma-separated expressions. This works but is surprising and easy to misuse. Please clarify the intended usage (statements terminated with `;`) and either wrap `__VA_ARGS__` in a `do { __VA_ARGS__; } while (0)` or standardize call sites to avoid comma expressions.

Suggested implementation:

```c
/*
 * DCC_FACTORY_CLASS
 *
 * Variadic arguments (`__VA_ARGS__`) are intended to be *statements* terminated
 * with semicolons. They are injected into an implementation lambda as a
 * statement block. Do not rely on comma-expressions here; always write
 * normal statements, e.g.:
 *
 *     DCC_FACTORY_CLASS(Foo,
 *         auto w = new FooWidget(parent);
 *         configureFoo(w);
 *         return w;
 *     )
 */
#define DCC_FACTORY_CLASS(classname, ...)                   \
    namespace {                                             \
    class classname##DccFactory : public dccV25::DccFactory \
    {                                                       \
        Q_OBJECT                                            \
        Q_PLUGIN_METADATA(IID DccFactory_iid)               \
        Q_INTERFACES(dccV25::DccFactory)                    \
    public:                                                 \
        using dccV25::DccFactory::DccFactory;               \
        QObject *create(QObject *parent = nullptr) override \
        {                                                   \

```

```c
        QObject *create(QObject *parent = nullptr) override \
        {                                                   \
            /* Ensure __VA_ARGS__ are always treated as a statement block */ \
            do { __VA_ARGS__; } while (0);                  \

```

I only see the beginning of the macro and not the full body. The intent is that wherever `__VA_ARGS__` is currently injected directly into the lambda body (e.g. something like `auto dccObject = [parent] { __VA_ARGS__; };`), that occurrence should be replaced with `do { __VA_ARGS__; } while (0);` inside the lambda instead. If the macro currently *returns* the result of `__VA_ARGS__` (e.g. `return __VA_ARGS__;`), you may need to restructure it to:

```c++
auto impl = [&]() {
    do { __VA_ARGS__; } while (0);
};
return impl();
```

so that the block form remains compatible. Please adjust the placement of the `do { __VA_ARGS__; } while (0);` line to match your actual lambda/body structure in `DCC_FACTORY_CLASS`.
</issue_to_address>

### Comment 3
<location path="src/plugin-sound/operation/soundInteraction.cpp" line_range="51-54" />
<code_context>
 }

-DCC_FACTORY_CLASS(soundInteraction)
+DCC_FACTORY_CLASS(soundInteraction,\
+                  qmlRegisterType<SoundWorker>("dcc", 1, 0, "SoundWorker"),\
+                  qmlRegisterType<SoundModel>("dcc", 1, 0, "SoundModel"),\
+                  qmlRegisterType<SoundDeviceModel>("SoundDeviceModel", 1, 0, "SoundDeviceModel"))

 #include "soundInteraction.moc"
</code_context>
<issue_to_address>
**suggestion:** Using commas between `qmlRegisterType` calls here relies on the comma operator, which is non-obvious and inconsistent with other call sites.

Here, the macro’s lambda ends up chaining these calls via the comma operator. While it evaluates all calls, it’s unconventional and differs from nearby uses (e.g., `BiometricAuthController`, `BluetoothInteraction`) that use `;`. Using semicolons instead would align with those sites and reduce the risk of subtle errors if more logic is added later.

```suggestion
DCC_FACTORY_CLASS(soundInteraction,\
                  qmlRegisterType<SoundWorker>("dcc", 1, 0, "SoundWorker");\
                  qmlRegisterType<SoundModel>("dcc", 1, 0, "SoundModel");\
                  qmlRegisterType<SoundDeviceModel>("SoundDeviceModel", 1, 0, "SoundDeviceModel"))
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


namespace dccV25 {
#define DccFactory_iid "org.deepin.dde.dcc-factory/v1.0"
#define QML_ENGINE_PROPERTY "QmlEngin"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The QML_ENGINE_PROPERTY string looks misspelled, which risks mismatches wherever it is read.

The macro value is "QmlEngin" (missing the final 'e'). Any code expecting "QmlEngine" will fail to read this property. Please either correct the spelling or verify that all existing usages intentionally match this exact string.

Comment on lines +29 to +38
#define DCC_FACTORY_CLASS(classname, ...) \
namespace { \
class classname##DccFactory : public dccV25::DccFactory \
{ \
Q_OBJECT \
Q_PLUGIN_METADATA(IID DccFactory_iid) \
Q_INTERFACES(dccV25::DccFactory) \
public: \
using dccV25::DccFactory::DccFactory; \
QObject *create(QObject *parent = nullptr) override \
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The variadic macro relies on call sites passing __VA_ARGS__ as statements; some current usages instead use comma expressions.

Inside dccObject, __VA_ARGS__ is injected directly into a lambda body, but some call sites use semicolon-terminated statements while others (e.g. soundInteraction, SystemInfoInteraction, CommonInfoInteraction) use comma-separated expressions. This works but is surprising and easy to misuse. Please clarify the intended usage (statements terminated with ;) and either wrap __VA_ARGS__ in a do { __VA_ARGS__; } while (0) or standardize call sites to avoid comma expressions.

Suggested implementation:

/*
 * DCC_FACTORY_CLASS
 *
 * Variadic arguments (`__VA_ARGS__`) are intended to be *statements* terminated
 * with semicolons. They are injected into an implementation lambda as a
 * statement block. Do not rely on comma-expressions here; always write
 * normal statements, e.g.:
 *
 *     DCC_FACTORY_CLASS(Foo,
 *         auto w = new FooWidget(parent);
 *         configureFoo(w);
 *         return w;
 *     )
 */
#define DCC_FACTORY_CLASS(classname, ...)                   \
    namespace {                                             \
    class classname##DccFactory : public dccV25::DccFactory \
    {                                                       \
        Q_OBJECT                                            \
        Q_PLUGIN_METADATA(IID DccFactory_iid)               \
        Q_INTERFACES(dccV25::DccFactory)                    \
    public:                                                 \
        using dccV25::DccFactory::DccFactory;               \
        QObject *create(QObject *parent = nullptr) override \
        {                                                   \
        QObject *create(QObject *parent = nullptr) override \
        {                                                   \
            /* Ensure __VA_ARGS__ are always treated as a statement block */ \
            do { __VA_ARGS__; } while (0);                  \

I only see the beginning of the macro and not the full body. The intent is that wherever __VA_ARGS__ is currently injected directly into the lambda body (e.g. something like auto dccObject = [parent] { __VA_ARGS__; };), that occurrence should be replaced with do { __VA_ARGS__; } while (0); inside the lambda instead. If the macro currently returns the result of __VA_ARGS__ (e.g. return __VA_ARGS__;), you may need to restructure it to:

auto impl = [&]() {
    do { __VA_ARGS__; } while (0);
};
return impl();

so that the block form remains compatible. Please adjust the placement of the do { __VA_ARGS__; } while (0); line to match your actual lambda/body structure in DCC_FACTORY_CLASS.

Comment on lines +51 to +54
DCC_FACTORY_CLASS(soundInteraction,\
qmlRegisterType<SoundWorker>("dcc", 1, 0, "SoundWorker"),\
qmlRegisterType<SoundModel>("dcc", 1, 0, "SoundModel"),\
qmlRegisterType<SoundDeviceModel>("SoundDeviceModel", 1, 0, "SoundDeviceModel"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Using commas between qmlRegisterType calls here relies on the comma operator, which is non-obvious and inconsistent with other call sites.

Here, the macro’s lambda ends up chaining these calls via the comma operator. While it evaluates all calls, it’s unconventional and differs from nearby uses (e.g., BiometricAuthController, BluetoothInteraction) that use ;. Using semicolons instead would align with those sites and reduce the risk of subtle errors if more logic is added later.

Suggested change
DCC_FACTORY_CLASS(soundInteraction,\
qmlRegisterType<SoundWorker>("dcc", 1, 0, "SoundWorker"),\
qmlRegisterType<SoundModel>("dcc", 1, 0, "SoundModel"),\
qmlRegisterType<SoundDeviceModel>("SoundDeviceModel", 1, 0, "SoundDeviceModel"))
DCC_FACTORY_CLASS(soundInteraction,\
qmlRegisterType<SoundWorker>("dcc", 1, 0, "SoundWorker");\
qmlRegisterType<SoundModel>("dcc", 1, 0, "SoundModel");\
qmlRegisterType<SoundDeviceModel>("SoundDeviceModel", 1, 0, "SoundDeviceModel"))

}
if (plugin->factory) {
plugin->factory->setProperty(QML_ENGINE_PROPERTY, QVariant::fromValue(m_manager->engine()));
QObject *obj = plugin->factory->dccObject();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个应该在module加载之前吧,不然有些类型没注册,在c++里是不是也存在问题呀,

// 未提供qml的,可在此自己加载qml返回DccObject对象
virtual DccObject *dccObject(QObject * = nullptr) { return nullptr; }
// 未提供qml的,可在此自己加载qml返回DccObject对象,qml相关操作,如注册qml类型(在主线程中执行)
virtual QObject *dccObject(QObject * = nullptr) { return nullptr; }
Copy link
Copy Markdown
Contributor

@18202781743 18202781743 Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

加个虚函数吧,在创建dccData之前,保证在主线程中被调用,这样代码也容易维护,
也可以保证兼容性, 在高版本的dde-control-center编译也不会在低版本的上面安装运行,

@deepin-bot
Copy link
Copy Markdown

deepin-bot bot commented Apr 3, 2026

TAG Bot

New tag: 6.1.80
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3153

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