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

f38a11
From 64e133f830ce48b6732397325b768ed9193c2cb4 Mon Sep 17 00:00:00 2001
b814f0
From: =?UTF-8?q?M=C3=A9ven=20Car?= <meven.car@enioka.com>
b814f0
Date: Wed, 18 Aug 2021 18:28:20 +0200
f38a11
Subject: [PATCH 22/40] Wayland client: use wl_keyboard to determine active
b814f0
 state
b814f0
b814f0
Commit f497a5bb87270174b8e0106b7eca1992d44ff15d made QWaylandDisplay
b814f0
use the xdgshell's active state for QWindow::isActive(), instead of
b814f0
using wl_keyboard activate/deactivate events.
b814f0
b814f0
That seems to have been a misunderstanding, since xdgshell activation
b814f0
is only supposed to be used to determine visual appearance, and there
b814f0
is an explicit warning not to assume it means focus.
b814f0
b814f0
This commit reverts this logic back to listening to wl_keyboard.
b814f0
It adds a fallback when there is no wl_keyboard available to handle
b814f0
activated/deactivated events through xdg-shell, in order to fix
b814f0
QTBUG-53702.
b814f0
b814f0
windowStates is handled so that we're not using the Xdg hint for
b814f0
anything with QWindowSystemInterface::handleWindowStateChanged or
b814f0
anything where we need to track only having one active.
b814f0
b814f0
We are still exposing it for decorations, which is the only reason to
b814f0
use the Xdghint over keyboard focus - so you can keep the toplevel
b814f0
active whilst you show a popup.
b814f0
b814f0
cherry-pick 40036a1b80e5234e6db7d5cbeff122aa7ee13e20
b814f0
b814f0
Change-Id: I4343d2ed9fb5b066cde95628ed0b4ccc84a424db
b814f0
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
b814f0
---
b814f0
 src/client/qwaylanddisplay.cpp                | 19 +++++++++++--------
b814f0
 src/client/qwaylanddisplay_p.h                |  1 +
b814f0
 src/client/qwaylandwindow.cpp                 | 13 +++++++++++--
b814f0
 src/client/qwaylandwindow_p.h                 |  1 +
b814f0
 .../qwaylandshellintegration_p.h              |  7 +++----
b814f0
 .../qwaylandxdgshellv5integration.cpp         |  7 -------
b814f0
 .../qwaylandxdgshellv5integration_p.h         |  1 -
b814f0
 .../qwaylandxdgshellv6integration.cpp         | 14 --------------
b814f0
 .../qwaylandxdgshellv6integration_p.h         |  1 -
b814f0
 .../xdg-shell/qwaylandxdgshell.cpp            | 16 +++++-----------
b814f0
 .../xdg-shell/qwaylandxdgshellintegration.cpp | 14 --------------
b814f0
 .../xdg-shell/qwaylandxdgshellintegration_p.h |  1 -
b814f0
 tests/auto/client/xdgshell/tst_xdgshell.cpp   | 10 +++++++---
b814f0
 13 files changed, 39 insertions(+), 66 deletions(-)
b814f0
b814f0
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
b814f0
index e0dfe8b2..27303110 100644
b814f0
--- a/src/client/qwaylanddisplay.cpp
b814f0
+++ b/src/client/qwaylanddisplay.cpp
b814f0
@@ -575,14 +575,10 @@ void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevic
b814f0
     if (mLastKeyboardFocus == keyboardFocus)
b814f0
         return;
b814f0
 
b814f0
-    if (mWaylandIntegration->mShellIntegration) {
b814f0
-        mWaylandIntegration->mShellIntegration->handleKeyboardFocusChanged(keyboardFocus, mLastKeyboardFocus);
b814f0
-    } else {
b814f0
-        if (keyboardFocus)
b814f0
-            handleWindowActivated(keyboardFocus);
b814f0
-        if (mLastKeyboardFocus)
b814f0
-            handleWindowDeactivated(mLastKeyboardFocus);
b814f0
-    }
b814f0
+    if (keyboardFocus)
b814f0
+        handleWindowActivated(keyboardFocus);
b814f0
+    if (mLastKeyboardFocus)
b814f0
+        handleWindowDeactivated(mLastKeyboardFocus);
b814f0
 
b814f0
     mLastKeyboardFocus = keyboardFocus;
b814f0
 }
b814f0
@@ -627,6 +623,13 @@ QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
b814f0
     return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
b814f0
 }
b814f0
 
