From 192a8364a983ceff7a7d9f2a33161e1da738ed70 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 3 Aug 2018 12:53:38 +0200 Subject: xdg-shell stable: Make sure popup parent is topmost popup when grabbing Avoids protocol errors on Weston, gnome-shell and wlroots-based compositors. This is the same fix as 75c996e7, but for the stable version of xdg shell. Change-Id: Ic998fb920a8b1b131e42833a61e663704c8663e4 Reviewed-by: Paul Olav Tvete --- .../xdg-shell/qwaylandxdgshell.cpp | 27 +++++++++++++++++++--- .../xdg-shell/qwaylandxdgshell_p.h | 8 +++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 7dabd96f2..8b3d07481 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -182,6 +182,7 @@ QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurf QtWayland::xdg_positioner *positioner) : xdg_popup(xdgSurface->get_popup(parent->object(), positioner->object())) , m_xdgSurface(xdgSurface) + , m_parent(parent) { } @@ -189,6 +190,19 @@ QWaylandXdgSurface::Popup::~Popup() { if (isInitialized()) destroy(); + + if (m_grabbing) { + auto *shell = m_xdgSurface->m_shell; + Q_ASSERT(shell->m_topmostPopup == this); + shell->m_topmostPopup = m_parent->m_popup; + } +} + +void QWaylandXdgSurface::Popup::grab(QWaylandInputDevice *seat, uint serial) +{ + m_xdgSurface->m_shell->m_topmostPopup = this; + xdg_popup::grab(seat->wl_seat(), serial); + m_grabbing = true; } void QWaylandXdgSurface::Popup::xdg_popup_popup_done() @@ -317,6 +331,14 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *d Q_ASSERT(!m_toplevel && !m_popup); auto parentXdgSurface = static_cast(parent->shellSurface()); + + auto *top = m_shell->m_topmostPopup; + if (grab && top && top->m_xdgSurface != parentXdgSurface) { + qCWarning(lcQpaWayland) << "setPopup called for a surface that was not the topmost popup, positions might be off."; + parentXdgSurface = top->m_xdgSurface; + parent = top->m_xdgSurface->m_window; + } + auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner()); // set_popup expects a position relative to the parent QPoint transientPos = m_window->geometry().topLeft(); // this is absolute @@ -332,9 +354,8 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *d m_popup = new Popup(this, parentXdgSurface, positioner); positioner->destroy(); delete positioner; - if (grab) { - m_popup->grab(device->wl_seat(), serial); - } + if (grab) + m_popup->grab(device, serial); } void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial) diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h index 37a4a8a4c..45d7d4b0e 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h @@ -129,9 +129,12 @@ private: Popup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parent, QtWayland::xdg_positioner *positioner); ~Popup() override; + void grab(QWaylandInputDevice *seat, uint serial); void xdg_popup_popup_done() override; QWaylandXdgSurface *m_xdgSurface = nullptr; + QWaylandXdgSurface *m_parent = nullptr; + bool m_grabbing = false; }; void setToplevel(); @@ -144,6 +147,8 @@ private: bool m_configured = false; QRegion m_exposeRegion; uint m_pendingConfigureSerial = 0; + + friend class QWaylandXdgShell; }; class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShell : public QtWayland::xdg_wm_base @@ -164,6 +169,9 @@ private: QWaylandDisplay *m_display = nullptr; QScopedPointer m_xdgDecorationManager; + QWaylandXdgSurface::Popup *m_topmostPopup = nullptr; + + friend class QWaylandXdgSurface; }; QT_END_NAMESPACE -- cgit v1.2.3