Skip to content

feat: add card surface plugin interface for QML-based plugins#474

Open
wjyrich wants to merge 1 commit into
linuxdeepin:masterfrom
wjyrich:CardPlugin
Open

feat: add card surface plugin interface for QML-based plugins#474
wjyrich wants to merge 1 commit into
linuxdeepin:masterfrom
wjyrich:CardPlugin

Conversation

@wjyrich

@wjyrich wjyrich commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Introduce PluginsItemInterfaceV3 extending V2 with virtual functions for card item key, QML source, icon source and preferred size. Implement CardPluginItem class and integrate into loader to support creating card QQuickView surfaces. Brightness plugin updated to V3 with a simple QML card showing icon, title and slider.

Log: Added card surface support for dock plugins with QML implementation

Influence:

  1. Verify brightness plugin detects card surfaces and shows QML card on dock
  2. Test card surface showing/hiding when support changes
  3. Verify card surface dark/light theme switching
  4. Test card surface resize when dock container changes size
  5. Verify fallback compatibility with plugins not implementing V3

feat: 添加基于 QML 的卡片表面插件接口

引入 PluginsItemInterfaceV3 扩展 V2,增加卡片项键、QML 源、图标源和首 选大小的虚函数。实现 CardPluginItem 类并集成到加载器中,支持创建卡片
QQuickView 表面。亮度插件更新至 V3,使用简单的 QML 卡片显示图标、标题和
滑块。

Log: 新增卡片表面支持,插件可使用 QML 实现

Influence:

  1. 验证亮度插件检测到卡片表面并在任务栏上显示 QML 卡片
  2. 测试支持状态变化时卡片表面的显示/隐藏
  3. 验证卡片表面深色/浅色主题切换
  4. 测试任务栏容器大小变化时卡片表面自适应调整
  5. 验证未实现 V3 的插件回退兼容性

Summary by Sourcery

Introduce a V3 plugins item interface and loader support for QML-based card surfaces, and adopt it in the brightness dock plugin.

New Features:

  • Add PluginsItemInterfaceV3 with card item key, QML source, icon source and preferred size for card surfaces.
  • Introduce CardPluginItem to host plugin-provided QML cards in a QQuickView and expose them as dock card surfaces.
  • Extend the brightness dock plugin to provide a QML card surface with icon, title and slider using the V3 interface.
  • Add a new Card plugin type for embedded dock plugins.

Enhancements:

  • Update WidgetPlugin to create, show, resize and destroy card surfaces alongside existing quick widgets with theme propagation.
  • Adjust plugin manager to prefer loading PluginsItemInterfaceV3 plugins while remaining compatible with V2 and legacy interfaces.

Build:

  • Update trayplugin-loader build to depend on Qt Quick and Qml and compile the new cardpluginitem sources.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: wjyrich

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

sourcery-ai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a QML-based card surface plugin interface (PluginsItemInterfaceV3) and a CardPluginItem loader path, wires it into the existing plugin manager/loader to create and manage Wayland-backed QQuickView card surfaces, and updates the brightness dock plugin to implement V3 with a QML card, while preserving backward compatibility for V2/legacy plugins.

Sequence diagram for creating a QML card surface on itemAdded

sequenceDiagram
    participant PluginManager
    participant BrightnessPlugin
    participant WidgetPlugin
    participant CardPluginItem
    participant EmbedPlugin

    PluginManager->>BrightnessPlugin: loadPlugin(pluginFilePath)
    BrightnessPlugin->>PluginManager: instance implements PluginsItemInterfaceV3
    PluginManager->>WidgetPlugin: new WidgetPlugin(pluginsItemInterface)

    BrightnessPlugin->>WidgetPlugin: itemAdded(this, cardItemKey())
    WidgetPlugin->>WidgetPlugin: createCardItemIfNeeded(itemInter, itemKey)
    WidgetPlugin->>CardPluginItem: new CardPluginItem(cardInterface, itemKey, this)
    CardPluginItem->>CardPluginItem: init()
    CardPluginItem->>CardPluginItem: QQuickView setSource(cardQmlSource())

    WidgetPlugin->>EmbedPlugin: Plugin::EmbedPlugin::get(CardPluginItem.window())
    EmbedPlugin->>EmbedPlugin: setPluginType(Plugin::EmbedPlugin::Card)
    EmbedPlugin->>WidgetPlugin: dockColorThemeChanged(uint32_t)
    WidgetPlugin->>CardPluginItem: setDockColorTheme(int)
    EmbedPlugin->>CardPluginItem: eventGeometry(QRect)
    CardPluginItem->>CardPluginItem: resize(QSize)

    WidgetPlugin->>CardPluginItem: show()
Loading

File-Level Changes

Change Details Files
Introduce PluginsItemInterfaceV3 and CardPluginItem to support QML-driven card surfaces for dock plugins.
  • Define PluginsItemInterfaceV3 extending V2 with virtual hooks for card item key, QML source, icon source and preferred size, plus a V3 Qt plugin IID.
  • Implement CardPluginItem that wraps a QQuickView, exposes theme-related properties to QML, and manages view lifecycle, sizing and QML context setup.
  • Add BrightnessCard.qml and cardQmlSource helper returning the card QML URL for the brightness plugin.
interfaces/pluginsiteminterface_v3.h
src/loader/cardpluginitem.h
src/loader/cardpluginitem.cpp
plugins/dde-dock/brightness/resources/qml/BrightnessCard.qml
plugins/dde-dock/brightness/brightness-constants.h
Integrate card surface handling into the loader and plugin manager, including lifecycle and theme/geometry updates.
  • Extend CMake and target_link_libraries to pull in Qt Quick/Qml and compile cardpluginitem sources.
  • Update PluginManager to prefer V3 interfaces, falling back to V2 and then the base interface for legacy plugins.
  • Enhance WidgetPlugin to detect V3 plugins, create/manage CardPluginItem per itemKey, hook EmbedPlugin signals for color theme and geometry, and track card items in a QHash.
  • Ensure card card items are cleaned up on WidgetPlugin destruction and on item removal, and add a Card type to EmbedPlugin::PluginType.
src/loader/CMakeLists.txt
src/loader/pluginmanager.cpp
src/loader/widgetplugin.h
src/loader/widgetplugin.cpp
src/tray-wayland-integration/plugin.h
Upgrade the brightness dock plugin to the V3 interface and expose a QML card surface with icon, title and slider.
  • Change BrightnessPlugin to implement PluginsItemInterfaceV3 and use the V3 Qt plugin metadata IID.
  • Add implementations for cardItemKey, cardQmlSource, cardIconSource and cardPreferredSize to describe the brightness card surface.
  • Modify brightness plugin init and support-change handling to register/unregister both the classic item and the card item with the proxy when brightness support toggles.
plugins/dde-dock/brightness/brightnessplugin.h
plugins/dde-dock/brightness/brightnessplugin.cpp

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • CardPluginItem instances are constructed with WidgetPlugin as parent and also deleted via qDeleteAll(m_cardItems) in the destructor, which can lead to double deletion; either drop the parent relationship or remove qDeleteAll and rely on QObject ownership.
  • In createCardItemIfNeeded(), when cardItem->init() or window() fails you still return true, which prevents the normal widget path from being created; consider returning false on failure so the plugin can gracefully fall back to the non-card implementation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- CardPluginItem instances are constructed with WidgetPlugin as parent and also deleted via qDeleteAll(m_cardItems) in the destructor, which can lead to double deletion; either drop the parent relationship or remove qDeleteAll and rely on QObject ownership.
- In createCardItemIfNeeded(), when cardItem->init() or window() fails you still return true, which prevents the normal widget path from being created; consider returning false on failure so the plugin can gracefully fall back to the non-card implementation.

## Individual Comments

### Comment 1
<location path="src/loader/widgetplugin.cpp" line_range="382" />
<code_context>
     return Plugin::EmbedPlugin::get(widget->windowHandle());
 }

+bool WidgetPlugin::createCardItemIfNeeded(PluginsItemInterface *itemInter, const QString &itemKey)
+{
+    auto cardInterface = dynamic_cast<PluginsItemInterfaceV3 *>(itemInter);
</code_context>
<issue_to_address>
**issue (complexity):** Consider separating card-item classification from lifecycle management and making the card helpers void and explicitly branched in itemAdded/itemRemoved to clarify control flow and responsibilities.

The added card path does increase complexity, mainly through the overloaded `createCardItemIfNeeded` and its hidden control‑flow contract. You can simplify the logic and make `itemAdded`/`itemRemoved` easier to reason about by:

1. **Separate classification from lifecycle**  
   Extract a small helper that decides “is this a card item?” and use it to branch explicitly in `itemAdded`/`itemRemoved`. Then make the lifecycle helper `void` so its return value no longer encodes behavior.

   ```cpp
   // New helper
   bool WidgetPlugin::isCardItem(PluginsItemInterface *itemInter, const QString &itemKey) const
   {
       auto cardInterface = dynamic_cast<PluginsItemInterfaceV3 *>(itemInter);
       return cardInterface && cardInterface->cardItemKey() == itemKey;
   }

   // Adjusted itemAdded
   void WidgetPlugin::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
   {
       qDebug() << "itemAdded:" << itemKey;

       if (isCardItem(itemInter, itemKey)) {
           ensureCardItem(itemInter, itemKey);
           return;
       }

       auto flag = getPluginFlags();
       if (flag & Dock::Type_Quick) {
           // existing quick path...
       }
       // existing normal widget path...
   }
   ```

2. **Make card lifecycle explicit and non‑boolean**  
   Rename `createCardItemIfNeeded` to something like `ensureCardItem` and change the signature to `void`. Keep the semantics identical: normal widget path should never run for card items.

   ```cpp
   // Refactored from createCardItemIfNeeded
   void WidgetPlugin::ensureCardItem(PluginsItemInterface *itemInter, const QString &itemKey)
   {
       auto cardInterface = static_cast<PluginsItemInterfaceV3 *>(itemInter);

       if (auto existing = m_cardItems.value(itemKey)) {
           existing->show();
           return;
       }

       auto cardItem = new CardPluginItem(cardInterface, itemKey, this);
       if (!cardItem->init() || !cardItem->window()) {
           cardItem->deleteLater();
           qWarning() << "create card plugin surface failed" << itemInter->pluginName() << itemKey;
           return; // still block normal widget path
       }

       auto plugin = Plugin::EmbedPlugin::get(cardItem->window());
       plugin->setPluginFlags(getPluginFlags());
       plugin->setPluginId(itemInter->pluginName());
       plugin->setDisplayName(itemInter->pluginDisplayName());
       plugin->setItemKey(itemKey);
       plugin->setPluginType(Plugin::EmbedPlugin::Card);
       plugin->setPluginSizePolicy(itemInter->pluginSizePolicy());

       connect(plugin, &Plugin::EmbedPlugin::dockColorThemeChanged,
               this, &WidgetPlugin::onDockColorThemeChanged, Qt::UniqueConnection);
       connect(plugin, &Plugin::EmbedPlugin::dockColorThemeChanged,
               cardItem, [cardItem](uint32_t colorTheme) {
                   cardItem->setDockColorTheme(static_cast<int>(colorTheme));
               });
       connect(plugin, &Plugin::EmbedPlugin::eventGeometry,
               cardItem, [cardItem](const QRect &geometry) {
                   cardItem->resize(geometry.size());
               });

       m_cardItems.insert(itemKey, cardItem);
       cardItem->show();
   }
   ```

3. **Mirror the explicit branching in `itemRemoved`**  
   Keep the current behavior, but make the “card vs normal widget” decision obvious:

   ```cpp
   void WidgetPlugin::itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey)
   {
       Q_UNUSED(itemInter);

       if (auto cardItem = m_cardItems.take(itemKey)) {
           cardItem->hide();
           cardItem->deleteLater();
           return;
       }

       auto widget = m_pluginsItemInterface->itemWidget(itemKey);
       if (widget && widget->window() && widget->window()->windowHandle()) {
           widget->window()->windowHandle()->hide();
       }

       auto quickPanel = m_pluginsItemInterface->itemWidget(Dock::QUICK_ITEM_KEY);
       if (quickPanel && quickPanel->window() && quickPanel->window()->windowHandle()) {
           quickPanel->window()->windowHandle()->hide();
       }
   }
   ```

These changes keep all current functionality (including “card creation failure blocks normal widget path”) but make the control flow and responsibilities clearer: classification (`isCardItem`), lifecycle (`ensureCardItem`), and normal widget handling are separated and easier to follow.
</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.

return Plugin::EmbedPlugin::get(widget->windowHandle());
}

