Client: Don't require an input device for non-grabbing popups

It's valid to create a non-grabbing XDG-popup, such as a tooltip, before an input event.

The current guard should only apply for grabbing popups, otherwise tooltips created early
are turned into XDG-toplevels resulting in incorrect positioning.

Change-Id: I5bb59a68964ef2375c81e8b4e1a73361b9d2cbcc
Reviewed-by: Johan Helsing <johan.helsing@qt.io>
This commit is contained in:
David Edmundson 2018-11-09 15:00:21 +00:00
parent c03495c90e
commit 27d39e7b3a
4 changed files with 40 additions and 26 deletions

View File

@ -199,8 +199,10 @@ QWaylandXdgSurfaceV6::QWaylandXdgSurfaceV6(QWaylandXdgShellV6 *shell, ::zxdg_sur
Qt::WindowType type = window->window()->type(); Qt::WindowType type = window->window()->type();
auto *transientParent = window->transientParent(); auto *transientParent = window->transientParent();
if ((type == Qt::Popup || type == Qt::ToolTip) && transientParent && display->lastInputDevice()) { if (type == Qt::ToolTip && transientParent) {
setPopup(transientParent, display->lastInputDevice(), display->lastInputSerial(), type == Qt::Popup); setPopup(transientParent);
} else if (type == Qt::Popup && transientParent && display->lastInputDevice()) {
setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial());
} else { } else {
setToplevel(); setToplevel();
if (transientParent) { if (transientParent) {
@ -304,19 +306,12 @@ void QWaylandXdgSurfaceV6::setToplevel()
m_toplevel = new Toplevel(this); m_toplevel = new Toplevel(this);
} }
void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial, bool grab) void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent)
{ {
Q_ASSERT(!m_toplevel && !m_popup); Q_ASSERT(!m_toplevel && !m_popup);
auto parentXdgSurface = static_cast<QWaylandXdgSurfaceV6 *>(parent->shellSurface()); 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()); auto positioner = new QtWayland::zxdg_positioner_v6(m_shell->create_positioner());
// set_popup expects a position relative to the parent // set_popup expects a position relative to the parent
QPoint transientPos = m_window->geometry().topLeft(); // this is absolute QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
@ -332,7 +327,18 @@ void QWaylandXdgSurfaceV6::setPopup(QWaylandWindow *parent, QWaylandInputDevice
m_popup = new Popup(this, parentXdgSurface, positioner); m_popup = new Popup(this, parentXdgSurface, positioner);
positioner->destroy(); positioner->destroy();
delete positioner; delete positioner;
if (grab) }
void QWaylandXdgSurfaceV6::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial)
{
auto parentXdgSurface = static_cast<QWaylandXdgSurfaceV6 *>(parent->shellSurface());
auto *top = m_shell->m_topmostPopup;
if (top && top->m_xdgSurface != parentXdgSurface) {
qCWarning(lcQpaWayland) << "setGrabPopup called for a surface that was not the topmost popup, positions might be off.";
parent = top->m_xdgSurface->m_window;
}
setPopup(parent);
m_popup->grab(device, serial); m_popup->grab(device, serial);
} }

View File

@ -131,7 +131,8 @@ private:
}; };
void setToplevel(); void setToplevel();
void setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial, bool grab); void setPopup(QWaylandWindow *parent);
void setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial);
QWaylandXdgShellV6 *m_shell = nullptr; QWaylandXdgShellV6 *m_shell = nullptr;
QWaylandWindow *m_window = nullptr; QWaylandWindow *m_window = nullptr;

View File

@ -227,8 +227,10 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s
Qt::WindowType type = window->window()->type(); Qt::WindowType type = window->window()->type();
auto *transientParent = window->transientParent(); auto *transientParent = window->transientParent();
if ((type == Qt::Popup || type == Qt::ToolTip) && transientParent && display->lastInputDevice()) { if (type == Qt::ToolTip && transientParent) {
setPopup(transientParent, display->lastInputDevice(), display->lastInputSerial(), type == Qt::Popup); setPopup(transientParent);
} else if (type == Qt::Popup && transientParent && display->lastInputDevice()) {
setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial());
} else { } else {
setToplevel(); setToplevel();
if (transientParent) { if (transientParent) {
@ -338,19 +340,12 @@ void QWaylandXdgSurface::setToplevel()
m_toplevel = new Toplevel(this); m_toplevel = new Toplevel(this);
} }
void QWaylandXdgSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial, bool grab) void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
{ {
Q_ASSERT(!m_toplevel && !m_popup); Q_ASSERT(!m_toplevel && !m_popup);
auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(parent->shellSurface()); auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(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()); auto positioner = new QtWayland::xdg_positioner(m_shell->create_positioner());
// set_popup expects a position relative to the parent // set_popup expects a position relative to the parent
QPoint transientPos = m_window->geometry().topLeft(); // this is absolute QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
@ -366,7 +361,18 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *d
m_popup = new Popup(this, parentXdgSurface, positioner); m_popup = new Popup(this, parentXdgSurface, positioner);
positioner->destroy(); positioner->destroy();
delete positioner; delete positioner;
if (grab) }
void QWaylandXdgSurface::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial)
{
auto parentXdgSurface = static_cast<QWaylandXdgSurface *>(parent->shellSurface());
auto *top = m_shell->m_topmostPopup;
if (top && top->m_xdgSurface != parentXdgSurface) {
qCWarning(lcQpaWayland) << "setGrabPopup called for a surface that was not the topmost popup, positions might be off.";
parent = top->m_xdgSurface->m_window;
}
setPopup(parent);
m_popup->grab(device, serial); m_popup->grab(device, serial);
} }

View File

@ -138,7 +138,8 @@ private:
}; };
void setToplevel(); void setToplevel();
void setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial, bool grab); void setPopup(QWaylandWindow *parent);
void setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial);
QWaylandXdgShell *m_shell = nullptr; QWaylandXdgShell *m_shell = nullptr;
QWaylandWindow *m_window = nullptr; QWaylandWindow *m_window = nullptr;