diff options
-rw-r--r-- | src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp | 35 | ||||
-rw-r--r-- | tests/auto/client/shared/xdgshell.cpp | 5 | ||||
-rw-r--r-- | tests/auto/client/shared/xdgshell.h | 3 | ||||
-rw-r--r-- | tests/auto/client/xdgshell/tst_xdgshell.cpp | 25 |
4 files changed, 59 insertions, 9 deletions
diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index c0d7a7d4..9bd5209f 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -58,19 +58,38 @@ void QWaylandXdgSurface::Toplevel::applyConfigure() m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates); m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states); - if (m_pending.size.isEmpty()) { - // An empty size in the configure means it's up to the client to choose the size - bool normalPending = !(m_pending.states & (Qt::WindowMaximized|Qt::WindowFullScreen)); - if (normalPending && !m_normalSize.isEmpty()) { - QSize size = m_normalSize; + // If the width or height is zero, the client should decide the size on its own. + QSize surfaceSize; + + if (m_pending.size.width() > 0) { + surfaceSize.setWidth(m_pending.size.width()); + } else { + if (Q_UNLIKELY(m_pending.states & (Qt::WindowMaximized | Qt::WindowFullScreen))) { + qCWarning(lcQpaWayland) << "Configure event with maximized or fullscreen state contains invalid width:" << m_pending.size.width(); + } else { + int width = m_normalSize.width(); if (!m_pending.bounds.isEmpty()) - size = size.boundedTo(m_pending.bounds); - m_xdgSurface->m_window->resizeFromApplyConfigure(size); + width = std::min(width, m_pending.bounds.width()); + surfaceSize.setWidth(width); } + } + + if (m_pending.size.height() > 0) { + surfaceSize.setHeight(m_pending.size.height()); } else { - m_xdgSurface->m_window->resizeFromApplyConfigure(m_pending.size); + if (Q_UNLIKELY(m_pending.states & (Qt::WindowMaximized | Qt::WindowFullScreen))) { + qCWarning(lcQpaWayland) << "Configure event with maximized or fullscreen state contains invalid height:" << m_pending.size.height(); + } else { + int height = m_normalSize.height(); + if (!m_pending.bounds.isEmpty()) + height = std::min(height, m_pending.bounds.height()); + surfaceSize.setHeight(height); + } } + if (!surfaceSize.isEmpty()) + m_xdgSurface->m_window->resizeFromApplyConfigure(surfaceSize); + m_applied = m_pending; qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states; } diff --git a/tests/auto/client/shared/xdgshell.cpp b/tests/auto/client/shared/xdgshell.cpp index eb9a1e87..4e4de4d1 100644 --- a/tests/auto/client/shared/xdgshell.cpp +++ b/tests/auto/client/shared/xdgshell.cpp @@ -143,6 +143,11 @@ XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version) connect(surface(), &Surface::commit, this, [this] { m_committed = m_pending; }); } +void XdgToplevel::sendConfigureBounds(const QSize &size) +{ + send_configure_bounds(size.width(), size.height()); +} + void XdgToplevel::sendConfigure(const QSize &size, const QList<uint> &states) { send_configure(size.width(), size.height(), toByteArray(states)); diff --git a/tests/auto/client/shared/xdgshell.h b/tests/auto/client/shared/xdgshell.h index 4c1cd6cd..a68ace0e 100644 --- a/tests/auto/client/shared/xdgshell.h +++ b/tests/auto/client/shared/xdgshell.h @@ -18,7 +18,7 @@ class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base { Q_OBJECT public: - explicit XdgWmBase(CoreCompositor *compositor, int version = 1); + explicit XdgWmBase(CoreCompositor *compositor, int version = 4); using QtWaylandServer::xdg_wm_base::send_ping; void send_ping(uint32_t) = delete; // It's a global, use resource specific instead bool isClean() override { return m_xdgSurfaces.empty(); } @@ -90,6 +90,7 @@ class XdgToplevel : public QObject, public QtWaylandServer::xdg_toplevel Q_OBJECT public: explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1); + void sendConfigureBounds(const QSize &size); void sendConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {}); uint sendCompleteConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {}); Surface *surface() { return m_xdgSurface->m_surface; } diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp index e560784e..efaa6a8f 100644 --- a/tests/auto/client/xdgshell/tst_xdgshell.cpp +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp @@ -19,6 +19,7 @@ private slots: void basicConfigure(); void configureSize(); void configureStates(); + void configureBounds(); void popup(); void tooltipOnPopup(); void tooltipAndSiblingPopup(); @@ -170,6 +171,30 @@ void tst_xdgshell::configureStates() QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT")); } +void tst_xdgshell::configureBounds() +{ + QRasterWindow window; + window.resize(1280, 1024); + window.show(); + QCOMPOSITOR_TRY_VERIFY(xdgToplevel()); + + // Take xdg_toplevel.configure_bounds into account only if the configure event has 0x0 size. + const uint serial1 = exec([=] { + xdgToplevel()->sendConfigureBounds(QSize(800, 600)); + return xdgToplevel()->sendCompleteConfigure(QSize(0, 0), { XdgToplevel::state_activated }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial1); + QCOMPARE(window.frameGeometry().size(), QSize(800, 600)); + + // Window size in xdg_toplevel configure events takes precedence over the configure bounds. + const uint serial2 = exec([=] { + xdgToplevel()->sendConfigureBounds(QSize(800, 600)); + return xdgToplevel()->sendCompleteConfigure(QSize(1600, 900), { XdgToplevel::state_activated }); + }); + QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committedConfigureSerial, serial2); + QCOMPARE(window.frameGeometry().size(), QSize(1600, 900)); +} + void tst_xdgshell::popup() { class Window : public QRasterWindow { |