wayland: Move output-management-v2 implementation in wayland/
Since both output-management-v2 protocol implementation and the rest of kwin live in the same place and the fact that kde-output-management-v2 is very plasma specific, we can move Platform::requestOutputsChange() to the implementation of kde-output-management-v2 protocol, it simplifies the code a bit and improve code encapsulation. In order to further simplify kde-output-management-v2 protocol, this change alters the behavior of the protocol so an output configuration can be applied only once, which is a very reasonable behavior.
This commit is contained in:
parent
a9267bdcdc
commit
5f15f3b47c
10 changed files with 127 additions and 829 deletions
|
@ -25,11 +25,6 @@
|
|||
#include "qpainterbackend.h"
|
||||
#include "scene.h"
|
||||
#include "screenedge.h"
|
||||
#include "screens.h"
|
||||
#include "wayland/outputchangeset_v2.h"
|
||||
#include "wayland/outputconfiguration_v2_interface.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <KCoreAddons>
|
||||
|
||||
|
@ -124,81 +119,6 @@ void Platform::createPlatformCursor(QObject *parent)
|
|||
new InputRedirectionCursor(parent);
|
||||
}
|
||||
|
||||
void Platform::requestOutputsChange(KWaylandServer::OutputConfigurationV2Interface *config)
|
||||
{
|
||||
if (!m_supportsOutputChanges) {
|
||||
qCWarning(KWIN_CORE) << "This backend does not support configuration changes.";
|
||||
config->setFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
OutputConfiguration cfg;
|
||||
const auto changes = config->changes();
|
||||
for (auto it = changes.begin(); it != changes.end(); it++) {
|
||||
const KWaylandServer::OutputChangeSetV2 *changeset = it.value();
|
||||
auto output = findOutput(it.key()->uuid());
|
||||
if (!output) {
|
||||
qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto modes = output->modes();
|
||||
const auto modeIt = std::find_if(modes.begin(), modes.end(), [&changeset](const auto &mode) {
|
||||
return mode->size() == changeset->size() && mode->refreshRate() == changeset->refreshRate();
|
||||
});
|
||||
if (modeIt == modes.end()) {
|
||||
qCWarning(KWIN_CORE).nospace() << "Could not find mode " << changeset->size() << "@" << changeset->refreshRate() << " for output " << this;
|
||||
config->setFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto props = cfg.changeSet(output);
|
||||
props->enabled = changeset->enabled();
|
||||
props->pos = changeset->position();
|
||||
props->scale = changeset->scale();
|
||||
props->mode = *modeIt;
|
||||
props->transform = static_cast<Output::Transform>(changeset->transform());
|
||||
props->overscan = changeset->overscan();
|
||||
props->rgbRange = static_cast<Output::RgbRange>(changeset->rgbRange());
|
||||
props->vrrPolicy = static_cast<RenderLoop::VrrPolicy>(changeset->vrrPolicy());
|
||||
}
|
||||
|
||||
const auto allOutputs = outputs();
|
||||
bool allDisabled = !std::any_of(allOutputs.begin(), allOutputs.end(), [&cfg](const auto &output) {
|
||||
return cfg.changeSet(output)->enabled;
|
||||
});
|
||||
if (allDisabled) {
|
||||
qCWarning(KWIN_CORE) << "Disabling all outputs through configuration changes is not allowed";
|
||||
config->setFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (applyOutputChanges(cfg)) {
|
||||
if (config->primaryChanged() || !primaryOutput()->isEnabled()) {
|
||||
auto requestedPrimaryOutput = findOutput(config->primary()->uuid());
|
||||
if (requestedPrimaryOutput && requestedPrimaryOutput->isEnabled()) {
|
||||
setPrimaryOutput(requestedPrimaryOutput);
|
||||
} else {
|
||||
Output *defaultPrimaryOutput = nullptr;
|
||||
const auto candidates = outputs();
|
||||
for (Output *output : candidates) {
|
||||
if (output->isEnabled()) {
|
||||
defaultPrimaryOutput = output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
qCWarning(KWIN_CORE) << "Requested invalid primary screen, using" << defaultPrimaryOutput;
|
||||
setPrimaryOutput(defaultPrimaryOutput);
|
||||
}
|
||||
}
|
||||
Q_EMIT workspace()->screens()->changed();
|
||||
config->setApplied();
|
||||
} else {
|
||||
qCDebug(KWIN_CORE) << "Applying config failed";
|
||||
config->setFailed();
|
||||
}
|
||||
}
|
||||
|
||||
bool Platform::applyOutputChanges(const OutputConfiguration &config)
|
||||
{
|
||||
const auto availableOutputs = outputs();
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
|
||||
class QAction;
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class OutputConfigurationV2Interface;
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -105,15 +100,6 @@ public:
|
|||
*/
|
||||
void setSceneEglGlobalShareContext(EGLContext context);
|
||||
|
||||
/**
|
||||
* Implement this method to receive configuration change requests through KWayland's
|
||||
* OutputManagement interface.
|
||||
*
|
||||
* Base implementation warns that the current backend does not implement this
|
||||
* functionality.
|
||||
*/
|
||||
void requestOutputsChange(KWaylandServer::OutputConfigurationV2Interface *config);
|
||||
|
||||
/**
|
||||
* Whether the Platform requires compositing for rendering.
|
||||
* Default implementation returns @c true. If the implementing Platform allows to be used
|
||||
|
|
|
@ -1,507 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
// KWin
|
||||
#include "wayland/compositor_interface.h"
|
||||
#include "wayland/display.h"
|
||||
#include "wayland/outputconfiguration_interface.h"
|
||||
#include "wayland/outputdevice_interface.h"
|
||||
#include "wayland/outputmanagement_interface.h"
|
||||
|
||||
#include "KWayland/Client/connection_thread.h"
|
||||
#include "KWayland/Client/event_queue.h"
|
||||
#include "KWayland/Client/output.h"
|
||||
#include "KWayland/Client/outputconfiguration.h"
|
||||
#include "KWayland/Client/outputdevice.h"
|
||||
#include "KWayland/Client/outputmanagement.h"
|
||||
#include "KWayland/Client/registry.h"
|
||||
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWaylandServer;
|
||||
|
||||
class TestWaylandOutputManagement : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestWaylandOutputManagement(QObject *parent = nullptr);
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void cleanup();
|
||||
void createConfig();
|
||||
|
||||
void testBasicMemoryManagement();
|
||||
void testMultipleSettings();
|
||||
void testConfigFailed();
|
||||
void testApplied();
|
||||
void testFailed();
|
||||
|
||||
void testExampleConfig();
|
||||
void testScale();
|
||||
|
||||
void testRemoval();
|
||||
|
||||
private:
|
||||
void createOutputDevices();
|
||||
void testEnable();
|
||||
void applyPendingChanges(KWaylandServer::OutputConfigurationInterface *configurationInterface);
|
||||
|
||||
KWaylandServer::Display *m_display;
|
||||
KWaylandServer::OutputManagementInterface *m_outputManagementInterface;
|
||||
QList<KWaylandServer::OutputDeviceInterface *> m_serverOutputs;
|
||||
|
||||
KWayland::Client::Registry *m_registry = nullptr;
|
||||
KWayland::Client::OutputDevice *m_outputDevice = nullptr;
|
||||
KWayland::Client::OutputManagement *m_outputManagement = nullptr;
|
||||
KWayland::Client::OutputConfiguration *m_outputConfiguration = nullptr;
|
||||
QList<KWayland::Client::OutputDevice *> m_clientOutputs;
|
||||
QList<KWaylandServer::OutputDeviceInterface::Mode> m_modes;
|
||||
|
||||
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
||||
KWayland::Client::EventQueue *m_queue = nullptr;
|
||||
QThread *m_thread;
|
||||
|
||||
QSignalSpy *m_announcedSpy;
|
||||
QSignalSpy *m_omSpy;
|
||||
};
|
||||
|
||||
static const QString s_socketName = QStringLiteral("kwin-test-wayland-output-0");
|
||||
|
||||
TestWaylandOutputManagement::TestWaylandOutputManagement(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_display(nullptr)
|
||||
, m_outputManagementInterface(nullptr)
|
||||
, m_connection(nullptr)
|
||||
, m_queue(nullptr)
|
||||
, m_thread(nullptr)
|
||||
, m_announcedSpy(nullptr)
|
||||
{
|
||||
qRegisterMetaType<KWaylandServer::OutputConfigurationInterface *>();
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::init()
|
||||
{
|
||||
using namespace KWaylandServer;
|
||||
delete m_display;
|
||||
m_display = new KWaylandServer::Display(this);
|
||||
m_display->addSocketName(s_socketName);
|
||||
m_display->start();
|
||||
QVERIFY(m_display->isRunning());
|
||||
|
||||
new CompositorInterface(m_display, this);
|
||||
auto outputDeviceInterface = new OutputDeviceInterface(m_display, this);
|
||||
|
||||
OutputDeviceInterface::Mode m0;
|
||||
m0.id = 0;
|
||||
m0.size = QSize(800, 600);
|
||||
m0.flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Preferred);
|
||||
outputDeviceInterface->addMode(m0);
|
||||
|
||||
OutputDeviceInterface::Mode m1;
|
||||
m1.id = 1;
|
||||
m1.size = QSize(1024, 768);
|
||||
outputDeviceInterface->addMode(m1);
|
||||
|
||||
OutputDeviceInterface::Mode m2;
|
||||
m2.id = 2;
|
||||
m2.size = QSize(1280, 1024);
|
||||
m2.refreshRate = 90000;
|
||||
outputDeviceInterface->addMode(m2);
|
||||
|
||||
OutputDeviceInterface::Mode m3;
|
||||
m3.id = 3;
|
||||
m3.size = QSize(1920, 1080);
|
||||
m3.flags = OutputDeviceInterface::ModeFlags();
|
||||
m3.refreshRate = 100000;
|
||||
outputDeviceInterface->addMode(m3);
|
||||
|
||||
m_modes << m0 << m1 << m2 << m3;
|
||||
|
||||
outputDeviceInterface->setCurrentMode(1);
|
||||
outputDeviceInterface->setGlobalPosition(QPoint(0, 1920));
|
||||
m_serverOutputs << outputDeviceInterface;
|
||||
|
||||
m_outputManagementInterface = new OutputManagementInterface(m_display, this);
|
||||
|
||||
// setup connection
|
||||
m_connection = new KWayland::Client::ConnectionThread;
|
||||
QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
|
||||
m_connection->setSocketName(s_socketName);
|
||||
|
||||
m_thread = new QThread(this);
|
||||
m_connection->moveToThread(m_thread);
|
||||
m_thread->start();
|
||||
|
||||
m_connection->initConnection();
|
||||
QVERIFY(connectedSpy.wait());
|
||||
|
||||
m_queue = new KWayland::Client::EventQueue(this);
|
||||
QVERIFY(!m_queue->isValid());
|
||||
m_queue->setup(m_connection);
|
||||
QVERIFY(m_queue->isValid());
|
||||
|
||||
m_registry = new Registry();
|
||||
|
||||
m_announcedSpy = new QSignalSpy(m_registry, &KWayland::Client::Registry::outputManagementAnnounced);
|
||||
m_omSpy = new QSignalSpy(m_registry, &KWayland::Client::Registry::outputDeviceAnnounced);
|
||||
|
||||
QVERIFY(m_announcedSpy->isValid());
|
||||
QVERIFY(m_omSpy->isValid());
|
||||
|
||||
m_registry->create(m_connection->display());
|
||||
QVERIFY(m_registry->isValid());
|
||||
m_registry->setEventQueue(m_queue);
|
||||
m_registry->setup();
|
||||
wl_display_flush(m_connection->display());
|
||||
|
||||
QVERIFY(m_announcedSpy->wait());
|
||||
QCOMPARE(m_announcedSpy->count(), 1);
|
||||
|
||||
m_outputManagement = m_registry->createOutputManagement(m_announcedSpy->first().first().value<quint32>(), m_announcedSpy->first().last().value<quint32>());
|
||||
createOutputDevices();
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::cleanup()
|
||||
{
|
||||
if (m_outputConfiguration) {
|
||||
delete m_outputConfiguration;
|
||||
m_outputConfiguration = nullptr;
|
||||
}
|
||||
if (m_outputManagement) {
|
||||
delete m_outputManagement;
|
||||
m_outputManagement = nullptr;
|
||||
}
|
||||
if (m_registry) {
|
||||
delete m_registry;
|
||||
m_registry = nullptr;
|
||||
}
|
||||
if (m_queue) {
|
||||
delete m_queue;
|
||||
m_queue = nullptr;
|
||||
}
|
||||
if (m_connection) {
|
||||
m_connection->deleteLater();
|
||||
m_connection = nullptr;
|
||||
}
|
||||
if (m_thread) {
|
||||
m_thread->quit();
|
||||
m_thread->wait();
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
delete m_display;
|
||||
m_display = nullptr;
|
||||
m_serverOutputs.clear();
|
||||
m_clientOutputs.clear();
|
||||
|
||||
// these are the children of the display
|
||||
m_outputManagementInterface = nullptr;
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::applyPendingChanges(KWaylandServer::OutputConfigurationInterface *configurationInterface)
|
||||
{
|
||||
auto changes = configurationInterface->changes();
|
||||
for (auto outputdevice : changes.keys()) {
|
||||
auto c = changes[outputdevice];
|
||||
if (c->enabledChanged()) {
|
||||
outputdevice->setEnabled(c->enabled());
|
||||
}
|
||||
if (c->modeChanged()) {
|
||||
outputdevice->setCurrentMode(c->mode());
|
||||
}
|
||||
if (c->transformChanged()) {
|
||||
outputdevice->setTransform(c->transform());
|
||||
}
|
||||
if (c->positionChanged()) {
|
||||
outputdevice->setGlobalPosition(c->position());
|
||||
}
|
||||
if (c->scaleChanged()) {
|
||||
outputdevice->setScaleF(c->scaleF());
|
||||
}
|
||||
if (c->colorCurvesChanged()) {
|
||||
outputdevice->setColorCurves(c->colorCurves());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::createOutputDevices()
|
||||
{
|
||||
QCOMPARE(m_omSpy->count(), 1);
|
||||
QCOMPARE(m_registry->interfaces(KWayland::Client::Registry::Interface::OutputDevice).count(), m_serverOutputs.count());
|
||||
|
||||
auto output = new KWayland::Client::OutputDevice();
|
||||
QVERIFY(!output->isValid());
|
||||
QCOMPARE(output->geometry(), QRect());
|
||||
QCOMPARE(output->globalPosition(), QPoint());
|
||||
QCOMPARE(output->manufacturer(), QString());
|
||||
QCOMPARE(output->model(), QString());
|
||||
QCOMPARE(output->physicalSize(), QSize());
|
||||
QCOMPARE(output->pixelSize(), QSize());
|
||||
QCOMPARE(output->refreshRate(), 0);
|
||||
QCOMPARE(output->scaleF(), 1.0);
|
||||
QCOMPARE(output->colorCurves().red, QVector<quint16>());
|
||||
QCOMPARE(output->colorCurves().green, QVector<quint16>());
|
||||
QCOMPARE(output->colorCurves().blue, QVector<quint16>());
|
||||
QCOMPARE(output->subPixel(), KWayland::Client::OutputDevice::SubPixel::Unknown);
|
||||
QCOMPARE(output->transform(), KWayland::Client::OutputDevice::Transform::Normal);
|
||||
QCOMPARE(output->enabled(), OutputDevice::Enablement::Enabled);
|
||||
QCOMPARE(output->edid(), QByteArray());
|
||||
QCOMPARE(output->uuid(), QString());
|
||||
|
||||
QSignalSpy outputChanged(output, &KWayland::Client::OutputDevice::changed);
|
||||
QVERIFY(outputChanged.isValid());
|
||||
|
||||
output->setup(m_registry->bindOutputDevice(m_omSpy->first().first().value<quint32>(), m_omSpy->first().last().value<quint32>()));
|
||||
wl_display_flush(m_connection->display());
|
||||
|
||||
QVERIFY(outputChanged.wait());
|
||||
QCOMPARE(output->globalPosition(), QPoint(0, 1920));
|
||||
QCOMPARE(output->enabled(), OutputDevice::Enablement::Enabled);
|
||||
|
||||
m_clientOutputs << output;
|
||||
m_outputDevice = output;
|
||||
|
||||
QVERIFY(m_outputManagement->isValid());
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testBasicMemoryManagement()
|
||||
{
|
||||
createConfig();
|
||||
|
||||
QSignalSpy serverApplySpy(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested);
|
||||
KWaylandServer::OutputConfigurationInterface *configurationInterface = nullptr;
|
||||
connect(m_outputManagementInterface,
|
||||
&OutputManagementInterface::configurationChangeRequested,
|
||||
[=, &configurationInterface](KWaylandServer::OutputConfigurationInterface *c) {
|
||||
configurationInterface = c;
|
||||
});
|
||||
m_outputConfiguration->apply();
|
||||
|
||||
QVERIFY(serverApplySpy.wait());
|
||||
QVERIFY(configurationInterface);
|
||||
QSignalSpy interfaceDeletedSpy(configurationInterface, &QObject::destroyed);
|
||||
|
||||
delete m_outputConfiguration;
|
||||
m_outputConfiguration = nullptr;
|
||||
QVERIFY(interfaceDeletedSpy.wait());
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testRemoval()
|
||||
{
|
||||
QSignalSpy outputManagementRemovedSpy(m_registry, &KWayland::Client::Registry::outputManagementRemoved);
|
||||
QVERIFY(outputManagementRemovedSpy.isValid());
|
||||
|
||||
delete m_outputManagementInterface;
|
||||
m_outputManagementInterface = nullptr;
|
||||
QVERIFY(outputManagementRemovedSpy.wait(200));
|
||||
QCOMPARE(outputManagementRemovedSpy.first().first(), m_announcedSpy->first().first());
|
||||
QVERIFY(!m_registry->hasInterface(KWayland::Client::Registry::Interface::OutputManagement));
|
||||
QVERIFY(m_registry->interfaces(KWayland::Client::Registry::Interface::OutputManagement).isEmpty());
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::createConfig()
|
||||
{
|
||||
m_outputConfiguration = m_outputManagement->createConfiguration();
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testApplied()
|
||||
{
|
||||
createConfig();
|
||||
QVERIFY(m_outputConfiguration->isValid());
|
||||
QSignalSpy appliedSpy(m_outputConfiguration, &KWayland::Client::OutputConfiguration::applied);
|
||||
|
||||
connect(m_outputManagementInterface,
|
||||
&OutputManagementInterface::configurationChangeRequested,
|
||||
[=](KWaylandServer::OutputConfigurationInterface *configurationInterface) {
|
||||
configurationInterface->setApplied();
|
||||
});
|
||||
m_outputConfiguration->apply();
|
||||
QVERIFY(appliedSpy.wait(200));
|
||||
QCOMPARE(appliedSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testFailed()
|
||||
{
|
||||
createConfig();
|
||||
QVERIFY(m_outputConfiguration->isValid());
|
||||
QSignalSpy failedSpy(m_outputConfiguration, &KWayland::Client::OutputConfiguration::failed);
|
||||
|
||||
connect(m_outputManagementInterface,
|
||||
&OutputManagementInterface::configurationChangeRequested,
|
||||
[=](KWaylandServer::OutputConfigurationInterface *configurationInterface) {
|
||||
configurationInterface->setFailed();
|
||||
});
|
||||
m_outputConfiguration->apply();
|
||||
QVERIFY(failedSpy.wait(200));
|
||||
QCOMPARE(failedSpy.count(), 1);
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testEnable()
|
||||
{
|
||||
createConfig();
|
||||
auto config = m_outputConfiguration;
|
||||
QVERIFY(config->isValid());
|
||||
|
||||
KWayland::Client::OutputDevice *output = m_clientOutputs.first();
|
||||
QCOMPARE(output->enabled(), OutputDevice::Enablement::Enabled);
|
||||
|
||||
QSignalSpy enabledChanged(output, &KWayland::Client::OutputDevice::enabledChanged);
|
||||
QVERIFY(enabledChanged.isValid());
|
||||
|
||||
config->setEnabled(output, OutputDevice::Enablement::Disabled);
|
||||
|
||||
QVERIFY(!enabledChanged.wait(200));
|
||||
|
||||
QCOMPARE(enabledChanged.count(), 0);
|
||||
|
||||
// Reset
|
||||
config->setEnabled(output, OutputDevice::Enablement::Disabled);
|
||||
config->apply();
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testMultipleSettings()
|
||||
{
|
||||
createConfig();
|
||||
auto config = m_outputConfiguration;
|
||||
QVERIFY(config->isValid());
|
||||
|
||||
KWayland::Client::OutputDevice *output = m_clientOutputs.first();
|
||||
QSignalSpy outputChangedSpy(output, &KWayland::Client::OutputDevice::changed);
|
||||
|
||||
KWaylandServer::OutputConfigurationInterface *configurationInterface;
|
||||
connect(m_outputManagementInterface,
|
||||
&OutputManagementInterface::configurationChangeRequested,
|
||||
[=, &configurationInterface](KWaylandServer::OutputConfigurationInterface *c) {
|
||||
applyPendingChanges(c);
|
||||
configurationInterface = c;
|
||||
});
|
||||
QSignalSpy serverApplySpy(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested);
|
||||
QVERIFY(serverApplySpy.isValid());
|
||||
|
||||
config->setMode(output, m_modes.first().id);
|
||||
config->setTransform(output, OutputDevice::Transform::Rotated90);
|
||||
config->setPosition(output, QPoint(13, 37));
|
||||
config->setScaleF(output, 2.0);
|
||||
const auto zeroVector = QVector<quint16>(256, 0);
|
||||
config->setColorCurves(output, zeroVector, zeroVector, zeroVector);
|
||||
config->setEnabled(output, OutputDevice::Enablement::Disabled);
|
||||
config->apply();
|
||||
|
||||
QVERIFY(serverApplySpy.wait(200));
|
||||
QCOMPARE(serverApplySpy.count(), 1);
|
||||
|
||||
configurationInterface->setApplied();
|
||||
|
||||
QSignalSpy configAppliedSpy(config, &OutputConfiguration::applied);
|
||||
QVERIFY(configAppliedSpy.isValid());
|
||||
QVERIFY(configAppliedSpy.wait(200));
|
||||
QCOMPARE(configAppliedSpy.count(), 1);
|
||||
QCOMPARE(outputChangedSpy.count(), 5);
|
||||
|
||||
config->setMode(output, m_modes.at(1).id);
|
||||
config->setTransform(output, OutputDevice::Transform::Normal);
|
||||
config->setPosition(output, QPoint(0, 1920));
|
||||
config->setScaleF(output, 1.0);
|
||||
const auto oneVector = QVector<quint16>(256, 1);
|
||||
config->setColorCurves(output, oneVector, oneVector, oneVector);
|
||||
config->setEnabled(output, OutputDevice::Enablement::Enabled);
|
||||
config->apply();
|
||||
|
||||
QVERIFY(serverApplySpy.wait(200));
|
||||
QCOMPARE(serverApplySpy.count(), 2);
|
||||
|
||||
configurationInterface->setApplied();
|
||||
|
||||
QVERIFY(configAppliedSpy.wait(200));
|
||||
QCOMPARE(configAppliedSpy.count(), 2);
|
||||
QCOMPARE(outputChangedSpy.count(), 10);
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testConfigFailed()
|
||||
{
|
||||
createConfig();
|
||||
auto config = m_outputConfiguration;
|
||||
KWayland::Client::OutputDevice *output = m_clientOutputs.first();
|
||||
|
||||
QVERIFY(config->isValid());
|
||||
QVERIFY(output->isValid());
|
||||
|
||||
QSignalSpy serverApplySpy(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested);
|
||||
QVERIFY(serverApplySpy.isValid());
|
||||
QSignalSpy outputChangedSpy(output, &KWayland::Client::OutputDevice::changed);
|
||||
QVERIFY(outputChangedSpy.isValid());
|
||||
QSignalSpy configAppliedSpy(config, &OutputConfiguration::applied);
|
||||
QVERIFY(configAppliedSpy.isValid());
|
||||
QSignalSpy configFailedSpy(config, &KWayland::Client::OutputConfiguration::failed);
|
||||
QVERIFY(configFailedSpy.isValid());
|
||||
|
||||
config->setMode(output, m_modes.last().id);
|
||||
config->setTransform(output, OutputDevice::Transform::Normal);
|
||||
config->setPosition(output, QPoint(-1, -1));
|
||||
|
||||
config->apply();
|
||||
|
||||
connect(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested, [=](KWaylandServer::OutputConfigurationInterface *c) {
|
||||
c->setFailed();
|
||||
});
|
||||
|
||||
QVERIFY(serverApplySpy.wait(200));
|
||||
|
||||
// Artificially make the server fail to apply the settings
|
||||
// Make sure the applied signal never comes, and that failed has been received
|
||||
QVERIFY(!configAppliedSpy.wait(200));
|
||||
QCOMPARE(configFailedSpy.count(), 1);
|
||||
QCOMPARE(configAppliedSpy.count(), 0);
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testExampleConfig()
|
||||
{
|
||||
createConfig();
|
||||
auto config = m_outputConfiguration;
|
||||
KWayland::Client::OutputDevice *output = m_clientOutputs.first();
|
||||
|
||||
config->setMode(output, m_clientOutputs.first()->modes().last().id);
|
||||
config->setTransform(output, OutputDevice::Transform::Normal);
|
||||
config->setPosition(output, QPoint(-1, -1));
|
||||
|
||||
QSignalSpy configAppliedSpy(config, &OutputConfiguration::applied);
|
||||
connect(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested, [=](KWaylandServer::OutputConfigurationInterface *c) {
|
||||
c->setApplied();
|
||||
});
|
||||
config->apply();
|
||||
|
||||
QVERIFY(configAppliedSpy.isValid());
|
||||
QVERIFY(configAppliedSpy.wait(200));
|
||||
}
|
||||
|
||||
void TestWaylandOutputManagement::testScale()
|
||||
{
|
||||
createConfig();
|
||||
|
||||
auto config = m_outputConfiguration;
|
||||
KWayland::Client::OutputDevice *output = m_clientOutputs.first();
|
||||
|
||||
config->setScaleF(output, 2.3);
|
||||
config->apply();
|
||||
|
||||
QSignalSpy configAppliedSpy(config, &OutputConfiguration::applied);
|
||||
connect(m_outputManagementInterface, &OutputManagementInterface::configurationChangeRequested, [=](KWaylandServer::OutputConfigurationInterface *c) {
|
||||
applyPendingChanges(c);
|
||||
c->setApplied();
|
||||
});
|
||||
QVERIFY(configAppliedSpy.isValid());
|
||||
QVERIFY(configAppliedSpy.wait(200));
|
||||
|
||||
QCOMPARE(wl_fixed_from_double(output->scaleF()), wl_fixed_from_double(2.3));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestWaylandOutputManagement)
|
||||
#include "test_wayland_outputmanagement.moc"
|
|
@ -9,7 +9,6 @@
|
|||
#include "wayland/clientconnection.h"
|
||||
#include "wayland/display.h"
|
||||
#include "wayland/output_interface.h"
|
||||
#include "wayland/outputmanagement_v2_interface.h"
|
||||
// Wayland
|
||||
#include <wayland-server.h>
|
||||
// system
|
||||
|
@ -28,7 +27,6 @@ private Q_SLOTS:
|
|||
void testAddRemoveOutput();
|
||||
void testClientConnection();
|
||||
void testConnectNoSocket();
|
||||
void testOutputManagement();
|
||||
void testAutoSocketName();
|
||||
};
|
||||
|
||||
|
@ -178,14 +176,6 @@ void TestWaylandServerDisplay::testConnectNoSocket()
|
|||
close(sv[1]);
|
||||
}
|
||||
|
||||
void TestWaylandServerDisplay::testOutputManagement()
|
||||
{
|
||||
KWaylandServer::Display display;
|
||||
display.addSocketName("kwayland-test-0");
|
||||
display.start();
|
||||
new OutputManagementV2Interface(&display, this);
|
||||
}
|
||||
|
||||
void TestWaylandServerDisplay::testAutoSocketName()
|
||||
{
|
||||
QTemporaryDir runtimeDir;
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
OutputDeviceV2Interface::RgbRange rgbRange() const;
|
||||
|
||||
private:
|
||||
friend class OutputConfigurationV2InterfacePrivate;
|
||||
friend class OutputConfigurationV2Interface;
|
||||
explicit OutputChangeSetV2(OutputDeviceV2Interface *outputdevice, QObject *parent = nullptr);
|
||||
|
||||
std::unique_ptr<OutputChangeSetV2Private> d;
|
||||
|
|
|
@ -11,49 +11,30 @@
|
|||
#include "outputdevice_v2_interface.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "outputconfiguration.h"
|
||||
#include "platform.h"
|
||||
#include "screens.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include "qwayland-server-kde-output-device-v2.h"
|
||||
#include "qwayland-server-kde-output-management-v2.h"
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include <optional>
|
||||
using namespace KWin;
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class OutputConfigurationV2InterfacePrivate : public QtWaylandServer::kde_output_configuration_v2
|
||||
|
||||
OutputConfigurationV2Interface::OutputConfigurationV2Interface(wl_resource *resource)
|
||||
: QtWaylandServer::kde_output_configuration_v2(resource)
|
||||
{
|
||||
public:
|
||||
OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface *q, OutputManagementV2Interface *outputManagement, wl_resource *resource);
|
||||
}
|
||||
|
||||
void sendApplied();
|
||||
void sendFailed();
|
||||
void emitConfigurationChangeRequested() const;
|
||||
void clearPendingChanges();
|
||||
OutputConfigurationV2Interface::~OutputConfigurationV2Interface()
|
||||
{
|
||||
qDeleteAll(changes.begin(), changes.end());
|
||||
}
|
||||
|
||||
bool hasPendingChanges(OutputDeviceV2Interface *outputdevice) const;
|
||||
OutputChangeSetV2 *pendingChanges(OutputDeviceV2Interface *outputdevice);
|
||||
|
||||
OutputManagementV2Interface *outputManagement;
|
||||
QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> changes;
|
||||
std::optional<OutputDeviceV2Interface *> primaryOutput;
|
||||
OutputConfigurationV2Interface *q;
|
||||
|
||||
protected:
|
||||
void kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable) override;
|
||||
void kde_output_configuration_v2_mode(Resource *resource, struct ::wl_resource *outputdevice, struct ::wl_resource *mode) override;
|
||||
void kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform) override;
|
||||
void kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y) override;
|
||||
void kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale) override;
|
||||
void kde_output_configuration_v2_apply(Resource *resource) override;
|
||||
void kde_output_configuration_v2_destroy(Resource *resource) override;
|
||||
void kde_output_configuration_v2_destroy_resource(Resource *resource) override;
|
||||
void kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan) override;
|
||||
void kde_output_configuration_v2_set_vrr_policy(Resource *resource, struct ::wl_resource *outputdevice, uint32_t policy) override;
|
||||
void kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange) override;
|
||||
void kde_output_configuration_v2_set_primary_output(Resource *resource, struct ::wl_resource *output) override;
|
||||
};
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
|
||||
|
@ -61,7 +42,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_enable(R
|
|||
pendingChanges(output)->d->enabled = enable == 1;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_mode(Resource *resource, wl_resource *outputdevice, wl_resource *modeResource)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_mode(Resource *resource, wl_resource *outputdevice, wl_resource *modeResource)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
|
||||
|
@ -74,7 +55,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_mode(Res
|
|||
pendingChanges(output)->d->refreshRate = mode->refreshRate();
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
auto toTransform = [transform]() {
|
||||
|
@ -103,7 +84,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_transfor
|
|||
pendingChanges(output)->d->transform = _transform;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
auto _pos = QPoint(x, y);
|
||||
|
@ -111,7 +92,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_position
|
|||
pendingChanges(output)->d->position = _pos;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
const qreal doubleScale = wl_fixed_to_double(scale);
|
||||
|
@ -125,13 +106,82 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_scale(Re
|
|||
pendingChanges(output)->d->scale = doubleScale;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_apply(Resource *resource)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_apply(Resource *resource)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
emitConfigurationChangeRequested();
|
||||
if (applied) {
|
||||
wl_resource_post_error(resource->handle, 0, "an output configuration can be applied only once");
|
||||
return;
|
||||
}
|
||||
|
||||
applied = true;
|
||||
|
||||
OutputConfiguration cfg;
|
||||
for (auto it = changes.constBegin(); it != changes.constEnd(); ++it) {
|
||||
const KWaylandServer::OutputChangeSetV2 *changeset = it.value();
|
||||
auto output = kwinApp()->platform()->findOutput(it.key()->uuid());
|
||||
if (!output) {
|
||||
qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto modes = output->modes();
|
||||
const auto modeIt = std::find_if(modes.begin(), modes.end(), [&changeset](const auto &mode) {
|
||||
return mode->size() == changeset->size() && mode->refreshRate() == changeset->refreshRate();
|
||||
});
|
||||
if (modeIt == modes.end()) {
|
||||
qCWarning(KWIN_CORE).nospace() << "Could not find mode " << changeset->size() << "@" << changeset->refreshRate() << " for output " << this;
|
||||
send_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto props = cfg.changeSet(output);
|
||||
props->enabled = changeset->enabled();
|
||||
props->pos = changeset->position();
|
||||
props->scale = changeset->scale();
|
||||
props->mode = *modeIt;
|
||||
props->transform = static_cast<Output::Transform>(changeset->transform());
|
||||
props->overscan = changeset->overscan();
|
||||
props->rgbRange = static_cast<Output::RgbRange>(changeset->rgbRange());
|
||||
props->vrrPolicy = static_cast<RenderLoop::VrrPolicy>(changeset->vrrPolicy());
|
||||
}
|
||||
|
||||
const auto allOutputs = kwinApp()->platform()->outputs();
|
||||
bool allDisabled = !std::any_of(allOutputs.begin(), allOutputs.end(), [&cfg](const auto &output) {
|
||||
return cfg.changeSet(output)->enabled;
|
||||
});
|
||||
if (allDisabled) {
|
||||
qCWarning(KWIN_CORE) << "Disabling all outputs through configuration changes is not allowed";
|
||||
send_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (kwinApp()->platform()->applyOutputChanges(cfg)) {
|
||||
if (primaryOutput.has_value() || !kwinApp()->platform()->primaryOutput()->isEnabled()) {
|
||||
auto requestedPrimaryOutput = kwinApp()->platform()->findOutput((*primaryOutput)->uuid());
|
||||
if (requestedPrimaryOutput && requestedPrimaryOutput->isEnabled()) {
|
||||
kwinApp()->platform()->setPrimaryOutput(requestedPrimaryOutput);
|
||||
} else {
|
||||
Output *defaultPrimaryOutput = nullptr;
|
||||
const auto candidates = kwinApp()->platform()->outputs();
|
||||
for (Output *output : candidates) {
|
||||
if (output->isEnabled()) {
|
||||
defaultPrimaryOutput = output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
qCWarning(KWIN_CORE) << "Requested invalid primary screen, using" << defaultPrimaryOutput;
|
||||
kwinApp()->platform()->setPrimaryOutput(defaultPrimaryOutput);
|
||||
}
|
||||
}
|
||||
Q_EMIT workspace()->screens()->changed();
|
||||
send_applied();
|
||||
} else {
|
||||
qCDebug(KWIN_CORE) << "Applying config failed";
|
||||
send_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
if (overscan > 100) {
|
||||
|
@ -142,7 +192,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_overscan
|
|||
pendingChanges(output)->d->overscan = overscan;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_vrr_policy(Resource *resource, wl_resource *outputdevice, uint32_t policy)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_set_vrr_policy(Resource *resource, wl_resource *outputdevice, uint32_t policy)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
if (policy > static_cast<uint32_t>(OutputDeviceV2Interface::VrrPolicy::Automatic)) {
|
||||
|
@ -153,7 +203,7 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_vrr_
|
|||
pendingChanges(output)->d->vrrPolicy = static_cast<OutputDeviceV2Interface::VrrPolicy>(policy);
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
if (rgbRange > static_cast<uint32_t>(OutputDeviceV2Interface::RgbRange::Limited)) {
|
||||
|
@ -164,107 +214,30 @@ void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_rgb_
|
|||
pendingChanges(output)->d->rgbRange = static_cast<OutputDeviceV2Interface::RgbRange>(rgbRange);
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_primary_output(Resource *resource, struct ::wl_resource *output)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_set_primary_output(Resource *resource, struct ::wl_resource *output)
|
||||
{
|
||||
Q_UNUSED(resource);
|
||||
primaryOutput = OutputDeviceV2Interface::get(output);
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy(Resource *resource)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy_resource(Resource *resource)
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_destroy_resource(Resource *resource)
|
||||
{
|
||||
Q_UNUSED(resource)
|
||||
delete q;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::emitConfigurationChangeRequested() const
|
||||
{
|
||||
Q_EMIT outputManagement->configurationChangeRequested(q);
|
||||
}
|
||||
|
||||
OutputConfigurationV2InterfacePrivate::OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface *q, OutputManagementV2Interface *outputManagement, wl_resource *resource)
|
||||
: QtWaylandServer::kde_output_configuration_v2(resource)
|
||||
, outputManagement(outputManagement)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> OutputConfigurationV2Interface::changes() const
|
||||
{
|
||||
return d->changes;
|
||||
}
|
||||
|
||||
bool OutputConfigurationV2Interface::primaryChanged() const
|
||||
{
|
||||
return d->primaryOutput.has_value();
|
||||
}
|
||||
|
||||
OutputDeviceV2Interface *OutputConfigurationV2Interface::primary() const
|
||||
{
|
||||
Q_ASSERT(d->primaryOutput.has_value());
|
||||
return *d->primaryOutput;
|
||||
}
|
||||
|
||||
void OutputConfigurationV2Interface::setApplied()
|
||||
{
|
||||
d->clearPendingChanges();
|
||||
d->sendApplied();
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::sendApplied()
|
||||
{
|
||||
send_applied();
|
||||
}
|
||||
|
||||
void OutputConfigurationV2Interface::setFailed()
|
||||
{
|
||||
d->clearPendingChanges();
|
||||
d->sendFailed();
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::sendFailed()
|
||||
{
|
||||
send_failed();
|
||||
}
|
||||
|
||||
OutputChangeSetV2 *OutputConfigurationV2InterfacePrivate::pendingChanges(OutputDeviceV2Interface *outputdevice)
|
||||
OutputChangeSetV2 *OutputConfigurationV2Interface::pendingChanges(OutputDeviceV2Interface *outputdevice)
|
||||
{
|
||||
auto &change = changes[outputdevice];
|
||||
if (!change) {
|
||||
change = new OutputChangeSetV2(outputdevice, q);
|
||||
change = new OutputChangeSetV2(outputdevice);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
bool OutputConfigurationV2InterfacePrivate::hasPendingChanges(OutputDeviceV2Interface *outputdevice) const
|
||||
{
|
||||
auto it = changes.constFind(outputdevice);
|
||||
if (it == changes.constEnd()) {
|
||||
return false;
|
||||
}
|
||||
auto c = *it;
|
||||
return c->enabledChanged() || c->sizeChanged() || c->refreshRateChanged() || c->transformChanged() || c->positionChanged() || c->scaleChanged();
|
||||
}
|
||||
|
||||
void OutputConfigurationV2InterfacePrivate::clearPendingChanges()
|
||||
{
|
||||
qDeleteAll(changes.begin(), changes.end());
|
||||
changes.clear();
|
||||
}
|
||||
|
||||
OutputConfigurationV2Interface::OutputConfigurationV2Interface(OutputManagementV2Interface *parent, wl_resource *resource)
|
||||
: QObject()
|
||||
, d(new OutputConfigurationV2InterfacePrivate(this, parent, resource))
|
||||
{
|
||||
}
|
||||
|
||||
OutputConfigurationV2Interface::~OutputConfigurationV2Interface()
|
||||
{
|
||||
d->clearPendingChanges();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,88 +6,44 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "kwin_export.h"
|
||||
#include "qwayland-server-kde-output-management-v2.h"
|
||||
|
||||
#include "outputchangeset_v2.h"
|
||||
#include "outputdevice_v2_interface.h"
|
||||
#include "outputmanagement_v2_interface.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
|
||||
class OutputConfigurationV2InterfacePrivate;
|
||||
|
||||
/** @class OutputConfigurationInterface
|
||||
*
|
||||
* Holds a new configuration for the outputs.
|
||||
*
|
||||
* The overall mechanism is to get a new OutputConfiguration from the OutputManagement global and
|
||||
* apply changes through the OutputConfiguration::set* calls. When all changes are set, the client
|
||||
* calls apply, which asks the server to look at the changes and apply them. The server will then
|
||||
* signal back whether the changes have been applied successfully (@c setApplied()) or were rejected
|
||||
* or failed to apply (@c setFailed()).
|
||||
*
|
||||
* Once the client has called applied, the OutputManagementInterface send the configuration object
|
||||
* to the compositor through the OutputManagement::configurationChangeRequested(OutputConfiguration*)
|
||||
* signal, the compositor can then decide what to do with the changes.
|
||||
*
|
||||
* These KWayland classes will not apply changes to the OutputDevices, this is the compositor's
|
||||
* task. As such, the configuration set through this interface can be seen as a hint what the
|
||||
* compositor should set up, but whether or not the compositor does it (based on hardware or
|
||||
* rendering policies, for example), is up to the compositor. The mode setting is passed on to
|
||||
* the DRM subsystem through the compositor. The compositor also saves this configuration and reads
|
||||
* it on startup, this interface is not involved in that process.
|
||||
*
|
||||
* @see OutputManagementInterface
|
||||
* @see OutputConfiguration
|
||||
*/
|
||||
class KWIN_EXPORT OutputConfigurationV2Interface : public QObject
|
||||
class OutputConfigurationV2Interface : public QtWaylandServer::kde_output_configuration_v2
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OutputConfigurationV2Interface(wl_resource *resource);
|
||||
~OutputConfigurationV2Interface() override;
|
||||
|
||||
/**
|
||||
* Accessor for the changes made to OutputDevices. The data returned from this call
|
||||
* will be deleted by the OutputConfigurationInterface when
|
||||
* OutputManagementInterface::setApplied() or OutputManagementInterface::setFailed()
|
||||
* is called, and on destruction of the OutputConfigurationInterface, so make sure you
|
||||
* do not keep these pointers around.
|
||||
* @returns A QHash of ChangeSets per outputdevice.
|
||||
* @see ChangeSet
|
||||
* @see OutputDeviceInterface
|
||||
* @see OutputManagement
|
||||
*/
|
||||
QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> changes() const;
|
||||
OutputChangeSetV2 *pendingChanges(OutputDeviceV2Interface *outputdevice);
|
||||
|
||||
bool primaryChanged() const;
|
||||
OutputDeviceV2Interface *primary() const;
|
||||
bool applied = false;
|
||||
QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> changes;
|
||||
std::optional<OutputDeviceV2Interface *> primaryOutput;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Called by the compositor once the changes have successfully been applied.
|
||||
* The compositor is responsible for updating the OutputDevices. After having
|
||||
* done so, calling this function sends applied() through the client.
|
||||
* @see setFailed
|
||||
* @see OutputConfiguration::applied
|
||||
*/
|
||||
void setApplied();
|
||||
/**
|
||||
* Called by the compositor when the changes as a whole are rejected or
|
||||
* failed to apply. This function results in the client OutputConfiguration emitting
|
||||
* failed().
|
||||
* @see setApplied
|
||||
* @see OutputConfiguration::failed
|
||||
*/
|
||||
void setFailed();
|
||||
|
||||
private:
|
||||
explicit OutputConfigurationV2Interface(OutputManagementV2Interface *parent, wl_resource *resource);
|
||||
friend class OutputManagementV2InterfacePrivate;
|
||||
|
||||
std::unique_ptr<OutputConfigurationV2InterfacePrivate> d;
|
||||
protected:
|
||||
void kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable) override;
|
||||
void kde_output_configuration_v2_mode(Resource *resource, struct ::wl_resource *outputdevice, struct ::wl_resource *mode) override;
|
||||
void kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform) override;
|
||||
void kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y) override;
|
||||
void kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale) override;
|
||||
void kde_output_configuration_v2_apply(Resource *resource) override;
|
||||
void kde_output_configuration_v2_destroy(Resource *resource) override;
|
||||
void kde_output_configuration_v2_destroy_resource(Resource *resource) override;
|
||||
void kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan) override;
|
||||
void kde_output_configuration_v2_set_vrr_policy(Resource *resource, struct ::wl_resource *outputdevice, uint32_t policy) override;
|
||||
void kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange) override;
|
||||
void kde_output_configuration_v2_set_primary_output(Resource *resource, struct ::wl_resource *output) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWaylandServer::OutputConfigurationV2Interface *)
|
||||
|
|
|
@ -42,7 +42,7 @@ void OutputManagementV2InterfacePrivate::kde_output_management_v2_create_configu
|
|||
wl_client_post_no_memory(resource->client());
|
||||
return;
|
||||
}
|
||||
new OutputConfigurationV2Interface(q, config_resource);
|
||||
new OutputConfigurationV2Interface(config_resource);
|
||||
}
|
||||
|
||||
OutputManagementV2Interface::OutputManagementV2Interface(Display *display, QObject *parent)
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace KWaylandServer
|
|||
|
||||
class Display;
|
||||
class OutputManagementV2InterfacePrivate;
|
||||
class OutputConfigurationV2Interface;
|
||||
|
||||
/**
|
||||
* @class OutputManagementInterface
|
||||
|
@ -38,22 +37,6 @@ public:
|
|||
explicit OutputManagementV2Interface(Display *display, QObject *parent = nullptr);
|
||||
~OutputManagementV2Interface() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted after the client has requested an OutputConfiguration to be applied.
|
||||
* through OutputConfiguration::apply. The compositor can use this object to get
|
||||
* notified when the new configuration is set up, and it should be applied to the
|
||||
* Wayland server's OutputInterfaces.
|
||||
*
|
||||
* @param config The OutputConfigurationInterface corresponding to the client that
|
||||
* called apply().
|
||||
* @see OutputConfiguration::apply
|
||||
* @see OutputConfigurationInterface
|
||||
* @see OutputDeviceInterface
|
||||
* @see OutputInterface
|
||||
*/
|
||||
void configurationChangeRequested(KWaylandServer::OutputConfigurationV2Interface *configurationInterface);
|
||||
|
||||
private:
|
||||
std::unique_ptr<OutputManagementV2InterfacePrivate> d;
|
||||
};
|
||||
|
|
|
@ -465,9 +465,6 @@ bool WaylandServer::init(InitializationFlags flags)
|
|||
});
|
||||
|
||||
m_outputManagement = new OutputManagementV2Interface(m_display, m_display);
|
||||
connect(m_outputManagement, &OutputManagementV2Interface::configurationChangeRequested, this, [](KWaylandServer::OutputConfigurationV2Interface *config) {
|
||||
kwinApp()->platform()->requestOutputsChange(config);
|
||||
});
|
||||
m_primary = new PrimaryOutputV1Interface(m_display, m_display);
|
||||
|
||||
m_xdgOutputManagerV1 = new XdgOutputManagerV1Interface(m_display, m_display);
|
||||
|
|
Loading…
Reference in a new issue