Skip to content

fix: improve window icon handling and model reset logic#1578

Merged
wjyrich merged 1 commit intolinuxdeepin:masterfrom
wjyrich:feat-hoverpreview
May 8, 2026
Merged

fix: improve window icon handling and model reset logic#1578
wjyrich merged 1 commit intolinuxdeepin:masterfrom
wjyrich:feat-hoverpreview

Conversation

@wjyrich
Copy link
Copy Markdown
Contributor

@wjyrich wjyrich commented Apr 29, 2026

  1. Fixed DockCombineModel to respect window split setting for icon display
  2. Simplified DockItemModel source model change to use full reset instead of incremental updates
  3. Optimized AppItem icon loading to avoid retaining while window is active
  4. Added explicit icon update for X11 windows on mapping

The changes fix icon display inconsistencies where window-specific icons were incorrectly overridden by application icons when window split is disabled. The model reset simplification fixes edge cases where incremental row updates could cause state corruption. The icon loading optimization improves performance by not retaining loading states for active windows.

Log: Fixed window icon display logic and model synchronization

Influence:

  1. Test dock icon display with multiple windows, verify window-specific icons show correctly
  2. Test window split mode toggle, verify icon behavior changes accordingly
  3. Test quick window switching, verify no icon loading artifacts
  4. Test X11 window mapping, verify icons update immediately
  5. Test model source changes, verify no crashes or data corruption
  6. Test with high window count, verify performance is not degraded

fix: 改进窗口图标处理和模型重置逻辑

  1. 修复 DockCombineModel 中图标显示逻辑,遵循窗口分裂设置
  2. 简化 DockItemModel 源模型变更时的处理,使用全量重置替代增量更新
  3. 优化 AppItem 图标加载,窗口活跃时不再保留加载状态
  4. 为 X11 窗口映射时添加显式图标更新

这些修改修复了当窗口分裂功能禁用时,窗口特定图标被应用程序图标错误覆盖的
问题。模型重置的简化修复了增量行更新可能导致的内部状态损坏问题。图标加载
优化通过不在活动窗口中保留加载状态来提高性能。

Log: 修复了窗口图标显示逻辑和模型同步问题

Influence:

  1. 测试多窗口 dock 图标显示,验证窗口特定图标正确显示
  2. 测试窗口分裂模式切换,验证图标行为相应变更
  3. 测试快速窗口切换,验证无图标加载残留
  4. 测试 X11 窗口映射,验证图标立即更新
  5. 测试模型源变更,验证无崩溃或数据损坏
  6. 测试高窗口数量场景,验证性能不下降

PMS: TASK-389031

Summary by Sourcery

Improve dock task manager icon handling and model synchronization for better window-specific icon display and stability.

Bug Fixes:

  • Ensure DockCombineModel prefers window icons over application icons when window split mode is enabled and avoids overriding valid window icons.
  • Prevent potential model state corruption by resetting DockItemModel fully when the source model changes instead of performing partial row updates.
  • Ensure X11 windows refresh their icons immediately upon mapping to avoid stale or missing icons.

Enhancements:

  • Adjust AppItem icon loading behavior to avoid retaining loading state for active windows, reducing visual artifacts and improving performance.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 29, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Refactors dock task manager models and related window/icon handling to use a full model reset on source changes, respect window-split settings for choosing window vs. app icons, optimize QML icon loading for active windows, and immediately refresh X11 window icons upon mapping.

Sequence diagram for X11 window mapping and immediate icon update

sequenceDiagram
    participant XServer
    participant X11WindowMonitor
    participant Window
    participant AbstractWindowMonitor

    XServer->>X11WindowMonitor: MapNotify(xcb_window)
    activate X11WindowMonitor
    X11WindowMonitor->>X11WindowMonitor: onWindowMapped(xcb_window)
    X11WindowMonitor->>X11WindowMonitor: xcb_change_window_attributes
    X11WindowMonitor->>Window: trackWindow(window)
    X11WindowMonitor->>Window: updateIcon()
    X11WindowMonitor->>AbstractWindowMonitor: windowAdded(window)
    deactivate X11WindowMonitor
