summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Zahorodnii <vlad.zahorodnii@kde.org>2023-08-16 09:16:15 +0300
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-08-17 09:34:20 +0000
commit964764e31883b8f588f759d4be448c29fd819e4b (patch)
tree2feee0dd88f02918ae4e3ed67d0c5f5f4988ef58
parent39fb9faf37a3f37202d5ef9e03990274e4ef4e9b (diff)
Client: Fix keyboard focus when closing a popup
325a2338976c3cca6278436af03e7bd4e4378d7c changed the order in which the shell surface and the QWaylandWindow::wlSurfaceDestroyed signal are ordered. Unfortunately, it broke popups with some compositors. When the wlSurfaceDestroyed signal is emitted, QWaylandInputDevice::Keyboard is going to reset its focused surface and call QWaylandDisplay::handleKeyboardFocusChanged(). QWaylandDisplay::handleKeyboardFocusChanged() is going to call QWaylandDisplay::handleWindowDeactivated(), it will make an async roundtrip to determine the current focused window. This is to batch leave and enter events. Since the wlSurfaceDestroyed signal is emitted before destroying the shell surface and the wl_surface, the compositor has no reason to change keyboard focus, so qtwayland will think that the app lost focus for good and close all popups. This change restores the old behavior by making QWaylandInputDevice::Keyboard connect to QWaylandSurface::destroyed signal, which is emitted after the window's wl_surface is gone. It also makes QWaylandInputDevice::Keyboard consistent with QWaylandInputDevice::Pointer. Fixes: QTBUG-116051 Change-Id: If866f94a0cec1659c27ffeb2d263a2480ca8fdf1 Reviewed-by: David Edmundson <davidedmundson@kde.org> (cherry picked from commit 1da23c86d54cefa6f3bd4285658ed6dc7b3f5175) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/client/qwaylandinputdevice.cpp25
-rw-r--r--src/client/qwaylandinputdevice_p.h2
2 files changed, 15 insertions, 12 deletions
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index 79a881a6e..738c57463 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -118,7 +118,7 @@ QWaylandInputDevice::Keyboard::~Keyboard()
QWaylandWindow *QWaylandInputDevice::Keyboard::focusWindow() const
{
- return mFocus ? QWaylandWindow::fromWlSurface(mFocus) : nullptr;
+ return mFocus ? mFocus->waylandWindow() : nullptr;
}
QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *seat)
@@ -1215,13 +1215,17 @@ void QWaylandInputDevice::Keyboard::keyboard_enter(uint32_t time, struct wl_surf
return;
}
+ QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
+ if (!window)
+ return;
+
if (mFocus) {
qCWarning(lcQpaWayland()) << "Unexpected wl_keyboard.enter event. Keyboard already has focus";
- disconnect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ disconnect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
}
- mFocus = surface;
- connect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ mFocus = window->waylandSurface();
+ connect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
mParent->mQDisplay->handleKeyboardFocusChanged(mParent);
}
@@ -1235,13 +1239,17 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf
return;
}
- if (surface != mFocus) {
+ QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);
+ if (!window)
+ return;
+
+ if (window->waylandSurface() != mFocus) {
qCWarning(lcQpaWayland) << "Ignoring unexpected wl_keyboard.leave event."
<< "wl_surface argument does not match the current focus"
<< "This is most likely a compositor bug";
return;
}
- disconnect(focusWindow(), &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
+ disconnect(mFocus, &QWaylandSurface::destroyed, this, &Keyboard::handleFocusDestroyed);
handleFocusLost();
}
@@ -1341,11 +1349,6 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
void QWaylandInputDevice::Keyboard::handleFocusDestroyed()
{
- // The signal is emitted by QWaylandWindow, which is not necessarily destroyed along with the
- // surface, so we still need to disconnect the signal
- auto *window = qobject_cast<QWaylandWindow *>(sender());
- disconnect(window, &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed);
- Q_ASSERT(window->wlSurface() == mFocus);
handleFocusLost();
}
diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h
index 0f36852b0..84ba84e82 100644
--- a/src/client/qwaylandinputdevice_p.h
+++ b/src/client/qwaylandinputdevice_p.h
@@ -223,7 +223,7 @@ public:
void keyboard_repeat_info(int32_t rate, int32_t delay) override;
QWaylandInputDevice *mParent = nullptr;
- ::wl_surface *mFocus = nullptr;
+ QPointer<QWaylandSurface> mFocus;
uint32_t mNativeModifiers = 0;