Add dummy placeholder output type
Placeholder outputs are not rendered so they don't need render data. Also, this simplifies the control flow when the last real output is removed. The Platform::screensQueried signal won't be emitted inside a Platform::screensQueried slot.
This commit is contained in:
parent
192a57e2e1
commit
d8ea87a9ea
18 changed files with 104 additions and 38 deletions
|
@ -106,6 +106,7 @@ target_sources(kwin PRIVATE
|
|||
osd.cpp
|
||||
outline.cpp
|
||||
placeholderinputeventfilter.cpp
|
||||
placeholderoutput.cpp
|
||||
placement.cpp
|
||||
placementtracker.cpp
|
||||
plugin.cpp
|
||||
|
|
|
@ -403,9 +403,9 @@ QString DrmBackend::supportInformation() const
|
|||
return supportInfo;
|
||||
}
|
||||
|
||||
Output *DrmBackend::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
|
||||
Output *DrmBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
|
||||
{
|
||||
auto output = primaryGpu()->createVirtualOutput(name, size * scale, scale, type);
|
||||
auto output = primaryGpu()->createVirtualOutput(name, size * scale, scale);
|
||||
Q_EMIT screensQueried();
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
QVector<CompositingType> supportedCompositors() const override;
|
||||
|
||||
QString supportInformation() const override;
|
||||
Output *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type) override;
|
||||
Output *createVirtualOutput(const QString &name, const QSize &size, double scale) override;
|
||||
void removeVirtualOutput(Output *output) override;
|
||||
|
||||
DrmGpu *primaryGpu() const;
|
||||
|
|
|
@ -587,9 +587,9 @@ const QVector<DrmPipeline *> DrmGpu::pipelines() const
|
|||
return m_pipelines;
|
||||
}
|
||||
|
||||
DrmVirtualOutput *DrmGpu::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
|
||||
DrmVirtualOutput *DrmGpu::createVirtualOutput(const QString &name, const QSize &size, double scale)
|
||||
{
|
||||
auto output = new DrmVirtualOutput(name, this, size, scale, type);
|
||||
auto output = new DrmVirtualOutput(name, this, size, scale);
|
||||
m_outputs << output;
|
||||
Q_EMIT outputAdded(output);
|
||||
return output;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#define DRM_GPU_H
|
||||
|
||||
#include "drm_pipeline.h"
|
||||
#include "drm_virtual_output.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QSize>
|
||||
|
@ -42,6 +41,7 @@ class DrmBackend;
|
|||
class EglGbmBackend;
|
||||
class DrmAbstractOutput;
|
||||
class DrmRenderBackend;
|
||||
class DrmVirtualOutput;
|
||||
|
||||
class DrmGpu : public QObject
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ public:
|
|||
|
||||
bool updateOutputs();
|
||||
|
||||
DrmVirtualOutput *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type);
|
||||
DrmVirtualOutput *createVirtualOutput(const QString &name, const QSize &size, double scale);
|
||||
void removeVirtualOutput(DrmVirtualOutput *output);
|
||||
|
||||
DrmPipeline::Error testPendingConfiguration();
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, qreal scale, VirtualOutputType type)
|
||||
DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, qreal scale)
|
||||
: DrmAbstractOutput(gpu)
|
||||
, m_vsyncMonitor(SoftwareVsyncMonitor::create())
|
||||
{
|
||||
|
@ -32,7 +32,6 @@ DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize
|
|||
setInformation(Information{
|
||||
.name = QStringLiteral("Virtual-") + name,
|
||||
.physicalSize = size,
|
||||
.placeholder = type == VirtualOutputType::Placeholder,
|
||||
});
|
||||
|
||||
setState(State{
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/platform.h"
|
||||
#include "drm_abstract_output.h"
|
||||
|
||||
#include <QObject>
|
||||
|
@ -27,7 +26,7 @@ class DrmVirtualOutput : public DrmAbstractOutput
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, qreal scale, VirtualOutputType type);
|
||||
DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, qreal scale);
|
||||
~DrmVirtualOutput() override;
|
||||
|
||||
bool present() override;
|
||||
|
|
|
@ -775,11 +775,11 @@ void WaylandBackend::createOutputs()
|
|||
|
||||
for (int i = 0; i < initialOutputCount(); i++) {
|
||||
const QString name = QStringLiteral("WL-%1").arg(i);
|
||||
createOutput(name, QSize(pixelWidth, pixelHeight), false);
|
||||
createOutput(name, QSize(pixelWidth, pixelHeight));
|
||||
}
|
||||
}
|
||||
|
||||
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, bool placeholder)
|
||||
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size)
|
||||
{
|
||||
auto surface = m_compositor->createSurface(this);
|
||||
if (!surface || !surface->isValid()) {
|
||||
|
@ -799,7 +799,7 @@ WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &si
|
|||
WaylandOutput *waylandOutput = nullptr;
|
||||
|
||||
if (m_xdgShell && m_xdgShell->isValid()) {
|
||||
waylandOutput = new XdgShellOutput(name, surface, m_xdgShell, this, m_nextId++, placeholder);
|
||||
waylandOutput = new XdgShellOutput(name, surface, m_xdgShell, this, m_nextId++);
|
||||
}
|
||||
|
||||
if (!waylandOutput) {
|
||||
|
@ -967,9 +967,9 @@ void WaylandBackend::clearDpmsFilter()
|
|||
m_dpmsFilter.reset();
|
||||
}
|
||||
|
||||
Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
|
||||
Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
|
||||
{
|
||||
return createOutput(name, size * scale, type == VirtualOutputType::Placeholder);
|
||||
return createOutput(name, size * scale);
|
||||
}
|
||||
|
||||
void WaylandBackend::removeVirtualOutput(Output *output)
|
||||
|
|
|
@ -298,7 +298,7 @@ public:
|
|||
void createDpmsFilter();
|
||||
void clearDpmsFilter();
|
||||
|
||||
Output *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type) override;
|
||||
Output *createVirtualOutput(const QString &name, const QSize &size, double scale) override;
|
||||
void removeVirtualOutput(Output *output) override;
|
||||
|
||||
std::optional<DmaBufParams> testCreateDmaBuf(const QSize &size, quint32 format, const QVector<uint64_t> &modifiers) override;
|
||||
|
@ -327,7 +327,7 @@ private:
|
|||
void createOutputs();
|
||||
void destroyOutputs();
|
||||
|
||||
WaylandOutput *createOutput(const QString &name, const QSize &size, bool placeholder);
|
||||
WaylandOutput *createOutput(const QString &name, const QSize &size);
|
||||
|
||||
wl_display *m_display;
|
||||
KWayland::Client::EventQueue *m_eventQueue;
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Wayland
|
|||
using namespace KWayland::Client;
|
||||
static const int s_refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host?
|
||||
|
||||
WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBackend *backend, bool placeholder)
|
||||
WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBackend *backend)
|
||||
: Output(backend)
|
||||
, m_renderLoop(std::make_unique<RenderLoop>())
|
||||
, m_surface(surface)
|
||||
|
@ -34,7 +34,6 @@ WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBacke
|
|||
.name = name,
|
||||
.model = name,
|
||||
.capabilities = Capability::Dpms,
|
||||
.placeholder = placeholder,
|
||||
});
|
||||
|
||||
connect(surface, &Surface::frameRendered, this, &WaylandOutput::frameRendered);
|
||||
|
@ -114,8 +113,8 @@ void WaylandOutput::updateEnabled(bool enabled)
|
|||
setState(next);
|
||||
}
|
||||
|
||||
XdgShellOutput::XdgShellOutput(const QString &name, Surface *surface, XdgShell *xdgShell, WaylandBackend *backend, int number, bool placeholder)
|
||||
: WaylandOutput(name, surface, backend, placeholder)
|
||||
XdgShellOutput::XdgShellOutput(const QString &name, Surface *surface, XdgShell *xdgShell, WaylandBackend *backend, int number)
|
||||
: WaylandOutput(name, surface, backend)
|
||||
, m_number(number)
|
||||
{
|
||||
m_xdgShellSurface = xdgShell->createSurface(surface, this);
|
||||
|
|
|
@ -39,7 +39,7 @@ class WaylandOutput : public Output
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WaylandOutput(const QString &name, KWayland::Client::Surface *surface, WaylandBackend *backend, bool placeholder);
|
||||
WaylandOutput(const QString &name, KWayland::Client::Surface *surface, WaylandBackend *backend);
|
||||
~WaylandOutput() override;
|
||||
|
||||
RenderLoop *renderLoop() const override;
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
XdgShellOutput(const QString &name,
|
||||
KWayland::Client::Surface *surface,
|
||||
KWayland::Client::XdgShell *xdgShell,
|
||||
WaylandBackend *backend, int number, bool placeholder);
|
||||
WaylandBackend *backend, int number);
|
||||
~XdgShellOutput() override;
|
||||
|
||||
void lockPointer(KWayland::Client::Pointer *pointer, bool lock) override;
|
||||
|
|
|
@ -142,12 +142,11 @@ void Platform::setReady(bool ready)
|
|||
Q_EMIT readyChanged(m_ready);
|
||||
}
|
||||
|
||||
Output *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
|
||||
Output *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale)
|
||||
{
|
||||
Q_UNUSED(name);
|
||||
Q_UNUSED(size);
|
||||
Q_UNUSED(scale);
|
||||
Q_UNUSED(type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,6 @@ class ScreenEdges;
|
|||
class OutputConfiguration;
|
||||
struct DmaBufParams;
|
||||
|
||||
enum class VirtualOutputType {
|
||||
Normal,
|
||||
Placeholder,
|
||||
};
|
||||
|
||||
class KWIN_EXPORT Outputs : public QVector<Output *>
|
||||
{
|
||||
public:
|
||||
|
@ -322,7 +317,7 @@ public:
|
|||
m_selectedCompositor = type;
|
||||
}
|
||||
|
||||
virtual Output *createVirtualOutput(const QString &name, const QSize &size, qreal scaling, VirtualOutputType type);
|
||||
virtual Output *createVirtualOutput(const QString &name, const QSize &size, qreal scale);
|
||||
virtual void removeVirtualOutput(Output *output);
|
||||
|
||||
/**
|
||||
|
|
42
src/placeholderoutput.cpp
Normal file
42
src/placeholderoutput.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "placeholderoutput.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
PlaceholderOutput::PlaceholderOutput(const QSize &size, qreal scale)
|
||||
{
|
||||
auto mode = std::make_shared<OutputMode>(size, 60000);
|
||||
|
||||
m_renderLoop = std::make_unique<RenderLoop>();
|
||||
m_renderLoop->setRefreshRate(mode->refreshRate());
|
||||
m_renderLoop->inhibit();
|
||||
|
||||
setState(State{
|
||||
.scale = scale,
|
||||
.modes = {mode},
|
||||
.currentMode = mode,
|
||||
.enabled = true,
|
||||
});
|
||||
|
||||
setInformation(Information{
|
||||
.name = QStringLiteral("Placeholder-1"),
|
||||
.placeholder = true,
|
||||
});
|
||||
}
|
||||
|
||||
PlaceholderOutput::~PlaceholderOutput()
|
||||
{
|
||||
}
|
||||
|
||||
RenderLoop *PlaceholderOutput::renderLoop() const
|
||||
{
|
||||
return m_renderLoop.get();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
28
src/placeholderoutput.h
Normal file
28
src/placeholderoutput.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/output.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class PlaceholderOutput : public Output
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlaceholderOutput(const QSize &size, qreal scale = 1);
|
||||
~PlaceholderOutput() override;
|
||||
|
||||
RenderLoop *renderLoop() const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<RenderLoop> m_renderLoop;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
|
@ -110,7 +110,7 @@ void ScreencastManager::streamVirtualOutput(KWaylandServer::ScreencastStreamV1In
|
|||
double scale,
|
||||
KWaylandServer::ScreencastV1Interface::CursorMode mode)
|
||||
{
|
||||
auto output = kwinApp()->platform()->createVirtualOutput(name, size, scale, VirtualOutputType::Normal);
|
||||
auto output = kwinApp()->platform()->createVirtualOutput(name, size, scale);
|
||||
streamOutput(stream, output, mode);
|
||||
connect(stream, &KWaylandServer::ScreencastStreamV1Interface::finished, output, [output] {
|
||||
kwinApp()->platform()->removeVirtualOutput(output);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "decorations/decorationbridge.h"
|
||||
#include "main.h"
|
||||
#include "placeholderinputeventfilter.h"
|
||||
#include "placeholderoutput.h"
|
||||
#include "placementtracker.h"
|
||||
#include "unmanaged.h"
|
||||
#include "useractions.h"
|
||||
|
@ -1452,8 +1453,9 @@ void Workspace::addOutput(Output *output)
|
|||
Q_EMIT outputAdded(output);
|
||||
|
||||
if (m_placeholderOutput) {
|
||||
kwinApp()->platform()->removeVirtualOutput(m_placeholderOutput);
|
||||
m_placeholderOutput = nullptr;
|
||||
m_outputs.removeOne(m_placeholderOutput.get());
|
||||
Q_EMIT outputRemoved(m_placeholderOutput.get());
|
||||
m_placeholderOutput.reset();
|
||||
m_placeholderFilter.reset();
|
||||
}
|
||||
}
|
||||
|
@ -1465,8 +1467,9 @@ void Workspace::removeOutput(Output *output)
|
|||
}
|
||||
if (m_outputs.empty()) {
|
||||
// not all parts of KWin handle having no output yet. To prevent crashes, create a placeholder output
|
||||
m_placeholderOutput = kwinApp()->platform()->createVirtualOutput("placeholder", output->pixelSize(), output->scale(), VirtualOutputType::Placeholder);
|
||||
m_placeholderOutput->renderLoop()->inhibit();
|
||||
m_placeholderOutput = std::make_unique<PlaceholderOutput>(output->pixelSize(), output->scale());
|
||||
m_outputs.append(m_placeholderOutput.get());
|
||||
Q_EMIT outputAdded(m_placeholderOutput.get());
|
||||
// also prevent accidental inputs while the user has no screen connected
|
||||
m_placeholderFilter = std::make_unique<PlaceholderInputEventFilter>();
|
||||
input()->prependInputEventFilter(m_placeholderFilter.get());
|
||||
|
|
|
@ -76,6 +76,7 @@ class Screens;
|
|||
class Activities;
|
||||
#endif
|
||||
class PlaceholderInputEventFilter;
|
||||
class PlaceholderOutput;
|
||||
class Placement;
|
||||
|
||||
class KWIN_EXPORT Workspace : public QObject
|
||||
|
@ -756,7 +757,7 @@ private:
|
|||
#endif
|
||||
std::unique_ptr<PlacementTracker> m_placementTracker;
|
||||
|
||||
Output *m_placeholderOutput = nullptr;
|
||||
std::unique_ptr<PlaceholderOutput> m_placeholderOutput;
|
||||
std::unique_ptr<PlaceholderInputEventFilter> m_placeholderFilter;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue