Skip to content

Conversation

@mhduiy
Copy link
Contributor

@mhduiy mhduiy commented Feb 3, 2026

Added connection to source model's dataChanged signal in DockCombineModel constructor to handle icon updates properly. When window icon changes (WinIconRole) but application icon name (IconNameRole) is not included in the change notification, the model now emits dataChanged signal for IconNameRole as well. This ensures that UI components relying on IconNameRole updates are properly refreshed when window icons change, particularly for windows without desktop files that use window icons as application icons.

Log: Fixed taskbar icon updates when window icons change

fix: 当窗口图标变化时发出 IconNameRole 变更通知

在 DockCombineModel 构造函数中添加了对源模型 dataChanged 信号的连接, 以正确处理图标更新。当窗口图标(WinIconRole)发生变化但应用图标名称
(IconNameRole)未包含在变更通知中时,模型现在会额外为 IconNameRole 发
出 dataChanged 信号。这确保了依赖 IconNameRole 更新的 UI 组件在窗口图标 变化时能正确刷新,特别是对于那些没有桌面文件而使用窗口图标作为应用图标的
窗口。

Log: 修复窗口图标变化时任务栏图标更新问题

PMS: BUG-321407

Summary by Sourcery

Bug Fixes:

  • Propagate source model window icon changes as IconNameRole updates so UI elements relying on application icon names are correctly refreshed.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 3, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Connects DockCombineModel to its source model's dataChanged signal and adds a slot that re-emits dataChanged for IconNameRole whenever WinIconRole changes without an accompanying IconNameRole update, ensuring taskbar icon updates for windows using window icons as app icons.

Sequence diagram for propagating WinIconRole changes to IconNameRole

sequenceDiagram
    participant SourceModel
    participant DockCombineModel
    participant TaskbarView

    SourceModel->>SourceModel: dataChanged(topLeft, bottomRight, [WinIconRole])
    SourceModel-->>DockCombineModel: dataChanged(topLeft, bottomRight, [WinIconRole])

    activate DockCombineModel
    DockCombineModel->>DockCombineModel: onSourceDataChanged(topLeft, bottomRight, roles)
    alt roles contains WinIconRole and not IconNameRole
        DockCombineModel-->>DockCombineModel: dataChanged(topLeft, bottomRight, [IconNameRole])
        DockCombineModel-->>TaskbarView: dataChanged(topLeft, bottomRight, [IconNameRole])
        TaskbarView->>TaskbarView: updateTaskbarIcon()
    else roles already contain IconNameRole
        DockCombineModel-->>TaskbarView: dataChanged(topLeft, bottomRight, roles)
    end
    deactivate DockCombineModel
Loading

Updated class diagram for DockCombineModel signal handling

classDiagram
    class QAbstractItemModel {
        <<abstract>>
        +dataChanged(topLeft QModelIndex, bottomRight QModelIndex, roles QList_int)
    }

    class RoleCombineModel {
    }

    class AbstractTaskManagerInterface {
    }

    class DockCombineModel {
        +DockCombineModel(major QAbstractItemModel, minor QAbstractItemModel, parent QObject)
        +data(index QModelIndex, role int) QVariant
        +roleNames() QHash_int_QByteArray
        +onSourceDataChanged(topLeft QModelIndex, bottomRight QModelIndex, roles QList_int)
        -m_roleMaps QHash_int_int
    }

    QAbstractItemModel <|-- RoleCombineModel
    RoleCombineModel <|-- DockCombineModel
    AbstractTaskManagerInterface <|-- DockCombineModel

    QAbstractItemModel "1" o-- "1" DockCombineModel : sourceModel
    DockCombineModel ..> QAbstractItemModel : connects dataChanged to onSourceDataChanged
Loading

File-Level Changes

Change Details Files
Wire DockCombineModel to source model dataChanged and re-emit IconNameRole changes when only WinIconRole is reported.
  • Connect sourceModel()'s dataChanged signal to a new DockCombineModel::onSourceDataChanged slot in the constructor.
  • Implement onSourceDataChanged to check incoming role list and emit dataChanged for IconNameRole when WinIconRole is present but IconNameRole is missing.
  • Declare onSourceDataChanged as a private slot in the DockCombineModel header for use with the new signal connection.
panels/dock/taskmanager/dockcombinemodel.cpp
panels/dock/taskmanager/dockcombinemodel.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

@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 1 issue, and left some high level feedback:

  • In onSourceDataChanged you emit dataChanged with TaskManager::IconNameRole, but since DockCombineModel remaps roles via m_roleMaps, the emitted role should likely be the proxy/model role (e.g. roleNames().key(MODEL_…)) rather than the source TaskManager role, otherwise views may not pick up the change correctly.
  • QAbstractItemModel::dataChanged can be emitted with an empty roles list to mean "all roles changed"; consider handling the case where roles is empty but the icon has effectively changed, so that IconNameRole notifications are also propagated in that scenario.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In onSourceDataChanged you emit dataChanged with TaskManager::IconNameRole, but since DockCombineModel remaps roles via m_roleMaps, the emitted role should likely be the proxy/model role (e.g. roleNames().key(MODEL_…)) rather than the source TaskManager role, otherwise views may not pick up the change correctly.
