xdg-shell v6: Make sure popup parent is topmost popup when grabbing

Avoids protocol errors on Weston, gnome-shell and wlroots-based
compositors.

[ChangeLog][QPA Plugin] Fixed a protocol error that sometimes happened
when showing popups such as nested menus on xdg-shell unstable v6.

Task-number: QTBUG-67988
Change-Id: I037aec94fba3d177dd0392e5a216a604bc65ac4f
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
Johan Klokkhammer Helsing 2018-05-03 15:21:01 +02:00 committed by Johan Helsing
parent 6b54806003
commit 2987de952c
2 changed files with 36 additions and 5 deletions

View File

@ -93,6 +93,7 @@ QWaylandXdgSurfaceV6::Popup::Popup(QWaylandXdgSurfaceV6 *xdgSurface, QWaylandXdg
QtWayland::zxdg_positioner_v6 *positioner)
: zxdg_popup_v6(xdgSurface->get_popup(parent->object(), positioner->object()))
, m_xdgSurface(xdgSurface)
, m_parent(parent)
{
}
@ -100,6 +101,12 @@ QWaylandXdgSurfaceV6::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 QWaylandXdgSurfaceV6::Popup::applyConfigure()
@ -107,6 +114,13 @@ void QWaylandXdgSurfaceV6::Popup::applyConfigure()
}
void QWaylandXdgSurfaceV6::Popup::grab(QWaylandInputDevice *seat, uint serial)
{
m_xdgSurface->m_shell->m_topmostPopup = this;
zxdg_popup_v6::grab(seat->wl_seat(), serial);
m_grabbing = true;
}
void QWaylandXdgSurfaceV6::Popup::zxdg_popup_v6_popup_done()
{
m_xdgSurface->m_window->window()->close();
@ -124,8 +138,10 @@ QWaylandXdgSurfaceV6::~QWaylandXdgSurfaceV6()
{
if (m_toplevel)
zxdg_toplevel_v6_destroy(m_toplevel->object());
if (m_popup)
zxdg_popup_v6_destroy(m_popup->object());
if (m_popup) {
delete m_popup;
m_popup = nullptr;
}
destroy();
}
@ -198,6 +214,14 @@ void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice
Q_ASSERT(!m_toplevel && !m_popup);
auto parentXdgSurface = static_cast<QWaylandXdgSurfaceV6 *>(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::zxdg_positioner_v6(m_shell->create_positioner());
// set_popup expects a position relative to the parent
QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
@ -213,9 +237,8 @@ void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice
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 QWaylandXdgSurfaceV6::zxdg_surface_v6_configure(uint32_t serial)

View File

@ -115,9 +115,12 @@ private:
~Popup() override;
void applyConfigure();
void grab(QWaylandInputDevice *seat, uint serial);
void zxdg_popup_v6_popup_done() override;
QWaylandXdgSurfaceV6 *m_xdgSurface = nullptr;
QWaylandXdgSurfaceV6 *m_parent = nullptr;
bool m_grabbing = false;
};
void setToplevel();
@ -129,6 +132,8 @@ private:
Popup *m_popup = nullptr;
bool m_configured = false;
QRegion m_exposeRegion;
friend class QWaylandXdgShellV6;
};
class Q_WAYLAND_CLIENT_EXPORT QWaylandXdgShellV6 : public QtWayland::zxdg_shell_v6
@ -142,6 +147,9 @@ public:
private:
void zxdg_shell_v6_ping(uint32_t serial) override;
QWaylandXdgSurfaceV6::Popup *m_topmostPopup = nullptr;
friend class QWaylandXdgSurfaceV6;
};
QT_END_NAMESPACE