Fix crash when connecting a new screen
In QWaylandWindow::virtualSiblings, don't include screens that have not been added yet. I.e. QWaylandScreens for which QPlatformIntegration::screenAdded has not yet been called. There are two reasons why this crash wasn't covered by the removePrimaryScreen() test. First of all, the mock output didn't send wl_output.done events when updating the mode/geometry. These wayland events are what causes QWindowSystemInterface::handleScreenGeometryChange() to be called (where virtualSiblings are called). Furthermore, virtualSiblings is only called when the geometry actually changes, so add a new test that changes the screen geometry of the existing screen while a new one is being added (i.e. moves it to the right). Task-number: QTBUG-62044 Change-Id: I623fbf8799d21c6b9293e7120ded301277639cc6 Reviewed-by: David Edmundson <davidedmundson@kde.org> Reviewed-by: Aleix Pol Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
parent
e3d236cfa7
commit
e87c6a3809
@ -138,8 +138,10 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
|
|||||||
QList<QPlatformScreen *> list;
|
QList<QPlatformScreen *> list;
|
||||||
const QList<QWaylandScreen*> screens = mWaylandDisplay->screens();
|
const QList<QWaylandScreen*> screens = mWaylandDisplay->screens();
|
||||||
list.reserve(screens.count());
|
list.reserve(screens.count());
|
||||||
foreach (QWaylandScreen *screen, screens)
|
for (QWaylandScreen *screen : qAsConst(screens)) {
|
||||||
list << screen;
|
if (screen->screen())
|
||||||
|
list << screen;
|
||||||
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,7 @@ public slots:
|
|||||||
private slots:
|
private slots:
|
||||||
void primaryScreen();
|
void primaryScreen();
|
||||||
void screens();
|
void screens();
|
||||||
|
void addScreenWithGeometryChange();
|
||||||
void windowScreens();
|
void windowScreens();
|
||||||
void removePrimaryScreen();
|
void removePrimaryScreen();
|
||||||
void createDestroyWindow();
|
void createDestroyWindow();
|
||||||
@ -197,6 +198,29 @@ void tst_WaylandClient::screens()
|
|||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//QTBUG-62044
|
||||||
|
void tst_WaylandClient::addScreenWithGeometryChange()
|
||||||
|
{
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
const QRect oldGeometry = QGuiApplication::primaryScreen()->geometry();
|
||||||
|
compositor->sendAddOutput();
|
||||||
|
|
||||||
|
// Move the primary screen to the right
|
||||||
|
const QRect newGeometry(QPoint(screenSize.width(), 0), screenSize);
|
||||||
|
Q_ASSERT(oldGeometry != newGeometry);
|
||||||
|
compositor->sendOutputGeometry(compositor->output(0), newGeometry);
|
||||||
|
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), newGeometry);
|
||||||
|
|
||||||
|
compositor->sendRemoveOutput(compositor->output(1));
|
||||||
|
QTRY_COMPARE(QGuiApplication::screens().size(), 1);
|
||||||
|
|
||||||
|
// Move the screen back
|
||||||
|
compositor->sendOutputGeometry(compositor->output(0), oldGeometry);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->geometry(), oldGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_WaylandClient::windowScreens()
|
void tst_WaylandClient::windowScreens()
|
||||||
{
|
{
|
||||||
QSharedPointer<MockOutput> firstOutput;
|
QSharedPointer<MockOutput> firstOutput;
|
||||||
@ -255,6 +279,7 @@ void tst_WaylandClient::removePrimaryScreen()
|
|||||||
compositor->sendAddOutput();
|
compositor->sendAddOutput();
|
||||||
|
|
||||||
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
QTRY_COMPARE(QGuiApplication::screens().size(), 2);
|
||||||
|
QTRY_COMPARE(QGuiApplication::primaryScreen()->virtualSiblings().size(), 2);
|
||||||
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
|
QScreen *secondaryScreen = QGuiApplication::screens().at(1);
|
||||||
QVERIFY(secondaryScreen);
|
QVERIFY(secondaryScreen);
|
||||||
|
|
||||||
|
@ -196,6 +196,14 @@ void MockCompositor::sendRemoveOutput(const QSharedPointer<MockOutput> &output)
|
|||||||
processCommand(command);
|
processCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendOutputGeometry, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(output);
|
||||||
|
command.parameters << QVariant::fromValue(geometry);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
|
void MockCompositor::sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output)
|
||||||
{
|
{
|
||||||
Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor);
|
Command command = makeCommand(Impl::Compositor::sendSurfaceEnter, m_compositor);
|
||||||
|
@ -89,6 +89,7 @@ public:
|
|||||||
static void setOutputMode(void *compositor, const QList<QVariant> ¶meters);
|
static void setOutputMode(void *compositor, const QList<QVariant> ¶meters);
|
||||||
static void sendAddOutput(void *data, const QList<QVariant> ¶meters);
|
static void sendAddOutput(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendRemoveOutput(void *data, const QList<QVariant> ¶meters);
|
static void sendRemoveOutput(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendOutputGeometry(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendSurfaceEnter(void *data, const QList<QVariant> ¶meters);
|
static void sendSurfaceEnter(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendSurfaceLeave(void *data, const QList<QVariant> ¶meters);
|
static void sendSurfaceLeave(void *data, const QList<QVariant> ¶meters);
|
||||||
|
|
||||||
@ -181,6 +182,7 @@ public:
|
|||||||
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
|
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
|
||||||
void sendAddOutput();
|
void sendAddOutput();
|
||||||
void sendRemoveOutput(const QSharedPointer<MockOutput> &output);
|
void sendRemoveOutput(const QSharedPointer<MockOutput> &output);
|
||||||
|
void sendOutputGeometry(const QSharedPointer<MockOutput> &output, const QRect &geometry);
|
||||||
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
void sendSurfaceEnter(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
||||||
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
void sendSurfaceLeave(const QSharedPointer<MockSurface> &surface, QSharedPointer<MockOutput> &output);
|
||||||
void waitForStartDrag();
|
void waitForStartDrag();
|
||||||
|
@ -54,6 +54,16 @@ void Compositor::sendRemoveOutput(void *data, const QList<QVariant> ¶meters)
|
|||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compositor::sendOutputGeometry(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
Output *output = resolveOutput(parameters.first());
|
||||||
|
Q_ASSERT(output);
|
||||||
|
QRect geometry = parameters.at(1).toRect();
|
||||||
|
output->sendGeometryAndMode(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
void Compositor::setOutputMode(void *data, const QList<QVariant> ¶meters)
|
void Compositor::setOutputMode(void *data, const QList<QVariant> ¶meters)
|
||||||
{
|
{
|
||||||
Compositor *compositor = static_cast<Compositor *>(data);
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
@ -74,16 +84,29 @@ Output::Output(wl_display *display, const QSize &resolution, const QPoint &posit
|
|||||||
|
|
||||||
void Output::setCurrentMode(const QSize &size)
|
void Output::setCurrentMode(const QSize &size)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << size;
|
|
||||||
m_size = size;
|
m_size = size;
|
||||||
for (Resource *resource : resourceMap())
|
for (Resource *resource : resourceMap()) {
|
||||||
sendCurrentMode(resource);
|
sendCurrentMode(resource);
|
||||||
|
send_done(resource->handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output::sendGeometryAndMode(const QRect &geometry)
|
||||||
|
{
|
||||||
|
m_size = geometry.size();
|
||||||
|
m_position = geometry.topLeft();
|
||||||
|
for (Resource *resource : resourceMap()) {
|
||||||
|
sendGeometry(resource);
|
||||||
|
sendCurrentMode(resource);
|
||||||
|
send_done(resource->handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource)
|
||||||
{
|
{
|
||||||
sendGeometry(resource);
|
sendGeometry(resource);
|
||||||
sendCurrentMode(resource);
|
sendCurrentMode(resource);
|
||||||
|
send_done(resource->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::sendGeometry(Resource *resource)
|
void Output::sendGeometry(Resource *resource)
|
||||||
|
@ -44,6 +44,7 @@ public:
|
|||||||
|
|
||||||
QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; }
|
QSharedPointer<MockOutput> mockOutput() const { return m_mockOutput; }
|
||||||
void setCurrentMode(const QSize &size);
|
void setCurrentMode(const QSize &size);
|
||||||
|
void sendGeometryAndMode(const QRect &geometry);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void output_bind_resource(Resource *resource) override;
|
void output_bind_resource(Resource *resource) override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user