bool WidgetPlugin::createCardItemIfNeeded(PluginsItemInterface *itemInter, const QString &itemKey)

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 (complexity): Consider separating card-item classification from lifecycle management and making the card helpers void and explicitly branched in itemAdded/itemRemoved to clarify control flow and responsibilities.

The added card path does increase complexity, mainly through the overloaded createCardItemIfNeeded and its hidden control‑flow contract. You can simplify the logic and make itemAdded/itemRemoved easier to reason about by:

  1. Separate classification from lifecycle
    Extract a small helper that decides “is this a card item?” and use it to branch explicitly in itemAdded/itemRemoved. Then make the lifecycle helper void so its return value no longer encodes behavior.

    // New helper
    bool WidgetPlugin::isCardItem(PluginsItemInterface *itemInter, const QString &itemKey) const
    {
        auto cardInterface = dynamic_cast<PluginsItemInterfaceV3 *>(itemInter);
        return cardInterface && cardInterface->cardItemKey() == itemKey;
    }
    
    // Adjusted itemAdded
    void WidgetPlugin::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
    {
        qDebug() << "itemAdded:" << itemKey;
    
        if (isCardItem(itemInter, itemKey)) {
            ensureCardItem(itemInter, itemKey);
            return;
        }
    
        auto flag = getPluginFlags();
        if (flag & Dock::Type_Quick) {
            // existing quick path...
        }
        // existing normal widget path...
    }
  2. Make card lifecycle explicit and non‑boolean
    Rename createCardItemIfNeeded to something like ensureCardItem and change the signature to void. Keep the semantics identical: normal widget path should never run for card items.

    // Refactored from createCardItemIfNeeded
    void WidgetPlugin::ensureCardItem(PluginsItemInterface *itemInter, const QString &itemKey)
    {
        auto cardInterface = static_cast<PluginsItemInterfaceV3 *>(itemInter);
    
        if (auto existing = m_cardItems.value(itemKey)) {
            existing->show();
            return;
        }
    
        auto cardItem = new CardPluginItem(cardInterface, itemKey, this);
        if (!cardItem->init() || !cardItem->window()) {
            cardItem->deleteLater();
            qWarning() << "create card plugin surface failed" << itemInter->pluginName() << itemKey;
            return; // still block normal widget path
        }
    
        auto plugin = Plugin::EmbedPlugin::get(cardItem->window());
        plugin->setPluginFlags(getPluginFlags());
        plugin->setPluginId(itemInter->pluginName());
        plugin->setDisplayName(itemInter->pluginDisplayName());
        plugin->setItemKey(itemKey);
        plugin->setPluginType(Plugin::EmbedPlugin::Card);
        plugin->setPluginSizePolicy(itemInter->pluginSizePolicy());
    
        connect(plugin, &Plugin::EmbedPlugin::dockColorThemeChanged,
                this, &WidgetPlugin::onDockColorThemeChanged, Qt::UniqueConnection);
        connect(plugin, &Plugin::EmbedPlugin::dockColorThemeChanged,
                cardItem, [cardItem](uint32_t colorTheme) {
                    cardItem->setDockColorTheme(static_cast<int>(colorTheme));
                });
        connect(plugin, &Plugin::EmbedPlugin::eventGeometry,
                cardItem, [cardItem](const QRect &geometry) {
                    cardItem->resize(geometry.size());
                });
    
        m_cardItems.insert(itemKey, cardItem);
        cardItem->show();
    }
  3. Mirror the explicit branching in itemRemoved
    Keep the current behavior, but make the “card vs normal widget” decision obvious:

    void WidgetPlugin::itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey)
    {
        Q_UNUSED(itemInter);
    
        if (auto cardItem = m_cardItems.take(itemKey)) {
            cardItem->hide();
            cardItem->deleteLater();
            return;
        }
    
        auto widget = m_pluginsItemInterface->itemWidget(itemKey);
        if (widget && widget->window() && widget->window()->windowHandle()) {
            widget->window()->windowHandle()->hide();
        }
    
        auto quickPanel = m_pluginsItemInterface->itemWidget(Dock::QUICK_ITEM_KEY);
        if (quickPanel && quickPanel->window() && quickPanel->window()->windowHandle()) {
            quickPanel->window()->windowHandle()->hide();
        }
    }

