Implement kde-output-device-v2 and kde-output-management-v2

This commit is contained in:
Méven Car 2021-07-23 16:12:28 +02:00
parent 8d9607391c
commit cee6912d00
15 changed files with 1694 additions and 42 deletions

View file

@ -30,10 +30,10 @@ set(SERVER_LIB_SRCS
layershell_v1_interface.cpp
linuxdmabufv1clientbuffer.cpp
output_interface.cpp
outputchangeset.cpp
outputconfiguration_interface.cpp
outputdevice_interface.cpp
outputmanagement_interface.cpp
outputdevice_v2_interface.cpp
outputconfiguration_v2_interface.cpp
outputmanagement_v2_interface.cpp
outputchangeset_v2.cpp
plasmashell_interface.cpp
plasmavirtualdesktop_interface.cpp
plasmawindowmanagement_interface.cpp
@ -84,13 +84,13 @@ ecm_add_qtwayland_server_protocol_kde(SERVER_LIB_SRCS
)
ecm_add_qtwayland_server_protocol_kde(SERVER_LIB_SRCS
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/output-management.xml
BASENAME outputmanagement
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-device-v2.xml
BASENAME kde-output-device-v2
)
ecm_add_qtwayland_server_protocol_kde(SERVER_LIB_SRCS
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/outputdevice.xml
BASENAME org-kde-kwin-outputdevice
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-management-v2.xml
BASENAME kde-output-management-v2
)
ecm_add_qtwayland_server_protocol_kde(SERVER_LIB_SRCS
@ -349,10 +349,10 @@ set(SERVER_LIB_HEADERS
layershell_v1_interface.h
linuxdmabufv1clientbuffer.h
output_interface.h
outputchangeset.h
outputconfiguration_interface.h
outputdevice_interface.h
outputmanagement_interface.h
outputchangeset_v2.h
outputconfiguration_v2_interface.h
outputdevice_v2_interface.h
outputmanagement_v2_interface.h
plasmashell_interface.h
plasmavirtualdesktop_interface.h
plasmawindowmanagement_interface.h

View file

@ -44,28 +44,6 @@ target_link_libraries( testShmPool Qt::Test Qt::Gui KF5::WaylandClient Plasma::K
add_test(NAME kwayland-testShmPool COMMAND testShmPool)
ecm_mark_as_test(testShmPool)
########################################################
# Test KWin OutputManagement
########################################################
set( test_wayland_outputmanagement_SRCS
test_wayland_outputmanagement.cpp
)
add_executable(testWaylandOutputManagement ${test_wayland_outputmanagement_SRCS})
target_link_libraries( testWaylandOutputManagement Qt::Test Qt::Gui KF5::WaylandClient Plasma::KWaylandServer Wayland::Client)
add_test(NAME kwayland-testWaylandOutputManagement COMMAND testWaylandOutputManagement)
ecm_mark_as_test(testWaylandOutputManagement)
########################################################
# Test KWin OutputDevice
########################################################
set( test_wayland_outputdevice_SRCS
test_wayland_outputdevice.cpp
)
add_executable(testWaylandOutputDevice ${test_wayland_outputdevice_SRCS})
target_link_libraries( testWaylandOutputDevice Qt::Test Qt::Gui KF5::WaylandClient Plasma::KWaylandServer Wayland::Client)
add_test(NAME kwayland-testWaylandOutputDevice COMMAND testWaylandOutputDevice)
ecm_mark_as_test(testWaylandOutputDevice)
########################################################
# Test Compositor
########################################################

View file

@ -10,6 +10,7 @@
#include "../../src/server/display.h"
#include "../../src/server/output_interface.h"
#include "../../src/server/outputmanagement_interface.h"
#include "../../src/server/outputmanagement_v2_interface.h"
// Wayland
#include <wayland-server.h>
// system
@ -183,7 +184,7 @@ void TestWaylandServerDisplay::testOutputManagement()
Display display;
display.addSocketName("kwayland-test-0");
display.start();
new OutputManagementInterface(&display, this);
new OutputManagementV2Interface(&display, this);
}
void TestWaylandServerDisplay::testAutoSocketName()

View file

@ -157,9 +157,9 @@ QList<OutputInterface *> Display::outputs() const
return d->outputs;
}
QList<OutputDeviceInterface *> Display::outputDevices() const
QList< OutputDeviceV2Interface* > Display::outputDevices() const
{
return d->outputdevices;
return d->outputdevicesV2;
}
QVector<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const

View file

@ -36,7 +36,7 @@ class ClientBuffer;
class ClientConnection;
class DisplayPrivate;
class OutputInterface;
class OutputDeviceInterface;
class OutputDeviceV2Interface;
class SeatInterface;
/**
@ -111,8 +111,8 @@ public:
/**
* @returns All SeatInterface currently managed on the Display.
*/
QVector<SeatInterface *> seats() const;
QList<OutputDeviceInterface *> outputDevices() const;
QVector<SeatInterface*> seats() const;
QList<OutputDeviceV2Interface *> outputDevices() const;
QList<OutputInterface *> outputs() const;
QVector<OutputInterface *> outputsIntersecting(const QRect &rect) const;

View file

@ -26,7 +26,7 @@ class ClientBuffer;
class ClientConnection;
class Display;
class OutputInterface;
class OutputDeviceInterface;
class OutputDeviceV2Interface;
class SeatInterface;
struct ClientBufferDestroyListener;
@ -47,7 +47,7 @@ public:
wl_event_loop *loop = nullptr;
bool running = false;
QList<OutputInterface *> outputs;
QList<OutputDeviceInterface *> outputdevices;
QList<OutputDeviceV2Interface *> outputdevicesV2;
QVector<SeatInterface *> seats;
QVector<ClientConnection *> clients;
QStringList socketNames;

View file

@ -0,0 +1,114 @@
/*
SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "outputchangeset_v2.h"
#include "outputchangeset_v2_p.h"
namespace KWaylandServer
{
OutputChangeSetV2Private::OutputChangeSetV2Private(OutputDeviceV2Interface *outputdevice, OutputChangeSetV2 *parent)
: q(parent)
, outputDevice(outputdevice)
, enabled(outputDevice->enabled())
, size(outputDevice->pixelSize())
, refreshRate(outputDevice->refreshRate())
, transform(outputDevice->transform())
, position(outputDevice->globalPosition())
, scale(outputDevice->scale())
, overscan(outputDevice->overscan())
{
}
OutputChangeSetV2::OutputChangeSetV2(OutputDeviceV2Interface *outputdevice, QObject *parent)
: QObject(parent)
, d(new OutputChangeSetV2Private(outputdevice, this))
{
}
OutputChangeSetV2::~OutputChangeSetV2() = default;
bool OutputChangeSetV2::enabledChanged() const
{
return d->enabled != d->outputDevice->enabled();
}
bool OutputChangeSetV2::enabled() const
{
return d->enabled;
}
QSize OutputChangeSetV2::size() const
{
return d->size;
}
bool OutputChangeSetV2::sizeChanged() const
{
return d->size != d->outputDevice->pixelSize();
}
int OutputChangeSetV2::refreshRate() const
{
return d->refreshRate;
}
bool OutputChangeSetV2::refreshRateChanged() const
{
return d->refreshRate != d->outputDevice->refreshRate();
}
bool OutputChangeSetV2::transformChanged() const
{
return d->transform != d->outputDevice->transform();
}
OutputDeviceV2Interface::Transform OutputChangeSetV2::transform() const
{
return d->transform;
}
bool OutputChangeSetV2::positionChanged() const
{
return d->position != d->outputDevice->globalPosition();
}
QPoint OutputChangeSetV2::position() const
{
return d->position;
}
bool OutputChangeSetV2::scaleChanged() const
{
return !qFuzzyCompare(d->scale, d->outputDevice->scale());
}
qreal OutputChangeSetV2::scale() const
{
return d->scale;
}
bool OutputChangeSetV2::overscanChanged() const
{
return d->overscan != d->outputDevice->overscan();
}
uint32_t OutputChangeSetV2::overscan() const
{
return d->overscan;
}
bool OutputChangeSetV2::vrrPolicyChanged() const
{
return d->vrrPolicy != d->outputDevice->vrrPolicy();
}
OutputDeviceV2Interface::VrrPolicy OutputChangeSetV2::vrrPolicy() const
{
return d->vrrPolicy;
}
}

View file

@ -0,0 +1,107 @@
/*
SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <QObject>
#include "outputdevice_v2_interface.h"
#include <KWaylandServer/kwaylandserver_export.h>
namespace KWaylandServer
{
class OutputChangeSetV2Private;
/**
* @brief Holds a set of changes to an OutputInterface or OutputDeviceInterface.
*
* This class implements a set of changes that the compositor can apply to an
* OutputInterface after OutputConfiguration::apply has been called on the client
* side. The changes are per-configuration.
*
* @see OutputConfiguration
*/
class KWAYLANDSERVER_EXPORT OutputChangeSetV2 : public QObject
{
Q_OBJECT
public:
~OutputChangeSetV2() override;
/** Whether the enabled() property of the outputdevice changed.
* @returns @c true if the enabled property of the outputdevice has changed.
*/
bool enabledChanged() const;
/** Whether the transform() property of the outputdevice changed.
* @returns @c true if the enabled property of the outputdevice has changed.
* bool modeChanged() const;
*/
/** Whether the transform() property of the outputdevice changed. */
bool transformChanged() const;
/** Whether the size property of the outputdevice changed.
*/
bool sizeChanged() const;
/** Whether the refreshRate property of the outputdevice changed.
*/
bool refreshRateChanged() const;
/** Whether the globalPosition() property of the outputdevice changed.
* @returns @c true if the globalPosition() property of the outputdevice has changed.
*/
bool positionChanged() const;
/** Whether the scale() property of the outputdevice changed.
* @returns @c true if the scale() property of the outputdevice has changed.
*/
bool scaleChanged() const;
/** Whether the overscan() property of the outputdevice changed.
* @returns @c true if the overscan() property of the outputdevice has changed
*/
bool overscanChanged() const;
/**
* Whether the vrrPolicy() property of the outputdevice changed.
* @returns @c true if the vrrPolicy() property of the outputdevice has changed.
*/
bool vrrPolicyChanged() const;
/** The new value for enabled. */
bool enabled() const;
/** The new size */
QSize size() const;
/** The new refresh rate */
int refreshRate() const;
/** The new value for transform. */
OutputDeviceV2Interface::Transform transform() const;
/** The new value for globalPosition. */
QPoint position() const;
/** The new value for scale.
*/
qreal scale() const;
/** the overscan value in % */
uint32_t overscan() const;
/** The new value for vrrPolicy */
OutputDeviceV2Interface::VrrPolicy vrrPolicy() const;
private:
friend class OutputConfigurationV2InterfacePrivate;
explicit OutputChangeSetV2(OutputDeviceV2Interface *outputdevice, QObject *parent = nullptr);
QScopedPointer<OutputChangeSetV2Private> d;
};
}

View file

@ -0,0 +1,31 @@
/*
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
*/
#pragma once
#include "outputchangeset_v2.h"
namespace KWaylandServer
{
class OutputChangeSetV2Private
{
public:
OutputChangeSetV2Private(OutputDeviceV2Interface *outputdevice, OutputChangeSetV2 *parent);
OutputChangeSetV2 *q;
OutputDeviceV2Interface *outputDevice;
bool enabled;
QSize size;
int refreshRate;
OutputDeviceV2Interface::Transform transform;
QPoint position;
qreal scale;
uint32_t overscan;
OutputDeviceV2Interface::VrrPolicy vrrPolicy = OutputDeviceV2Interface::VrrPolicy::Automatic;
};
}

View file

@ -0,0 +1,238 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "display.h"
#include "outputconfiguration_v2_interface.h"
#include "outputdevice_v2_interface.h"
#include "logging.h"
#include "outputchangeset_v2_p.h"
#include "qwayland-server-kde-output-management-v2.h"
#include "qwayland-server-kde-output-device-v2.h"
namespace KWaylandServer
{
class OutputConfigurationV2InterfacePrivate : public QtWaylandServer::kde_output_configuration_v2
{
public:
OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface *q, OutputManagementV2Interface *outputManagement, wl_resource *resource);
void sendApplied();
void sendFailed();
void emitConfigurationChangeRequested() const;
void clearPendingChanges();
bool hasPendingChanges(OutputDeviceV2Interface *outputdevice) const;
OutputChangeSetV2 *pendingChanges(OutputDeviceV2Interface *outputdevice);
OutputManagementV2Interface *outputManagement;
QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> changes;
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 OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable)
{
Q_UNUSED(resource)
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->enabled = enable == 1;
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_mode(Resource *resource, wl_resource *outputdevice, wl_resource *modeResource)
{
Q_UNUSED(resource)
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
OutputDeviceModeV2Interface *mode = OutputDeviceModeV2Interface::get(modeResource);
pendingChanges(output)->d->size = mode->size();
pendingChanges(output)->d->refreshRate = mode->refreshRate();
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform)
{
Q_UNUSED(resource)
auto toTransform = [transform]() {
switch (transform) {
case WL_OUTPUT_TRANSFORM_90:
return OutputDeviceV2Interface::Transform::Rotated90;
case WL_OUTPUT_TRANSFORM_180:
return OutputDeviceV2Interface::Transform::Rotated180;
case WL_OUTPUT_TRANSFORM_270:
return OutputDeviceV2Interface::Transform::Rotated270;
case WL_OUTPUT_TRANSFORM_FLIPPED:
return OutputDeviceV2Interface::Transform::Flipped;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
return OutputDeviceV2Interface::Transform::Flipped90;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
return OutputDeviceV2Interface::Transform::Flipped180;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
return OutputDeviceV2Interface::Transform::Flipped270;
case WL_OUTPUT_TRANSFORM_NORMAL:
default:
return OutputDeviceV2Interface::Transform::Normal;
}
};
auto _transform = toTransform();
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->transform = _transform;
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y)
{
Q_UNUSED(resource)
auto _pos = QPoint(x, y);
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->position = _pos;
}
void OutputConfigurationV2InterfacePrivate::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);
if (doubleScale <= 0) {
qCWarning(KWAYLAND_SERVER) << "Requested to scale output device to" << doubleScale << ", but I can't do that.";
return;
}
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->scale = doubleScale;
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_apply(Resource *resource)
{
Q_UNUSED(resource)
emitConfigurationChangeRequested();
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan)
{
Q_UNUSED(resource)
if (overscan > 100) {
qCWarning(KWAYLAND_SERVER) << "Invalid overscan requested:" << overscan;
return;
}
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->overscan = overscan;
}
void OutputConfigurationV2InterfacePrivate::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)) {
qCWarning(KWAYLAND_SERVER) << "Invalid Vrr Policy requested:" << policy;
return;
}
OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
pendingChanges(output)->d->vrrPolicy = static_cast<OutputDeviceV2Interface::VrrPolicy>(policy);
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy_resource(Resource *resource)
{
Q_UNUSED(resource)
delete q;
}
void OutputConfigurationV2InterfacePrivate::emitConfigurationChangeRequested() const
{
auto configinterface = reinterpret_cast<OutputConfigurationV2Interface *>(q);
Q_EMIT outputManagement->configurationChangeRequested(configinterface);
}
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;
}
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)
{
auto &change = changes[outputdevice];
if (!change) {
change = new OutputChangeSetV2(outputdevice, q);
}
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();
}
}

