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:
parent
e6d2bc153f
commit
f3ec05c85a
5 changed files with 91 additions and 3 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue