client: Force a roundtrip when an XdgOutput is not ready yet

Is possible that the server sends a surface_enter before
all the information of the XdgOutput have been processed by the client.
in this case the associated QScreen doesn't exist yet, causing a
QWindow::SetScreen(nullptr), which will fall back to
QGuiApplication::primaryScreen(), having the QWindow being assigned the
wrong screen

Change-Id: I923d5d3a35484deafa6f0572f79c16c27b1f87f0
Reviewed-by: David Edmundson <davidedmundson@kde.org>
This commit is contained in:
Marco Martin 2023-02-24 17:40:48 +01:00 committed by David Edmundson
parent ba604ed786
commit 6e7de758be
4 changed files with 42 additions and 0 deletions

View File

@ -1306,6 +1306,8 @@ void QWaylandWindow::handleScreensChanged()
if (newScreen == mLastReportedScreen) if (newScreen == mLastReportedScreen)
return; return;
if (!newScreen->isPlaceholder() && !newScreen->QPlatformScreen::screen())
mDisplay->forceRoundTrip();
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
mLastReportedScreen = newScreen; mLastReportedScreen = newScreen;

View File

@ -226,6 +226,8 @@ void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource
if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION) if (m_version >= WL_OUTPUT_DONE_SINCE_VERSION)
wl_output::send_done(resource->handle); wl_output::send_done(resource->handle);
Q_EMIT outputBound(resource);
} }
// Seat stuff // Seat stuff

View File

@ -288,6 +288,9 @@ public:
OutputData m_data; OutputData m_data;
int m_version = 1; // TODO: remove on libwayland upgrade int m_version = 1; // TODO: remove on libwayland upgrade
Q_SIGNALS:
void outputBound(Resource *resource);
protected: protected:
void output_bind_resource(Resource *resource) override; void output_bind_resource(Resource *resource) override;
}; };

View File

@ -30,6 +30,7 @@ private slots:
void primaryScreen(); void primaryScreen();
void overrideGeometry(); void overrideGeometry();
void changeGeometry(); void changeGeometry();
void outputCreateEnterRace();
}; };
void tst_xdgoutput::cleanup() void tst_xdgoutput::cleanup()
@ -109,5 +110,39 @@ void tst_xdgoutput::changeGeometry()
exec([=] { remove(output(1)); }); exec([=] { remove(output(1)); });
} }
void tst_xdgoutput::outputCreateEnterRace()
{
m_config.autoConfigure = true;
m_config.autoEnter = false;
QRasterWindow window;
QSignalSpy screenChanged(&window, &QWindow::screenChanged);
window.resize(400, 320);
window.show();
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
exec([=] { xdgToplevel()->surface()->sendEnter(output(0));});
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
QScreen *primaryScreen = QGuiApplication::screens().first();
QCOMPARE(window.screen(), primaryScreen);
auto *out = exec([=] {
return add<Output>();
});
// In Compositor Thread
connect(out, &Output::outputBound, this, [this](QtWaylandServer::wl_output::Resource *resource){
auto surface = xdgToplevel()->surface();
surface->sendLeave(output(0));
surface->QtWaylandServer::wl_surface::send_enter(surface->resource()->handle, resource->handle);
}, Qt::DirectConnection);
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
QTRY_COMPARE(window.screen(), QGuiApplication::screens()[1]);
exec([=] { remove(out); });
m_config.autoConfigure = false;
m_config.autoEnter = true;
}
QCOMPOSITOR_TEST_MAIN(tst_xdgoutput) QCOMPOSITOR_TEST_MAIN(tst_xdgoutput)
#include "tst_xdgoutput.moc" #include "tst_xdgoutput.moc"