Loading

Class diagram for updated dock task manager models and window/icon handling

classDiagram
    class DockItemModel {
        +bool m_isUpdating
        +void setSourceModel(QAbstractItemModel *model)
    }

    class QAbstractProxyModel {
        +void setSourceModel(QAbstractItemModel *model)
        +int rowCount()
    }

    DockItemModel --|> QAbstractProxyModel

    class DockCombineModel {
        +QVariant data(const QModelIndex &index, int role) const
        -QHash<int,int> m_roleMaps
        +DockCombineModel(QAbstractItemModel *major, QAbstractItemModel *minor, int majorRoles, CombineFunc func, QObject *parent)
    }

    class RoleCombineModel {
        +QVariant data(const QModelIndex &index, int role) const
    }

    DockCombineModel --|> RoleCombineModel

    class TaskManager {
        <<enumeration>>
        +int IconNameRole
        +int WinIconRole
    }

    DockCombineModel ..> TaskManager : uses roles

    class TaskManagerSettings {
        +static TaskManagerSettings* instance()
        +bool isWindowSplit() const
    }

    DockCombineModel ..> TaskManagerSettings : queries isWindowSplit

    class X11WindowMonitor {
        +void onWindowMapped(xcb_window_t xcb_window)
        +void trackWindow(Window *window)
    }

    class AbstractWindowMonitor {
        +void windowAdded(QPointer<AbstractWindow> window)
    }

    X11WindowMonitor --|> AbstractWindowMonitor

    class Window {
        +void updateIcon()
    }

    X11WindowMonitor ..> Window : trackWindow

    class AppItem {
        +bool titleActive
        +Image iconImage
    }

    class Image {
        +bool retainWhileLoading
    }

    AppItem *-- Image : contains iconImage
Loading

Flow diagram for DockCombineModel icon selection logic

flowchart TD
    A(Start) --> B[Request data for IconNameRole]
    B --> C[Read winIcon from WinIconRole]
    C --> D{isWindowSplit and winIcon not empty}
    D -- Yes --> E[Return winIcon]
    D -- No --> F[Read icon from IconNameRole]
    F --> G{icon empty}
    G -- Yes --> H[Set icon to winIcon]
    G -- No --> I[Keep app icon]
    H --> J[Return icon]
    I --> J[Return icon]
    E --> K(End)
    J --> K(End)
Loading

Flow diagram for DockItemModel source model reset logic

flowchart TD
    A(Start setSourceModel) --> B{Existing sourceModel}
    B -- Yes --> C[Disconnect old source model signals]
    B -- No --> D[Skip disconnect]
    C --> E
    D --> E
    E[beginResetModel] --> F["QAbstractProxyModel::setSourceModel new model"]
    F --> G[endResetModel]
    G --> H[Connect rowsInserted, rowsRemoved, rowsMoved, dataChanged signals]
    H --> I[Set m_isUpdating to false]
    I --> J(End)
Loading

File-Level Changes

Change Details Files
Switch DockItemModel source model updates to a full model reset instead of manual row insert/remove and dataChanged handling.
  • Wrap QAbstractProxyModel::setSourceModel in beginResetModel/endResetModel when changing the source model.
  • Remove manual row count comparison and beginInsertRows/beginRemoveRows logic.
  • Remove explicit dataChanged emission after adjusting rows and rely on the reset to notify views.
  • Keep existing row-inserted/removed/moved signal connections unchanged.
panels/dock/taskmanager/dockitemmodel.cpp
Adjust DockCombineModel icon selection to respect window-split settings and favor per-window icons only when appropriate.
  • Include TaskManagerSettings to access dock configuration.
  • Retrieve the window icon separately and return it directly when non-empty and window split is enabled.
  • Fall back to the application icon first, and only then to the window icon if the app icon is empty, when window split is disabled.
  • Update SPDX copyright header to cover years 2025-2026.
