Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions include/dccfactory.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef DCCFACTORY_H
Expand All @@ -8,6 +8,7 @@

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.

class DccObject;

class DccFactory : public QObject
Expand All @@ -16,28 +17,36 @@ class DccFactory : public QObject
public:
using QObject::QObject;

// 作为数据返回,会导出为dccData供main.qml使用
// 作为数据返回,会导出为dccData供main.qml使用(在子线程执行)
virtual QObject *create(QObject * = nullptr) { return nullptr; }

// 未提供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编译也不会在低版本的上面安装运行,

};
} // namespace dccV25
Q_DECLARE_INTERFACE(dccV25::DccFactory, DccFactory_iid)

#define DCC_FACTORY_CLASS(classname) \
namespace { \
class Q_DECL_EXPORT 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 \
{ \
return new classname(parent); \
} \
}; \
#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 \
Comment on lines +29 to +38
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.

{ \
return new classname(parent); \
} \
QObject *dccObject(QObject * = nullptr) override \
{ \
auto executeQmlRegisters = []() { \
__VA_ARGS__; \
}; \
executeQmlRegisters(); \
return nullptr; \
} \
}; \
}
#endif // DCCFACTORY_H
20 changes: 15 additions & 5 deletions src/dde-control-center/dccmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ DccManager::DccManager(QObject *parent)
QJSEngine::setObjectOwnership(m_noParentObjects, QQmlEngine::CppOwnership);

