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:
提交邮箱中包含我们的合作伙伴,但您似乎并非合作伙伴的成员或对接人,请联系相关对接人将您添加至组织之中,或由其重新发起 Pull Request。
The commit email domain belongs to one of our partners, but it seems you are not yet a member of the current organization, please contact the contact person to add you to the organization or let them submit the Pull Request.

You can retrigger this bot by commenting recheck in this Pull Request

@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 added 3 commits January 6, 2026 20:29
1. 新增 DConfig 配置项 cgroupsBasedGroupingSkipCategories
2. 默认跳过 TerminalEmulator 类别的应用,避免终端中启动的程序被错误识别
3. 实现 shouldSkipCgroupsByCategories() 函数,通过 DBus 查询应用类别
4. 在窗口匹配流程中集成类别检查逻辑

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

Influence:
1. 测试在 Alacritty 等终端模拟器中启动图形应用
2. 验证新启动的应用在任务栏显示独立图标
3. 检查 DConfig 配置项可正常读取和修改
4. 确认不影响非终端类应用的正常分组行为
5. 验证深度终端等原有白名单应用仍正常工作

PMS: TASK-384865
…r factory

1. 使用 DesktopFileParserFactory 替代直接 DBus 调用
2. 在 DesktopfileAbstractParser 中添加 categories() 虚方法
3. 在 DesktopFileAMParser 中实现 categories() 方法
4. 利用工厂的对象缓存机制,提升性能
5. 移除直接的 Application DBus 接口创建代码

Log: 重构基于类别的 cgroups 跳过实现,使用 Parser 工厂模式替代直接 DBus 调用,提升代码复用性和性能

Influence:
1. 功能保持不变,仍然正确识别终端模拟器类应用
2. 利用 Parser 对象缓存,减少重复创建开销
3. 代码架构更统一,与现有 Parser 体系集成
4. 验证在 Alacritty 等终端中启动的应用仍显示独立图标
5. 确认性能优化不影响功能正确性

PMS: TASK-384865
1. 在 dde-apps 的 AppItem 中添加 categories 属性
2. 在 AppItemModel 中添加 CategoriesRole
3. 在 AMAppItem 构造函数中保存从 AM 获取的 categories
4. 修改 shouldSkipCgroupsByCategories() 函数,从 dde-apps 读取 categories
5. 移除对即将废弃的 DESKTOPFILEFACTORY 的依赖
6. 回退 desktopfileabstractparser 和 desktopfileamparser 中的 categories 方法

Log: 实现基于应用类别的 cgroups 分组跳过功能,默认跳过 TerminalEmulator 类别应用

Influence:
1. 测试在终端模拟器中启动图形应用,验证应用显示为独立图标
2. 验证 categories 从 dde-apps 缓存读取,无额外 DBus 调用
3. 确认不影响非终端类应用的正常分组行为
4. 验证 DConfig 配置项可正常读取和修改

PMS: TASK-384865
@Ivy233 Ivy233 force-pushed the feature/cgroups-skip-categories branch from a0e2e66 to 3b87e6d Compare January 6, 2026 15:42
@deepin-ci-robot
Copy link

deepin pr auto review

我来对这个diff进行详细的代码审查:

  1. 功能概述
    这个改动主要是为任务管理器添加了基于应用类别的分组跳过功能。允许通过配置文件指定某些类别的应用不进行cgroups分组。

  2. 代码质量分析

优点:

  • 代码结构清晰,新增功能与现有代码风格保持一致
  • 添加了必要的配置项和接口
  • 实现了完整的配置读取和使用逻辑
  • 添加了适当的调试日志

需要改进的地方:

a) 性能优化:

// 在 shouldSkipCgroupsByCategories 函数中
static bool shouldSkipCgroupsByCategories(const QString &desktopId, QAbstractItemModel *activeAppModel, const QHash<int, QByteArray> &roleNames)
{
    auto skipCategories = Settings->cgroupsBasedGroupingSkipCategories();
    if (skipCategories.isEmpty() || desktopId.isEmpty()) {
        return false;
    }

    // 建议:将categories转换成QSet,提高查找效率
    QSet<QString> skipCategoriesSet(skipCategories.begin(), skipCategories.end());
    
    // ... 其余代码
    
    // 使用QSet::contains替代QList::contains
    for (const QString &category : categories) {
        if (skipCategoriesSet.contains(category)) {
            qCDebug(taskManagerLog) << "Skipping cgroups grouping for" << desktopId
                                   << "due to category:" << category;
            return true;
        }
    }
}

b) 安全性:

  • 建议在读取配置时添加数据验证,确保categories列表只包含有效的类别名称
  • 可以考虑对desktopId进行规范化处理,防止大小写不一致导致的匹配问题

c) 错误处理:

// 建议在读取categories时添加错误处理
if (existingItem.isValid()) {
    auto categoriesData = activeAppModel->data(existingItem, roleNames.key("categories"));
    if (categoriesData.isValid()) {
        categories = categoriesData.toStringList();
    }
}

d) 代码复用:

// 建议将获取categories的逻辑抽取为独立函数
static QStringList getAppCategories(const QString &desktopId, QAbstractItemModel *activeAppModel, const QHash<int, QByteArray> &roleNames)
{
    if (!activeAppModel || desktopId.isEmpty()) {
        return {};
    }

    auto existingItem = activeAppModel->match(activeAppModel->index(0, 0), roleNames.key("desktopId"), desktopId, 1, Qt::MatchFixedString | Qt::MatchWrap).value(0);
    if (existingItem.isValid()) {
        auto categoriesData = activeAppModel->data(existingItem, roleNames.key("categories"));
        if (categoriesData.isValid()) {
            return categoriesData.toStringList();
        }
    }
    return {};
}
  1. 建议的改进措施:
  • 添加单元测试覆盖新增功能
  • 在配置文件中添加更详细的说明文档
  • 考虑添加配置变更的动态响应机制
  • 可以添加性能监控,确保新功能不会显著影响性能
  1. 其他建议:
  • 考虑添加对多语言配置的支持
  • 可以考虑添加配置验证机制,确保配置的有效性
  • 建议添加更多的日志记录,便于问题排查

总的来说,这个实现基本满足了功能需求,但在性能优化、错误处理和代码复用方面还有改进空间。建议在后续版本中逐步完善这些方面。

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

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