Blame SOURCES/qtwayland-client-use-wl-keyboard-to-determine-active-state.patch

6f97c1
From cc54267e93851f067aba51cae015ca8fc3147c11 Mon Sep 17 00:00:00 2001
6f97c1
From: Méven Car <meven.car@enioka.com>
6f97c1
Date: Wed, 18 Aug 2021 18:28:20 +0200
6f97c1
Subject: [PATCH] Wayland client: use wl_keyboard to determine active state
6f97c1
6f97c1
Commit f497a5bb87270174b8e0106b7eca1992d44ff15d made QWaylandDisplay
6f97c1
use the xdgshell's active state for QWindow::isActive(), instead of
6f97c1
using wl_keyboard activate/deactivate events.
6f97c1
6f97c1
That seems to have been a misunderstanding, since xdgshell activation
6f97c1
is only supposed to be used to determine visual appearance, and there
6f97c1
is an explicit warning not to assume it means focus.
6f97c1
6f97c1
This commit reverts this logic back to listening to wl_keyboard.
6f97c1
It adds a fallback when there is no wl_keyboard available to handle
6f97c1
activated/deactivated events through xdg-shell, in order to fix
6f97c1
QTBUG-53702.
6f97c1
6f97c1
windowStates is handled so that we're not using the Xdg hint for
6f97c1
anything with QWindowSystemInterface::handleWindowStateChanged or
6f97c1
anything where we need to track only having one active.
6f97c1
6f97c1
We are still exposing it for decorations, which is the only reason to
6f97c1
use the Xdghint over keyboard focus - so you can keep the toplevel
6f97c1
active whilst you show a popup.
6f97c1
6f97c1
Change-Id: I4343d2ed9fb5b066cde95628ed0b4ccc84a424db
6f97c1
---
6f97c1
6f97c1
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
6f97c1
index e0dfe8b..2730311 100644
6f97c1
--- a/src/client/qwaylanddisplay.cpp
6f97c1
+++ b/src/client/qwaylanddisplay.cpp
6f97c1
@@ -575,14 +575,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
6f97c1
     if (mLastKeyboardFocus == keyboardFocus)
6f97c1
         return;
6f97c1
6f97c1
-    if (mWaylandIntegration->mShellIntegration) {
6f97c1
-        mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
6f97c1
-    } else {
6f97c1
-        if (keyboardFocus)
6f97c1
-            handleWindowActivated(keyboardFocus);
6f97c1
-        if (mLastKeyboardFocus)
6f97c1
-            handleWindowDeactivated(mLastKeyboardFocus);
6f97c1
-    }
6f97c1
+    if (keyboardFocus)
6f97c1
+        handleWindowActivated(keyboardFocus);
6f97c1
+    if (mLastKeyboardFocus)
6f97c1
+        handleWindowDeactivated(mLastKeyboardFocus);
6f97c1
6f97c1
     mLastKeyboardFocus = keyboardFocus;
6f97c1
 }
6f97c1
@@ -627,6 +623,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
6f97c1
     return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
6f97c1
 }
