From fc6532e97e4227feafdace88c9120a66a16cfff0 Mon Sep 17 00:00:00 2001 From: Christoph Cullmann Date: Wed, 13 Aug 2025 13:10:00 +0200 Subject: [PATCH] add a DBus slot to get an XDG activation token Will check if the passed shellSessionId is the current one for safety. Will try to generate a token and pass it back. Allows e.g. Kate to properly activate existing instance windows CCBUG: 442265 --- src/session/Session.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ src/session/Session.h | 18 ++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/session/Session.cpp b/src/session/Session.cpp index c97ae6409..de688e223 100644 --- a/src/session/Session.cpp +++ b/src/session/Session.cpp @@ -34,12 +34,19 @@ #include #include #include +#include #ifndef Q_OS_WIN #include #endif #include +// wayland window activation +#define HAVE_WAYLAND __has_include() +#if HAVE_WAYLAND +#include +#endif + // Konsole #if HAVE_DBUS #include @@ -2161,4 +2168,49 @@ void Session::runCommandFromLayout(const QString &command) const _emulation->sendText(command + QLatin1Char('\n')); } +QString Session::activationToken(const QString &shellSessionIdForRequest) const +{ + // safety check, only work if the caller knows our id + // they will read it from the SHELL_SESSION_ID env var inside this session + if (shellSessionIdForRequest != shellSessionId()) { + return {}; + } + +#if HAVE_DBUS && HAVE_WAYLAND + // no window active, no token + // same if we don't run wayland + const auto window = qApp->activeWindow(); + if (!window || !window->window() || !KWindowSystem::isPlatformWayland()) { + return {}; + } + + // we will respond delayed, as the token needs to arrive + Q_ASSERT(calledFromDBus()); + const auto msg = message(); + setDelayedReply(true); + + // we need to filter the response with the request serial + const int launchedSerial = KWaylandExtras::self()->lastInputSerial(window->window()->windowHandle()); + connect( + KWaylandExtras::self(), + &KWaylandExtras::xdgActivationTokenArrived, + this, + [msg, launchedSerial](int tokenSerial, QString token) { + // if wrong token, ignore it, but we must always reply to not stall the caller + // we use here a SingleShotConnection, we will just be called once! + if (tokenSerial != launchedSerial) { + token.clear(); + } + auto reply = msg.createReply(token); + QDBusConnection::sessionBus().send(reply); + }, + Qt::SingleShotConnection); + + KWaylandExtras::requestXdgActivationToken(window->window()->windowHandle(), launchedSerial, {}); + +#endif + + return {}; +} + #include "moc_Session.cpp" diff --git a/src/session/Session.h b/src/session/Session.h index 987c7ed67..bd6fdb4b7 100644 --- a/src/session/Session.h +++ b/src/session/Session.h @@ -9,6 +9,8 @@ #ifndef SESSION_H #define SESSION_H +#include "config-konsole.h" + // Qt #include #include @@ -19,6 +21,10 @@ #include #include +#if HAVE_DBUS +#include +#endif + // Konsole #include "Shortcut_p.h" #include "config-konsole.h" @@ -51,7 +57,11 @@ class SessionController; * or send input to the program in the terminal in the form of keypresses and mouse * activity. */ +#if HAVE_DBUS +class KONSOLEPRIVATE_EXPORT Session : public QObject, protected QDBusContext +#else class KONSOLEPRIVATE_EXPORT Session : public QObject +#endif { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.konsole.Session") @@ -728,6 +738,14 @@ public Q_SLOTS: */ Q_SCRIPTABLE QStringList getDisplayedTextList(int startLineOffset, int endLineOffset); + /** + * DBus slot to get an XDG activation token. + * Will check if the passed shellSessionId is the current one for safety. + * Will try to generate a token and pass it back. + * Can only be called from DBus, will answer delayed. + */ + Q_SCRIPTABLE QString activationToken(const QString &shellSessionIdForRequest) const; + Q_SIGNALS: /** Emitted when the terminal process starts. */