- QAbstractItemModel::dataChanged can be emitted with an empty roles list to mean "all roles changed"; consider handling the case where roles is empty but the icon has effectively changed, so that IconNameRole notifications are also propagated in that scenario.

## Individual Comments

### Comment 1
<location> `panels/dock/taskmanager/dockcombinemodel.cpp:78-84` </location>
<code_context>
     return QVariant();
 }
+
+void DockCombineModel::onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles)
+{
+    // 部分窗口没有desktop, 应用图标使用的是窗口图标,当窗口图标变化的时候也需要发送应用图标变化的通知,以便前端更新
+    if (roles.contains(TaskManager::WinIconRole) && !roles.contains(TaskManager::IconNameRole)) {
+        Q_EMIT dataChanged(topLeft, bottomRight, {TaskManager::IconNameRole});
+    }
</code_context>

<issue_to_address>
**suggestion:** The roles list may be empty to indicate all roles changed, which is not handled here.

Qt’s `dataChanged` may be emitted with an empty `roles` list to indicate that any role might have changed. In that case, this condition will skip emitting the synthesized `IconNameRole` change even if the window icon changed. Consider treating an empty list as “all roles” and emitting `IconNameRole` when `roles.isEmpty()` or `roles.contains(TaskManager::WinIconRole)`, for example:

```cpp
if ((roles.isEmpty() || roles.contains(TaskManager::WinIconRole)) &&
    !roles.contains(TaskManager::IconNameRole)) {
    Q_EMIT dataChanged(topLeft, bottomRight, { TaskManager::IconNameRole });
}
```

```suggestion
void DockCombineModel::onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles)
{
    // 部分窗口没有desktop, 应用图标使用的是窗口图标,当窗口图标变化的时候也需要发送应用图标变化的通知,以便前端更新
    if ((roles.isEmpty() || roles.contains(TaskManager::WinIconRole)) &&
        !roles.contains(TaskManager::IconNameRole)) {
        Q_EMIT dataChanged(topLeft, bottomRight, { TaskManager::IconNameRole });
    }
}
```
</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.

Added connection to source model's dataChanged signal in
DockCombineModel constructor to handle icon updates properly.
When window icon changes (WinIconRole) but application icon name
(IconNameRole) is not included in the change notification, the model now
emits dataChanged signal for IconNameRole as well. This ensures that UI
components relying on IconNameRole updates are properly refreshed when
window icons change, particularly for windows without desktop files that
use window icons as application icons.

Log: Fixed taskbar icon updates when window icons change

fix: 当窗口图标变化时发出 IconNameRole 变更通知

在 DockCombineModel 构造函数中添加了对源模型 dataChanged 信号的连接,
以正确处理图标更新。当窗口图标(WinIconRole)发生变化但应用图标名称
(IconNameRole)未包含在变更通知中时,模型现在会额外为 IconNameRole 发
出 dataChanged 信号。这确保了依赖 IconNameRole 更新的 UI 组件在窗口图标
变化时能正确刷新,特别是对于那些没有桌面文件而使用窗口图标作为应用图标的
窗口。

Log: 修复窗口图标变化时任务栏图标更新问题

PMS: BUG-321407
@mhduiy
Copy link
Contributor Author

mhduiy commented Feb 3, 2026

也可以在window icon 变化的时候同时发出iconname changed的信号

@deepin-ci-robot
Copy link

deepin pr auto review

这段代码的目的是在 DockCombineModel 中处理源模型数据变化时的逻辑,特别是当窗口图标(WinIconRole)变化时,同步通知应用图标(IconNameRole)发生变化,以便前端更新。

以下是对这段代码的详细审查意见,包括语法逻辑、代码质量、代码性能和代码安全方面的改进建议:

1. 语法逻辑与代码质量

优点:

  • 意图清晰:代码注释很好地解释了为什么需要这个逻辑(处理部分窗口没有 desktop 文件,导致应用图标依赖窗口图标的情况)。
  • 信号槽连接:正确地使用了 connect 连接源模型的 dataChanged 信号到自定义槽函数。
  • 角色映射:逻辑上正确地检查了 WinIconRole 的变化并触发了 IconNameRole 的变化。

改进意见:

  1. 信号连接时机与对象生命周期

    • 问题:在构造函数中直接调用 sourceModel()RoleCombineModel(父类)通常会在 setSourceModel 时才设置源模型。如果父类构造函数尚未调用 setSourceModel,或者当前 sourceModel() 返回 nullptrconnect 可能会失败或无效。
    • 建议:检查父类 RoleCombineModel 的实现。通常建议重写 setSourceModel 方法,在设置新模型时进行连接,并断开旧模型的连接。如果父类保证构造时已有源模型,则当前写法可行,但需确保父类逻辑正确。
  2. 信号参数的有效性检查

    • 问题:槽函数 onSourceDataChanged 直接使用了传入的 topLeftbottomRight 索引。这些索引属于源模型。直接将它们传递给 Q_EMIT dataChanged 是正确的(因为 DockCombineModel 是代理模型,通常映射源模型的索引),但需要确认 RoleCombineModelmapFromSource 行为。如果父类没有自动映射索引,这里可能需要手动映射。
    • 建议:确认 RoleCombineModel 是否为 QAbstractProxyModel 的子类。如果是,通常不需要手动映射。如果是直接操作数据结构,需确保索引在当前模型中有效。
  3. 槽函数声明位置

    • 问题onSourceDataChanged 被声明为 private slots。在现代 Qt(Qt 5 及以上)中,如果使用函数指针连接(如代码中所示),slots 关键字不是严格必须的,普通的 private 成员函数也可以。但保留 slots 是良好的习惯,便于阅读和兼容旧语法。

2. 代码性能

潜在问题:

  • 频繁的信号发射
    • 分析:如果源模型频繁触发 dataChanged(例如窗口标题实时更新),且每次都满足 WinIconRole 变化的条件,这里会再次发射 dataChanged 信号。这会导致视图(View)进行不必要的重绘。
    • 建议:目前的逻辑看起来是必要的(必须通知前端更新)。但可以确认一下 roles 的判断逻辑是否足够精确,避免误触发。目前的逻辑 !roles.contains(TaskManager::IconNameRole) 是为了避免重复触发或死循环,这是很好的做法。

3. 代码安全

改进意见:

  1. 空指针检查

    • 建议:在 onSourceDataChanged 中,虽然 sourceModel() 发射信号时通常保证自身有效,但在处理索引前,可以增加对 topLeftbottomRight 有效性的检查(例如 topLeft.isValid()),防止源模型传递无效索引导致崩溃。
  2. 防止信号循环

    • 现状:代码中 !roles.contains(TaskManager::IconNameRole) 的判断有效地防止了无限循环(即:源模型变了Icon -> 触发信号 -> 如果这个信号又导致源模型变化...)。
    • 建议:保持这个逻辑,并确保未来添加其他 Role 时不会引入循环。

4. 修改后的代码建议

结合以上分析,以下是优化后的代码片段建议:

// dockcombinemodel.h
// ...
private slots:
    // 添加 override 关键字(如果继承自接口)或保持现状
    void onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles);
