diff --git a/debian/control b/debian/control index b30978d23..5370e5c2c 100644 --- a/debian/control +++ b/debian/control @@ -82,7 +82,7 @@ Depends: qml6-module-qtquick-layouts, qml6-module-qtquick-window, qt6-wayland (>= 6.8), - dde-application-manager (>> 1.2.54), + dde-application-manager (>> 1.2.55), ${misc:Depends}, ${shlibs:Depends}, Breaks: diff --git a/frame/wayland/xdgactivation.cpp b/frame/wayland/xdgactivation.cpp index ca5675cf2..118fdf1cc 100644 --- a/frame/wayland/xdgactivation.cpp +++ b/frame/wayland/xdgactivation.cpp @@ -4,8 +4,9 @@ #include "xdgactivation_p.h" -#include #include +#include +#include #include #include #include @@ -150,6 +151,11 @@ void XdgActivation::requestToken(QWindow *window, const QString &appId) qCWarning(dsXdgActivation) << "XDG activation request has empty app id"; auto effectiveWindow = window ? window : QGuiApplication::focusWindow(); + if (!effectiveWindow) { + // fallback to top-level window at cursor position if the focused window is not a Wayland window + qCDebug(dsXdgActivation) << "No focused window, falling back to top-level window at cursor position"; + effectiveWindow = QGuiApplication::topLevelAt(QCursor::pos()); + } if (!effectiveWindow) { qCWarning(dsXdgActivation) << "XDG activation request has no target window"; Q_EMIT tokenReady({}); diff --git a/panels/notification/server/dbusadaptor.h b/panels/notification/server/dbusadaptor.h index 243921756..cc1de93d4 100644 --- a/panels/notification/server/dbusadaptor.h +++ b/panels/notification/server/dbusadaptor.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -32,7 +32,7 @@ public Q_SLOTS: // methods Q_SIGNALS: void ActionInvoked(uint id, const QString &actionKey); void NotificationClosed(uint id, uint reason); - // todo void ActivationToken(uint id, const QString &activationToken) + void ActivationToken(uint id, const QString &token); }; class DDENotificationDbusAdaptor : public QDBusAbstractAdaptor @@ -54,7 +54,7 @@ public Q_SLOTS: // methods Q_SIGNALS: void ActionInvoked(uint id, const QString &actionKey); void NotificationClosed(uint id, uint reason); - // todo void ActivationToken(uint id, const QString &activationToken) + void ActivationToken(uint id, const QString &token); public Q_SLOTS: // methods uint recordCount() const; diff --git a/panels/notification/server/notificationmanager.cpp b/panels/notification/server/notificationmanager.cpp index b8f565c90..74c564197 100644 --- a/panels/notification/server/notificationmanager.cpp +++ b/panels/notification/server/notificationmanager.cpp @@ -26,6 +26,7 @@ #include #include +#include DCORE_USE_NAMESPACE DS_USE_NAMESPACE @@ -134,8 +135,30 @@ void NotificationManager::actionInvoked(qint64 id, uint bubbleId, const QString qInfo(notifyLog) << "Action invoked, bubbleId:" << bubbleId << ", id:" << id << ", actionKey" << actionKey; actionInvoked(id, actionKey); - Q_EMIT ActionInvoked(bubbleId, actionKey); - Q_EMIT NotificationClosed(bubbleId, NotifyEntity::Closed); + if (isExtendedAction(id, actionKey)) { + // Extended action (x-deepin-action-*) handles token request internally in doActionInvoked, + // so we skip the outer token request to avoid requesting twice. + Q_EMIT ActionInvoked(bubbleId, actionKey); + Q_EMIT NotificationClosed(bubbleId, NotifyEntity::Closed); + } else { + // 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) { + 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); + activation->deleteLater(); + }, + Qt::SingleShotConnection); + activation->requestToken(); + } } void NotificationManager::notificationClosed(qint64 id, uint bubbleId, uint reason) @@ -542,6 +565,16 @@ QString NotificationManager::appIdByAppName(const QString &appName) const return QString(); } +bool NotificationManager::isExtendedAction(qint64 id, const QString &actionId) const +{ + auto entity = m_persistence->fetchEntity(id); + if (!entity.isValid()) { + return false; + } + QMap hints = entity.hints(); + return hints.contains("x-deepin-action-" + actionId); +} + void NotificationManager::doActionInvoked(const NotifyEntity &entity, const QString &actionId) { qDebug(notifyLog) << "Invoke the notification:" << entity.id() << entity.appName() << actionId; @@ -566,13 +599,27 @@ void NotificationManager::doActionInvoked(const NotifyEntity &entity, const QStr amArgs << "--" << args; } - QProcess pro; - pro.setProgram("dde-am"); - pro.setArguments(amArgs); - QProcessEnvironment proEnv = QProcessEnvironment::systemEnvironment(); - proEnv.remove("DSG_APP_ID"); - pro.setProcessEnvironment(proEnv); - pro.startDetached(); + // Get activation token, then start process + auto *activation = new DS_NAMESPACE::XdgActivation(this); + auto amArgsCopy = amArgs; + connect(activation, &DS_NAMESPACE::XdgActivation::tokenReady, this, + [amArgsCopy, activation](const QString &token) { + QProcess pro; + pro.setProgram("dde-am"); + pro.setArguments(amArgsCopy); + 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(); + activation->deleteLater(); + }, Qt::SingleShotConnection); + activation->requestToken(); } } else if (i.key() == "deepin-dde-shell-action-" + actionId) { const QString data(i.value().toString()); diff --git a/panels/notification/server/notificationmanager.h b/panels/notification/server/notificationmanager.h index 790ab7f59..f2756669d 100644 --- a/panels/notification/server/notificationmanager.h +++ b/panels/notification/server/notificationmanager.h @@ -50,6 +50,9 @@ class NotificationManager : public QObject, public QDBusContext void NotificationStateChanged(qint64 id, int processedType); + // Activation token signal for Wayland + void ActivationToken(uint id, const QString &token); + public Q_SLOTS: // Standard Notifications dbus implementation QStringList GetCapabilities(); @@ -78,6 +81,7 @@ public Q_SLOTS: QString appIdByAppName(const QString &appName) const; void doActionInvoked(const NotifyEntity &entity, const QString &actionId); + bool isExtendedAction(qint64 id, const QString &actionId) const; bool invokeShellAction(const QString &data); void initScreenLockedState();