From 52118d94ebb408ed9fb83c501c19b896bfcee746 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 19 Jan 2021 20:26:18 +0200 Subject: [PATCH] wayland: Fix crash when all outputs are disconnected If all outputs have been disconnected, the screensQueried() signal won't be emitted and Screens::count() and Screens::size() won't be updated. The signal is not emitted to ensure that kwin is initialized properly when there are no outputs. Unfortunately, this breaks repaint scheduling code as it doesn't take into account that the Screens class may lie in rare cases. The drm backend should probably create a placeholder screen in case all physical outputs have been disconnected, but in meanwhile, let's work around this issue by porting the scene to the output api in the Platform. --- scene.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/scene.cpp b/scene.cpp index f29bedb50a..e2ad870eb7 100644 --- a/scene.cpp +++ b/scene.cpp @@ -89,7 +89,8 @@ Scene::Scene(QObject *parent) : QObject(parent) { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - connect(screens(), &Screens::countChanged, this, &Scene::reallocRepaints); + connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Scene::reallocRepaints); + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Scene::reallocRepaints); } reallocRepaints(); } @@ -102,11 +103,12 @@ Scene::~Scene() void Scene::addRepaint(const QRegion ®ion) { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - if (m_repaints.count() != screens()->count()) { + const QVector outputs = kwinApp()->platform()->enabledOutputs(); + if (m_repaints.count() != outputs.count()) { return; // Repaints haven't been reallocated yet, do nothing. } for (int screenId = 0; screenId < m_repaints.count(); ++screenId) { - AbstractOutput *output = kwinApp()->platform()->findOutput(screenId); + AbstractOutput *output = outputs[screenId]; const QRegion dirtyRegion = region & output->geometry(); if (!dirtyRegion.isEmpty()) { m_repaints[screenId] += dirtyRegion; @@ -134,7 +136,7 @@ void Scene::resetRepaints(int screenId) void Scene::reallocRepaints() { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - m_repaints.resize(screens()->count()); + m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); } else { m_repaints.resize(1); } @@ -732,7 +734,8 @@ Scene::Window::Window(Toplevel *client, QObject *parent) , cached_quad_list(nullptr) { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - connect(screens(), &Screens::countChanged, this, &Window::reallocRepaints); + connect(kwinApp()->platform(), &Platform::outputEnabled, this, &Window::reallocRepaints); + connect(kwinApp()->platform(), &Platform::outputDisabled, this, &Window::reallocRepaints); } reallocRepaints(); @@ -1167,11 +1170,12 @@ void Scene::Window::preprocess() void Scene::Window::addLayerRepaint(const QRegion ®ion) { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - if (m_repaints.count() != screens()->count()) { + const QVector outputs = kwinApp()->platform()->enabledOutputs(); + if (m_repaints.count() != outputs.count()) { return; // Repaints haven't been reallocated yet, do nothing. } for (int screenId = 0; screenId < m_repaints.count(); ++screenId) { - AbstractOutput *output = kwinApp()->platform()->findOutput(screenId); + AbstractOutput *output = outputs[screenId]; const QRegion dirtyRegion = region & output->geometry(); if (!dirtyRegion.isEmpty()) { m_repaints[screenId] += dirtyRegion; @@ -1204,7 +1208,7 @@ void Scene::Window::resetRepaints(int screen) void Scene::Window::reallocRepaints() { if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { - m_repaints.resize(screens()->count()); + m_repaints.resize(kwinApp()->platform()->enabledOutputs().count()); } else { m_repaints.resize(1); }