diff options
author | Vlad Zahorodnii <vlad.zahorodnii@kde.org> | 2023-08-16 09:16:15 +0300 |
---|---|---|
committer | Vlad Zahorodnii <vlad.zahorodnii@kde.org> | 2023-08-17 11:48:52 +0300 |
commit | 1da23c86d54cefa6f3bd4285658ed6dc7b3f5175 (patch) | |
tree | 6d0fb12c2b178b7bc0c63d7fa2c2a99d8189a89a /src/client | |
parent | e630e066d8f2672e20a5487c4c726eabbf30045e (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.
Pick-to: 6.5 6.6
Fixes: QTBUG-116051
Change-Id: If866f94a0cec1659c27ffeb2d263a2480ca8fdf1
Reviewed-by: David Edmundson <davidedmundson@kde.org>
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 25 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice_p.h | 2 |
2 files changed, 15 insertions, 12 deletions
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 24dc93612..a5d3eb8f2 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -119,7 +119,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) @@ -1224,13 +1224,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); } @@ -1244,13 +1248,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(); } @@ -1350,11 +1358,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 3f19f2b21..dbdc89bde 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -225,7 +225,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; |