Skip to content

Conversation

@Ivy233
Copy link
Contributor

@Ivy233 Ivy233 commented Jan 4, 2026

概述

新增基于应用类别(Categories)的 cgroups 分组跳过列表功能,解决终端模拟器中启动的图形程序被错误归类到终端应用的问题。

问题描述

目前任务栏基于 cgroup 识别应用时,终端中启动的图形程序会继承父进程(终端)的 cgroup 信息,导致窗口被错误识别为归属终端应用。虽然存在白名单 cgroupsBasedGroupingSkipAppIds,但需要逐个手动添加终端模拟器的 appId。

解决方案

  1. 新增 DConfig 配置项 cgroupsBasedGroupingSkipCategories

    • 默认值:["TerminalEmulator"]
    • 支持基于 desktop 文件的 Categories 字段进行匹配
  2. 实现类别检查函数 shouldSkipCgroupsByCategories()

    • 通过 DBus 查询应用的 Categories
    • 检查是否在跳过列表中
  3. 集成到窗口匹配流程

    • 在 cgroups 匹配前进行类别检查
    • 如果应用属于跳过类别,则跳过 cgroups 匹配

修改文件

  • panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json - 新增配置项
  • panels/dock/taskmanager/globals.h - 新增配置键常量
  • panels/dock/taskmanager/taskmanager.cpp - 实现类别检查逻辑
  • panels/dock/taskmanager/taskmanagersettings.cpp - 读取配置
  • panels/dock/taskmanager/taskmanagersettings.h - 添加接口

测试验证

  • 安装 Alacritty 终端模拟器
  • 在 Alacritty 中运行 dde-dconfig-editor
  • 验证 dde-dconfig-editor 显示为独立图标(不被归类到 Alacritty)
  • 验证深度终端等原有白名单应用仍正常工作
  • 确认非终端类应用的分组行为不受影响

Summary by Sourcery

Add configurable category-based skip list for cgroup-based taskbar grouping to avoid mis-grouping terminal-launched GUI apps.

New Features:

  • Introduce a DConfig option to define application categories that should be excluded from cgroup-based window grouping.
  • Use desktop file Categories retrieved via DBus to decide whether to skip cgroup-based grouping for a window.

Enhancements:

  • Extend task manager settings and matching logic to combine app ID and category-based skip rules when applying cgroup-based grouping.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Ivy233

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

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 4, 2026

Reviewer's Guide

Adds a configurable, category-based skip list to the task manager’s cgroups-based window grouping, so that apps in specified desktop Categories (default: TerminalEmulator) bypass cgroup-based grouping and avoid being incorrectly grouped under terminal emulators.

Sequence diagram for cgroups-based grouping with category skip check

sequenceDiagram
    actor User
    participant TerminalEmulator
    participant GUIApp
    participant TaskManager
    participant Settings
    participant ApplicationManager
    participant Application

    User->>TerminalEmulator: Start terminal emulator
    User->>TerminalEmulator: Run graphical app command
    TerminalEmulator->>GUIApp: Spawn GUI process
    GUIApp->>TaskManager: New window detected

    TaskManager->>Settings: cgroupsBasedGrouping()
    alt cgroups based grouping enabled
        TaskManager->>TaskManager: getDesktopIdByPid(identifies)
        alt desktopId is empty
            TaskManager->>TaskManager: Fallback grouping (no desktopId)
        else desktopId is not empty
            TaskManager->>Settings: cgroupsBasedGroupingSkipIds()
            alt desktopId in skip id list
                TaskManager->>TaskManager: Skip cgroups grouping (whitelisted by id)
            else desktopId not in skip id list
                TaskManager->>TaskManager: shouldSkipCgroupsByCategories(desktopId)
                TaskManager->>Settings: cgroupsBasedGroupingSkipCategories()
                TaskManager->>ApplicationManager: Create Application proxy with desktopId
                alt Application proxy is valid
                    TaskManager->>Application: categories()
                    alt category in skip category list
                        TaskManager->>TaskManager: Skip cgroups grouping (whitelisted by category)
                    else no matching category
                        TaskManager->>TaskManager: Perform cgroups based grouping
                    end
                else Application proxy invalid
                    TaskManager->>TaskManager: Perform cgroups based grouping
                end
            end
        end
    else cgroups based grouping disabled
        TaskManager->>TaskManager: Use existing non cgroups grouping
    end

    TaskManager-->>User: Window appears in taskbar (grouped or independent depending on checks)