6f97c1
6f97c1
+bool QWaylandDisplay::isKeyboardAvailable() const
6f97c1
+{
6f97c1
+    return std::any_of(
6f97c1
+            mInputDevices.constBegin(), mInputDevices.constEnd(),
6f97c1
+            [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
6f97c1
+}
6f97c1
+
6f97c1
 #if QT_CONFIG(cursor)
6f97c1
6f97c1
 QWaylandCursor *QWaylandDisplay::waylandCursor()
6f97c1
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
6f97c1
index 3b092bc..09a1736 100644
6f97c1
--- a/src/client/qwaylanddisplay_p.h
6f97c1
+++ b/src/client/qwaylanddisplay_p.h
6f97c1
@@ -215,6 +215,7 @@ public:
6f97c1
     void destroyFrameQueue(const FrameQueue &q);
6f97c1
     void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
6f97c1
6f97c1
+    bool isKeyboardAvailable() const;
6f97c1
 public slots:
6f97c1
     void blockingReadEvents();
6f97c1
     void flushRequests();
6f97c1
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
6f97c1
index e0b91dd..8d56be1 100644
6f97c1
--- a/src/client/qwaylandwindow.cpp
6f97c1
+++ b/src/client/qwaylandwindow.cpp
6f97c1
@@ -96,7 +96,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
6f97c1
 QWaylandWindow::~QWaylandWindow()
6f97c1
 {
6f97c1
     mDisplay->destroyFrameQueue(mFrameQueue);
6f97c1
-    mDisplay->handleWindowDestroyed(this);
6f97c1
6f97c1
     delete mWindowDecoration;
6f97c1
6f97c1
@@ -266,6 +265,8 @@ void QWaylandWindow::reset()
6f97c1
6f97c1
     mMask = QRegion();
6f97c1
     mQueuedBuffer = nullptr;
6f97c1
+
6f97c1
+    mDisplay->handleWindowDestroyed(this);
6f97c1
 }
6f97c1
6f97c1
 QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
6f97c1
@@ -1097,7 +1098,10 @@ Qt::WindowStates QWaylandWindow::windowStates() const
6f97c1
 void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
6f97c1
 {
6f97c1
     createDecoration();
6f97c1
-    QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
6f97c1
+    Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
6f97c1
+    Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
6f97c1
+    QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
6f97c1
+                                                     lastStatesWithoutActive);
6f97c1
     mLastReportedWindowStates = states;
6f97c1
 }
6f97c1
6f97c1
diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
6f97c1
index ccad004..b308ffe 100644
6f97c1
--- a/src/client/shellintegration/qwaylandshellintegration_p.h
6f97c1
+++ b/src/client/shellintegration/qwaylandshellintegration_p.h
6f97c1
@@ -73,12 +73,6 @@ public:
6f97c1
         return true;
6f97c1
     }
6f97c1
     virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
6f97c1
-    virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
6f97c1
-        if (newFocus)
6f97c1
-            m_display->handleWindowActivated(newFocus);
6f97c1
-        if (oldFocus)
6f97c1
-            m_display->handleWindowDeactivated(oldFocus);
6f97c1
-    }
6f97c1
     virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
6f97c1
         Q_UNUSED(resource);
6f97c1
         Q_UNUSED(window);
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
6f97c1
index 4e25949..cfc6093 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
6f97c1
@@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
6f97c1
     return m_xdgShell->createXdgSurface(window);
6f97c1
 }
6f97c1
6f97c1
-void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
6f97c1
-    if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
6f97c1
-        m_display->handleWindowActivated(newFocus);
6f97c1
-    if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
6f97c1
-        m_display->handleWindowDeactivated(oldFocus);
6f97c1
-}
6f97c1
-
6f97c1
 }
6f97c1
6f97c1
 QT_END_NAMESPACE
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
6f97c1
index ce6bdb9..aed8867 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
6f97c1
@@ -67,7 +67,6 @@ public:
6f97c1
     QWaylandXdgShellV5Integration() {}
6f97c1
     bool initialize(QWaylandDisplay *display) override;
6f97c1
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
6f97c1
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
6f97c1
6f97c1
 private:
6f97c1
     QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
6f97c1
index 0316431..e8da8ba 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
6f97c1
@@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
6f97c1
     return m_xdgShell->getXdgSurface(window);
6f97c1
 }
6f97c1
6f97c1
-void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
6f97c1
-{
6f97c1
-    if (newFocus) {
6f97c1
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
6f97c1
-        if (xdgSurface && !xdgSurface->handlesActiveState())
6f97c1
-            m_display->handleWindowActivated(newFocus);
6f97c1
-    }
6f97c1
-    if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
6f97c1
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
6f97c1
-        if (xdgSurface && !xdgSurface->handlesActiveState())
6f97c1
-            m_display->handleWindowDeactivated(oldFocus);
6f97c1
-    }
6f97c1
-}
6f97c1
-
6f97c1
 }
6f97c1
6f97c1
 QT_END_NAMESPACE
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
6f97c1
index 261f8cb..c1bcd5c 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
6f97c1
@@ -65,7 +65,6 @@ public:
6f97c1
     QWaylandXdgShellV6Integration() {}
6f97c1
     bool initialize(QWaylandDisplay *display) override;