These changes keep all current functionality (including “card creation failure blocks normal widget path”) but make the control flow and responsibilities clearer: classification (isCardItem), lifecycle (ensureCardItem), and normal widget handling are separated and easier to follow.

@18202781743 18202781743 self-requested a review July 6, 2026 06:56
Comment thread src/loader/widgetplugin.cpp Outdated
void WidgetPlugin::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
{
qDebug() << "itemAdded:" << itemKey;
if (createCardItemIfNeeded(itemInter, itemKey)) {

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.

可以按照flag来处理card,

Comment thread interfaces/pluginsiteminterface_v3.h Outdated
* The loader creates a QQuickView for this URL and exposes it to the dock
* compositor as a Wayland surface.
*/
virtual QUrl cardQmlSource() const

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.

这里返回一个qwindow是不是更好,让应用控制,这样也能支持qml和qwidget,

@deepin-bot

deepin-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

TAG Bot

New tag: 2.0.36
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #476

@wjyrich wjyrich force-pushed the CardPlugin branch 2 times, most recently from db8987a to 6c683d2 Compare July 10, 2026 09:59
UI

Add a new plugin interface version (V3) supporting card surface
rendering via native QWindow, enabling richer plugin UI like media
player controls. Implement the media plugin card feature with QML-
based music player card, previous song support, and improved metadata
handling.

- Add PluginsItemInterfaceV3 with cardItemKey() and cardWindow() for
native window rendering
- Add Attribute_HasCard plugin flag to identify card-capable plugins
- Implement CardPluginItem in loader to manage card windows as
EmbedPlugin
- Add media card QML UI with playback controls, artwork display, and
metadata
- Add previous track support and playback toggle to MediaController
- Improve MPRIS metadata handling (artist list, title, artwork path)
- Fix plugin unload issues with QPointer guard in EmbedPlugin
- Update media plugin to use V3 interface and create card surface
- Add play-previous SVG icon and update CMakeLists for QtQuick
dependencies

Log: Added card surface support for dock plugins and music player card
UI

Influence:
1. Test media plugin card appears when music player is active
2. Verify card artwork display with various mpris:artUrl sources
3. Test playback controls (play/pause, next, previous) via card
4. Verify card auto-hides when plugin/player is removed
5. Test plugin loading with V2 backwards compatibility
6. Test card window resize and positioning in dock
7. Verify metadata display (title, artist) update in real-time
8. Test hover behavior and control animations in card UI
9. Test clean plugin unload and resource cleanup
10. Verify card works with different system themes (light/dark)

feat: 为任务栏插件添加卡片表面支持及音乐播放器卡片UI

新增插件接口版本V3,支持通过原生QWindow渲染卡片表面,实现更丰富的插件
UI(如媒体播放控制)。实现媒体插件的卡片功能,包含基于QML的音乐播放器卡
片、上一曲支持和改进的元数据处理。

- 新增PluginsItemInterfaceV3接口,提供cardItemKey()和cardWindow()实现原
生窗口渲染
- 新增Attribute_HasCard插件标志,用于标识支持卡片的插件
- 在加载器中实现CardPluginItem,管理作为EmbedPlugin的卡片窗口
- 添加媒体卡片QML UI,包含播放控制、封面显示和元数据展示
- 在MediaController中添加上一曲支持和播放切换功能
- 改进MPRIS元数据处理(艺术家列表、标题、封面路径)
- 使用QPointer守卫修复EmbedPlugin中的插件卸载问题
- 更新媒体插件使用V3接口并创建卡片表面
- 添加上一曲SVG图标并更新CMakeLists添加QtQuick依赖

Log: 新增任务栏插件卡片表面功能和音乐播放器卡片UI

Influence:
1. 测试音乐播放器活动时媒体插件卡片正确显示
2. 验证卡片封面图在不同mpris:artUrl源下的显示效果
3. 测试通过卡片进行播放控制(播放/暂停、下一曲、上一曲)
4. 验证插件/播放器移除时卡片自动隐藏
5. 测试V2版本插件的向后兼容加载
6. 测试卡片窗口在任务栏中的尺寸调整和定位
7. 验证元数据(标题、艺术家)实时更新
8. 测试卡片UI的悬停行为和控件动画
9. 测试插件的干净卸载和资源清理
10. 验证卡片在不同系统主题(浅色/深色)下的显示效果
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码实现了插件卡片表面系统并修复了Wayland集成的UAF漏洞,架构设计清晰且安全性高
逻辑正确且修复了高危UAF缺陷,整体质量优秀,无明显扣分项

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

src/tray-wayland-integration/plugin.cppEmbedPlugin::get 函数的 visibleChanged lambda 捕获方式由裸指针改为 QPointer,有效避免了对象销毁后信号触发导致的野指针访问。src/loader/widgetplugin.cppcreateCardItemIfNeeded 函数逻辑严谨,正确处理了接口转换、对象创建及属性设置。
潜在问题:CardPluginItem 析构函数仅调用 hide() 未释放 m_window 内存,依赖插件自身管理生命周期,若插件未正确释放可能导致内存泄漏
建议:在 CardPluginItem 析构函数中增加对 m_windowdeleteLater 调用,或在文档中明确所有权转移规则

  • 2.代码质量(良好)✓

新增接口 PluginsItemInterfaceV3 注释完整,明确了 cardItemKeycardWindow 的职责与所有权归属。MediaController 新增属性封装规范,信号槽连接清晰。MusicCard.qml 采用组件化设计,属性绑定合理。
潜在问题:MusicCard.qml 中存在大量内联属性计算,如 artSizecontentHeight 等,增加了单文件复杂度
建议:可将部分布局计算逻辑抽取为独立的 QML 函数或 JS 文件,降低组件复杂度

  • 3.代码性能(高效)✓

MediaController::loadMediaPath 将同步 DBus 调用改为异步 asyncCall 配合 QDBusPendingCallWatcher,避免了阻塞主线程。onMetaDataChanged 中使用 QImageReader::setScaledSize 直接读取缩放后的图片,减少了内存开销。QML 中 Image 组件设置了 asynchronous: true,防止 UI 卡顿。
潜在问题:无
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 1 个,持平 0 个
本次代码修复了历史存在的 Use-After-Free 漏洞,未引入新的安全风险。原代码在 plugin.cpp 中捕获裸指针 plugin,存在对象销毁后被访问的风险,现已通过 QPointer 修复。
建议:继续保持使用智能指针管理对象生命周期的最佳实践

■ 【改进建议代码示例】

// src/tray-wayland-integration/plugin.cpp
// 修复 Use-After-Free 缺陷,使用 QPointer 守护对象生命周期

QPointer<EmbedPlugin> pluginGuard(plugin);
QObject::connect(window, &QWindow::visibleChanged, window, [window, pluginGuard] (bool visible) {
    if (!visible) {
        if (!pluginGuard) {
            s_map.remove(window);
            return;
        }

        pluginGuard->deleteLater();
        s_map.remove(window);
    }
});

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