diff --git a/abstract_output.h b/abstract_output.h --- a/abstract_output.h +++ b/abstract_output.h @@ -27,6 +27,14 @@ #include #include +namespace KWayland +{ +namespace Server +{ +class OutputChangeSet; +} +} + namespace KWin { @@ -100,6 +108,27 @@ */ virtual QString name() const = 0; + /** + * Returns the identifying uuid of this output. + * + * Default implementation returns an empty byte array. + */ + virtual QByteArray uuid() const; + + /** + * Enable or disable the output. + * + * Default implementation does nothing + */ + virtual void setEnabled(bool enable); + + /** + * This sets the changes and tests them against the specific output. + * + * Default implementation does nothing + */ + virtual void applyChanges(const KWayland::Server::OutputChangeSet *changeSet); + /** * Returns geometry of this output in device independent pixels. */ diff --git a/abstract_output.cpp b/abstract_output.cpp --- a/abstract_output.cpp +++ b/abstract_output.cpp @@ -73,6 +73,21 @@ { } +QByteArray AbstractOutput::uuid() const +{ + return QByteArray(); +} + +void AbstractOutput::setEnabled(bool enable) +{ + Q_UNUSED(enable) +} + +void AbstractOutput::applyChanges(const KWayland::Server::OutputChangeSet *changeSet) +{ + Q_UNUSED(changeSet) +} + bool AbstractOutput::isInternal() const { return false; diff --git a/abstract_wayland_output.h b/abstract_wayland_output.h --- a/abstract_wayland_output.h +++ b/abstract_wayland_output.h @@ -60,6 +60,7 @@ ~AbstractWaylandOutput() override; QString name() const override; + QByteArray uuid() const override; bool isEnabled() const { return !m_waylandOutput.isNull(); } @@ -88,10 +89,7 @@ void setGlobalPos(const QPoint &pos); void setScale(qreal scale); - /** - * This sets the changes and tests them against the specific output. - */ - void setChanges(KWayland::Server::OutputChangeSet *changeset); + void applyChanges(const KWayland::Server::OutputChangeSet *changeSet) override; QPointer waylandOutput() const { return m_waylandOutput; @@ -103,7 +101,7 @@ * This differs from updateDpms as it also removes the wl_output. * The default is on. */ - void setEnabled(bool enable); + void setEnabled(bool enable) override; Q_SIGNALS: void modeChanged(); diff --git a/abstract_wayland_output.cpp b/abstract_wayland_output.cpp --- a/abstract_wayland_output.cpp +++ b/abstract_wayland_output.cpp @@ -52,6 +52,11 @@ return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); } +QByteArray AbstractWaylandOutput::uuid() const +{ + return m_waylandOutputDevice->uuid(); +} + QRect AbstractWaylandOutput::geometry() const { return QRect(globalPos(), pixelSize() / scale()); @@ -117,31 +122,31 @@ } } -void AbstractWaylandOutput::setChanges(KWayland::Server::OutputChangeSet *changes) +void AbstractWaylandOutput::applyChanges(const KWayland::Server::OutputChangeSet *changeSet) { - qCDebug(KWIN_CORE) << "Set changes in AbstractWaylandOutput."; + qCDebug(KWIN_CORE) << "Apply changes to the Wayland output."; bool emitModeChanged = false; - //enabledChanged is handled by plugin code - if (changes->modeChanged()) { - qCDebug(KWIN_CORE) << "Setting new mode:" << changes->mode(); - m_waylandOutputDevice->setCurrentMode(changes->mode()); - updateMode(changes->mode()); + // Enablement changes are handled by platform. + if (changeSet->modeChanged()) { + qCDebug(KWIN_CORE) << "Setting new mode:" << changeSet->mode(); + m_waylandOutputDevice->setCurrentMode(changeSet->mode()); + updateMode(changeSet->mode()); emitModeChanged = true; } - if (changes->transformChanged()) { - qCDebug(KWIN_CORE) << "Server setting transform: " << (int)(changes->transform()); - transform(changes->transform()); + if (changeSet->transformChanged()) { + qCDebug(KWIN_CORE) << "Server setting transform: " << (int)(changeSet->transform()); + transform(changeSet->transform()); emitModeChanged = true; } - if (changes->positionChanged()) { - qCDebug(KWIN_CORE) << "Server setting position: " << changes->position(); - setGlobalPos(changes->position()); + if (changeSet->positionChanged()) { + qCDebug(KWIN_CORE) << "Server setting position: " << changeSet->position(); + setGlobalPos(changeSet->position()); // may just work already! } - if (changes->scaleChanged()) { - qCDebug(KWIN_CORE) << "Setting scale:" << changes->scale(); - setScale(changes->scaleF()); + if (changeSet->scaleChanged()) { + qCDebug(KWIN_CORE) << "Setting scale:" << changeSet->scale(); + setScale(changeSet->scaleF()); emitModeChanged = true; } diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -176,7 +176,7 @@ * Base implementation warns that the current backend does not implement this * functionality. */ - virtual void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config); + void requestOutputsChange(KWayland::Server::OutputConfigurationInterface *config); /** * Whether the Platform requires compositing for rendering. @@ -418,6 +418,9 @@ return Outputs(); } + AbstractOutput *findOutput(const QByteArray &uuid); + virtual void enableOutput(AbstractOutput *output, bool enable); + /** * A string of information to include in kwin debug output * It should not be translated. @@ -501,6 +504,13 @@ m_supportsGammaControl = set; } + /** + * Whether the backend is supposed to change the configuration of outputs. + */ + void supportsOutputChanges() { + m_supportsOutputChanges = true; + } + /** * Actual platform specific way to hide the cursor. * Sub-classes need to implement if they support hiding the cursor. @@ -545,6 +555,7 @@ int m_hideCursorCounter = 0; ColorCorrect::Manager *m_colorCorrect = nullptr; bool m_supportsGammaControl = false; + bool m_supportsOutputChanges = false; CompositingType m_selectedCompositor = NoCompositing; }; diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -18,6 +18,8 @@ along with this program. If not, see . *********************************************************************/ #include "platform.h" + +#include "abstract_output.h" #include #include "composite.h" #include "cursor.h" @@ -27,11 +29,13 @@ #include "outline.h" #include "pointer_input.h" #include "scene.h" +#include "screens.h" #include "screenedge.h" #include "wayland_server.h" #include "colorcorrection/manager.h" #include +#include namespace KWin { @@ -116,11 +120,86 @@ new InputRedirectionCursor(parent); } -void Platform::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) +void Platform::requestOutputsChange(KWayland::Server::OutputConfigurationInterface *config) +{ + if (!m_supportsOutputChanges) { + qCWarning(KWIN_CORE) << "This backend does not support configuration changes."; + config->setFailed(); + return; + } + + using Enablement = KWayland::Server::OutputDeviceInterface::Enablement; + + const auto changes = config->changes(); + bool countChanged = false; + + //process all non-disabling changes + for (auto it = changes.begin(); it != changes.end(); it++) { + const KWayland::Server::OutputChangeSet *changeset = it.value(); + + auto output = findOutput(it.key()->uuid()); + if (!output) { + qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid(); + continue; + } + + if (changeset->enabledChanged() && + changeset->enabled() == Enablement::Enabled) { + output->setEnabled(true); + enableOutput(output, true); + countChanged = true; + } + output->applyChanges(changeset); + } + + //process any disable requests + for (auto it = changes.begin(); it != changes.end(); it++) { + const KWayland::Server::OutputChangeSet *changeset = it.value(); + + if (changeset->enabledChanged() && + changeset->enabled() == Enablement::Disabled) { + if (enabledOutputs().count() == 1) { + // TODO: check beforehand this condition and set failed otherwise + // TODO: instead create a dummy output? + qCWarning(KWIN_CORE) << "Not disabling final screen" << it.key()->uuid(); + continue; + } + auto output = findOutput(it.key()->uuid()); + if (!output) { + qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid(); + continue; + } + output->setEnabled(false); + enableOutput(output, false); + countChanged = true; + } + } + + if (countChanged) { + emit screensQueried(); + } else { + emit screens()->changed(); + } + config->setApplied(); +} + +AbstractOutput *Platform::findOutput(const QByteArray &uuid) { - qCWarning(KWIN_CORE) << "This backend does not support configuration changes."; + const auto outs = outputs(); + auto it = std::find_if(outs.constBegin(), outs.constEnd(), + [uuid](AbstractOutput *output) { + return output->uuid() == uuid; } + ); + if (it != outs.constEnd()) { + return *it; + } + return nullptr; +} - config->setFailed(); +void Platform::enableOutput(AbstractOutput *output, bool enable) +{ + Q_UNUSED(output) + Q_UNUSED(enable) } void Platform::setSoftWareCursor(bool set) diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -42,17 +42,6 @@ struct gbm_device; struct gbm_surface; -namespace KWayland -{ -namespace Server -{ -class OutputInterface; -class OutputDeviceInterface; -class OutputChangeSet; -class OutputManagementInterface; -} -} - namespace KWin { @@ -75,7 +64,6 @@ explicit DrmBackend(QObject *parent = nullptr); ~DrmBackend() override; - void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) override; Screens *createScreens(QObject *parent = nullptr) override; QPainterBackend *createQPainterBackend() override; OpenGLBackend* createOpenGLBackend() override; @@ -99,6 +87,8 @@ return m_enabledOutputs; } + void enableOutput(AbstractOutput *output, bool enable) override; + QVector planes() const { return m_planes; } @@ -173,7 +163,6 @@ void writeOutputsConfiguration(); QByteArray generateOutputConfigurationUuid() const; DrmOutput *findOutput(quint32 connector); - DrmOutput *findOutput(const QByteArray &uuid); QScopedPointer m_udev; QScopedPointer m_udevMonitor; int m_fd = -1; @@ -201,7 +190,6 @@ QVector m_planes; QVector m_overlayPlanes; QScopedPointer m_dpmsFilter; - KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr; gbm_device *m_gbmDevice = nullptr; }; diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -40,7 +40,6 @@ #endif // KWayland #include -#include // KF5 #include #include @@ -83,6 +82,7 @@ } #endif setSupportsGammaControl(true); + supportsOutputChanges(); } DrmBackend::~DrmBackend() @@ -558,54 +558,16 @@ return hash.result().toHex().left(10); } -void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) +void DrmBackend::enableOutput(AbstractOutput *output, bool enable) { - const auto changes = config->changes(); - bool countChanged = false; - - //process all non-disabling 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(); - continue; - } - if (changeset->enabledChanged() && changeset->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Enabled) { - drmoutput->setEnabled(true); - m_enabledOutputs << drmoutput; - emit outputAdded(drmoutput); - countChanged = true; - } - drmoutput->setChanges(changeset); - } - //process any disable requests - for (auto it = changes.begin(); it != changes.end(); it++) { - KWayland::Server::OutputChangeSet *changeset = it.value(); - if (changeset->enabledChanged() && changeset->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Disabled) { - if (m_enabledOutputs.count() == 1) { - qCWarning(KWIN_DRM) << "Not disabling final screen" << it.key()->uuid(); - continue; - } - auto drmoutput = findOutput(it.key()->uuid()); - if (drmoutput == nullptr) { - qCWarning(KWIN_DRM) << "Could NOT find DrmOutput matching " << it.key()->uuid(); - continue; - } - drmoutput->setEnabled(false); - m_enabledOutputs.removeOne(drmoutput); - emit outputRemoved(drmoutput); - countChanged = true; - } - } - - if (countChanged) { - emit screensQueried(); + auto *drmOutput = static_cast(output); + if (enable) { + m_enabledOutputs << drmOutput; + emit outputAdded(drmOutput); } else { - emit screens()->changed(); + m_enabledOutputs.removeOne(drmOutput); + emit outputRemoved(drmOutput); } - config->setApplied(); } DrmOutput *DrmBackend::findOutput(quint32 connector) @@ -619,17 +581,6 @@ 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; -} - bool DrmBackend::present(DrmBuffer *buffer, DrmOutput *output) { if (!buffer || buffer->bufferId() == 0) { diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -72,10 +72,6 @@ return m_dpmsModePending == DpmsMode::On; } - QByteArray uuid() const { - return m_uuid; - } - const DrmCrtc *crtc() const { return m_crtc; } diff --git a/wayland_server.cpp b/wayland_server.cpp --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -452,9 +452,7 @@ m_outputManagement = m_display->createOutputManagement(m_display); connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested, - this, [this](KWayland::Server::OutputConfigurationInterface *config) { - kwinApp()->platform()->configurationChangeRequested(config); - }); + kwinApp()->platform(), &Platform::requestOutputsChange); m_outputManagement->create(); m_xdgOutputManager = m_display->createXdgOutputManager(m_display);