View file

@ -0,0 +1,91 @@
/*
SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include "outputmanagement_v2_interface.h"
#include "outputdevice_v2_interface.h"
#include "outputchangeset_v2.h"
#include <KWaylandServer/kwaylandserver_export.h>
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 KWAYLANDSERVER_EXPORT OutputConfigurationV2Interface : public QObject
{
Q_OBJECT
public:
~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;
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;
QScopedPointer<OutputConfigurationV2InterfacePrivate> d;
};
}
Q_DECLARE_METATYPE(KWaylandServer::OutputConfigurationV2Interface*)

View file

@ -0,0 +1,773 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "outputdevice_v2_interface.h"
#include "display_p.h"
#include "display.h"
#include "logging.h"
#include "utils.h"
#include <QDebug>
#include <QString>
#include <QPointer>
#include "qwayland-server-kde-output-device-v2.h"
namespace KWaylandServer
{
static const quint32 s_version = 1;
class OutputDeviceV2InterfacePrivate : public QtWaylandServer::kde_output_device_v2
{
public:
OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display);
~OutputDeviceV2InterfacePrivate() override;
void updateGeometry();
void updateUuid();
void updateEdid();
void updateEnabled();
void updateScale();
void updateEisaId();
void updateSerialNumber();
void updateCapabilities();
void updateOverscan();
void updateVrrPolicy();
void sendGeometry(Resource *resource);
wl_resource *sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode);
void sendCurrentMode(Resource *resource, OutputDeviceModeV2Interface *mode);
void sendDone(Resource *resource);
void sendUuid(Resource *resource);
void sendEdid(Resource *resource);
void sendEnabled(Resource *resource);
void sendScale(Resource *resource);
void sendEisaId(Resource *resource);
void sendSerialNumber(Resource *resource);
void sendCapabilities(Resource *resource);
void sendOverscan(Resource *resource);
void sendVrrPolicy(Resource *resource);
QSize physicalSize;
QPoint globalPosition;
QString manufacturer = QStringLiteral("org.kde.kwin");
QString model = QStringLiteral("none");
qreal scale = 1.0;
QString serialNumber;
QString eisaId;
OutputDeviceV2Interface::SubPixel subPixel = OutputDeviceV2Interface::SubPixel::Unknown;
OutputDeviceV2Interface::Transform transform = OutputDeviceV2Interface::Transform::Normal;
QList<OutputDeviceModeV2Interface *> modes;
OutputDeviceModeV2Interface *currentMode = nullptr;
QByteArray edid;
bool enabled = true;
QUuid uuid;
OutputDeviceV2Interface::Capabilities capabilities;
uint32_t overscan = 0;
OutputDeviceV2Interface::VrrPolicy vrrPolicy = OutputDeviceV2Interface::VrrPolicy::Automatic;
QPointer<Display> display;
OutputDeviceV2Interface *q;
private:
int32_t toTransform() const;
int32_t toSubPixel() const;
protected:
void kde_output_device_v2_bind_resource(Resource *resource) override;
void kde_output_device_v2_destroy_global() override;
};
class OutputDeviceModeV2InterfacePrivate : public QtWaylandServer::kde_output_device_mode_v2
{
public:
OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, const QSize &size, int refreshRate, OutputDeviceModeV2Interface::ModeFlags flags);
~OutputDeviceModeV2InterfacePrivate() override;
void bindResource(wl_resource *resource);
static OutputDeviceModeV2InterfacePrivate *get(OutputDeviceModeV2Interface *mode) { return mode->d.data(); }
OutputDeviceModeV2Interface *q;
QSize m_size;
int m_refreshRate = 60000;
OutputDeviceModeV2Interface::ModeFlags m_flags;
};
OutputDeviceV2InterfacePrivate::OutputDeviceV2InterfacePrivate(OutputDeviceV2Interface *q, Display *display)
: QtWaylandServer::kde_output_device_v2(*display, s_version)
, display(display)
, q(q)
{
DisplayPrivate *displayPrivate = DisplayPrivate::get(display);
displayPrivate->outputdevicesV2.append(q);
}
OutputDeviceV2InterfacePrivate::~OutputDeviceV2InterfacePrivate()
{
if (display) {
DisplayPrivate *displayPrivate = DisplayPrivate::get(display);
displayPrivate->outputdevicesV2.removeOne(q);
}
}
OutputDeviceV2Interface::OutputDeviceV2Interface(Display *display, QObject *parent)
: QObject(parent)
, d(new OutputDeviceV2InterfacePrivate(this, display))
{
connect(this, &OutputDeviceV2Interface::subPixelChanged, this, [this] { d->updateGeometry(); });
connect(this, &OutputDeviceV2Interface::transformChanged, this, [this] { d->updateGeometry(); });
connect(this, &OutputDeviceV2Interface::globalPositionChanged, this, [this] { d->updateGeometry(); });
connect(this, &OutputDeviceV2Interface::modelChanged, this, [this] { d->updateGeometry(); });
connect(this, &OutputDeviceV2Interface::manufacturerChanged, this, [this] { d->updateGeometry(); });
connect(this, &OutputDeviceV2Interface::scaleChanged, this, [this] { d->updateScale(); });
}
OutputDeviceV2Interface::~OutputDeviceV2Interface()
{
d->globalRemove();
}
void OutputDeviceV2Interface::remove()
{
if (d->isGlobalRemoved()) {
return;
}
if (d->display) {
DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
displayPrivate->outputdevicesV2.removeOne(this);
}
d->globalRemove();
}
QSize OutputDeviceV2Interface::pixelSize() const
{
if (d->currentMode == nullptr) {
return QSize();
}
return d->currentMode->size();
}
int OutputDeviceV2Interface::refreshRate() const
{
if (d->currentMode == nullptr) {
return 60000;
}
return d->currentMode->refreshRate();
}
void OutputDeviceV2Interface::setCurrentMode(OutputDeviceModeV2Interface *mode)
{
if (mode == d->currentMode) {
return;
}
if (d->currentMode) {
// another mode has the current flag - remove
d->currentMode->setFlags(d->currentMode->flags() & ~uint(OutputDeviceModeV2Interface::ModeFlag::Current));
}
mode->setFlags(mode->flags() | OutputDeviceModeV2Interface::ModeFlag::Current);
d->currentMode = mode;
const auto clientResources = d->resourceMap();
for (auto it = clientResources.begin(); it != clientResources.end(); ++it) {
auto resource = *it;
d->sendCurrentMode(resource, d->currentMode);
d->sendDone(resource);
}
Q_EMIT currentModeChanged();
}
bool OutputDeviceV2Interface::setCurrentMode(const QSize &size, int refreshRate)
{
auto mode = std::find_if(d->modes.begin(), d->modes.end(),
[size, refreshRate](OutputDeviceModeV2Interface *mode) {
return mode->size() == size && mode->refreshRate() == refreshRate;
}
);
if (mode == d->modes.end()) {
return false;
}
setCurrentMode(*mode);
return true;
}
int32_t OutputDeviceV2InterfacePrivate::toTransform() const
{
switch (transform) {
case OutputDeviceV2Interface::Transform::Normal:
return WL_OUTPUT_TRANSFORM_NORMAL;
case OutputDeviceV2Interface::Transform::Rotated90:
return WL_OUTPUT_TRANSFORM_90;
case OutputDeviceV2Interface::Transform::Rotated180:
return WL_OUTPUT_TRANSFORM_180;
case OutputDeviceV2Interface::Transform::Rotated270:
return WL_OUTPUT_TRANSFORM_270;
case OutputDeviceV2Interface::Transform::Flipped:
return WL_OUTPUT_TRANSFORM_FLIPPED;
case OutputDeviceV2Interface::Transform::Flipped90:
return WL_OUTPUT_TRANSFORM_FLIPPED_90;
case OutputDeviceV2Interface::Transform::Flipped180:
return WL_OUTPUT_TRANSFORM_FLIPPED_180;
case OutputDeviceV2Interface::Transform::Flipped270:
return WL_OUTPUT_TRANSFORM_FLIPPED_270;
default:
Q_UNREACHABLE();
}
}
int32_t OutputDeviceV2InterfacePrivate::toSubPixel() const
{
switch (subPixel) {
case OutputDeviceV2Interface::SubPixel::Unknown:
return WL_OUTPUT_SUBPIXEL_UNKNOWN;
case OutputDeviceV2Interface::SubPixel::None:
return WL_OUTPUT_SUBPIXEL_NONE;
case OutputDeviceV2Interface::SubPixel::HorizontalRGB:
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
case OutputDeviceV2Interface::SubPixel::HorizontalBGR:
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
case OutputDeviceV2Interface::SubPixel::VerticalRGB:
return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
case OutputDeviceV2Interface::SubPixel::VerticalBGR:
return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
default:
Q_UNREACHABLE();
}
}
void OutputDeviceV2InterfacePrivate::kde_output_device_v2_destroy_global()
{
delete q;
}
void OutputDeviceV2InterfacePrivate::kde_output_device_v2_bind_resource(Resource *resource)
{
sendGeometry(resource);
sendScale(resource);
sendEisaId(resource);
sendSerialNumber(resource);
auto currentModeIt = modes.end();
for (auto it = modes.begin(); it != modes.end(); ++it) {
auto &mode = *it;
if (mode->flags().testFlag(OutputDeviceModeV2Interface::ModeFlag::Current)) {
// needs to be sent as last mode
currentModeIt = it;
continue;
}
sendNewMode(resource, mode);
}
if (currentModeIt != modes.end()) {
auto modeResource = sendNewMode(resource, *currentModeIt);
send_current_mode(resource->handle, modeResource);
}
sendUuid(resource);
sendEdid(resource);
sendEnabled(resource);
sendCapabilities(resource);
sendOverscan(resource);
sendVrrPolicy(resource);
sendDone(resource);
}
wl_resource *OutputDeviceV2InterfacePrivate::sendNewMode(Resource *resource, OutputDeviceModeV2Interface *mode)
{
auto privateMode = OutputDeviceModeV2InterfacePrivate::get(mode);
// bind mode to client
const auto modeResource = privateMode->add(resource->client(), resource->version())->handle;
send_mode(resource->handle, modeResource);
privateMode->bindResource(modeResource);
return modeResource;
}
void OutputDeviceV2InterfacePrivate::sendCurrentMode(Resource *outputResource, OutputDeviceModeV2Interface *mode)
{
// mode must already be known to the client
const auto modeResources = OutputDeviceModeV2InterfacePrivate::get(mode)->resourceMap();
for (auto modeResource : modeResources) {
send_current_mode(outputResource->handle, modeResource->handle);
}
}
void OutputDeviceV2InterfacePrivate::sendGeometry(Resource *resource)
{
send_geometry(resource->handle,
globalPosition.x(),
globalPosition.y(),
physicalSize.width(),
physicalSize.height(),
toSubPixel(),
manufacturer,
model,
toTransform());
}
void OutputDeviceV2InterfacePrivate::sendScale(Resource *resource)
{
send_scale(resource->handle, wl_fixed_from_double(scale));
}
void OutputDeviceV2InterfacePrivate::sendSerialNumber(Resource *resource)
{
send_serial_number(resource->handle, serialNumber);
}
void OutputDeviceV2InterfacePrivate::sendEisaId(Resource *resource)
{
send_eisa_id(resource->handle, eisaId);
}
void OutputDeviceV2InterfacePrivate::sendDone(Resource *resource)
{
send_done(resource->handle);
}
void OutputDeviceV2InterfacePrivate::updateGeometry()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendGeometry(resource);
sendDone(resource);
}
}
void OutputDeviceV2InterfacePrivate::updateScale()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendScale(resource);
sendDone(resource);
}
}
void OutputDeviceV2Interface::setPhysicalSize(const QSize &arg)
{
if (d->physicalSize == arg) {
return;
}
d->physicalSize = arg;
Q_EMIT physicalSizeChanged(d->physicalSize);
}
void OutputDeviceV2Interface::setGlobalPosition(const QPoint &arg)
{
if (d->globalPosition == arg) {
return;
}
d->globalPosition = arg;
Q_EMIT globalPositionChanged(d->globalPosition);
}
void OutputDeviceV2Interface::setManufacturer(const QString &arg)
{
if (d->manufacturer == arg) {
return;
}
d->manufacturer = arg;
Q_EMIT manufacturerChanged(d->manufacturer);
}
void OutputDeviceV2Interface::setModel(const QString &arg)
{
if (d->model == arg) {
return;
}
d->model = arg;
Q_EMIT modelChanged(d->model);
}
void OutputDeviceV2Interface::setSerialNumber(const QString &arg)
{
if (d->serialNumber == arg) {
return;
}
d->serialNumber = arg;
Q_EMIT serialNumberChanged(d->serialNumber);
}
void OutputDeviceV2Interface::setEisaId(const QString &arg)
{
if (d->eisaId == arg) {
return;
}
d->eisaId = arg;
Q_EMIT eisaIdChanged(d->eisaId);
}
void OutputDeviceV2Interface::setSubPixel(SubPixel arg)
{
if (d->subPixel == arg) {
return;
}
d->subPixel = arg;
Q_EMIT subPixelChanged(d->subPixel);
}
void OutputDeviceV2Interface::setTransform(Transform arg)
{
if (d->transform == arg) {
return;
}
d->transform = arg;
Q_EMIT transformChanged(d->transform);
}
void OutputDeviceV2Interface::setScale(qreal scale)
{
if (qFuzzyCompare(d->scale, scale)) {
return;
}
d->scale = scale;
Q_EMIT scaleChanged(d->scale);
}
QSize OutputDeviceV2Interface::physicalSize() const
{
return d->physicalSize;
}
QPoint OutputDeviceV2Interface::globalPosition() const
{
return d->globalPosition;
}
QString OutputDeviceV2Interface::manufacturer() const
{
return d->manufacturer;
}
QString OutputDeviceV2Interface::model() const
{
return d->model;
}
QString OutputDeviceV2Interface::serialNumber() const
{
return d->serialNumber;
}
QString OutputDeviceV2Interface::eisaId() const
{
return d->eisaId;
}
qreal OutputDeviceV2Interface::scale() const
{
return d->scale;
}
OutputDeviceV2Interface::SubPixel OutputDeviceV2Interface::subPixel() const
{
return d->subPixel;
}
OutputDeviceV2Interface::Transform OutputDeviceV2Interface::transform() const
{
return d->transform;
}
void OutputDeviceV2Interface::setModes(const QList<OutputDeviceModeV2Interface *> &modes)
{
if (modes.isEmpty()) {
qCWarning(KWAYLAND_SERVER) << "Tried to set no modes for output";
return;
}
const auto clientResources = d->resourceMap();
const auto oldModes = d->modes;
d->modes.clear();
const auto oldCurrentMode = d->currentMode;
d->currentMode = nullptr;
for (OutputDeviceModeV2Interface *outputDeviceMode : modes) {
d->modes << outputDeviceMode;
outputDeviceMode->setParent(this);
if (outputDeviceMode->flags().testFlag(OutputDeviceModeV2Interface::ModeFlag::Current)) {
d->currentMode = outputDeviceMode;
} else {
for (auto resource : clientResources) {
d->sendNewMode(resource, outputDeviceMode);
}
}
}
if (!d->currentMode) {
d->currentMode = d->modes.at(0);
}
for (auto resource : clientResources) {
d->sendNewMode(resource, d->currentMode);
d->sendCurrentMode(resource, d->currentMode);
}
qDeleteAll(oldModes.crbegin(), oldModes.crend());
for (auto resource : clientResources) {
d->sendDone(resource);
}
if (oldCurrentMode != d->currentMode) {
Q_EMIT currentModeChanged();
}
Q_EMIT modesChanged();
}
void OutputDeviceV2Interface::setEdid(const QByteArray &edid)
{
d->edid = edid;
d->updateEdid();
Q_EMIT edidChanged();
}
QByteArray OutputDeviceV2Interface::edid() const
{
return d->edid;
}
void OutputDeviceV2Interface::setEnabled(bool enabled)
{
if (d->enabled != enabled) {
d->enabled = enabled;
d->updateEnabled();
Q_EMIT enabledChanged();
}
}
bool OutputDeviceV2Interface::enabled() const
{
return d->enabled;
}
void OutputDeviceV2Interface::setUuid(const QUuid &uuid)
{
if (d->uuid != uuid) {
d->uuid = uuid;
d->updateUuid();
Q_EMIT uuidChanged();
}
}
QUuid OutputDeviceV2Interface::uuid() const
{
return d->uuid;
}
void OutputDeviceV2InterfacePrivate::sendEdid(Resource *resource)
{
send_edid(resource->handle, QString::fromStdString(edid.toBase64().toStdString()));
}
void OutputDeviceV2InterfacePrivate::sendEnabled(Resource *resource)
{
send_enabled(resource->handle, enabled);
}
void OutputDeviceV2InterfacePrivate::sendUuid(Resource *resource)
{
send_uuid(resource->handle, uuid.toString(QUuid::WithoutBraces));
}
void OutputDeviceV2InterfacePrivate::updateEnabled()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendEnabled(resource);
}
}
void OutputDeviceV2InterfacePrivate::updateEdid()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendEdid(resource);
}
}
void OutputDeviceV2InterfacePrivate::updateUuid()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendUuid(resource);
}
}
void OutputDeviceV2InterfacePrivate::updateEisaId()
{
const auto clientResources = resourceMap();
for (auto resource : clientResources) {
sendEisaId(resource);
}
}
uint32_t OutputDeviceV2Interface::overscan() const
{
return d->overscan;
}
OutputDeviceV2Interface::Capabilities OutputDeviceV2Interface::capabilities() const
{
return d->capabilities;
}
void OutputDeviceV2Interface::setCapabilities(Capabilities cap)
{
if (d->capabilities != cap) {
d->capabilities = cap;
d->updateCapabilities();
Q_EMIT capabilitiesChanged();
}
}
void OutputDeviceV2InterfacePrivate::sendCapabilities(Resource *resource)
{
send_capabilities(resource->handle, static_cast<uint32_t>(capabilities));
}
void OutputDeviceV2InterfacePrivate::updateCapabilities()
{
const auto clientResources = resourceMap();
for (const auto &resource : clientResources) {
sendCapabilities(resource);
}
}
void OutputDeviceV2Interface::setOverscan(uint32_t overscan)
{
if (d->overscan != overscan) {
d->overscan = overscan;
d->updateOverscan();
Q_EMIT overscanChanged();
}
}
void OutputDeviceV2InterfacePrivate::sendOverscan(Resource *resource)
{
send_overscan(resource->handle, static_cast<uint32_t>(overscan));
}
void OutputDeviceV2InterfacePrivate::updateOverscan()
{
const auto clientResources = resourceMap();
for (const auto &resource : clientResources) {
sendOverscan(resource);
}
}
void OutputDeviceV2InterfacePrivate::sendVrrPolicy(Resource *resource)
{
send_vrr_policy(resource->handle, static_cast<uint32_t>(vrrPolicy));
}
OutputDeviceV2Interface::VrrPolicy OutputDeviceV2Interface::vrrPolicy() const
{
return d->vrrPolicy;
}
void OutputDeviceV2Interface::setVrrPolicy(VrrPolicy policy)
{
if (d->vrrPolicy != policy) {
d->vrrPolicy = policy;
d->updateVrrPolicy();
Q_EMIT vrrPolicyChanged();
}
}
void OutputDeviceV2InterfacePrivate::updateVrrPolicy()
{
const auto clientResources = resourceMap();
for (const auto &resource : clientResources) {
sendVrrPolicy(resource);
}
}
OutputDeviceV2Interface *OutputDeviceV2Interface::get(wl_resource *native)
{
if (auto devicePrivate = resource_cast<OutputDeviceV2InterfacePrivate *>(native)) {
return devicePrivate->q;
}
return nullptr;
}
OutputDeviceModeV2InterfacePrivate::OutputDeviceModeV2InterfacePrivate(OutputDeviceModeV2Interface *q, const QSize &size, int refreshRate, OutputDeviceModeV2Interface::ModeFlags flags)
: QtWaylandServer::kde_output_device_mode_v2()
, q(q)
, m_size(size)
, m_refreshRate(refreshRate)
, m_flags(flags)
{}
OutputDeviceModeV2Interface::OutputDeviceModeV2Interface(const QSize &size, int refreshRate, ModeFlags flags, QObject *parent)
: QObject(parent)
, d(new OutputDeviceModeV2InterfacePrivate(this, size, refreshRate, flags))
{}
OutputDeviceModeV2Interface::~OutputDeviceModeV2Interface() = default;
OutputDeviceModeV2InterfacePrivate::~OutputDeviceModeV2InterfacePrivate()
{
const auto map = resourceMap();
for (Resource *resource : map) {
send_removed(resource->handle);
}
}
QSize OutputDeviceModeV2Interface::size() const
{
return d->m_size;
}
int OutputDeviceModeV2Interface::refreshRate() const
{
return d->m_refreshRate;
}
OutputDeviceModeV2Interface::ModeFlags OutputDeviceModeV2Interface::flags() const
{
return d->m_flags;
}
void OutputDeviceModeV2Interface::setFlags(OutputDeviceModeV2Interface::ModeFlags flags)
{
d->m_flags = flags;
}
void OutputDeviceModeV2InterfacePrivate::bindResource(wl_resource *resource)
{
send_size(resource, m_size.width(), m_size.height());
send_refresh(resource, m_refreshRate);
if (m_flags.testFlag(OutputDeviceModeV2Interface::ModeFlag::Preferred)) {
send_preferred(resource);
}
}
OutputDeviceModeV2Interface *OutputDeviceModeV2Interface::get(wl_resource *native)
{
if (auto devicePrivate = resource_cast<OutputDeviceModeV2InterfacePrivate *>(native)) {
return devicePrivate->q;
}
return nullptr;
}
}

View file

@ -0,0 +1,204 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <KWaylandServer/kwaylandserver_export.h>
#include <QObject>
#include <QPoint>
#include <QSize>
#include <QUuid>
#include <QVector>
struct wl_resource;
namespace KWaylandServer
{
class Display;
class OutputDeviceV2InterfacePrivate;
class OutputDeviceModeV2Interface;
class OutputDeviceModeV2InterfacePrivate;
/** @class OutputDeviceV2Interface
*
* Represents an output device, the difference to Output is that this output can be disabled,
* so not currently used to display content.
*
* @see OutputManagementV2Interface
*/
class KWAYLANDSERVER_EXPORT OutputDeviceV2Interface : public QObject
{
Q_OBJECT
Q_PROPERTY(QSize physicalSize READ physicalSize WRITE setPhysicalSize NOTIFY physicalSizeChanged)
Q_PROPERTY(QPoint globalPosition READ globalPosition WRITE setGlobalPosition NOTIFY globalPositionChanged)
Q_PROPERTY(QString manufacturer READ manufacturer WRITE setManufacturer NOTIFY manufacturerChanged)
Q_PROPERTY(QString model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(QString serialNumber READ serialNumber WRITE setSerialNumber NOTIFY serialNumberChanged)
Q_PROPERTY(QString eisaId READ eisaId WRITE setEisaId NOTIFY eisaIdChanged)
Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
Q_PROPERTY(QByteArray edid READ edid WRITE setEdid NOTIFY edidChanged)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QUuid uuid READ uuid WRITE setUuid NOTIFY uuidChanged)
Q_PROPERTY(Capabilities capabilities READ capabilities WRITE setCapabilities NOTIFY capabilitiesChanged)
Q_PROPERTY(uint32_t overscan READ overscan WRITE setOverscan NOTIFY overscanChanged)
Q_PROPERTY(VrrPolicy vrrPolicy READ vrrPolicy WRITE setVrrPolicy NOTIFY vrrPolicyChanged)
public:
enum class SubPixel {
Unknown,
None,
HorizontalRGB,
HorizontalBGR,
VerticalRGB,
VerticalBGR,
};
Q_ENUM(SubPixel)
enum class Transform {
Normal,
Rotated90,
Rotated180,
Rotated270,
Flipped,
Flipped90,
Flipped180,
Flipped270,
};
Q_ENUM(Transform)
enum class Capability {
Overscan = 0x1,
Vrr = 0x2,
};
Q_ENUM(Capability)
Q_DECLARE_FLAGS(Capabilities, Capability)
enum class VrrPolicy {
Never = 0,
Always = 1,
Automatic = 2
};
Q_ENUM(VrrPolicy)
explicit OutputDeviceV2Interface(Display *display, QObject *parent = nullptr);
~OutputDeviceV2Interface() override;
void remove();
QSize physicalSize() const;
QPoint globalPosition() const;
QString manufacturer() const;
QString model() const;
QString serialNumber() const;
QString eisaId() const;
QSize pixelSize() const;
int refreshRate() const;
qreal scale() const;
SubPixel subPixel() const;
Transform transform() const;
QByteArray edid() const;
bool enabled() const;
QUuid uuid() const;
Capabilities capabilities() const;
uint32_t overscan() const;
VrrPolicy vrrPolicy() const;
void setPhysicalSize(const QSize &size);
void setGlobalPosition(const QPoint &pos);
void setManufacturer(const QString &manufacturer);
void setModel(const QString &model);
void setSerialNumber(const QString &serialNumber);
void setEisaId(const QString &eisaId);
void setScale(qreal scale);
void setSubPixel(SubPixel subPixel);
void setTransform(Transform transform);
void setModes(const QList<KWaylandServer::OutputDeviceModeV2Interface *> &modes);
void setCurrentMode(KWaylandServer::OutputDeviceModeV2Interface *mode);
/**
* Makes the mode with the specified @a size and @a refreshRate current.
* Returns @c false if no mode with the given attributes exists; otherwise returns @c true.
*/
bool setCurrentMode(const QSize &size, int refreshRate);
void setEdid(const QByteArray &edid);
void setEnabled(bool enabled);
void setUuid(const QUuid &uuid);
void setCapabilities(Capabilities cap);
void setOverscan(uint32_t overscan);
void setVrrPolicy(VrrPolicy policy);
static OutputDeviceV2Interface *get(wl_resource *native);
Q_SIGNALS:
void physicalSizeChanged(const QSize&);
void globalPositionChanged(const QPoint&);
void manufacturerChanged(const QString&);
void modelChanged(const QString&);
void serialNumberChanged(const QString&);
void eisaIdChanged(const QString &);
void scaleChanged(qreal);
void subPixelChanged(SubPixel);
void transformChanged(Transform);
void modesChanged();
void currentModeChanged();
void edidChanged();
void enabledChanged();
void uuidChanged();
void capabilitiesChanged();
void overscanChanged();
void vrrPolicyChanged();
private:
QScopedPointer<OutputDeviceV2InterfacePrivate> d;
};
/**
* @class The OutputDeviceModeV2Interface class
*
* Represents an output device mode.
*
* @see OutputDeviceV2Interface
*/
class KWAYLANDSERVER_EXPORT OutputDeviceModeV2Interface : public QObject
{
Q_OBJECT
public:
enum class ModeFlag {
Current = 0x1,
Preferred = 0x2,
};
Q_ENUM(ModeFlag)
Q_DECLARE_FLAGS(ModeFlags, ModeFlag)
OutputDeviceModeV2Interface(const QSize &size, int refreshRate, ModeFlags flags, QObject *parent = nullptr);
~OutputDeviceModeV2Interface() override;
QSize size() const;
int refreshRate() const;
OutputDeviceModeV2Interface::ModeFlags flags() const;
void setFlags(OutputDeviceModeV2Interface::ModeFlags newFlags);
static OutputDeviceModeV2Interface *get(wl_resource *native);
private:
friend class OutputDeviceModeV2InterfacePrivate;
QScopedPointer<OutputDeviceModeV2InterfacePrivate> d;
};
}
Q_DECLARE_METATYPE(KWaylandServer::OutputDeviceModeV2Interface::ModeFlag)
Q_DECLARE_METATYPE(KWaylandServer::OutputDeviceV2Interface::SubPixel)
Q_DECLARE_METATYPE(KWaylandServer::OutputDeviceV2Interface::Transform)

