Client: Delete decoration object when frameless window hint is added

We don't want windows with FramelessWindowHint to have a
zxdg_toplevel_decoration_v1 object, because that allows the compositor to
force server-side window decorations.

We already have code in place that avoids creating the decoration object when
the window is created. However, if the frameless window hint is added after
the window has been shown, then the decoration object has already been created.

The protocol states that if a decoration object is destroyed, the window will
switch back to a mode without any server-side decorations on the next commit...
so this is what we do in this patch.

Unfortunately, there is no clean way to handle the case when the hint is
removed while the window is visible since the protocol explicitly forbids
creating toplevel decoration objects for surfaces with committed buffers.

Discussion is ongoing as to whether this should be fixed in the next version of
the protocol: https://gitlab.freedesktop.org/wayland/wayland-protocols/issues/9

If we want to work around it, it is perhaps possible to destroy and create a
new wl_surface, but ideally, it will be fixed in the next version of the
xdg-decoration protocol and we can just wait for that.

Task-number: QTBUG-80702
Change-Id: I7e76c05fc3629f1fbbba1d18482808fe588e3878
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Johan Klokkhammer Helsing 2020-02-11 14:46:17 +01:00 committed by Johan Helsing
parent 75fd4b4669
commit 9b50fed3c4
2 changed files with 25 additions and 3 deletions

View File

@ -156,11 +156,13 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_close()
void QWaylandXdgSurface::Toplevel::requestWindowFlags(Qt::WindowFlags flags) void QWaylandXdgSurface::Toplevel::requestWindowFlags(Qt::WindowFlags flags)
{ {
if (m_decoration) { if (m_decoration) {
if (flags & Qt::FramelessWindowHint) if (flags & Qt::FramelessWindowHint) {
m_decoration->requestMode(QWaylandXdgToplevelDecorationV1::mode_client_side); delete m_decoration;
else m_decoration = nullptr;
} else {
m_decoration->unsetMode(); m_decoration->unsetMode();
} }
}
} }
void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states) void QWaylandXdgSurface::Toplevel::requestWindowStates(Qt::WindowStates states)

View File

@ -154,6 +154,7 @@ private slots:
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); } void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
void clientSidePreferredByCompositor(); void clientSidePreferredByCompositor();
void initialFramelessWindowHint(); void initialFramelessWindowHint();
void delayedFramelessWindowHint();
}; };
void tst_xdgdecorationv1::initTestCase() void tst_xdgdecorationv1::initTestCase()
@ -200,5 +201,24 @@ void tst_xdgdecorationv1::initialFramelessWindowHint()
QCOMPOSITOR_TRY_VERIFY(!toplevelDecoration()); QCOMPOSITOR_TRY_VERIFY(!toplevelDecoration());
} }
void tst_xdgdecorationv1::delayedFramelessWindowHint()
{
QRasterWindow window;
window.show();
QCOMPOSITOR_TRY_COMPARE(get<XdgDecorationManagerV1>()->resourceMap().size(), 1);
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
exec([=]{
xdgToplevel()->sendCompleteConfigure();
});
QCOMPOSITOR_TRY_VERIFY(xdgSurface()->m_committedConfigureSerial);
QCOMPOSITOR_TRY_VERIFY(toplevelDecoration());
window.setFlag(Qt::FramelessWindowHint, true);
// The client should now destroy the decoration object, so the compositor is no longer
// able to force window decorations
QCOMPOSITOR_TRY_VERIFY(!toplevelDecoration());
}
QCOMPOSITOR_TEST_MAIN(tst_xdgdecorationv1) QCOMPOSITOR_TEST_MAIN(tst_xdgdecorationv1)
#include "tst_xdgdecorationv1.moc" #include "tst_xdgdecorationv1.moc"