b814f0
+bool QWaylandDisplay::isKeyboardAvailable() const
b814f0
+{
b814f0
+    return std::any_of(
b814f0
+            mInputDevices.constBegin(), mInputDevices.constEnd(),
b814f0
+            [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
b814f0
+}
b814f0
+
b814f0
 #if QT_CONFIG(cursor)
b814f0
 
b814f0
 QWaylandCursor *QWaylandDisplay::waylandCursor()
b814f0
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
b814f0
index 3b092bc8..09a1736a 100644
b814f0
--- a/src/client/qwaylanddisplay_p.h
b814f0
+++ b/src/client/qwaylanddisplay_p.h
b814f0
@@ -215,6 +215,7 @@ public:
b814f0
     void destroyFrameQueue(const FrameQueue &q);
b814f0
     void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
b814f0
 
b814f0
+    bool isKeyboardAvailable() const;
b814f0
 public slots:
b814f0
     void blockingReadEvents();
b814f0
     void flushRequests();
b814f0
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
b814f0
index c020a58f..ba881cb3 100644
b814f0
--- a/src/client/qwaylandwindow.cpp
b814f0
+++ b/src/client/qwaylandwindow.cpp
b814f0
@@ -96,7 +96,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
b814f0
 QWaylandWindow::~QWaylandWindow()
b814f0
 {
b814f0
     mDisplay->destroyFrameQueue(mFrameQueue);
b814f0
-    mDisplay->handleWindowDestroyed(this);
b814f0
 
b814f0
     delete mWindowDecoration;
b814f0
 
b814f0
@@ -266,6 +265,8 @@ void QWaylandWindow::reset()
b814f0
 
b814f0
     mMask = QRegion();
b814f0
     mQueuedBuffer = nullptr;
b814f0
+
b814f0
+    mDisplay->handleWindowDestroyed(this);
b814f0
 }
b814f0
 
b814f0
 QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface)
b814f0
@@ -1083,10 +1084,18 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab)
b814f0
     return true;
b814f0
 }
b814f0
 
b814f0
+Qt::WindowStates QWaylandWindow::windowStates() const
b814f0
+{
b814f0
+    return mLastReportedWindowStates;
b814f0
+}
b814f0
+
b814f0
 void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states)
b814f0
 {
b814f0
     createDecoration();
b814f0
-    QWindowSystemInterface::handleWindowStateChanged(window(), states, mLastReportedWindowStates);
b814f0
+    Qt::WindowStates statesWithoutActive = states & ~Qt::WindowActive;
b814f0
+    Qt::WindowStates lastStatesWithoutActive = mLastReportedWindowStates & ~Qt::WindowActive;
b814f0
+    QWindowSystemInterface::handleWindowStateChanged(window(), statesWithoutActive,
b814f0
+                                                     lastStatesWithoutActive);
b814f0
     mLastReportedWindowStates = states;
b814f0
 }
b814f0
 
b814f0
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
b814f0
index 6cc1664b..e0687962 100644
b814f0
--- a/src/client/qwaylandwindow_p.h
b814f0
+++ b/src/client/qwaylandwindow_p.h
b814f0
@@ -148,6 +148,7 @@ public:
b814f0
     void setWindowState(Qt::WindowStates states) override;
b814f0
     void setWindowFlags(Qt::WindowFlags flags) override;
b814f0
     void handleWindowStatesChanged(Qt::WindowStates states);
b814f0
+    Qt::WindowStates windowStates() const;
b814f0
 
b814f0
     void raise() override;
b814f0
     void lower() override;
b814f0
diff --git a/src/client/shellintegration/qwaylandshellintegration_p.h b/src/client/shellintegration/qwaylandshellintegration_p.h
b814f0
index ccad0048..4cc9b3b8 100644
b814f0
--- a/src/client/shellintegration/qwaylandshellintegration_p.h
b814f0
+++ b/src/client/shellintegration/qwaylandshellintegration_p.h
b814f0
@@ -73,11 +73,10 @@ public:
b814f0
         return true;
b814f0
     }
b814f0
     virtual QWaylandShellSurface *createShellSurface(QWaylandWindow *window) = 0;
b814f0
+    // kept for binary compat with layer-shell-qt
b814f0
     virtual void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
b814f0
-        if (newFocus)
b814f0
-            m_display->handleWindowActivated(newFocus);
b814f0
-        if (oldFocus)
b814f0
-            m_display->handleWindowDeactivated(oldFocus);
b814f0
+        Q_UNUSED(newFocus);
b814f0
+        Q_UNUSED(oldFocus);
b814f0
     }
