Client: Improve handling of 0xH and Wx0 xdg_toplevel configure events
The compositor can send a configure event with 0xH and Wx0 when it wants the window to have some concrete size along one dimension but wants the client to pick the size along the other dimension. Change-Id: I2e72017d4a71b19a930da24fa5c58b6ce672fb94 Reviewed-by: David Edmundson <davidedmundson@kde.org>
This commit is contained in:
parent
389f01d835
commit
f45244946c
@ -58,19 +58,38 @@ void QWaylandXdgSurface::Toplevel::applyConfigure()
|
|||||||
m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates);
|
m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates);
|
||||||
m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
|
m_xdgSurface->m_window->handleWindowStatesChanged(m_pending.states);
|
||||||
|
|
||||||
if (m_pending.size.isEmpty()) {
|
// If the width or height is zero, the client should decide the size on its own.
|
||||||
// An empty size in the configure means it's up to the client to choose the size
|
QSize surfaceSize;
|
||||||
bool normalPending = !(m_pending.states & (Qt::WindowMaximized|Qt::WindowFullScreen));
|
|
||||||
if (normalPending && !m_normalSize.isEmpty()) {
|
if (m_pending.size.width() > 0) {
|
||||||
QSize size = m_normalSize;
|
surfaceSize.setWidth(m_pending.size.width());
|
||||||
if (!m_pending.bounds.isEmpty())
|
|
||||||
size = size.boundedTo(m_pending.bounds);
|
|
||||||
m_xdgSurface->m_window->resizeFromApplyConfigure(size);
|
|
||||||
}
|
|
||||||
} else {
|
} 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 width:" << m_pending.size.width();
|
||||||
|
} else {
|
||||||
|
int width = m_normalSize.width();
|
||||||
|
if (!m_pending.bounds.isEmpty())
|
||||||
|
width = std::min(width, m_pending.bounds.width());
|
||||||
|
surfaceSize.setWidth(width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pending.size.height() > 0) {
|
||||||
|
surfaceSize.setHeight(m_pending.size.height());
|
||||||
|
} else {
|
||||||
|
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;
|
m_applied = m_pending;
|
||||||
qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
|
qCDebug(lcQpaWayland) << "Applied pending xdg_toplevel configure event:" << m_applied.size << m_applied.states;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,11 @@ XdgToplevel::XdgToplevel(XdgSurface *xdgSurface, int id, int version)
|
|||||||
connect(surface(), &Surface::commit, this, [this] { m_committed = m_pending; });
|
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)
|
void XdgToplevel::sendConfigure(const QSize &size, const QList<uint> &states)
|
||||||
{
|
{
|
||||||
send_configure(size.width(), size.height(), toByteArray(states));
|
send_configure(size.width(), size.height(), toByteArray(states));
|
||||||
|
@ -18,7 +18,7 @@ class XdgWmBase : public Global, public QtWaylandServer::xdg_wm_base
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit XdgWmBase(CoreCompositor *compositor, int version = 1);
|
explicit XdgWmBase(CoreCompositor *compositor, int version = 4);
|
||||||
using QtWaylandServer::xdg_wm_base::send_ping;
|
using QtWaylandServer::xdg_wm_base::send_ping;
|
||||||
void send_ping(uint32_t) = delete; // It's a global, use resource specific instead
|
void send_ping(uint32_t) = delete; // It's a global, use resource specific instead
|
||||||
bool isClean() override { return m_xdgSurfaces.empty(); }
|
bool isClean() override { return m_xdgSurfaces.empty(); }
|
||||||
@ -90,6 +90,7 @@ class XdgToplevel : public QObject, public QtWaylandServer::xdg_toplevel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit XdgToplevel(XdgSurface *xdgSurface, int id, int version = 1);
|
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 = {});
|
void sendConfigure(const QSize &size = {0, 0}, const QList<uint> &states = {});
|
||||||
uint sendCompleteConfigure(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; }
|
Surface *surface() { return m_xdgSurface->m_surface; }
|
||||||
|
@ -19,6 +19,7 @@ private slots:
|
|||||||
void basicConfigure();
|
void basicConfigure();
|
||||||
void configureSize();
|
void configureSize();
|
||||||
void configureStates();
|
void configureStates();
|
||||||
|
void configureBounds();
|
||||||
void popup();
|
void popup();
|
||||||
void tooltipOnPopup();
|
void tooltipOnPopup();
|
||||||
void tooltipAndSiblingPopup();
|
void tooltipAndSiblingPopup();
|
||||||
@ -170,6 +171,30 @@ void tst_xdgshell::configureStates()
|
|||||||
QVERIFY(qunsetenv("QT_WAYLAND_FRAME_CALLBACK_TIMEOUT"));
|
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()
|
void tst_xdgshell::popup()
|
||||||
{
|
{
|
||||||
class Window : public QRasterWindow {
|
class Window : public QRasterWindow {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user