Loading

Class diagram for updated TaskManagerSettings and Application interface usage

classDiagram
    class TaskManagerSettings {
        -bool m_cgroupsBasedGrouping
        -QStringList m_dockedElements
        -QStringList m_cgroupsBasedGroupingSkipAppIds
        -QStringList m_cgroupsBasedGroupingSkipCategories
        +TaskManagerSettings(QObject parent)
        +bool cgroupsBasedGrouping()
        +QStringList cgroupsBasedGroupingSkipIds()
        +QStringList cgroupsBasedGroupingSkipCategories()
        +QStringList dockedElements()
        +void setDockedElements(QStringList elements)
        +void toggleDockedElement(QString element)
    }

    class TaskManager {
        +bool init()
    }

    class Application {
        +QStringList categories()
        +bool isValid()
    }

    class Settings {
        +bool cgroupsBasedGrouping()
        +QStringList cgroupsBasedGroupingSkipIds()
        +QStringList cgroupsBasedGroupingSkipCategories()
    }

    TaskManager --> Settings : uses
    TaskManager --> Application : queries categories via DBus
    Settings --> TaskManagerSettings : wraps persistent config
    TaskManagerSettings ..> QStringList : stores skip lists
Loading

File-Level Changes

Change Details Files
Add DConfig-backed setting for cgroups grouping skip categories and expose it via TaskManagerSettings.
  • Introduce TASKMANAGER_CGROUPS_BASED_GROUPING_SKIP_CATEGORIES key in globals.
  • Load cgroupsBasedGroupingSkipCategories from DConfig with default ["TerminalEmulator"].
  • Add cgroupsBasedGroupingSkipCategories() accessor and backing member on TaskManagerSettings.
panels/dock/taskmanager/globals.h
panels/dock/taskmanager/taskmanagersettings.h
panels/dock/taskmanager/taskmanagersettings.cpp
panels/dock/taskmanager/dconfig/org.deepin.ds.dock.taskmanager.json
Integrate category-based skip logic into the cgroups-based window matching flow using ApplicationManager DBus API.
  • Include applicationinterface.h in taskmanager.cpp to talk to ApplicationManager over DBus.
  • Implement shouldSkipCgroupsByCategories(desktopId) that queries the app’s Categories via DBus and checks them against the configured skip categories list.
  • Extend the cgroups-based matching condition to also require that desktopId is not in the skip categories (using shouldSkipCgroupsByCategories).
panels/dock/taskmanager/taskmanager.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

@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 left some high level feedback:

  • The per-window DBus lookup in shouldSkipCgroupsByCategories may add noticeable overhead in the hot path of window matching; consider caching categories by desktopId or precomputing the skip decision to avoid repeated DBus calls.
  • When checking skipCategories.contains(category), you might want to normalize case or use a QSet for skipCategories to avoid subtle mismatches and to make the membership checks more efficient.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The per-window DBus lookup in shouldSkipCgroupsByCategories may add noticeable overhead in the hot path of window matching; consider caching categories by desktopId or precomputing the skip decision to avoid repeated DBus calls.
- When checking skipCategories.contains(category), you might want to normalize case or use a QSet for skipCategories to avoid subtle mismatches and to make the membership checks more efficient.

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.

Comment on lines 80 to 90
QString dbusPath = QStringLiteral("/org/desktopspec/ApplicationManager1/") + escapeToObjectPath(desktopId);

// 创建 Application 接口
Application appInterface(QStringLiteral("org.desktopspec.ApplicationManager1"),
dbusPath,
QDBusConnection::sessionBus());

if (!appInterface.isValid()) {
qCDebug(taskManagerLog) << "Failed to create Application interface for:" << desktopId;
return false;
}
Copy link
Member

Choose a reason for hiding this comment

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

不再绕一次 dbus 了,在 AppItem 一层新增一个 CategoryRole(可以参考现有的 DDECategoryRole),然后直接使用这个新增的 role 即可。

@Ivy233
Copy link
Contributor Author

Ivy233 commented Jan 5, 2026

recheck

