diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -65,7 +65,8 @@ None = 0, ///< None of the mentioned features are supported. PrimaryDisplay = 1, ///< The backend knows about the concept of a primary display, this is mostly limited to X11. Writable = 1 << 1, ///< The backend supports setting the config, it's not read-only. - PerOutputScaling = 1 << 2 ///< The backend supports scaling each output individually. + PerOutputScaling = 1 << 2, ///< The backend supports scaling each output individually. + OutputReplication = 1 << 3, ///< The backend supports replication of outputs. }; Q_DECLARE_FLAGS(Features, Feature) diff --git a/src/configserializer.cpp b/src/configserializer.cpp --- a/src/configserializer.cpp +++ b/src/configserializer.cpp @@ -92,6 +92,7 @@ obj[QLatin1String("clones")] = serializeList(output->clones()); //obj[QLatin1String("edid")] = output->edid()->raw(); obj[QLatin1String("sizeMM")] = serializeSize(output->sizeMm()); + obj[QLatin1String("replicationSource")] = output->replicationSource(); QJsonArray modes; Q_FOREACH (const ModePtr &mode, output->modes()) { @@ -251,6 +252,8 @@ output->setPrimary(value.toBool()); } else if (key == QLatin1String("clones")) { output->setClones(deserializeList(value.value())); + } else if (key == QLatin1String("replicationSource")) { + output->setReplicationSource(value.toInt()); } else if (key == QLatin1String("sizeMM")) { output->setSizeMm(deserializeSize(value.value())); } else if (key == QLatin1String("modes")) { diff --git a/src/output.h b/src/output.h --- a/src/output.h +++ b/src/output.h @@ -56,6 +56,8 @@ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY isEnabledChanged) Q_PROPERTY(bool primary READ isPrimary WRITE setPrimary NOTIFY isPrimaryChanged) Q_PROPERTY(QList clones READ clones WRITE setClones NOTIFY clonesChanged) + Q_PROPERTY(int replicationSource READ replicationSource + WRITE setReplicationSource NOTIFY replicationSourceChanged) Q_PROPERTY(KScreen::Edid* edid READ edid CONSTANT) Q_PROPERTY(QSize sizeMm READ sizeMm CONSTANT) Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged) @@ -190,9 +192,41 @@ bool isPrimary() const; void setPrimary(bool primary); + /** + * @brief Immutable clones because of hardware restrictions + * + * Clones are set symmetcally on all outputs. The list contains ids + * for all other outputs being clones of this output. + * + * @return List of output ids being clones of each other. + */ QList clones() const; + /** + * @brief Set the clones list. + * + * When this output is part of a configuration this call is followed by + * similar calls on other outputs making the lists in all outputs + * symmetric. + * @param outputlist + */ void setClones(const QList &outputlist); + /** + * @brief Provides the source for an ongoing replication + * + * If the returned output id is non-null this output is a replica of the + * returned output. If null is returned the output is no replica of any + * other output. + * + * @return Replication source output id of this output + */ + int replicationSource() const; + /** + * @brief Set the replication source. + * @param source + */ + void setReplicationSource(int source); + void setEdid(const QByteArray &rawData); /** @@ -212,6 +246,16 @@ QSize sizeMm() const; void setSizeMm(const QSize &size); + /** + * Returns if the output needs to be taken account for in the overall compositor/screen + * space and if it should be depicted on its own in a graphical view for repositioning. + * + * @return true if the output is positionable in compositor/screen space. + * + * @since 5.17 + */ + bool isPositionable() const; + /** * Returns a rectangle containing the currently set output position and * size. @@ -269,6 +313,7 @@ void isEnabledChanged(); void isPrimaryChanged(); void clonesChanged(); + void replicationSourceChanged(); void scaleChanged(); void followPreferredModeChanged(bool followPreferredMode); diff --git a/src/output.cpp b/src/output.cpp --- a/src/output.cpp +++ b/src/output.cpp @@ -37,6 +37,7 @@ Private(): id(0), type(Unknown), + replicationSource(0), rotation(None), scale(1.0), connected(false), @@ -51,6 +52,7 @@ type(other.type), icon(other.icon), clones(other.clones), + replicationSource(other.replicationSource), currentMode(other.currentMode), preferredMode(other.preferredMode), preferredModes(other.preferredModes), @@ -81,6 +83,7 @@ QString icon; ModeList modeList; QList clones; + int replicationSource; QString currentMode; QString preferredMode; QStringList preferredModes; @@ -484,6 +487,22 @@ Q_EMIT clonesChanged(); } +int Output::replicationSource() const +{ + return d->replicationSource; +} + +void Output::setReplicationSource(int source) +{ + if (d->replicationSource == source) { + return; + } + + d->replicationSource = source; + + Q_EMIT replicationSourceChanged(); +} + void Output::setEdid(const QByteArray& rawData) { Q_ASSERT(d->edid.isNull()); @@ -518,6 +537,11 @@ } } +bool Output::isPositionable() const +{ + return isConnected() && isEnabled() && !replicationSource(); +} + QRect Output::geometry() const { if (!currentMode()) { @@ -590,6 +614,10 @@ changes << &Output::clonesChanged; setClones(other->d->clones);; } + if (d->replicationSource != other->d->replicationSource) { + changes << &Output::replicationSourceChanged; + setReplicationSource(other->d->replicationSource);; + } if (!d->compareModeList(d->modeList, other->d->modeList)) { changes << &Output::outputChanged; changes << &Output::modesChanged; @@ -627,6 +655,7 @@ << "pos:" << output->pos() << "res:" << output->size() << "modeId:" << output->currentModeId() << "scale:" << output->scale() + << "clone:" << (output->clones().isEmpty() ? "no" : "yes") << "followPreferredMode:" << output->followPreferredMode() << ")"; } else { diff --git a/src/setconfigoperation.cpp b/src/setconfigoperation.cpp --- a/src/setconfigoperation.cpp +++ b/src/setconfigoperation.cpp @@ -141,7 +141,7 @@ int offsetX = INT_MAX; int offsetY = INT_MAX; Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { - if (!output->isConnected() || !output->isEnabled()) { + if (!output->isPositionable()) { continue; } offsetX = qMin(output->pos().x(), offsetX);