panels/dock/taskmanager/dockcombinemodel.cpp
Optimize QML AppItem icon loading behavior for active windows to avoid unnecessary retention of loading placeholders.
  • Change the Image element's retainWhileLoading property to be disabled while the window title is active by binding it to !root.titleActive.
panels/dock/taskmanager/package/AppItem.qml
Ensure X11 window icons are refreshed immediately when a window is mapped.
  • After tracking a newly mapped X11 window, explicitly call updateIcon() before emitting windowAdded.
  • Leave existing X11 event mask setup and windowAdded emission logic intact.
panels/dock/taskmanager/x11windowmonitor.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

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

  • In DockItemModel::setSourceModel, consider skipping the beginResetModel/endResetModel path when the new source model is identical to the current one to avoid unnecessary full model resets and view churn.
  • DockCombineModel::data now depends on TaskManagerSettings::isWindowSplit(), but the model does not emit any dataChanged signals when this setting toggles; consider listening to the setting change and triggering a suitable dataChanged/model reset so views update their icons immediately when the split mode changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In DockItemModel::setSourceModel, consider skipping the beginResetModel/endResetModel path when the new source model is identical to the current one to avoid unnecessary full model resets and view churn.
- DockCombineModel::data now depends on TaskManagerSettings::isWindowSplit(), but the model does not emit any dataChanged signals when this setting toggles; consider listening to the setting change and triggering a suitable dataChanged/model reset so views update their icons immediately when the split mode changes.

## Individual Comments

### Comment 1
<location path="panels/dock/taskmanager/x11windowmonitor.cpp" line_range="189" />
<code_context>
     xcb_change_window_attributes(X11->getXcbConnection(), xcb_window, XCB_CW_EVENT_MASK, value_list);
     trackWindow(window.get());
+
+    window->updateIcon();
     Q_EMIT AbstractWindowMonitor::windowAdded(static_cast<QPointer<AbstractWindow>>(window.get()));
 }
</code_context>
<issue_to_address>
**question (bug_risk):** Check for any ordering assumptions between `updateIcon()` and `windowAdded`.

Calling `updateIcon()` before emitting `windowAdded` changes the lifecycle: listeners now see a window whose icon may already be updated, and any signals from `updateIcon()` fire first. Please confirm that no existing `windowAdded` consumers assume they run before icon‑related updates; if they do, consider keeping `updateIcon()` after `windowAdded` or clearly documenting this new ordering.
</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.

xcb_change_window_attributes(X11->getXcbConnection(), xcb_window, XCB_CW_EVENT_MASK, value_list);
trackWindow(window.get());

window->updateIcon();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

question (bug_risk): Check for any ordering assumptions between updateIcon() and windowAdded.

Calling updateIcon() before emitting windowAdded changes the lifecycle: listeners now see a window whose icon may already be updated, and any signals from updateIcon() fire first. Please confirm that no existing windowAdded consumers assume they run before icon‑related updates; if they do, consider keeping updateIcon() after windowAdded or clearly documenting this new ordering.

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 29, 2026

TAG Bot

New tag: 2.0.39
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1580

@wjyrich wjyrich force-pushed the feat-hoverpreview branch 2 times, most recently from a8ac6c7 to 7907104 Compare May 6, 2026 02:27
Comment thread panels/dock/taskmanager/dockcombinemodel.cpp Outdated
Comment thread panels/dock/taskmanager/x11windowmonitor.cpp Outdated
@wjyrich wjyrich force-pushed the feat-hoverpreview branch 4 times, most recently from 6ec1bac to a64660d Compare May 8, 2026 06:53
@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, 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

1. Add a new dconfig setting "windowIconWhitelist" with default value
["wechat"]
2. When window split mode is enabled, the dock now checks the whitelist
to decide whether to use window icons instead of app icons for specific
applications
3. Fix model reset in DockItemModel::setSourceModel to use
beginResetModel/endResetModel instead of manual row insertion/removal
for better model consistency
4. Update X11 window monitor to trigger icon update when a new window
is mapped

