Blame SOURCES/0035-Wayland-client-use-wl_keyboard-to-determine-active-s.patch

147f94
From 5c180bdc1042e7cb1555e188051f09e219b00ec9 Mon Sep 17 00:00:00 2001
147f94
From: =?UTF-8?q?M=C3=A9ven=20Car?= <meven.car@enioka.com>
6f97c1
Date: Wed, 18 Aug 2021 18:28:20 +0200
9fb289
Subject: [PATCH 35/52] Wayland client: use wl_keyboard to determine active
147f94
 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
147f94
cherry-pick 40036a1b80e5234e6db7d5cbeff122aa7ee13e20
147f94
6f97c1
Change-Id: I4343d2ed9fb5b066cde95628ed0b4ccc84a424db
147f94
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
6f97c1
---
147f94
 src/client/qwaylanddisplay.cpp                | 19 +++++++++++--------
147f94
 src/client/qwaylanddisplay_p.h                |  1 +
147f94
 src/client/qwaylandwindow.cpp                 | 13 +++++++++++--
147f94
 src/client/qwaylandwindow_p.h                 |  1 +
147f94
 .../qwaylandshellintegration_p.h              |  7 +++----
147f94
 .../qwaylandxdgshellv5integration.cpp         |  7 -------
147f94
 .../qwaylandxdgshellv5integration_p.h         |  1 -
147f94
 .../qwaylandxdgshellv6integration.cpp         | 14 --------------
147f94
 .../qwaylandxdgshellv6integration_p.h         |  1 -
147f94
 .../xdg-shell/qwaylandxdgshell.cpp            | 16 +++++-----------
147f94
 .../xdg-shell/qwaylandxdgshellintegration.cpp | 14 --------------
147f94
 .../xdg-shell/qwaylandxdgshellintegration_p.h |  1 -
147f94
 tests/auto/client/xdgshell/tst_xdgshell.cpp   | 10 +++++++---
147f94
 13 files changed, 39 insertions(+), 66 deletions(-)
6f97c1
6f97c1
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
147f94
index e0dfe8b2..27303110 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;
147f94
 
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);
147f94
 
6f97c1
     mLastKeyboardFocus = keyboardFocus;
6f97c1
 }
6f97c1
@@ -627,6 +623,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
6f97c1
     return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
6f97c1
 }
147f94
 
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)
147f94
 
6f97c1
 QWaylandCursor *QWaylandDisplay::waylandCursor()
6f97c1
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
147f94
index 3b092bc8..09a1736a 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);
147f94
 
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
147f94
index c020a58f..ba881cb3 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);
147f94
 
6f97c1
     delete mWindowDecoration;
147f94
 
6f97c1
@@ -266,6 +265,8 @@ void QWaylandWindow::reset()
147f94
 
6f97c1
     mMask = QRegion();
6f97c1
     mQueuedBuffer = nullptr;
6f97c1
+
6f97c1
+    mDisplay->handleWindowDestroyed(this);
6f97c1
 }
147f94
 
6f97c1
 QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
147f94
@@ -1083,10 +1084,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
147f94
     return true;
147f94
 }
147f94
 
147f94
+Qt::WindowStates QWaylandWindow::windowStates() const
147f94
+{
147f94
+    return mLastReportedWindowStates;
147f94
+}
147f94
+
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
 }
147f94
 
147f94
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
147f94
index 6cc1664b..e0687962 100644
147f94
--- a/src/client/qwaylandwindow_p.h
147f94
+++ b/src/client/qwaylandwindow_p.h
147f94
@@ -148,6 +148,7 @@ public:
147f94
     void setWindowState(Qt::WindowStates states) override;
147f94
     void setWindowFlags(Qt::WindowFlags flags) override;
147f94
     void handleWindowStatesChanged(Qt::WindowStates states);
147f94
+    Qt::WindowStates windowStates() const;
147f94
 
147f94
     void raise() override;
147f94
     void lower() override;
6f97c1
diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
147f94
index ccad0048..4cc9b3b8 100644
6f97c1
--- a/src/client/shellintegration/qwaylandshellintegration_p.h
6f97c1
+++ b/src/client/shellintegration/qwaylandshellintegration_p.h
147f94
@@ -73,11 +73,10 @@ public:
6f97c1
         return true;
6f97c1
     }
6f97c1
     virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
147f94
+    // kept for binary compat with layer-shell-qt
147f94
     virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
6f97c1
-        if (newFocus)
6f97c1
-            m_display->handleWindowActivated(newFocus);
6f97c1
-        if (oldFocus)
6f97c1
-            m_display->handleWindowDeactivated(oldFocus);
147f94
+        Q_UNUSED(newFocus);
147f94
+        Q_UNUSED(oldFocus);
147f94
     }
6f97c1
     virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
6f97c1
         Q_UNUSED(resource);
6f97c1
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
147f94
index 4e25949f..cfc60939 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
 }
147f94
 
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
 }
147f94
 
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
147f94
index ce6bdb9e..aed88670 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;
147f94
 
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
147f94
index 03164316..e8da8ba1 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
 }
147f94
 
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
 }
147f94
 
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
147f94
index 261f8cbb..c1bcd5c6 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;
147f94
 
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
147f94
index 7d33dabd..d7d0ddf7 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)
147f94
 
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;
147f94
@@ -85,16 +80,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
6f97c1
     if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
6f97c1
         m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
147f94
 
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);
147f94
 
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);
147f94
 
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->handleWindowStatesChanged(statesWithoutActive);
6f97c1
+    m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
147f94
 
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
147f94
index 8769d971..da0dd6a7 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
 }
147f94
 
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
 }
147f94
 
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
147f94
index b6caa6c9..2f929f98 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;
147f94
 
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
147f94
index e2593314..73d1eb9c 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>
147f94
 
6f97c1
 using namespace MockCompositor;
147f94
 
147f94
@@ -155,9 +156,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
147f94
 
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
147f94
 
6f97c1
     const QSize screenSize(640, 480);
6f97c1
     const uint maximizedSerial = exec([=] {
147f94
-- 
9fb289
2.35.1
147f94