diff --git a/src/input.cpp b/src/input.cpp index d366b50c66..cfd6a565d6 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -2635,6 +2635,64 @@ void InputRedirection::setLastInputHandler(QObject *device) m_lastInputDevice = device; } +class WindowInteractedSpy : public InputEventSpy +{ +public: + void keyEvent(KeyEvent *event) override + { + if (event->isAutoRepeat() || event->type() != QEvent::KeyPress) { + return; + } + update(); + } + + void pointerEvent(KWin::MouseEvent *event) override + { + if (event->type() != QEvent::MouseButtonPress) { + return; + } + update(); + } + + void tabletPadButtonEvent(uint, bool pressed, const KWin::TabletPadId &) override + { + if (!pressed) { + return; + } + update(); + } + + void tabletToolButtonEvent(uint, bool pressed, const KWin::TabletToolId &) override + { + if (!pressed) { + return; + } + update(); + } + + void tabletToolEvent(KWin::TabletEvent *event) override + { + if (event->type() != QEvent::TabletPress) { + return; + } + update(); + } + + void touchDown(qint32, const QPointF &, quint32) override + { + update(); + } + + void update() + { + auto window = workspace()->activeWindow(); + if (!window) { + return; + } + window->setLastUsageSerial(waylandServer()->seat()->display()->serial()); + } +}; + class UserActivitySpy : public InputEventSpy { public: @@ -2793,6 +2851,7 @@ void InputRedirection::setupInputFilters() } installInputEventSpy(new HideCursorSpy); installInputEventSpy(new UserActivitySpy); + installInputEventSpy(new WindowInteractedSpy); if (hasGlobalShortcutSupport) { installInputEventFilter(new TerminateServerFilter); } diff --git a/src/window.cpp b/src/window.cpp index d4c8302ce6..41636ebfcb 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -4566,6 +4566,18 @@ void Window::applyWindowRules() setDesktopFileName(rules()->checkDesktopFile(desktopFileName()).toUtf8()); } +void Window::setLastUsageSerial(quint32 serial) +{ + if (m_lastUsageSerial < serial) { + m_lastUsageSerial = serial; + } +} + +quint32 Window::lastUsageSerial() const +{ + return m_lastUsageSerial; +} + } // namespace KWin #include "moc_window.cpp" diff --git a/src/window.h b/src/window.h index 8ea5a65d2c..d048a100b4 100644 --- a/src/window.h +++ b/src/window.h @@ -1399,6 +1399,12 @@ public: */ static QString iconFromDesktopFile(const QString &fileName); + /** + * Sets the last user usage serial of the surface as @p serial + */ + void setLastUsageSerial(quint32 serial); + quint32 lastUsageSerial() const; + public Q_SLOTS: virtual void closeWindow() = 0; @@ -1980,6 +1986,7 @@ private: QKeySequence _shortcut; WindowRules m_rules; + quint32 m_lastUsageSerial = 0; }; /** diff --git a/src/xdgactivationv1.cpp b/src/xdgactivationv1.cpp index 275a60df4c..26e1387620 100644 --- a/src/xdgactivationv1.cpp +++ b/src/xdgactivationv1.cpp @@ -37,6 +37,15 @@ XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface if (!m_currentActivationToken || !window || window->property("token").toString() == m_currentActivationToken->token) { return; } + + // We check that it's not the app that we are trying to activate + if (window->desktopFileName() != m_currentActivationToken->applicationId) { + // But also that the new one has been requested after the token was requested + if (window->lastUsageSerial() < m_currentActivationToken->serial) { + return; + } + } + clear(); }); activation->setActivationTokenCreator([this](ClientConnection *client, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId) -> QString { @@ -82,10 +91,10 @@ void XdgActivationV1Integration::activateSurface(SurfaceInterface *surface, cons auto ownerWindow = waylandServer()->findWindow(m_currentActivationToken->surface); qCDebug(KWIN_CORE) << "activating" << window << surface << "on behalf of" << m_currentActivationToken->surface << "into" << ownerWindow; - if (ws->activeWindow() == ownerWindow || isPrivilegedInWindowManagement(m_currentActivationToken->client)) { + if (ws->activeWindow() == ownerWindow || ws->activeWindow()->lastUsageSerial() < m_currentActivationToken->serial || isPrivilegedInWindowManagement(m_currentActivationToken->client)) { ws->activateWindow(window); } else { - qCWarning(KWIN_CORE) << "Activation requested while owner isn't active" << ownerWindow->desktopFileName() + qCWarning(KWIN_CORE) << "Activation requested while owner isn't active" << (ownerWindow ? ownerWindow->desktopFileName() : "null") << m_currentActivationToken->applicationId; window->demandAttention(); clear(); diff --git a/src/xdgactivationv1.h b/src/xdgactivationv1.h index b7bc14b315..8ac69309e0 100644 --- a/src/xdgactivationv1.h +++ b/src/xdgactivationv1.h @@ -11,6 +11,7 @@ #include "kwin_export.h" #include +#include #include namespace KWaylandServer @@ -36,7 +37,7 @@ public: const QString token; const KWaylandServer::ClientConnection *client; - const KWaylandServer::SurfaceInterface *surface; + QPointer surface; const uint serial; const KWaylandServer::SeatInterface *seat; QString applicationId;