The window icon whitelist is needed for apps like WeChat that provide
superior window icon quality compared to their app icons, enhancing the
visual experience when window split is disabled.

Log: Added window icon whitelist config for dock task manager

Influence:
1. Verify WeChat and other whitelisted apps display correct icons when
window split is disabled
2. Test default whitelist behavior with WeChat running
3. Check that non-whitelisted apps still use app icons when window split
is disabled
4. Test the new dconfig setting can be modified and persists correctly
5. Ensure DockItemModel resets work correctly without data corruption
6. Verify X11 window monitor still functions properly with icon update
call

feat: 为任务栏任务管理器添加窗口图标白名单功能

1. 添加新的 dconfig 设置"windowIconWhitelist",默认值为["wechat"]
2. 当窗口拆分模式启用时,任务栏会检查白名单,决定是否对特定应用使用窗口
图标而非应用图标
3. 修复 DockItemModel::setSourceModel 中的模型重置,改用
beginResetModel/endResetModel 替代手动行插入/删除,以提高模型一致性
4. 更新 X11 窗口监视器,在新窗口映射时触发图标更新

对于微信等提供比应用图标更优质窗口图标的应用,窗口图标白名单是必要的,可
在窗口拆分禁用时提升视觉体验。

Log: 为任务栏添加窗口图标白名单配置

Influence:
1. 验证在白名单中的应用(如微信)在禁用窗口拆分时显示正确图标
2. 使用微信测试默认白名单行为
3. 检查非白名单应用在禁用窗口拆分时仍使用应用图标
4. 测试新的 dconfig 设置可以被修改并持久保存
5. 确保 DockItemModel 重置操作正常,无数据损坏
6. 验证 X11 窗口监视器在添加图标更新调用后仍正常工作

PMS: TASK-389031
@wjyrich wjyrich force-pushed the feat-hoverpreview branch from a64660d to bcde740 Compare May 8, 2026 06:59
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

代码审查报告

总体评价

这段代码主要实现了在任务栏中为特定应用(如微信)优先使用窗口图标而非应用图标的功能。整体代码结构清晰,功能实现基本合理,但在性能优化、代码规范和健壮性方面还有改进空间。

详细审查意见

1. 语法逻辑

1.1 dockcombinemodel.cpp 中的逻辑问题

if (TaskManagerSettings::instance()->isWindowSplit()) {
    auto desktopId = data(index, TaskManager::DesktopIdRole).toString();
    auto whitelist = TaskManagerSettings::instance()->windowIconWhitelist();
    if (whitelist.contains(desktopId)) {
        auto winIcon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::WinIconRole)).toString();
        if (!winIcon.isEmpty()) {
            return winIcon;
        }
    }
}

问题

  • 逻辑判断顺序可能导致不必要的性能开销
  • isWindowSplit() 为 false 时仍会执行后续代码

建议

// 优化后的逻辑
auto desktopId = data(index, TaskManager::DesktopIdRole).toString();
auto whitelist = TaskManagerSettings::instance()->windowIconWhitelist();
if (!whitelist.contains(desktopId) || TaskManagerSettings::instance()->isWindowSplit()) {
    // 不在白名单中或窗口已拆分,使用默认图标逻辑
    auto icon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::IconNameRole)).toString();
    if (icon.isEmpty()) {
        icon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::WinIconRole)).toString();
    }
    return icon;
}

// 在白名单中且窗口未拆分,优先使用窗口图标
auto winIcon = RoleCombineModel::data(index, m_roleMaps.value(TaskManager::WinIconRole)).toString();
if (!winIcon.isEmpty()) {
    return winIcon;
}
return RoleCombineModel::data(index, m_roleMaps.value(TaskManager::IconNameRole)).toString();

1.2 dockitemmodel.cpp 中的模型重置逻辑

void DockItemModel::setSourceModel(QAbstractItemModel *model)
{
    // ...
    beginResetModel();
    QAbstractProxyModel::setSourceModel(model);
    endResetModel();
    // ...
}

