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;
}
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);
}

View file

@ -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"

View file

@ -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;
};
/**

View file

@ -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();

View file

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