6f97c1
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
6f97c1
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
6f97c1
6f97c1
 private:
6f97c1
     QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
6f97c1
index cf7eb4e..2c6e84b 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
6f97c1
@@ -67,11 +67,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
6f97c1
6f97c1
 QWaylandXdgSurface::Toplevel::~Toplevel()
6f97c1
 {
6f97c1
-    if (m_applied.states & Qt::WindowActive) {
6f97c1
-        QWaylandWindow *window = m_xdgSurface->window();
6f97c1
-        window->display()->handleWindowDeactivated(window);
6f97c1
-    }
6f97c1
-
6f97c1
     // The protocol spec requires that the decoration object is deleted before xdg_toplevel.
6f97c1
     delete m_decoration;
6f97c1
     m_decoration = nullptr;
6f97c1
@@ -85,17 +80,16 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
6f97c1
     if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
6f97c1
         m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
6f97c1
6f97c1
-    if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
6f97c1
+    if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
6f97c1
+        && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
6f97c1
         m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
6f97c1
6f97c1
-    if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
6f97c1
+    if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
6f97c1
+        && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
6f97c1
         m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
6f97c1
6f97c1
-    // TODO: none of the other plugins send WindowActive either, but is it on purpose?
6f97c1
-    Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
6f97c1
-
6f97c1
     m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates);
6f97c1
-    m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
6f97c1
+    m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
6f97c1
6f97c1
     if (m_pending.size.isEmpty()) {
6f97c1
         // An empty size in the configure means it's up to the client to choose the size
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
6f97c1
index 8769d97..da0dd6a 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
6f97c1
@@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
6f97c1
     return m_xdgShell->getXdgSurface(window);
6f97c1
 }
6f97c1
6f97c1
-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
6f97c1
-{
6f97c1
-    if (newFocus) {
6f97c1
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
6f97c1
-        if (xdgSurface && !xdgSurface->handlesActiveState())
6f97c1
-            m_display->handleWindowActivated(newFocus);
6f97c1
-    }
6f97c1
-    if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
6f97c1
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
6f97c1
-        if (xdgSurface && !xdgSurface->handlesActiveState())
6f97c1
-            m_display->handleWindowDeactivated(oldFocus);
6f97c1
-    }
6f97c1
-}
6f97c1
-
6f97c1
 }
6f97c1
6f97c1
 QT_END_NAMESPACE
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
6f97c1
index b6caa6c..2f929f9 100644
6f97c1
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
6f97c1
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
6f97c1
@@ -65,7 +65,6 @@ public:
6f97c1
     QWaylandXdgShellIntegration() {}
6f97c1
     bool initialize(QWaylandDisplay *display) override;
6f97c1
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
6f97c1
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
6f97c1
6f97c1
 private:
6f97c1
     QScopedPointer<QWaylandXdgShell> m_xdgShell;
6f97c1
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
6f97c1
index 2fdd0a7..5346b6e 100644
6f97c1
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
6f97c1
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
6f97c1
@@ -31,6 +31,7 @@
6f97c1
 #include <QtGui/QOpenGLWindow>
6f97c1
 #include <QtGui/qpa/qplatformnativeinterface.h>
6f97c1
 #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
6f97c1
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
6f97c1
6f97c1
 using namespace MockCompositor;
6f97c1
6f97c1
@@ -154,9 +155,12 @@ void tst_xdgshell::configureStates()
6f97c1
     // Toplevel windows don't know their position on xdg-shell
6f97c1
 //    QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
6f97c1
6f97c1
-//    QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
6f97c1
-//    QVERIFY(window.isActive());
6f97c1
-    QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
6f97c1
+    // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
6f97c1
+    // XDGShell this is internal to QtWayland so it is queried directly
6f97c1
+    auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
6f97c1
+    Q_ASSERT(waylandWindow);
6f97c1
+    QTRY_VERIFY(waylandWindow->windowStates().testFlag(
6f97c1
+            Qt::WindowActive)); // Just make sure it eventually get's set correctly
6f97c1
6f97c1
     const QSize screenSize(640, 480);
6f97c1
     const uint maximizedSerial = exec([=] {