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

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