b814f0
     virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) {
b814f0
         Q_UNUSED(resource);
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
b814f0
index 4e25949f..cfc60939 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
b814f0
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration.cpp
b814f0
@@ -85,13 +85,6 @@ QWaylandShellSurface *QWaylandXdgShellV5Integration::createShellSurface(QWayland
b814f0
     return m_xdgShell->createXdgSurface(window);
b814f0
 }
b814f0
 
b814f0
-void QWaylandXdgShellV5Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) {
b814f0
-    if (newFocus && qobject_cast<QWaylandXdgPopupV5 *>(newFocus->shellSurface()))
b814f0
-        m_display->handleWindowActivated(newFocus);
b814f0
-    if (oldFocus && qobject_cast<QWaylandXdgPopupV5 *>(oldFocus->shellSurface()))
b814f0
-        m_display->handleWindowDeactivated(oldFocus);
b814f0
-}
b814f0
-
b814f0
 }
b814f0
 
b814f0
 QT_END_NAMESPACE
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
b814f0
index ce6bdb9e..aed88670 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
b814f0
+++ b/src/plugins/shellintegration/xdg-shell-v5/qwaylandxdgshellv5integration_p.h
b814f0
@@ -67,7 +67,6 @@ public:
b814f0
     QWaylandXdgShellV5Integration() {}
b814f0
     bool initialize(QWaylandDisplay *display) override;
b814f0
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
b814f0
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
b814f0
 
b814f0
 private:
b814f0
     QScopedPointer<QWaylandXdgShellV5> m_xdgShell;
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
b814f0
index 03164316..e8da8ba1 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
b814f0
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration.cpp
b814f0
@@ -68,20 +68,6 @@ QWaylandShellSurface *QWaylandXdgShellV6Integration::createShellSurface(QWayland
b814f0
     return m_xdgShell->getXdgSurface(window);
b814f0
 }
b814f0
 
b814f0
-void QWaylandXdgShellV6Integration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
b814f0
-{
b814f0
-    if (newFocus) {
b814f0
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(newFocus->shellSurface());
b814f0
-        if (xdgSurface && !xdgSurface->handlesActiveState())
b814f0
-            m_display->handleWindowActivated(newFocus);
b814f0
-    }
b814f0
-    if (oldFocus && qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface())) {
b814f0
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurfaceV6 *>(oldFocus->shellSurface());
b814f0
-        if (xdgSurface && !xdgSurface->handlesActiveState())
b814f0
-            m_display->handleWindowDeactivated(oldFocus);
b814f0
-    }
b814f0
-}
b814f0
-
b814f0
 }
b814f0
 
b814f0
 QT_END_NAMESPACE
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
b814f0
index 261f8cbb..c1bcd5c6 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
b814f0
+++ b/src/plugins/shellintegration/xdg-shell-v6/qwaylandxdgshellv6integration_p.h
b814f0
@@ -65,7 +65,6 @@ public:
b814f0
     QWaylandXdgShellV6Integration() {}
b814f0
     bool initialize(QWaylandDisplay *display) override;
b814f0
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
b814f0
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
b814f0
 
b814f0
 private:
b814f0
     QScopedPointer<QWaylandXdgShellV6> m_xdgShell;
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
b814f0
index 7d33dabd..d7d0ddf7 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
b814f0
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
b814f0
@@ -67,11 +67,6 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
b814f0
 
b814f0
 QWaylandXdgSurface::Toplevel::~Toplevel()
b814f0
 {
b814f0
-    if (m_applied.states & Qt::WindowActive) {
b814f0
-        QWaylandWindow *window = m_xdgSurface->window();
b814f0
-        window->display()->handleWindowDeactivated(window);
b814f0
-    }
b814f0
-
b814f0
     // The protocol spec requires that the decoration object is deleted before xdg_toplevel.
b814f0
     delete m_decoration;
b814f0
     m_decoration = nullptr;
b814f0
@@ -85,16 +80,15 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
b814f0
     if (!(m_applied.states & (Qt::WindowMaximized|Qt::WindowFullScreen)))
b814f0
         m_normalSize = m_xdgSurface->m_window->windowFrameGeometry().size();
b814f0
 
b814f0
-    if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive))
b814f0
+    if ((m_pending.states & Qt::WindowActive) && !(m_applied.states & Qt::WindowActive)
b814f0
+        && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
b814f0
         m_xdgSurface->m_window->display()->handleWindowActivated(m_xdgSurface->m_window);
b814f0
 
b814f0
-    if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive))
b814f0
+    if (!(m_pending.states & Qt::WindowActive) && (m_applied.states & Qt::WindowActive)
b814f0
+        && !m_xdgSurface->m_window->display()->isKeyboardAvailable())
b814f0
         m_xdgSurface->m_window->display()->handleWindowDeactivated(m_xdgSurface->m_window);
