wayland: Fix activation when activating surfaces disappear

We track when the user last interacted with a window so that we can
decide on the relevance of newly activated windows.

Fixes network/neochat#524
This commit is contained in:
Aleix Pol 2022-05-05 02:19:24 +02:00
parent e6d2bc153f
commit f3ec05c85a
5 changed files with 91 additions and 3 deletions

View file

@ -2635,6 +2635,64 @@ void InputRedirection::setLastInputHandler(QObject *device)
m_lastInputDevice = 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 class UserActivitySpy : public InputEventSpy
{ {
public: public:
@ -2793,6 +2851,7 @@ void InputRedirection::setupInputFilters()
} }
installInputEventSpy(new HideCursorSpy); installInputEventSpy(new HideCursorSpy);
installInputEventSpy(new UserActivitySpy); installInputEventSpy(new UserActivitySpy);
installInputEventSpy(new WindowInteractedSpy);
if (hasGlobalShortcutSupport) { if (hasGlobalShortcutSupport) {
installInputEventFilter(new TerminateServerFilter); installInputEventFilter(new TerminateServerFilter);
} }

View file

@ -4566,6 +4566,18 @@ void Window::applyWindowRules()
setDesktopFileName(rules()->checkDesktopFile(desktopFileName()).toUtf8()); 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 } // namespace KWin
#include "moc_window.cpp" #include "moc_window.cpp"

View file

@ -1399,6 +1399,12 @@ public:
*/ */
static QString iconFromDesktopFile(const QString &fileName); 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: public Q_SLOTS:
virtual void closeWindow() = 0; virtual void closeWindow() = 0;
@ -1980,6 +1986,7 @@ private:
QKeySequence _shortcut; QKeySequence _shortcut;
WindowRules m_rules; WindowRules m_rules;
quint32 m_lastUsageSerial = 0;
}; };
/** /**

View file

@ -37,6 +37,15 @@ XdgActivationV1Integration::XdgActivationV1Integration(XdgActivationV1Interface
if (!m_currentActivationToken || !window || window->property("token").toString() == m_currentActivationToken->token) { if (!m_currentActivationToken || !window || window->property("token").toString() == m_currentActivationToken->token) {
return; 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(); clear();
}); });
activation->setActivationTokenCreator([this](ClientConnection *client, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId) -> QString { 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); auto ownerWindow = waylandServer()->findWindow(m_currentActivationToken->surface);
qCDebug(KWIN_CORE) << "activating" << window << surface << "on behalf of" << m_currentActivationToken->surface << "into" << ownerWindow; 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); ws->activateWindow(window);
} else { } 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; << m_currentActivationToken->applicationId;
window->demandAttention(); window->demandAttention();
clear(); clear();

View file

@ -11,6 +11,7 @@
#include "kwin_export.h" #include "kwin_export.h"
#include <QObject> #include <QObject>
#include <QPointer>
#include <QSharedPointer> #include <QSharedPointer>
namespace KWaylandServer namespace KWaylandServer
@ -36,7 +37,7 @@ public:
const QString token; const QString token;
const KWaylandServer::ClientConnection *client; const KWaylandServer::ClientConnection *client;
const KWaylandServer::SurfaceInterface *surface; QPointer<const KWaylandServer::SurfaceInterface> surface;
const uint serial; const uint serial;
const KWaylandServer::SeatInterface *seat; const KWaylandServer::SeatInterface *seat;
QString applicationId; QString applicationId;