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;