b814f0
 
b814f0
-    // TODO: none of the other plugins send WindowActive either, but is it on purpose?
b814f0
-    Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive;
b814f0
-
b814f0
-    m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive);
b814f0
+    m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
b814f0
 
b814f0
     if (m_pending.size.isEmpty()) {
b814f0
         // An empty size in the configure means it's up to the client to choose the size
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
b814f0
index 8769d971..da0dd6a7 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
b814f0
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp
b814f0
@@ -69,20 +69,6 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi
b814f0
     return m_xdgShell->getXdgSurface(window);
b814f0
 }
b814f0
 
b814f0
-void QWaylandXdgShellIntegration::handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus)
b814f0
-{
b814f0
-    if (newFocus) {
b814f0
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(newFocus->shellSurface());
b814f0
-        if (xdgSurface && !xdgSurface->handlesActiveState())
b814f0
-            m_display->handleWindowActivated(newFocus);
b814f0
-    }
b814f0
-    if (oldFocus && qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface())) {
b814f0
-        auto *xdgSurface = qobject_cast<QWaylandXdgSurface *>(oldFocus->shellSurface());
b814f0
-        if (xdgSurface && !xdgSurface->handlesActiveState())
b814f0
-            m_display->handleWindowDeactivated(oldFocus);
b814f0
-    }
b814f0
-}
b814f0
-
b814f0
 }
b814f0
 
b814f0
 QT_END_NAMESPACE
b814f0
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
b814f0
index b6caa6c9..2f929f98 100644
b814f0
--- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
b814f0
+++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration_p.h
b814f0
@@ -65,7 +65,6 @@ public:
b814f0
     QWaylandXdgShellIntegration() {}
b814f0
     bool initialize(QWaylandDisplay *display) override;
b814f0
     QWaylandShellSurface *createShellSurface(QWaylandWindow *window) override;
b814f0
-    void handleKeyboardFocusChanged(QWaylandWindow *newFocus, QWaylandWindow *oldFocus) override;
b814f0
 
b814f0
 private:
b814f0
     QScopedPointer<QWaylandXdgShell> m_xdgShell;
b814f0
diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp
b814f0
index e2593314..73d1eb9c 100644
b814f0
--- a/tests/auto/client/xdgshell/tst_xdgshell.cpp
b814f0
+++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp
b814f0
@@ -31,6 +31,7 @@
b814f0
 #include <QtGui/QOpenGLWindow>
b814f0
 #include <QtGui/qpa/qplatformnativeinterface.h>
b814f0
 #include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
b814f0
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
b814f0
 
b814f0
 using namespace MockCompositor;
b814f0
 
b814f0
@@ -155,9 +156,12 @@ void tst_xdgshell::configureStates()
b814f0
     // Toplevel windows don't know their position on xdg-shell
b814f0
 //    QCOMPARE(window.frameGeometry().topLeft(), QPoint()); // TODO: this doesn't currently work when window decorations are enabled
b814f0
 
b814f0
-//    QEXPECT_FAIL("", "configure has already been acked, we shouldn't have to wait for isActive", Continue);
b814f0
-//    QVERIFY(window.isActive());
b814f0
-    QTRY_VERIFY(window.isActive()); // Just make sure it eventually get's set correctly
b814f0
+    // window.windowstate() is driven by keyboard focus, however for decorations we want to follow
b814f0
+    // XDGShell this is internal to QtWayland so it is queried directly
b814f0
+    auto waylandWindow = static_cast<QtWaylandClient::QWaylandWindow *>(window.handle());
b814f0
+    Q_ASSERT(waylandWindow);
b814f0
+    QTRY_VERIFY(waylandWindow->windowStates().testFlag(
b814f0
+            Qt::WindowActive)); // Just make sure it eventually get's set correctly
b814f0
 
b814f0
     const QSize screenSize(640, 480);
b814f0
     const uint maximizedSerial = exec([=] {
b814f0
-- 
b814f0
2.35.1
b814f0