feat: add compositor-side xdg-activation-v1 proxy for plugin clients#1617
feat: add compositor-side xdg-activation-v1 proxy for plugin clients#161718202781743 wants to merge 3 commits into
Conversation
Add XdgActivationManager that implements xdg-activation-v1 server protocol, proxying token requests from plugin clients to the outer compositor via dde-shell's XdgActivation client. Log: SNI托盘图标Wayland下点击时申请xdgactivation token激活DBus窗口 Issue: #6
There was a problem hiding this comment.
Sorry @18202781743, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 18202781743 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
deepin pr auto review你好!我是CodeGeeX。我已经仔细审查了你提供的Git Diff。本次修改主要为Dock面板添加了 整体来看,代码结构清晰,对Wayland协议的C++封装和QtCompositor的扩展使用基本正确。但在语法逻辑、代码质量、代码性能和代码安全方面,有一些需要改进和注意的地方。 以下是详细的审查意见: 1. 语法与逻辑问题
2. 代码质量
3. 代码性能
4. 代码安全
改进后的代码示例针对以上问题,我为你修改了核心的 C++ 文件,主要解决了:1. 使用 QMap 管理并发 Token 请求;2. 补充了
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QMap>
#include <QPointer>
#include <QtWaylandCompositor/QWaylandCompositor>
#include <QtWaylandCompositor/QWaylandCompositorExtension>
#include <QtWaylandCompositor/QWaylandQuickExtension>
#include <QtWaylandCompositor/QWaylandResource>
#include <QtWaylandCompositor/QWaylandSurface>
#include "qwayland-server-xdg-activation-v1.h"
namespace ds { class XdgActivation; }
class XdgActivationTokenV1;
class XdgActivationManager : public QWaylandCompositorExtensionTemplate<XdgActivationManager>, public QtWaylandServer::xdg_activation_v1
{
Q_OBJECT
QML_ELEMENT
public:
XdgActivationManager(QWaylandCompositor *compositor = nullptr);
void initialize() override;
void addPendingToken(const QString &appId, XdgActivationTokenV1 *token);
void requestOuterToken(const QString &appId);
void clearPendingTokenIf(XdgActivationTokenV1 *token);
protected:
void xdg_activation_v1_destroy(Resource *resource) override;
void xdg_activation_v1_get_activation_token(Resource *resource, uint32_t id) override;
// 必须实现的安全方法:处理客户端携带 Token 激活窗口的请求
void xdg_activation_v1_activate(Resource *resource, const QString &token, struct ::wl_resource *surface) override;
private:
void onTokenReady(const QString &token);
QWaylandCompositor *m_compositor = nullptr;
ds::XdgActivation *m_outerActivation = nullptr;
// 修改:使用 QMap 存储待处理的 Token,支持同一 AppId 的最新请求,避免并发覆盖丢失
QMap<QString, QPointer<XdgActivationTokenV1>> m_pendingTokens;
};
class XdgActivationTokenV1 : public QObject, public QtWaylandServer::xdg_activation_token_v1
{
Q_OBJECT
public:
XdgActivationTokenV1(XdgActivationManager *manager, const QWaylandResource &resource);
~XdgActivationTokenV1() override;
void sendToken(const QString &token);
protected:
void xdg_activation_token_v1_set_serial(Resource *resource, uint32_t serial, struct ::wl_resource *seat) override;
void xdg_activation_token_v1_set_app_id(Resource *resource, const QString &app_id) override;
void xdg_activation_token_v1_set_surface(Resource *resource, struct ::wl_resource *surface) override;
void xdg_activation_token_v1_commit(Resource *resource) override;
void xdg_activation_token_v1_destroy(Resource *resource) override;
private:
XdgActivationManager *m_manager;
QPointer<QWaylandSurface> m_surface;
uint32_t m_serial = 0; // 如果外部 API 需要,请将其传递出去
QString m_appId;
};
Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(XdgActivationManager)
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "xdgactivationmanager_p.h"
#include <wayland/xdgactivation.h>
#include <QGuiApplication>
#include <QLoggingCategory>
#include <QWindow>
#include <QtWaylandCompositor/QWaylandSeat>
Q_LOGGING_CATEGORY(xdgActivationMgr, "dde.shell.xdgactivation.manager")
// ---------------------------------------------------------------------------
// XdgActivationManager
// ---------------------------------------------------------------------------
XdgActivationManager::XdgActivationManager(QWaylandCompositor *compositor)
: QWaylandCompositorExtensionTemplate(compositor)
, m_compositor(compositor)
{
}
void XdgActivationManager::initialize()
{
QWaylandCompositorExtensionTemplate::initialize();
QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
Q_ASSERT(compositor);
m_compositor = compositor;
// 改进:避免魔法数字
init(compositor->display(), 1);
m_outerActivation = new ds::XdgActivation(this);
connect(m_outerActivation, &ds::XdgActivation::tokenReady,
this, &XdgActivationManager::onTokenReady);
}
void XdgActivationManager::xdg_activation_v1_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void XdgActivationManager::xdg_activation_v1_get_activation_token(Resource *resource, uint32_t id)
{
QWaylandResource tokenResource(
wl_resource_create(resource->client(), &xdg_activation_token_v1_interface,
wl_resource_get_version(resource->handle), id));
new XdgActivationTokenV1(this, tokenResource);
}
void XdgActivationManager::addPendingToken(const QString &appId, XdgActivationTokenV1 *token)
{
// 如果同一个 appId 有旧的 pending token,应当作废处理
if (m_pendingTokens.contains(appId) && !m_pendingTokens[appId].isNull()) {
qCWarning(xdgActivationMgr) << "Overwriting pending token for appId:" << appId;
// 可选:给旧的 token 发送一个错误或直接销毁
}
m_pendingTokens[appId] = token;
}
void XdgActivationManager::requestOuterToken(const QString &appId)
{
QWindow *window = QGuiApplication::focusWindow();
// 建议:如果可能,使用 dockCompositor 对应的 QWindow 而不是 focusWindow
m_outerActivation->requestToken(window, appId);
}
void XdgActivationManager::clearPendingTokenIf(XdgActivationTokenV1 *token)
{
// 改进:遍历 Map 清理失效的 Token
for (auto it = m_pendingTokens.begin(); it != m_pendingTokens.end(); ) {
if (it.value() == token) {
it = m_pendingTokens.erase(it);
} else {
++it;
}
}
}
void XdgActivationManager::onTokenReady(const QString &token)
{
// 外部合成器返回的 token 通常也关联了 appId,如果 ds::XdgActivation API 能返回 appId,最好精确匹配
// 这里假设按先进先出或需要遍历匹配
if (!m_pendingTokens.isEmpty()) {
auto it = m_pendingTokens.begin();
if (!it.value().isNull()) {
qCDebug(xdgActivationMgr) << "Forwarding activation token to plugin client";
it.value()->sendToken(token);
m_pendingTokens.erase(it);
} else {
// 清理已失效的 QPointer
m_pendingTokens.erase(it);
}
} else {
qCWarning(xdgActivationMgr) << "Received outer token but no pending internal request!";
}
}
void XdgActivationManager::xdg_activation_v1_activate(Resource *resource, const QString &token, struct ::wl_resource *surface)
{
Q_UNUSED(resource)
// 安全性关键:必须验证 token 的合法性!
// 1. 检查 token 是否是我们之前通过 onTokenReady 分发出去的。
// 2. 获取 QWaylandSurface 并执行激活逻辑。
QWaylandSurface *waylandSurface = QWaylandSurface::fromResource(surface);
if (!waylandSurface) {
qCWarning(xdgActivationMgr) << "Activation requested for invalid surface";
return;
}
// TODO: 实现 Token 校验和 Surface 激活逻辑
qCDebug(xdgActivationMgr) << "Client requested activation with token:" << token;
}
// ---------------------------------------------------------------------------
// XdgActivationTokenV1
// ---------------------------------------------------------------------------
XdgActivationTokenV1::XdgActivationTokenV1(XdgActivationManager *manager, const QWaylandResource &resource)
: QObject(manager)
, m_manager(manager)
{
init(resource.resource());
}
XdgActivationTokenV1::~XdgActivationTokenV1() = default;
void XdgActivationTokenV1::sendToken(const QString &token)
{
send_done(token);
}
void XdgActivationTokenV1::xdg_activation_token_v1_set_serial(Resource *resource, uint32_t serial, struct ::wl_resource *seat)
{
Q_UNUSED(resource)
Q_UNUSED(seat)
m_serial = serial;
}
void XdgActivationTokenV1::xdg_activation_token_v1_set_app_id(Resource *resource, const QString &app_id)
{
Q_UNUSED(resource)
m_appId = app_id;
}
void XdgActivationTokenV1::xdg_activation_token_v1_set_surface(Resource *resource, struct ::wl_resource *surface)
{
Q_UNUSED(resource)
m_surface = QWaylandSurface::fromResource(surface);
}
void XdgActivationTokenV1::xdg_activation_token_v1_commit(Resource *resource)
{
Q_UNUSED(resource)
qCDebug(xdgActivationMgr) << "Token committed by plugin client, appId:" << m_appId;
// 修改:使用新的 map 逻辑
m_manager->addPendingToken(m_appId, this);
m_manager->requestOuterToken(m_appId);
}
void XdgActivationTokenV1::xdg_activation_token_v1_destroy(Resource *resource)
{
Q_UNUSED(resource)
m_manager->clearPendingTokenIf(this);
deleteLater();
}希望这些审查意见和代码改进能对你有所帮助!如果有任何具体实现细节需要进一步讨论,欢迎随时提问。 |
|
TAG Bot New tag: 2.0.44 |
Add XdgActivationManager that exposes xdg_activation_v1 to plugin clients (dde-tray-loader) and proxies token requests to the outer compositor using dde-shell's existing XdgActivation client.
Issue: #6