Skip to content

feat(notification): add ActivationToken support for wayland#1627

Open
18202781743 wants to merge 1 commit into
linuxdeepin:masterfrom
18202781743:agent/agent/975b667c
Open

feat(notification): add ActivationToken support for wayland#1627
18202781743 wants to merge 1 commit into
linuxdeepin:masterfrom
18202781743:agent/agent/975b667c

Conversation

@18202781743

@18202781743 18202781743 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

为通知服务添加 wayland 激活令牌支持:

  • 非扩展动作先发送 ActivationToken 信号再发送 ActionInvoked
  • 扩展动作通过环境变量 XDG_ACTIVATION_TOKEN 传递令牌给 dde-am
  • 使用异步方式获取令牌,不阻塞主线程

Changes

  • panels/notification/server/notificationmanager.h: 添加 ActivationToken 信号
  • panels/notification/server/notificationmanager.cpp: 实现异步令牌请求和传递逻辑
  • panels/notification/server/dbusadaptor.h: 添加 ActivationToken D-Bus 信号

Test Plan

  1. 在 wayland 环境下测试通知动作触发
  2. 验证扩展动作是否正确传递 XDG_ACTIVATION_TOKEN 环境变量
  3. 验证非扩展动作是否正确发送 ActivationToken 信号

Summary by Sourcery

Add Wayland activation token support to notification actions and expose it via D-Bus.

New Features:

  • Emit an ActivationToken D-Bus signal from the notification manager for Wayland activation support.
  • Attach XDG activation tokens to extended notification actions when launching dde-am.
  • Emit activation tokens for non-extended notification actions before action invocation when available.

Enhancements:

  • Use asynchronous XdgActivation token retrieval to avoid blocking the notification handling thread.

@sourcery-ai

sourcery-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds Wayland XDG activation token support to the notification service by emitting a new ActivationToken D-Bus signal for non-extended actions and propagating the token to dde-am via XDG_ACTIVATION_TOKEN for extended actions, using an asynchronous token retrieval mechanism.

Sequence diagram for Wayland activation token handling in notification actions

sequenceDiagram
    actor User
    participant NotificationManager
    participant XdgActivation
    participant DbusAdaptor
    participant DdeAm

    rect rgb(230,230,255)
        User ->> NotificationManager: actionInvoked(id, bubbleId, actionKey)
        NotificationManager ->> XdgActivation: new XdgActivation
        NotificationManager ->> XdgActivation: requestToken()
        XdgActivation -->> NotificationManager: tokenReady(token)
        alt [token not empty]
            NotificationManager ->> DbusAdaptor: ActivationToken(bubbleId, token)
        end
        NotificationManager ->> DbusAdaptor: ActionInvoked(bubbleId, actionKey)
        NotificationManager ->> DbusAdaptor: NotificationClosed(bubbleId, Closed)
    end

    rect rgb(230,255,230)
        User ->> NotificationManager: doActionInvoked(entity, actionId, actionKey)
        NotificationManager ->> XdgActivation: new XdgActivation
        NotificationManager ->> XdgActivation: requestToken()
        XdgActivation -->> NotificationManager: tokenReady(token)
        NotificationManager ->> DdeAm: startDetached("dde-am", amArgs)
        opt [token not empty]
            NotificationManager ->> DdeAm: set env XDG_ACTIVATION_TOKEN
        end
    end
Loading

File-Level Changes

Change Details Files
Emit ActivationToken signal for non-extended notification actions after asynchronously obtaining a Wayland activation token.
  • Include the XdgActivation header to enable Wayland activation token handling.
  • Wrap the existing ActionInvoked/NotificationClosed emission in an asynchronous XdgActivation::tokenReady callback.
  • On tokenReady, emit the new ActivationToken signal if a non-empty token is available, then emit ActionInvoked and NotificationClosed, and clean up the XdgActivation instance.
panels/notification/server/notificationmanager.cpp
panels/notification/server/notificationmanager.h
Pass Wayland activation tokens to dde-am as XDG_ACTIVATION_TOKEN for extended actions before launching the process.
  • Replace the direct QProcess start for dde-am extended actions with an asynchronous XdgActivation flow.
  • In the tokenReady callback, construct the QProcess, clear DSG_APP_ID from the environment, and insert XDG_ACTIVATION_TOKEN when a token is available.
  • Start dde-am detached with the modified environment and delete the XdgActivation instance after use.
panels/notification/server/notificationmanager.cpp
Expose the new ActivationToken signal over D-Bus and update copyright years.
  • Add an ActivationToken(uint id, const QString &token) signal to both notification D-Bus adaptor classes, replacing the previous TODO comment.
  • Update the SPDX-FileCopyrightText year range to 2024 - 2026.
panels/notification/server/dbusadaptor.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

