summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp35
-rw-r--r--tests/auto/client/shared/xdgshell.cpp5
-rw-r--r--tests/auto/client/shared/xdgshell.h3
-rw-r--r--tests/auto/client/xdgshell/tst_xdgshell.cpp25
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 c0d7a7d46..9bd5209f0 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 eb9a1e87a..4e4de4d11 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 4c1cd6cdb..a68ace0ee 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 e560784e9..efaa6a8f1 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 {