diff --git a/autotests/testscreenconfig.cpp b/autotests/testscreenconfig.cpp --- a/autotests/testscreenconfig.cpp +++ b/autotests/testscreenconfig.cpp @@ -38,14 +38,15 @@ private Q_SLOTS: void initTestCase(); + void cleanupTestCase(); + void singleOutput(); void singleOutputWithoutPreferred(); void multiOutput(); void clonesOutput(); void configCanBeApplied(); void supportedFeatures(); void testInvalidMode(); - void cleanupTestCase(); void testOutputPositionNormalization(); }; @@ -97,6 +98,7 @@ QCOMPARE(screen->currentSize(), QSize(1280, 800)); QCOMPARE(config->outputs().count(), 1); + QCOMPARE(config->connectedOutputsHash(), QStringLiteral("6238ed9400a789a4925099b532ec8c61")); const OutputPtr output = config->outputs().take(1); QVERIFY(!output.isNull()); @@ -113,6 +115,7 @@ QCOMPARE(output->isConnected(), true); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); + QCOMPARE(output->hash(), QStringLiteral("9384061b2b87ad193f841e07d60e9e1a")); //QCOMPARE(output->isEmbedded(), true); QVERIFY2(output->clones().isEmpty(), "In singleOutput is impossible to have clones"); @@ -138,15 +141,16 @@ { qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "multipleoutput.json"); - const ConfigPtr config = getConfig(); + ConfigPtr config = getConfig(); QVERIFY(!config.isNull()); const ScreenPtr screen = config->screen(); QVERIFY(!screen.isNull()); QCOMPARE(screen->minSize(), QSize(320, 200)); QCOMPARE(screen->maxSize(), QSize(8192, 8192)); QCOMPARE(screen->currentSize(), QSize(3200, 1880)); + QCOMPARE(config->connectedOutputsHash(), QStringLiteral("a852c6ad86a3150d6a49219024deda60")); QCOMPARE(config->outputs().count(), 2); const OutputPtr output = config->outputs().take(2); @@ -164,12 +168,36 @@ QCOMPARE(output->isConnected(), true); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), false); + QCOMPARE(output->hash(), QStringLiteral("be55eeb5fcc1e775f321c1ae3aa02ef0")); QVERIFY2(output->clones().isEmpty(), "This simulates extended output, no clones"); const ModePtr mode = output->currentMode(); QVERIFY(!mode.isNull()); QCOMPARE(mode->size(), QSize(1920, 1080)); QCOMPARE(mode->refreshRate(), (float)60.0); + + QSignalSpy removeSpy(config.data(), &Config::outputRemoved); + QVERIFY(removeSpy.isValid()); + QSignalSpy connectedOutputsHashSpy(config.data(), &Config::connectedOutputsHashChanged); + QVERIFY(connectedOutputsHashSpy.isValid()); + + config->removeOutput(output->id()); + + QCOMPARE(config->outputs().count(), 1); + QCOMPARE(removeSpy.count(), 1); + QCOMPARE(connectedOutputsHashSpy.count(), 1); + QCOMPARE(config->outputs().take(1)->hash(), QStringLiteral("9384061b2b87ad193f841e07d60e9e1a")); + QCOMPARE(config->connectedOutputsHash(), QStringLiteral("6238ed9400a789a4925099b532ec8c61")); + + QSignalSpy addSpy(config.data(), &Config::outputAdded); + QVERIFY(addSpy.isValid()); + + config->addOutput(output); + + QCOMPARE(config->outputs().count(), 2); + QCOMPARE(addSpy.count(), 1); + QCOMPARE(connectedOutputsHashSpy.count(), 2); + QCOMPARE(config->connectedOutputsHash(), QStringLiteral("a852c6ad86a3150d6a49219024deda60")); } void testScreenConfig::clonesOutput() diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -168,6 +168,7 @@ void outputAdded(const KScreen::OutputPtr &output); void outputRemoved(int outputId); void primaryOutputChanged(const KScreen::OutputPtr &output); + void connectedOutputsHashChanged(); private: Q_DISABLE_COPY(Config) diff --git a/src/config.cpp b/src/config.cpp --- a/src/config.cpp +++ b/src/config.cpp @@ -81,15 +81,35 @@ output->disconnect(q); Q_EMIT q->outputRemoved(outputId); + recalculateConnectedOutputsHash(); return iter; } + void recalculateConnectedOutputsHash() + { + QStringList hashedOutputs; + const auto outputs = q->connectedOutputs(); + for (const OutputPtr &output : outputs) { + hashedOutputs << output->hash(); + } + std::sort(hashedOutputs.begin(), hashedOutputs.end()); + const auto byteHash = QCryptographicHash::hash(hashedOutputs.join(QString()).toLatin1(), + QCryptographicHash::Md5); + const auto hash = QString::fromLatin1(byteHash.toHex()); + if (hash == connectedOutputsHash) { + return; + } + connectedOutputsHash = hash; + Q_EMIT q->connectedOutputsHashChanged(); + } + bool valid; ScreenPtr screen; OutputPtr primaryOutput; OutputList outputs; Features supportedFeatures; + QString connectedOutputsHash; private: Config *q; @@ -223,16 +243,7 @@ QString Config::connectedOutputsHash() const { - QStringList hashedOutputs; - - const auto outputs = connectedOutputs(); - for (const OutputPtr &output : outputs) { - hashedOutputs << output->hash(); - } - std::sort(hashedOutputs.begin(), hashedOutputs.end()); - const auto hash = QCryptographicHash::hash(hashedOutputs.join(QString()).toLatin1(), - QCryptographicHash::Md5); - return QString::fromLatin1(hash.toHex()); + return d->connectedOutputsHash; } ScreenPtr Config::screen() const @@ -317,8 +328,15 @@ d->outputs.insert(output->id(), output); connect(output.data(), &KScreen::Output::isPrimaryChanged, d, &KScreen::Config::Private::onPrimaryOutputChanged); + connect(output.data(), &KScreen::Output::isConnectedChanged, + d, &KScreen::Config::Private::recalculateConnectedOutputsHash); + if (!output->edid()) { + connect(output.data(), &KScreen::Output::edidSet, + d, &KScreen::Config::Private::recalculateConnectedOutputsHash); + } Q_EMIT outputAdded(output); + d->recalculateConnectedOutputsHash(); if (output->isPrimary()) { setPrimaryOutput(output); diff --git a/src/output.h b/src/output.h --- a/src/output.h +++ b/src/output.h @@ -251,6 +251,7 @@ void clonesChanged(); void scaleChanged(); void followPreferredModeChanged(bool followPreferredMode); + void edidSet(); /** The mode list changed. * diff --git a/src/output.cpp b/src/output.cpp --- a/src/output.cpp +++ b/src/output.cpp @@ -477,6 +477,7 @@ { Q_ASSERT(d->edid.isNull()); d->edid.reset(new Edid(rawData)); + Q_EMIT edidSet(); } Edid *Output::edid() const @@ -593,6 +594,7 @@ // Non-notifyable changes if (other->d->edid) { d->edid.reset(other->d->edid->clone()); + changes << &Output::edidSet; } blockSignals(keepBlocked);