View file

@ -0,0 +1,57 @@
/*
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
*/
#include "display.h"
#include "outputmanagement_v2_interface.h"
#include "outputconfiguration_v2_interface.h"
#include <wayland-server.h>
#include "qwayland-server-kde-output-management-v2.h"
#include <QHash>
namespace KWaylandServer
{
static const quint32 s_version = 1;
class OutputManagementV2InterfacePrivate : public QtWaylandServer::kde_output_management_v2
{
public:
OutputManagementV2InterfacePrivate(OutputManagementV2Interface *_q, Display *display);
private:
OutputManagementV2Interface *q;
protected:
void kde_output_management_v2_create_configuration(Resource *resource, uint32_t id) override;
};
OutputManagementV2InterfacePrivate::OutputManagementV2InterfacePrivate(OutputManagementV2Interface *_q, Display *display)
: QtWaylandServer::kde_output_management_v2(*display, s_version)
, q(_q)
{
}
void OutputManagementV2InterfacePrivate::kde_output_management_v2_create_configuration(Resource *resource, uint32_t id)
{
wl_resource *config_resource = wl_resource_create(resource->client(), &kde_output_configuration_v2_interface, resource->version(), id);
if (!config_resource) {
wl_client_post_no_memory(resource->client());
return;
}
new OutputConfigurationV2Interface(q, config_resource);
}
OutputManagementV2Interface::OutputManagementV2Interface(Display *display, QObject *parent)
: QObject(parent)
, d(new OutputManagementV2InterfacePrivate(this, display))
{
}
OutputManagementV2Interface::~OutputManagementV2Interface() = default;
}

View file

@ -0,0 +1,58 @@
/*
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
*/
#pragma once
#include <QObject>
#include <KWaylandServer/kwaylandserver_export.h>
namespace KWaylandServer
{
class OutputManagementV2InterfacePrivate;
class OutputConfigurationV2Interface;
/**
* @class OutputManagementInterface
*
* This class is used to change the configuration of the Wayland server's outputs.
* The client requests an OutputConfiguration, changes its OutputDevices and then
* calls OutputConfiguration::apply, which makes this class emit a signal, carrying
* the new configuration.
* The server is then expected to make the requested changes by applying the settings
* of the OutputDevices to the Outputs.
*
* @see OutputConfiguration
* @see OutputConfigurationInterface
*/
class KWAYLANDSERVER_EXPORT OutputManagementV2Interface : public QObject
{
Q_OBJECT
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:
QScopedPointer<OutputManagementV2InterfacePrivate> d;
};
}