From 77b3ec8cf4fb9414167bb15bcc3c69b1be6c2dbf Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 16 Sep 2025 15:52:29 +0300 Subject: [PATCH 1/2] shell: Pass an xdg activation token from DesktopView to KRunner This makes sure that krunner gets focused after starting to type while a desktop view is focused when using medium or high focus stealing prevention level. --- krunner/dbus/org.kde.krunner.App.xml | 4 ++ krunner/view.cpp | 14 +++++++ krunner/view.h | 1 + shell/desktopview.cpp | 61 ++++++++++++++++++++++++++-- shell/desktopview.h | 2 + 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/krunner/dbus/org.kde.krunner.App.xml b/krunner/dbus/org.kde.krunner.App.xml index 6553e9a1b56..e6926b1b63a 100644 --- a/krunner/dbus/org.kde.krunner.App.xml +++ b/krunner/dbus/org.kde.krunner.App.xml @@ -17,5 +17,9 @@ + + + + diff --git a/krunner/view.cpp b/krunner/view.cpp index afefe9ab486..bb7edd5d654 100644 --- a/krunner/view.cpp +++ b/krunner/view.cpp @@ -263,6 +263,20 @@ void View::querySingleRunner(const QString &runnerName, const QString &term) m_engine->rootObject()->setProperty("query", term); } +void View::queryWithActivationToken(const QString &term, const QString &activationToken) +{ + qputenv("XDG_ACTIVATION_TOKEN", activationToken.toUtf8()); + + if (!isVisible()) { + display(); + } else { + requestActivate(); + } + + m_engine->rootObject()->setProperty("singleRunner", QString()); + m_engine->rootObject()->setProperty("query", term); +} + bool View::pinned() const { return m_pinned; diff --git a/krunner/view.h b/krunner/view.h index 979c6d3b483..af1d477d6f3 100644 --- a/krunner/view.h +++ b/krunner/view.h @@ -93,6 +93,7 @@ public Q_SLOTS: void displayWithClipboardContents(); void query(const QString &term); void querySingleRunner(const QString &runnerName, const QString &term); + void queryWithActivationToken(const QString &term, const QString &activationToken); protected Q_SLOTS: void loadConfig(); diff --git a/shell/desktopview.cpp b/shell/desktopview.cpp index 36e23149272..744176e6d3e 100644 --- a/shell/desktopview.cpp +++ b/shell/desktopview.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -384,11 +385,54 @@ bool DesktopView::event(QEvent *e) { if (e->type() == QEvent::FocusOut) { m_krunnerText.clear(); + + if (!m_krunnerFuture.isCanceled()) { + m_krunnerFuture.cancel(); + m_krunnerFuture = {}; + } } return PlasmaQuick::ContainmentView::event(e); } +class ActivationTokenRequest : public QObject +{ + Q_OBJECT + +public: + explicit ActivationTokenRequest(QWindow *window) + : m_serial(KWaylandExtras::lastInputSerial(window)) + { + m_promise.start(); + + connect(KWaylandExtras::self(), &KWaylandExtras::xdgActivationTokenArrived, this, [this](int serial, const QString &token) { + if (m_serial == serial) { + if (!m_promise.isCanceled()) { + m_promise.addResult(token); + } + m_promise.finish(); + delete this; + } + }); + KWaylandExtras::requestXdgActivationToken(window, m_serial, QString()); + } + + QFuture future() const + { + return m_promise.future(); + } + +private: + QPromise m_promise; + int m_serial; +}; + +static QFuture fetchActivationToken(QWindow *window) +{ + auto request = new ActivationTokenRequest(window); + return request->future(); +} + bool DesktopView::handleKRunnerTextInput(QKeyEvent *e) { // allow only Shift and GroupSwitch modifiers @@ -408,12 +452,22 @@ bool DesktopView::handleKRunnerTextInput(QKeyEvent *e) krunnerTextChanged = true; } if (krunnerTextChanged) { - const QString interface(QStringLiteral("org.kde.krunner")); if (!KAuthorized::authorize(QStringLiteral("run_command"))) { return false; } - org::kde::krunner::App krunner(interface, QStringLiteral("/App"), QDBusConnection::sessionBus()); - krunner.query(m_krunnerText); + if (KWindowSystem::isPlatformWayland()) { + if (!m_krunnerFuture.isCanceled()) { + m_krunnerFuture.cancel(); + } + m_krunnerFuture = fetchActivationToken(this); + m_krunnerFuture.then(this, [this](const QString &token) { + org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus()); + krunner.queryWithActivationToken(m_krunnerText, token); + }); + } else { + org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus()); + krunner.query(m_krunnerText); + } return true; } return false; @@ -596,4 +650,5 @@ void DesktopView::setAccentColorFromWallpaper(const QColor &accentColor) QDBusConnection::sessionBus().send(applyAccentColor); } +#include "desktopview.moc" #include "moc_desktopview.cpp" diff --git a/shell/desktopview.h b/shell/desktopview.h index c2b642d9a15..9e152611a31 100644 --- a/shell/desktopview.h +++ b/shell/desktopview.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -127,6 +128,7 @@ private: QPointer m_screenToFollow; LayerShellQt::Window *m_layerWindow = nullptr; QString m_krunnerText; + QFuture m_krunnerFuture; // KRunner config KConfigWatcher::Ptr m_configWatcher; -- GitLab From b3d97405cb5b0ee9859576309bd826dea6b74274 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 17 Sep 2025 09:59:07 +0300 Subject: [PATCH 2/2] shell: Use org.freedesktop.Application.ActivateAction to pass xdg activation token to krunner --- krunner/dbus/org.kde.krunner.App.xml | 4 ---- krunner/main.cpp | 4 +++- krunner/view.cpp | 14 ------------ krunner/view.h | 1 - shell/CMakeLists.txt | 4 ---- shell/desktopview.cpp | 32 +++++++++++++++++++++++----- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/krunner/dbus/org.kde.krunner.App.xml b/krunner/dbus/org.kde.krunner.App.xml index e6926b1b63a..6553e9a1b56 100644 --- a/krunner/dbus/org.kde.krunner.App.xml +++ b/krunner/dbus/org.kde.krunner.App.xml @@ -17,9 +17,5 @@ - - - - diff --git a/krunner/main.cpp b/krunner/main.cpp index 514c34b032f..02174bb2cda 100644 --- a/krunner/main.cpp +++ b/krunner/main.cpp @@ -136,9 +136,11 @@ int main(int argc, char **argv) parser.parse(arguments); updateVisibility(); }); - QObject::connect(&service, &KDBusService::activateActionRequested, &view, [&view](const QString &action) { + QObject::connect(&service, &KDBusService::activateActionRequested, &view, [&view](const QString &action, const QVariant ¶meter) { if (action == QLatin1String("RunClipboard")) { view.displayWithClipboardContents(); + } else if (action == QLatin1String("Query")) { + view.query(parameter.toString()); } }); diff --git a/krunner/view.cpp b/krunner/view.cpp index bb7edd5d654..afefe9ab486 100644 --- a/krunner/view.cpp +++ b/krunner/view.cpp @@ -263,20 +263,6 @@ void View::querySingleRunner(const QString &runnerName, const QString &term) m_engine->rootObject()->setProperty("query", term); } -void View::queryWithActivationToken(const QString &term, const QString &activationToken) -{ - qputenv("XDG_ACTIVATION_TOKEN", activationToken.toUtf8()); - - if (!isVisible()) { - display(); - } else { - requestActivate(); - } - - m_engine->rootObject()->setProperty("singleRunner", QString()); - m_engine->rootObject()->setProperty("query", term); -} - bool View::pinned() const { return m_pinned; diff --git a/krunner/view.h b/krunner/view.h index af1d477d6f3..979c6d3b483 100644 --- a/krunner/view.h +++ b/krunner/view.h @@ -93,7 +93,6 @@ public Q_SLOTS: void displayWithClipboardContents(); void query(const QString &term); void querySingleRunner(const QString &runnerName, const QString &term); - void queryWithActivationToken(const QString &term, const QString &activationToken); protected Q_SLOTS: void loadConfig(); diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 96b91888f1b..814413ac827 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -92,10 +92,6 @@ qt6_generate_wayland_protocol_client_sources(plasmashell ${PLASMA_WAYLAND_PROTOCOLS_DIR}/plasma-shell.xml ) -set(krunner_xml ${plasma-workspace_SOURCE_DIR}/krunner/dbus/org.kde.krunner.App.xml) -qt_add_dbus_interface(plasma_shell_SRCS ${krunner_xml} krunner_interface) - - target_sources(plasmashell PRIVATE ${plasma_shell_SRCS}) target_link_libraries(plasmashell PRIVATE diff --git a/shell/desktopview.cpp b/shell/desktopview.cpp index 744176e6d3e..9c3baa84b91 100644 --- a/shell/desktopview.cpp +++ b/shell/desktopview.cpp @@ -6,12 +6,12 @@ #include "desktopview.h" #include "containmentconfigview.h" -#include "krunner_interface.h" #include "screenpool.h" #include "shellcorona.h" #include #include +#include #include #include #include @@ -461,12 +461,34 @@ bool DesktopView::handleKRunnerTextInput(QKeyEvent *e) } m_krunnerFuture = fetchActivationToken(this); m_krunnerFuture.then(this, [this](const QString &token) { - org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus()); - krunner.queryWithActivationToken(m_krunnerText, token); + auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.krunner"), + QStringLiteral("/org/kde/krunner"), + QStringLiteral("org.freedesktop.Application"), + QStringLiteral("ActivateAction")); + message.setArguments({ + QStringLiteral("Query"), + QVariantList{ + m_krunnerText, + }, + QVariantMap{ + {QStringLiteral("activation-token"), token}, + }, + }); + QDBusConnection::sessionBus().asyncCall(message); }); } else { - org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus()); - krunner.query(m_krunnerText); + auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.krunner"), + QStringLiteral("/org/kde/krunner"), + QStringLiteral("org.freedesktop.Application"), + QStringLiteral("ActivateAction")); + message.setArguments({ + QStringLiteral("Query"), + QVariantList{ + m_krunnerText, + }, + QVariantMap{}, + }); + QDBusConnection::sessionBus().asyncCall(message); } return true; } -- GitLab