diff --git a/panels/dock/CMakeLists.txt b/panels/dock/CMakeLists.txt index 34825ad34..16d6aa5e0 100644 --- a/panels/dock/CMakeLists.txt +++ b/panels/dock/CMakeLists.txt @@ -117,6 +117,8 @@ file( pluginmanagerintegration.cpp dockpositioner.h dockpositioner.cpp + xdgactivationmanager_p.h + xdgactivationmanager.cpp ) set_source_files_properties(DockCompositor.qml PROPERTIES @@ -148,6 +150,7 @@ qt_generate_wayland_protocol_server_sources(dock-plugin FILES ${DDE_TRAY_LOADER_PROTOCOL} ${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml + ${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml ) target_link_libraries(dock-plugin PUBLIC diff --git a/panels/dock/DockCompositor.qml b/panels/dock/DockCompositor.qml index 730cdfe40..dd1ed95e9 100644 --- a/panels/dock/DockCompositor.qml +++ b/panels/dock/DockCompositor.qml @@ -139,5 +139,7 @@ Item { id: pluginScaleManager pluginScale: dockCompositor.panelScale * 120 } + + XdgActivationManager {} } } diff --git a/panels/dock/pluginmanagerextension.cpp b/panels/dock/pluginmanagerextension.cpp index c6ff5e517..ba901593f 100644 --- a/panels/dock/pluginmanagerextension.cpp +++ b/panels/dock/pluginmanagerextension.cpp @@ -4,8 +4,11 @@ #include "pluginmanagerextension_p.h" #include "pluginmanagerintegration_p.h" +#include "xdgactivationmanager_p.h" #include "constants.h" +#include + #include #include diff --git a/panels/dock/xdgactivationmanager.cpp b/panels/dock/xdgactivationmanager.cpp new file mode 100644 index 000000000..388f29e32 --- /dev/null +++ b/panels/dock/xdgactivationmanager.cpp @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "xdgactivationmanager_p.h" + +#include + +#include +#include +#include + +#include + +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(extensionContainer()); + Q_ASSERT(compositor); + m_compositor = compositor; + init(compositor->display(), 1); + + // Create the client-side xdg_activation_v1 connection to the outer compositor + 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::setPendingToken(XdgActivationTokenV1 *token) +{ + m_pendingToken = token; +} + +void XdgActivationManager::requestOuterToken(const QString &appId) +{ + QWindow *window = QGuiApplication::focusWindow(); + m_outerActivation->requestToken(window, appId); +} + +void XdgActivationManager::clearPendingTokenIf(XdgActivationTokenV1 *token) +{ + if (m_pendingToken == token) { + m_pendingToken = nullptr; + } +} + +void XdgActivationManager::onTokenReady(const QString &token) +{ + if (m_pendingToken) { + qCDebug(xdgActivationMgr) << "Forwarding activation token to plugin client"; + m_pendingToken->sendToken(token); + m_pendingToken = nullptr; + } +} + +// --------------------------------------------------------------------------- +// XdgActivationTokenV1 +// --------------------------------------------------------------------------- +// 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; + + // Store this token as pending and request from the outer compositor + m_manager->setPendingToken(this); + m_manager->requestOuterToken(m_appId); +} + +void XdgActivationTokenV1::xdg_activation_token_v1_destroy(Resource *resource) +{ + Q_UNUSED(resource) + m_manager->clearPendingTokenIf(this); + deleteLater(); +} diff --git a/panels/dock/xdgactivationmanager_p.h b/panels/dock/xdgactivationmanager_p.h new file mode 100644 index 000000000..d21a89001 --- /dev/null +++ b/panels/dock/xdgactivationmanager_p.h @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "qwayland-server-xdg-activation-v1.h" + +namespace ds { class XdgActivation; } + +class XdgActivationTokenV1; +class XdgActivationManager : public QWaylandCompositorExtensionTemplate, public QtWaylandServer::xdg_activation_v1 +{ + Q_OBJECT + QML_ELEMENT +public: + XdgActivationManager(QWaylandCompositor *compositor = nullptr); + void initialize() override; + + void setPendingToken(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; + +private: + void onTokenReady(const QString &token); + + QWaylandCompositor *m_compositor = nullptr; + ds::XdgActivation *m_outerActivation = nullptr; + QPointer m_pendingToken; +}; + +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 m_surface; + uint32_t m_serial = 0; + QString m_appId; +}; + +Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(XdgActivationManager)