问题

  • 使用 beginResetModel()/endResetModel() 会导致视图完全重建,性能较差
  • 原有的增量更新逻辑被完全移除

建议

void DockItemModel::setSourceModel(QAbstractItemModel *model)
{
    if (sourceModel()) {
        sourceModel()->disconnect(this);
    }

    auto currentCount = this->rowCount();
    auto newCount = model ? model->rowCount() : 0;
    
    QAbstractProxyModel::setSourceModel(model);
    
    if (newCount > currentCount) {
        beginInsertRows(QModelIndex(), currentCount, newCount - 1);
        endInsertRows();
    } else if (newCount < currentCount) {
        beginRemoveRows(QModelIndex(), newCount, currentCount - 1);
        endRemoveRows();
    }
    
    if (currentCount > 0 && newCount > 0) {
        auto bottomRight = this->index(std::min(currentCount, newCount) - 1, 0);
        Q_EMIT dataChanged(index(0, 0), bottomRight);
    }

    // 连接信号...
}

2. 代码质量

2.1 命名规范

  • TASKMANAGER_WINDOW_ICON_WHITELIST_KEY 命名过长,建议简化为 WINDOW_ICON_WHITELIST_KEY
  • windowIconWhitelist 方法名符合驼峰命名规范,但建议添加 get 前缀,如 getWindowIconWhitelist()

2.2 代码重复

auto desktopId = data(index, TaskManager::DesktopIdRole).toString();
auto whitelist = TaskManagerSettings::instance()->windowIconWhitelist();

这段代码在每次调用 data() 时都会执行,建议提取为类成员变量或缓存。

3. 代码性能

3.1 频繁的设置访问

TaskManagerSettings::instance()->isWindowSplit()
TaskManagerSettings::instance()->windowIconWhitelist()

每次调用 data() 都会访问设置,建议:

  • isWindowSplit() 的结果缓存
  • 将白名单内容缓存并在设置变更时更新

3.2 字符串操作

auto desktopId = data(index, TaskManager::DesktopIdRole).toString();

频繁的 toString() 调用会产生临时字符串对象,可以考虑使用 QVariant 直接比较。

4. 代码安全

4.1 配置文件安全性

"windowIconWhitelist": {
    "value": ["com.tencent.wechat"],
    "serial": 0,
    "flags": [],
    "name": "windowIconWhitelist",
    "name[zh_CN]": "窗口图标白名单",
    "description": "List of app id that should prefer window icon when window split is disabled",
    "permissions": "readwrite",
    "visibility": "private"
}

建议

  • 添加对白名单内容的验证,防止注入非法应用ID
  • 考虑限制白名单的最大长度,防止内存耗尽攻击
  • 添加白名单格式验证,确保只允许有效的应用ID格式

4.2 空指针检查

auto desktopId = data(index, TaskManager::DesktopIdRole).toString();

没有检查 index 的有效性,建议添加:

if (!index.isValid()) {
    return QVariant();
}

5. 其他建议

  1. 添加单元测试:为新增的白名单功能添加单元测试,特别是边界条件测试。

  2. 文档完善:为 windowIconWhitelist 功能添加更详细的文档说明,包括:

    • 功能用途
    • 使用场景
    • 配置示例
  3. 日志记录:在关键逻辑处添加调试日志,便于问题排查:

qDebug() << "Checking window icon for" << desktopId << "in whitelist:" << whitelist.contains(desktopId);
  1. 考虑国际化name[zh_CN] 只提供了中文翻译,建议添加英文和其他语言的翻译。

总结

这段代码实现了窗口图标白名单功能,但在性能优化和代码健壮性方面还有改进空间。建议:

  1. 优化图标选择逻辑,减少不必要的设置访问
  2. 恢复并优化模型增量更新逻辑
  3. 添加输入验证和安全检查
  4. 完善文档和测试

这些改进将使代码更高效、更安全、更易于维护。

@wjyrich wjyrich merged commit 5e3b941 into linuxdeepin:master May 8, 2026
11 of 12 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