initConfig();
connect(m_plugins, &PluginManager::addObject, this, &DccManager::addObject, Qt::QueuedConnection);
connect(m_plugins, &PluginManager::addObject, this, &DccManager::addObject);
connect(m_plugins, &PluginManager::loadAllFinished, this, &DccManager::tryShow, Qt::QueuedConnection);
m_showTimer = new QTimer(this);
connect(m_showTimer, &QTimer::timeout, this, &DccManager::tryShow);
Expand Down Expand Up @@ -191,10 +191,12 @@ void DccManager::addObject(DccObject *obj)
{
if (!obj)
return;
qWarning()<<__LINE__<<__FUNCTION__<<obj;
QVector<DccObject *> objs;
objs.append(obj);
while (!objs.isEmpty()) {
DccObject *o = objs.takeFirst();
qWarning()<<__LINE__<<__FUNCTION__<<(void*)o;
if (!o->name().isEmpty()) {
m_objMap[o->name()].append(o);
connect(o, &DccObject::destroyed, this, &DccManager::onDccObjectDestroyed, Qt::UniqueConnection);
Expand Down Expand Up @@ -468,22 +470,27 @@ void DccManager::initConfig()
connect(m_dconfig, &DConfig::valueChanged, this, &DccManager::updateModuleConfig);
}

bool DccManager::contains(const QSet<QString> &urls, const DccObject *obj)
bool DccManager::containsByName(const QSet<QString> &urls, const QString &name)
{
for (auto &&url : urls) {
if (url.contains("*")) {
if (isMatch(url, obj)) {
if (isMatchByName(url, name)) {
return true;
}
} else {
if (isEqual(url, obj)) {
if (isEqualByName(url, name)) {
return true;
}
}
}
return false;
}

bool DccManager::contains(const QSet<QString> &urls, const DccObject *obj)
{
return containsByName(urls, obj->parentName() + "/" + obj->name());
}

QStringList DccManager::splitUrl(const QString &url, QString &targetName)
{
QStringList paths = url.split("/", Qt::SkipEmptyParts);
Expand Down Expand Up @@ -777,7 +784,7 @@ void DccManager::clearShowParam()

void DccManager::tryShow()
{
if (m_showUrl.isEmpty() && !m_activeObject) {
if (m_showUrl.isEmpty() && m_showTimer) {
clearShowParam();
showPage(m_root, QString());
return;
Expand All @@ -801,6 +808,9 @@ void DccManager::tryShow()
QDBusConnection::sessionBus().send(m_showMessage.createErrorReply(QDBusError::InvalidArgs, QString("not found url:") + m_showUrl));
}
clearShowParam();
if (!m_activeObject) {
showPage(m_root, QString());
}
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/dde-control-center/dccmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@

inline const QSet<QString> &hideModule() const { return m_hideModule; }

static bool isMatchByName(const QString &url, const QString &name);
static bool isMatch(const QString &url, const DccObject *obj);
static bool isEqualByName(const QString &url, const QString &name);
static bool isEqual(const QString &url, const DccObject *obj);
static bool containsByName(const QSet<QString> &urls, const QString &name);
static bool contains(const QSet<QString> &urls, const DccObject *obj);

public Q_SLOTS:

Check warning on line 69 in src/dde-control-center/dccmanager.h

View workflow job for this annotation

GitHub Actions / cppcheck

There is an unknown macro here somewhere. Configuration is required. If Q_SLOTS is a macro then please configure it.

Check warning on line 69 in src/dde-control-center/dccmanager.h

View workflow job for this annotation

GitHub Actions / cppcheck

There is an unknown macro here somewhere. Configuration is required. If Q_SLOTS is a macro then please configure it.
DccObject *object(const QString &name) override;
void addObject(DccObject *obj) override;
void removeObject(DccObject *obj) override;
Expand Down Expand Up @@ -89,12 +96,7 @@

private:
void initConfig();
bool contains(const QSet<QString> &urls, const DccObject *obj);
QStringList splitUrl(const QString &url, QString &targetName);
bool isMatchByName(const QString &url, const QString &name);
bool isMatch(const QString &url, const DccObject *obj);
bool isEqualByName(const QString &url, const QString &name);
bool isEqual(const QString &url, const DccObject *obj);
DccObject *findObject(const QString &url);
QVector<DccObject *> findObjects(const QString &url, bool one = false);
const DccObject *findParent(const DccObject *obj);
Expand Down
20 changes: 18 additions & 2 deletions src/dde-control-center/plugin/dccobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
#include <QLoggingCategory>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>

Check warning on line 11 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickItem> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 11 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickItem> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQuickWindow>

Check warning on line 12 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickWindow> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 12 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickWindow> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTimer>

Check warning on line 13 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTimer> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 13 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTimer> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QThread>

Check warning on line 14 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QThread> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 14 in src/dde-control-center/plugin/dccobject.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QThread> not found. Please note: Cppcheck does not need standard library headers to get proper results.
namespace dccV25 {
static Q_LOGGING_CATEGORY(dccLog, "dde.dcc.object");

Expand All @@ -30,11 +30,16 @@
, m_currentObject(nullptr)
, m_page(nullptr)
, m_parentItem(nullptr)
, m_pParent(nullptr)
{
}

DccObject::Private::~Private()
{
if(m_pParent){
m_pParent->removeObject(q_ptr);
}
clearObject();
if (m_page && (!m_page->parent() || m_page->parent() == q_ptr)) {
// Use deleteLater() to avoid dangling QObjectWrapper references in QML's
// JS engine. Synchronous delete can cause crashes when GC runs during
Expand All @@ -46,6 +51,7 @@
}
if (m_parent) {
m_parent->p_ptr->removeChild(q_ptr);
// m_parent->removeObject(q_ptr);
}
while (!m_children.isEmpty()) {
DccObject *child = m_children.first();
Expand All @@ -55,6 +61,10 @@
// delete, then defer destruction so QML's GC can safely process any
// remaining QObjectWrapper references to this child.
child->setParent(nullptr);
// if(child->p_ptr->m_pParent){
// child->p_ptr->m_pParent->removeObject(child);
// // child->p_ptr->m_pParent = nullptr;
// }
child->deleteLater();
}
}
Expand Down Expand Up @@ -193,20 +203,24 @@
{
if (child && !m_objects.contains(child)) {
m_objects.append(child);
child->p_ptr->m_pParent=this;
Q_EMIT q_ptr->addObject(child);
}
}

void DccObject::Private::removeObject(DccObject *child)
{
if (child && m_objects.removeOne(child)) {
if (child ) {
child->p_ptr->m_pParent=nullptr;
m_objects.removeOne(child);
Q_EMIT q_ptr->removeObject(child);
}
}

void DccObject::Private::clearObject()
{
for (auto obj : m_objects) {
obj->p_ptr->m_pParent=nullptr;
Q_EMIT q_ptr->removeObject(obj);
}
m_objects.clear();
Expand Down Expand Up @@ -249,10 +263,12 @@
: QObject(parent)
, p_ptr(new DccObject::Private(this))
{
qWarning()<<__LINE__<<__FUNCTION__<<"===== ===="<<this<<QThread::currentThread();
}

DccObject::~DccObject()
{
qWarning()<<__LINE__<<__FUNCTION__<<"===== ~~~ ===="<<this<<name()<<QThread::currentThread();
delete p_ptr;
}

Expand Down
1 change: 1 addition & 0 deletions src/dde-control-center/plugin/dccobject_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class DccObject::Private
QObjectList m_data; // data属性,为qml能加子项
QPointer<QQmlComponent> m_page;
QPointer<QQuickItem> m_parentItem; // Item父项
DccObject::Private *m_pParent;

QString m_parentName;
QString m_displayName;
Expand Down
4 changes: 3 additions & 1 deletion src/dde-control-center/plugin/dccrepeater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class DccRepeaterPrivate

for (int i = 0; i < itemCount; i++) {
if (i >= deletables.size() || !deletables.at(i))
model->object(i, QQmlIncubator::AsynchronousIfNested);
model->object(i, QQmlIncubator::Asynchronous);
}
}

Expand Down Expand Up @@ -185,6 +185,8 @@ void DccRepeater::createdItem(int index, QObject *item)
{
DccObject *dccObj = qmlobject_cast<DccObject *>(item);
if (dccObj) {
Q_D(const DccRepeater);
d->model->object(index);
dccObj->setParent(this);
p_ptr->addObject(dccObj);
Q_EMIT objAdded(index, item);
Expand Down
Loading
Loading