@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:

  • Both in actionInvoked and doActionInvoked the asynchronous XdgActivation flow can indefinitely delay emitting ActionInvoked/NotificationClosed or starting dde-am if tokenReady is never emitted; consider adding an error/timeout path or a fallback that proceeds without a token.
  • You unconditionally create a new XdgActivation instance for every action, which may be unnecessary on non-Wayland sessions and could add overhead; consider guarding this logic with a Wayland/session check or reusing a shared helper instead of allocating per-action.
  • The XdgActivation setup and cleanup code is duplicated in two places; consider extracting a small helper (e.g., requestActivationToken(callback)) to centralize token acquisition and ensure consistent behavior and resource management.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Both in `actionInvoked` and `doActionInvoked` the asynchronous `XdgActivation` flow can indefinitely delay emitting `ActionInvoked`/`NotificationClosed` or starting `dde-am` if `tokenReady` is never emitted; consider adding an error/timeout path or a fallback that proceeds without a token.
- You unconditionally create a new `XdgActivation` instance for every action, which may be unnecessary on non-Wayland sessions and could add overhead; consider guarding this logic with a Wayland/session check or reusing a shared helper instead of allocating per-action.
- The `XdgActivation` setup and cleanup code is duplicated in two places; consider extracting a small helper (e.g., `requestActivationToken(callback)`) to centralize token acquisition and ensure consistent behavior and resource management.

## Individual Comments

### Comment 1
<location path="panels/notification/server/notificationmanager.cpp" line_range="139" />
<code_context>
-    Q_EMIT ActionInvoked(bubbleId, actionKey);
-    Q_EMIT NotificationClosed(bubbleId, NotifyEntity::Closed);
+    // For non-extended actions, emit ActivationToken first if available
+    auto *activation = new DS_NAMESPACE::XdgActivation(this);
+    connect(activation, &DS_NAMESPACE::XdgActivation::tokenReady, this,
+        [this, bubbleId, actionKey, activation](const QString &token) {
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the repeated XdgActivation setup into a reusable helper that takes a handler functor to simplify control flow and avoid duplication in both call sites.

The `XdgActivation` usage is duplicated and adds nested lambdas and lifetime handling in both call sites. Extracting a small helper that owns `XdgActivation` and just calls a functor when the token is ready will keep both sites linear and remove the extra `amArgsCopy`.

Example helper (private method in `NotificationManager`):

```c++
class NotificationManager : public QObject
{
    Q_OBJECT
    // ...
private:
    template <typename F>
    void withActivationToken(F &&handler)
    {
        auto *activation = new DS_NAMESPACE::XdgActivation(this);
        connect(activation, &DS_NAMESPACE::XdgActivation::tokenReady, this,
                [activation, handler = std::forward<F>(handler)](const QString &token) mutable {
                    handler(token);
                    activation->deleteLater();
                },
                Qt::SingleShotConnection);
        activation->requestToken();
    }
};
```

Then `actionInvoked` becomes simpler and closer to the original structure:

```c++
void NotificationManager::actionInvoked(qint64 id, uint bubbleId, const QString &actionKey)
{
    qInfo(notifyLog) << "Action invoked, bubbleId:" << bubbleId << ", id:" << id << ", actionKey" << actionKey;
    actionInvoked(id, actionKey);

    withActivationToken([this, bubbleId, actionKey](const QString &token) {
        if (!token.isEmpty()) {
            Q_EMIT ActivationToken(bubbleId, token);
            qDebug(notifyLog) << "Emitted ActivationToken for non-extended action:" << token;
        }
        Q_EMIT ActionInvoked(bubbleId, actionKey);
        Q_EMIT NotificationClosed(bubbleId, NotifyEntity::Closed);
    });
}
```

And the extended action (`dde-am` launch) stays linear and avoids `amArgsCopy`:

```c++
if (!args.isEmpty()) {
    QString cmd = args.takeFirst();

    QStringList amArgs;
    amArgs << "-c" << cmd;
    if (!args.isEmpty()) {
        amArgs << "--" << args;
    }

    withActivationToken([amArgs = std::move(amArgs)](const QString &token) {
        QProcess pro;
        pro.setProgram("dde-am");
        pro.setArguments(amArgs);

        QProcessEnvironment proEnv = QProcessEnvironment::systemEnvironment();
        proEnv.remove("DSG_APP_ID");

        if (!token.isEmpty()) {
            proEnv.insert("XDG_ACTIVATION_TOKEN", token);
            qDebug(notifyLog) << "Set XDG_ACTIVATION_TOKEN for extended action:" << token;
        }

        pro.setProcessEnvironment(proEnv);
        pro.startDetached();
    });
}
```

This keeps all behavior (including token emission, `ActivationToken` signal, and process environment setup) while reducing duplication, nesting, and manual `new`/`deleteLater` in the main logic.
</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.

Comment thread panels/notification/server/notificationmanager.cpp Outdated
@18202781743 18202781743 force-pushed the agent/agent/975b667c branch from 6056b09 to 65c61fe Compare June 10, 2026 10:03
@18202781743 18202781743 requested review from BLumia and mhduiy June 10, 2026 10:03
@18202781743 18202781743 force-pushed the agent/agent/975b667c branch from 65c61fe to 469d53b Compare June 10, 2026 10:05
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

我来对这段代码进行审查,并提出改进意见:

  1. 依赖版本更新:
  • 将 dde-application-manager 的依赖版本从 1.2.54 更新到 1.2.55,这是一个正常的版本更新,确保了功能的兼容性。
  1. 版权信息更新:
  • 版权年份从 2024 更新到 2024-2026,这是一个常规的年份更新,符合实际开发周期。
  1. 新增功能 - ActivationToken 支持:
  • 在 dbusadaptor.h 和 notificationmanager.h 中添加了 ActivationToken 信号声明
  • 在 notificationmanager.cpp 中实现了 ActivationToken 相关功能
  • 新增了 isExtendedAction 函数用于判断是否为扩展动作
  1. 改进点:

a) 代码质量:

  • 新增的 XdgActivation 相关代码增加了对 Wayland 激活令牌的支持,这是对桌面环境协议的完善
  • 使用了 Qt::SingleShotConnection 确保信号槽连接只触发一次,避免重复处理
  • activation 对象使用 deleteLater() 确保正确的内存管理

b) 代码性能:

  • 每次请求都创建新的 XdgActivation 对象,虽然有 deleteLater(),但在高频场景下可能会影响性能
  • 建议考虑对象池模式来管理 XdgActivation 对象,减少频繁创建销毁的开销