@Ivy233 Ivy233 force-pushed the feature/cgroups-skip-categories branch from a0e2e66 to 3b87e6d Compare January 6, 2026 15:42
if (activeAppModel) {
auto existingItem = activeAppModel->match(activeAppModel->index(0, 0), roleNames.key("desktopId"), desktopId, 1, Qt::MatchFixedString | Qt::MatchWrap).value(0);
if (existingItem.isValid()) {
categories = activeAppModel->data(existingItem, roleNames.key("categories")).toStringList();
Copy link
Member

Choose a reason for hiding this comment

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

不用再从 roleNames.key("categories") 获取 role 了吧?已经有 TaskManager::CategoriesRole 了。

}

// 检查是否有任何 category 在跳过列表中
for (const QString &category : categories) {
Copy link
Member

Choose a reason for hiding this comment

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

是不是反了,不应该是迭代 skipCategories 然后判断 categories 是否包含 skipCategoriy 吗?

skipCategories 配置里预期不会有太多值,默认只有终端,也不期望用户自己随便加。

}

// 检查应用的 Categories 是否在跳过列表中
static bool shouldSkipCgroupsByCategories(const QString &desktopId, QAbstractItemModel *activeAppModel, const QHash<int, QByteArray> &roleNames)
Copy link
Member

Choose a reason for hiding this comment

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

倒不如直接把 “尝试通过AM(Application Manager)匹配应用程序” 那块提出来。只提目前这一部分有点怪怪的。

@deepin-bot
Copy link

deepin-bot bot commented Jan 7, 2026

TAG Bot

New tag: 2.0.25
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1394

@Ivy233
Copy link
Contributor Author

Ivy233 commented Jan 13, 2026

recheck

@deepin-bot
Copy link

deepin-bot bot commented Jan 14, 2026

TAG Bot

New tag: 2.0.26
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1396

@Ivy233 Ivy233 force-pushed the feature/cgroups-skip-categories branch from 3b87e6d to 62a5b07 Compare January 14, 2026 10:23
Copy link
Member

@BLumia BLumia left a comment

Choose a reason for hiding this comment

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

见下方评注

1. 新增 DConfig 配置项 cgroupsBasedGroupingSkipCategories
2. 默认跳过 TerminalEmulator 类别的应用,避免终端中启动的程序被错误识别
3. 在 dde-apps 的 AppItem 中添加 categories 属性
4. 在 AppItemModel 中添加 CategoriesRole
5. 在 AMAppItem 构造函数中保存从 AM 获取的 categories
6. 实现 shouldSkipCgroupsByCategories() 函数,从 dde-apps 缓存读取 categories
7. 提取 tryMatchByApplicationManager() 函数,优化代码结构
8. 使用 TaskManager::CategoriesRole 枚举常量替代运行时查找
9. 优化迭代逻辑,迭代 skipCategories 而非 categories,提升性能
10. 在窗口匹配流程中集成类别检查逻辑

Log: 新增基于应用类别的 cgroups 分组跳过列表,解决终端中启动的图形程序被错误归类的问题

Influence:
1. 测试在 Alacritty 等终端模拟器中启动图形应用
2. 验证新启动的应用在任务栏显示独立图标
3. 验证 categories 从 dde-apps 缓存读取,无额外 DBus 调用
4. 检查 DConfig 配置项可正常读取和修改
5. 确认不影响非终端类应用的正常分组行为
6. 验证深度终端等原有白名单应用仍正常工作
7. 确认代码结构优化不影响功能正确性

PMS: TASK-384865
@Ivy233 Ivy233 force-pushed the feature/cgroups-skip-categories branch from 62a5b07 to 6fe519b Compare January 18, 2026 12:40
@deepin-ci-robot
Copy link

deepin pr auto review

代码审查报告

总体概述

这段代码实现了一个新功能,允许基于应用程序的类别(Categories)来决定是否跳过基于cgroups的任务图标分组。主要修改包括添加了新的配置项、模型角色和相关检查逻辑。

详细审查

1. 语法与逻辑

优点

  1. 代码结构清晰,功能实现逻辑完整
  2. 新增的shouldSkipCgroupsByCategoriestryMatchByApplicationManager函数职责单一,便于维护
  3. 配置项添加完整,包括中英文描述

问题与建议

  1. taskmanager.cpp中,tryMatchByApplicationManager函数的参数roleNames未被使用,可以考虑移除:

    // 当前代码
    static QModelIndex tryMatchByApplicationManager(const QStringList &identifies,
                                                      QAbstractItemModel *model,
                                                      const QHash<int, QByteArray> &roleNames)

    如果该参数确实需要,应在函数中明确使用。

  2. shouldSkipCgroupsByCategories函数中,使用model->data(itemIndex, model->roleNames().key("desktopId"))获取desktopId效率不高,可以考虑直接使用预定义的role常量:

    // 建议修改为
    QString desktopId = model->data(itemIndex, TaskManager::DesktopIdRole).toString();
  3. taskmanager.cpp中,MODEL_DESKTOPID宏未在提供的diff中定义,建议确保其定义在适当位置。

2. 代码质量

优点

  1. 函数命名清晰,如shouldSkipCgroupsByCategoriestryMatchByApplicationManager准确表达了函数功能
  2. 添加了适当的日志输出,便于调试
  3. 代码格式统一,符合项目风格

问题与建议

  1. appitem.cpp中,setCategories函数使用了return setData(...),虽然语法正确,但setData返回值通常表示操作是否成功,建议:

    void AppItem::setCategories(const QStringList &categories)
    {
        setData(categories, AppItemModel::CategoriesRole);
    }
  2. taskmanager.cpp中,tryMatchByApplicationManager函数较长,可以考虑进一步拆分:

    static QModelIndex tryMatchByApplicationManager(const QStringList &identifies,
                                                      QAbstractItemModel *model)
    {
        if (!Settings->cgroupsBasedGrouping()) {
            return QModelIndex();
        }
    
        auto desktopId = getDesktopIdByPid(identifies);
        if (shouldSkipCgroupsGrouping(desktopId, model)) {
            return QModelIndex();
        }
    
        return findAppItemByDesktopId(desktopId, model);
    }

3. 代码性能

问题与建议

  1. shouldSkipCgroupsByCategories中,使用QStringList::contains进行线性搜索,如果跳过类别列表较大,可以考虑使用QSet提高查找效率:

    // 在Settings类中
    QSet<QString> m_cgroupsBasedGroupingSkipCategoriesSet;
    
    // 初始化时
    m_cgroupsBasedGroupingSkipCategoriesSet = QSet<QString>(m_cgroupsBasedGroupingSkipCategories.begin(), 
                                                            m_cgroupsBasedGroupingSkipCategories.end());
    
    // 在shouldSkipCgroupsByCategories中
    for (const QString &category : categories) {
        if (skipCategoriesSet.contains(category)) {
            // ...
        }
    }
  2. tryMatchByApplicationManager中,model->match操作可能比较耗时,特别是当模型较大时。可以考虑添加缓存机制,避免重复查找。

4. 代码安全

问题与建议

  1. appitem.cpp中,setCategories直接使用传入的categories参数,未进行验证。建议添加基本验证:

    void AppItem::setCategories(const QStringList &categories)
    {
        // 过滤空字符串和无效类别
        QStringList validCategories;
        for (const QString &category : categories) {
            if (!category.trimmed().isEmpty()) {
                validCategories.append(category.trimmed());
            }
        }
        setData(validCategories, AppItemModel::CategoriesRole);
    }
  2. taskmanagersettings.cpp中,从配置读取的cgroupsBasedGroupingSkipCategories未进行验证,建议添加:

    m_cgroupsBasedGroupingSkipCategories = m_taskManagerDconfig->value(
        TASKMANAGER_CGROUPS_BASED_GROUPING_SKIP_CATEGORIES, 
        QStringList{"TerminalEmulator"}).toStringList();
    
    // 验证类别有效性
    m_cgroupsBasedGroupingSkipCategories = validateCategories(m_cgroupsBasedGroupingSkipCategories);
  3. shouldSkipCgroupsByCategories中,对空模型和空索引的检查是好的,但建议也检查model->data返回值的有效性:

    QStringList categories = model->data(itemIndex, TaskManager::CategoriesRole).toStringList();
    if (categories.isEmpty() || !model->data(itemIndex, TaskManager::CategoriesRole).isValid()) {
        return false;
    }

总结

这段代码实现了一个有用的功能,整体质量良好。主要改进方向包括:

  1. 移除未使用的函数参数
  2. 使用预定义的role常量代替字符串查找
  3. 考虑使用QSet提高查找效率
  4. 添加输入验证
  5. 考虑添加缓存机制提高性能

建议在合并前进行充分测试,特别是测试各种边界情况和异常输入。

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