diff --git a/abstract_backend.cpp b/abstract_backend.cpp
index 13e0f83d8b..8f0172caac 100644
--- a/abstract_backend.cpp
+++ b/abstract_backend.cpp
@@ -67,6 +67,12 @@ QPainterBackend *AbstractBackend::createQPainterBackend()
return nullptr;
}
+void AbstractBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config)
+{
+ Q_UNUSED(config)
+ qCWarning(KWIN_CORE) << "This backend does not support configuration changes.";
+}
+
void AbstractBackend::setSoftWareCursor(bool set)
{
if (m_softWareCursor == set) {
diff --git a/abstract_backend.h b/abstract_backend.h
index 1ac2c7e35f..d597ad9e4f 100644
--- a/abstract_backend.h
+++ b/abstract_backend.h
@@ -25,6 +25,12 @@ along with this program. If not, see .
#include
#include
+namespace KWayland {
+ namespace Server {
+ class OutputConfigurationInterface;
+ }
+}
+
namespace KWin
{
@@ -72,6 +78,14 @@ public:
* Base implementation returns one QRect positioned at 0/0 with screenSize() as size.
**/
virtual QVector screenGeometries() const;
+ /**
+ * 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.
+ */
+ virtual void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config);
bool usesSoftwareCursor() const {
return m_softWareCursor;
diff --git a/backends/drm/drm_backend.cpp b/backends/drm/drm_backend.cpp
index 920757f6a4..08cf29d875 100644
--- a/backends/drm/drm_backend.cpp
+++ b/backends/drm/drm_backend.cpp
@@ -33,6 +33,10 @@ along with this program. If not, see .
// KWayland
#include
#include
+#include
+#include
+#include
+#include
// KF5
#include
#include
@@ -463,6 +467,22 @@ QByteArray DrmBackend::generateOutputConfigurationUuid() const
return hash.result().toHex().left(10);
}
+void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config)
+{
+ const auto changes = config->changes();
+ for (auto it = changes.begin(); it != changes.end(); it++) {
+
+ KWayland::Server::OutputChangeSet *changeset = it.value();
+
+ auto drmoutput = findOutput(it.key()->uuid());
+ if (drmoutput == nullptr) {
+ qCWarning(KWIN_DRM) << "Could NOT find DrmOutput matching " << it.key()->uuid();
+ return;
+ }
+ drmoutput->setChanges(changeset);
+ }
+}
+
DrmOutput *DrmBackend::findOutput(quint32 connector)
{
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) {
@@ -474,6 +494,17 @@ DrmOutput *DrmBackend::findOutput(quint32 connector)
return nullptr;
}
+DrmOutput *DrmBackend::findOutput(const QByteArray &uuid)
+{
+ auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) {
+ return o->m_uuid == uuid;
+ });
+ if (it != m_outputs.constEnd()) {
+ return *it;
+ }
+ return nullptr;
+}
+
quint32 DrmBackend::findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok)
{
if (ok) {
@@ -670,6 +701,7 @@ DrmOutput::~DrmOutput()
hideCursor();
cleanupBlackBuffer();
delete m_waylandOutput.data();
+ delete m_waylandOutputDevice.data();
}
void DrmOutput::hideCursor()
@@ -803,11 +835,20 @@ void DrmOutput::init(drmModeConnector *connector)
m_waylandOutput.clear();
}
m_waylandOutput = waylandServer()->display()->createOutput();
+ if (!m_waylandOutputDevice.isNull()) {
+ delete m_waylandOutputDevice.data();
+ m_waylandOutputDevice.clear();
+ }
+ m_waylandOutputDevice = waylandServer()->display()->createOutputDevice();
+ m_waylandOutputDevice->setUuid(m_uuid);
+
if (!m_edid.eisaId.isEmpty()) {
m_waylandOutput->setManufacturer(QString::fromLatin1(m_edid.eisaId));
} else {
m_waylandOutput->setManufacturer(i18n("unknown"));
}
+ m_waylandOutputDevice->setManufacturer(m_waylandOutput->manufacturer());
+
if (!m_edid.monitorName.isEmpty()) {
QString model = QString::fromLatin1(m_edid.monitorName);
if (!m_edid.serialNumber.isEmpty()) {
@@ -820,6 +861,7 @@ void DrmOutput::init(drmModeConnector *connector)
} else {
m_waylandOutput->setModel(i18n("unknown"));
}
+ m_waylandOutputDevice->setModel(m_waylandOutput->model());
QSize physicalSize = !m_edid.physicalSize.isEmpty() ? m_edid.physicalSize : QSize(connector->mmWidth, connector->mmHeight);
// the size might be completely borked. E.g. Samsung SyncMaster 2494HS reports 160x90 while in truth it's 520x292
@@ -834,16 +876,20 @@ void DrmOutput::init(drmModeConnector *connector)
physicalSize = overwriteSize;
}
m_waylandOutput->setPhysicalSize(physicalSize);
+ m_waylandOutputDevice->setPhysicalSize(physicalSize);
// read in mode information
for (int i = 0; i < connector->count_modes; ++i) {
auto *m = &connector->modes[i];
KWayland::Server::OutputInterface::ModeFlags flags;
+ KWayland::Server::OutputDeviceInterface::ModeFlags deviceflags;
if (isCurrentMode(m)) {
flags |= KWayland::Server::OutputInterface::ModeFlag::Current;
+ deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Current;
}
if (m->type & DRM_MODE_TYPE_PREFERRED) {
flags |= KWayland::Server::OutputInterface::ModeFlag::Preferred;
+ deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred;
}
// Calculate higher precision (mHz) refresh rate
@@ -859,6 +905,14 @@ void DrmOutput::init(drmModeConnector *connector)
refreshRate /= m->vscan;
}
m_waylandOutput->addMode(QSize(m->hdisplay, m->vdisplay), flags, refreshRate);
+
+ KWayland::Server::OutputDeviceInterface::Mode mode;
+ mode.id = i;
+ mode.size = QSize(m->hdisplay, m->vdisplay);
+ mode.flags = deviceflags;
+ mode.refreshRate = refreshRate;
+ qCDebug(KWIN_DRM) << "Adding mode: " << i << mode.size;
+ m_waylandOutputDevice->addMode(mode);
}
// set dpms
@@ -873,6 +927,8 @@ void DrmOutput::init(drmModeConnector *connector)
}
m_waylandOutput->create();
+ qCDebug(KWIN_DRM) << "Created OutputDevice";
+ m_waylandOutputDevice->create();
}
void DrmOutput::initUuid()
@@ -1149,6 +1205,55 @@ void DrmOutput::setGlobalPos(const QPoint &pos)
if (m_waylandOutput) {
m_waylandOutput->setGlobalPosition(pos);
}
+ if (m_waylandOutputDevice) {
+ m_waylandOutputDevice->setGlobalPosition(pos);
+ }
+}
+
+void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes)
+{
+ m_changeset = changes;
+ qCDebug(KWIN_DRM) << "set changes in DrmOutput";
+ commitChanges();
+}
+
+bool DrmOutput::commitChanges()
+{
+ Q_ASSERT(!m_waylandOutputDevice.isNull());
+ Q_ASSERT(!m_waylandOutput.isNull());
+
+ if (m_changeset.isNull()) {
+ qCDebug(KWIN_DRM) << "no changes";
+ // No changes to an output is an entirely valid thing
+ return true;
+ }
+
+ if (m_changeset->enabledChanged()) {
+ qCDebug(KWIN_DRM) << "Setting enabled:";
+ m_waylandOutputDevice->setEnabled(m_changeset->enabled());
+ // FIXME: implement
+ }
+ if (m_changeset->modeChanged()) {
+ qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode();
+ m_waylandOutputDevice->setCurrentMode(m_changeset->mode());
+ // FIXME: implement for wl_output
+ }
+ if (m_changeset->transformChanged()) {
+ qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(m_changeset->transform());
+ m_waylandOutputDevice->setTransform(m_changeset->transform());
+ // FIXME: implement for wl_output
+ }
+ if (m_changeset->positionChanged()) {
+ qCDebug(KWIN_DRM) << "Server setting position: " << m_changeset->position();
+ m_waylandOutput->setGlobalPosition(m_changeset->position());
+ m_waylandOutputDevice->setGlobalPosition(m_changeset->position());
+ }
+ if (m_changeset->scaleChanged()) {
+ qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale();
+ m_waylandOutputDevice->setScale(m_changeset->scale());
+ // FIXME: implement for wl_output
+ }
+ return true;
}
DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size)
diff --git a/backends/drm/drm_backend.h b/backends/drm/drm_backend.h
index 977dd26e31..421356ac0c 100644
--- a/backends/drm/drm_backend.h
+++ b/backends/drm/drm_backend.h
@@ -36,6 +36,9 @@ namespace KWayland
namespace Server
{
class OutputInterface;
+class OutputDeviceInterface;
+class OutputChangeSet;
+class OutputManagementInterface;
}
}
@@ -68,6 +71,7 @@ public:
explicit DrmBackend(QObject *parent = nullptr);
virtual ~DrmBackend();
+ void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) override;
Screens *createScreens(QObject *parent = nullptr) override;
QPainterBackend *createQPainterBackend() override;
OpenGLBackend* createOpenGLBackend() override;
@@ -118,6 +122,7 @@ private:
void readOutputsConfiguration();
QByteArray generateOutputConfigurationUuid() const;
DrmOutput *findOutput(quint32 connector);
+ DrmOutput *findOutput(const QByteArray &uuid);
QScopedPointer m_udev;
QScopedPointer m_udevMonitor;
int m_fd = -1;
@@ -129,6 +134,7 @@ private:
bool m_active = false;
QVector m_buffers;
QScopedPointer m_dpmsFilter;
+ KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
};
class DrmOutput : public QObject
@@ -151,6 +157,12 @@ public:
void restoreSaved();
void blank();
+ /**
+ * This sets the changes and tests them against the DRM output
+ */
+ void setChanges(KWayland::Server::OutputChangeSet *changeset);
+ bool commitChanges();
+
QSize size() const;
QRect geometry() const;
QString name() const;
@@ -201,6 +213,8 @@ private:
Edid m_edid;
QScopedPointer<_drmModeCrtc, CrtcCleanup> m_savedCrtc;
QPointer m_waylandOutput;
+ QPointer m_waylandOutputDevice;
+ QPointer m_changeset;
ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms;
DpmsMode m_dpmsMode = DpmsMode::On;
QByteArray m_uuid;
diff --git a/wayland_server.cpp b/wayland_server.cpp
index 8d205c5912..418a2ce4f1 100644
--- a/wayland_server.cpp
+++ b/wayland_server.cpp
@@ -46,6 +46,8 @@ along with this program. If not, see .
#include
#include
#include
+#include
+#include
// Qt
#include
@@ -231,6 +233,12 @@ void WaylandServer::init(const QByteArray &socketName, InitalizationFlags flags)
}
);
m_decorationManager->create();
+
+ m_outputManagement = m_display->createOutputManagement(m_display);
+ connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested,
+ this, [this](KWayland::Server::OutputConfigurationInterface *config) {
+ m_backend->configurationChangeRequested(config);
+ });
}
void WaylandServer::initWorkspace()
diff --git a/wayland_server.h b/wayland_server.h
index 4c1d170446..26b2eec2b6 100644
--- a/wayland_server.h
+++ b/wayland_server.h
@@ -49,6 +49,8 @@ class OutputInterface;
class PlasmaShellInterface;
class PlasmaWindowManagementInterface;
class QtSurfaceExtensionInterface;
+class OutputManagementInterface;
+class OutputConfigurationInterface;
}
}
@@ -162,6 +164,7 @@ Q_SIGNALS:
private:
quint16 createClientId(KWayland::Server::ClientConnection *c);
void destroyInternalConnection();
+ void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config);
KWayland::Server::Display *m_display = nullptr;
KWayland::Server::CompositorInterface *m_compositor = nullptr;
KWayland::Server::SeatInterface *m_seat = nullptr;
@@ -170,6 +173,7 @@ private:
KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr;
KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr;
KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr;
+ KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
struct {
KWayland::Server::ClientConnection *client = nullptr;
QMetaObject::Connection destroyConnection;