c) 代码安全:

  • 在设置进程环境变量时正确移除了 DSG_APP_ID,避免了潜在的环境污染
  • 使用 token.isEmpty() 检查确保空值不会传递给系统
  • 建议为 token 添加长度限制和格式验证,防止恶意构造的令牌

d) 代码逻辑:

  • isExtendedAction 函数的实现简单直接,但可以考虑添加缓存机制,避免每次都查询持久层
  • actionInvoked 函数中的分支逻辑清晰,但建议将 token 请求相关的代码抽取为独立函数,提高可维护性
  1. 建议改进:
// 建议在 NotificationManager 类中添加 XdgActivation 对象池
QVector<XdgActivation*> m_activationPool;

// 优化后的 isExtended 实现
bool NotificationManager::isExtendedAction(qint64 id, const QString &actionId) const
{
    static QCache<qint64, QMap<QString, QVariant>> entityHintCache(100);
    auto *hints = entityHintCache.object(id);
    if (!hints) {
        auto entity = m_persistence->fetchEntity(id);
        if (!entity.isValid()) {
            return false;
        }
        hints = new QMap<QString, QVariant>(entity.hints());
        entityHintCache.insert(id, hints);
    }
    return hints->contains("x-deepin-action-" + actionId);
}

// 抽取的 token 处理函数
void NotificationManager::handleActivationToken(uint bubbleId, const QString &actionKey, 
    std::function<void(const QString &)> callback)
{
    auto *activation = m_activationPool.isEmpty() ? 
        new DS_NAMESPACE::XdgActivation(this) : 
        m_activationPool.takeFirst();
        
    connect(activation, &DS_NAMESPACE::XdgActivation::tokenReady, this,
        [this, activation, callback](const QString &token) {
            if (!token.isEmpty() && token.length() <= 256) { // 添加长度限制
                callback(token);
            }
            m_activationPool.append(activation);
        }, Qt::SingleShotConnection);
    activation->requestToken();
}
  1. 其他建议:
  • 考虑添加日志记录,记录 token 请求的成功/失败情况
  • 添加单元测试覆盖新增的功能
  • 在文档中说明扩展动作和非扩展动作的处理差异

总体来说,这次更新增加了对 Wayland 激活令牌的支持,改进了通知系统的功能完整性。代码结构清晰,但仍有性能优化和安全性加强的空间。

1. Implement ActivationToken signal in notification DBus adapters
2. Add XdgActivation token request for non-extended actions
3. Integrate activation token into dde-am execution for extended actions
4. Add isExtendedAction helper to check for deepin-specific actions

Log: Notifications now properly set XDG_ACTIVATION_TOKEN when launching
actions

Influence:
1. Verify notification action buttons trigger ActivationToken signal
2. Test extended actions (x-deepin-action-*) set XDG_ACTIVATION_TOKEN
in environment
3. Confirm non-extended actions emit ActivationToken before
ActionInvoked
4. Check token is passed to dde-am process for app launching
5. Verify backward compatibility with existing notification flows
6. Test multiple rapid notifications to ensure proper token handling

feat: 通知支持 XdgActivation 协议

1. 在通知DBus适配器中实现ActivationToken信号
2. 为非扩展操作添加XdgActivation令牌请求
3. 将激活令牌集成到扩展操作的dde-am执行中
4. 添加isExtendedAction辅助方法检查深度特定操作

Log: 通知现在在启动操作时正确设置 XDG_ACTIVATION_TOKEN

Influence:
1. 验证通知操作按钮触发ActivationToken信号
2. 测试扩展操作(x-deepin-action-*)在环境中设置XDG_ACTIVATION_TOKEN
3. 确认非扩展操作在ActionInvoked之前发出ActivationToken
4. 检查令牌是否正确传递给dde-am进程用于应用启动
5. 验证与现有通知流程的向后兼容性
6. 测试多个快速通知以确保令牌处理正确
@18202781743 18202781743 force-pushed the agent/agent/975b667c branch from 469d53b to ad02d3f Compare June 10, 2026 10:53
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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