// ...

// dockcombinemodel.cpp
// ...

// 建议在 setSourceModel 中连接,或者在构造函数中确认 sourceModel() 不为空
// 如果必须在构造函数中连接,建议增加断言或检查
DockCombineModel::DockCombineModel(QAbstractItemModel *major, QAbstractItemModel *minor)
    : RoleCombineModel(major, minor)
{
    // ... 初始化代码 ...

    if (sourceModel()) {
        connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &DockCombineModel::onSourceDataChanged);
    }
}

// ...

void DockCombineModel::onSourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles)
{
    // 增加索引有效性检查
    if (!topLeft.isValid() || !bottomRight.isValid()) {
        return;
    }

    // 部分窗口没有desktop, 应用图标使用的是窗口图标,当窗口图标变化的时候也需要发送应用图标变化的通知,以便前端更新
    // 逻辑:如果角色列表为空(表示所有角色可能都变了) 或者 包含了 WinIconRole
    // 并且 角色列表中不包含 IconNameRole(防止循环或重复通知)
    if ((roles.isEmpty() || roles.contains(TaskManager::WinIconRole)) &&
        !roles.contains(TaskManager::IconNameRole)) {
        
        // 注意:如果 RoleCombineModel 是代理模型,通常需要确保发射的索引是当前模型的索引。
        // 如果父类已经处理了映射,直接传递 topLeft/bottomRight 是可以的。
        // 如果父类没有自动映射,且 sourceModel 的索引直接用于当前 model,则需确保逻辑一致。
        // 这里假设直接传递是符合模型架构的。
        Q_EMIT dataChanged(topLeft, bottomRight, { TaskManager::IconNameRole });
    }
}

总结

这段代码逻辑上是正确的,解决了窗口图标变化同步到应用图标的需求。主要的改进点在于:

  1. 增加 sourceModel() 的空指针检查,确保连接安全。
  2. 在槽函数中增加索引有效性检查,增强鲁棒性。
  3. 确认父类的索引映射机制,确保 dataChanged 发射的索引在当前模型上下文中是有效的。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, mhduiy

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

@mhduiy mhduiy merged commit 8c0e2a3 into linuxdeepin:master Feb 3, 2026
10 of 11 checks passed
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