diff --git a/kded/CMakeLists.txt b/kded/CMakeLists.txt --- a/kded/CMakeLists.txt +++ b/kded/CMakeLists.txt @@ -4,7 +4,7 @@ set(kscreen_daemon_SRCS daemon.cpp - serializer.cpp + config.cpp generator.cpp device.cpp osd.cpp diff --git a/kded/config.h b/kded/config.h new file mode 100644 --- /dev/null +++ b/kded/config.h @@ -0,0 +1,75 @@ +/******************************************************************** +Copyright 2019 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KDED_CONFIG_H +#define KDED_CONFIG_H + +#include +#include + +#include + +#include + +class Config +{ +public: + explicit Config(KScreen::ConfigPtr config); + ~Config() = default; + + static void setDirPath(const QString &path); + + QString id() const; + + bool fileExists() const; + std::unique_ptr readFile(); + std::unique_ptr readOpenLidFile(); + bool writeFile(); + bool writeOpenLidFile(); + + KScreen::ConfigPtr data() const { + return m_data; + } + + void log(); + + void setValidityFlags(KScreen::Config::ValidityFlags flags) { + m_validityFlags = flags; + } + + bool canBeApplied() const; + +private: + friend class TestConfig; + + QString filePath(); + std::unique_ptr readFile(const QString &fileName); + bool writeFile(const QString &filePath); + + bool canBeApplied(KScreen::ConfigPtr config) const; + + // this could probably be done on m_data + KScreen::OutputPtr findOutput(const KScreen::ConfigPtr &config, const QVariantMap &info); + + KScreen::ConfigPtr m_data; + + KScreen::Config::ValidityFlags m_validityFlags; + + static QString s_dirPath; + static QString s_fixedConfigFileName; +}; + +#endif diff --git a/kded/serializer.cpp b/kded/config.cpp rename from kded/serializer.cpp rename to kded/config.cpp --- a/kded/serializer.cpp +++ b/kded/config.cpp @@ -1,24 +1,24 @@ -/************************************************************************************* - * Copyright (C) 2012 by Alejandro Fiestas Olivares * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * - *************************************************************************************/ - -#include "serializer.h" +/******************************************************************** +Copyright 2012 Alejandro Fiestas Olivares +Copyright 2019 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "config.h" #include "kscreen_daemon_debug.h" #include "generator.h" +#include "device.h" #include #include @@ -34,56 +34,86 @@ #include #include -QString Serializer::sConfigPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/"); -QString Serializer::sFixedConfig = QStringLiteral("fixed-config"); -void Serializer::setConfigPath(const QString &path) +QString Config::s_fixedConfigFileName = QStringLiteral("fixed-config"); +QString Config::s_dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/"); + +Config::Config(KScreen::ConfigPtr config) + : m_data(config) +{ +} + +void Config::setDirPath(const QString &path) { - sConfigPath = path; - if (!sConfigPath.endsWith(QLatin1Char('/'))) { - sConfigPath += QLatin1Char('/'); + s_dirPath = path; + if (!s_dirPath.endsWith(QLatin1Char('/'))) { + s_dirPath += QLatin1Char('/'); } } -QString Serializer::configFileName(const QString &configId) +QString Config::filePath() { - if (!QDir().mkpath(sConfigPath)) { + if (!QDir().mkpath(s_dirPath)) { return QString(); } - return sConfigPath % configId; + return s_dirPath % id(); } -QString Serializer::configId(const KScreen::ConfigPtr &config) +QString Config::id() const { - if (!config) { + if (!m_data) { return QString(); } - return config->connectedOutputsHash(); + return m_data->connectedOutputsHash(); +} + +bool Config::fileExists() const +{ + return (QFile::exists(s_dirPath % id()) || QFile::exists(s_dirPath % s_fixedConfigFileName)); } -bool Serializer::configExists(const KScreen::ConfigPtr &config) +std::unique_ptr Config::readFile() { - return Serializer::configExists(Serializer::configId(config)); + if (Device::self()->isLaptop() && !Device::self()->isLidClosed()) { + // We may look for a config that has been set when the lid was closed, Bug: 353029 + const QString lidOpenedFilePath(filePath() % QStringLiteral("_lidOpened")); + const QFile srcFile(lidOpenedFilePath); + + if (srcFile.exists()) { + QFile::remove(filePath()); + if (QFile::copy(lidOpenedFilePath, filePath())) { + QFile::remove(lidOpenedFilePath); + qCDebug(KSCREEN_KDED) << "Restored lid opened config to" << id(); + } + } + } + return readFile(id()); } -bool Serializer::configExists(const QString &id) +std::unique_ptr Config::readOpenLidFile() { - return (QFile::exists(sConfigPath % id) || QFile::exists(sConfigPath % sFixedConfig)); + const QString openLidFilePath = filePath() % QStringLiteral("_lidOpened"); + auto config = readFile(openLidFilePath); + QFile::remove(openLidFilePath); + return config; } -KScreen::ConfigPtr Serializer::loadConfig(const KScreen::ConfigPtr ¤tConfig, const QString &id) +std::unique_ptr Config::readFile(const QString &fileName) { - KScreen::ConfigPtr config = currentConfig->clone(); + if (!m_data) { + return nullptr; + } + KScreen::ConfigPtr config = m_data->clone(); QFile file; - if (QFile::exists(sConfigPath % sFixedConfig)) { - file.setFileName(sConfigPath % sFixedConfig); + if (QFile::exists(s_dirPath % s_fixedConfigFileName)) { + file.setFileName(s_dirPath % s_fixedConfigFileName); qCDebug(KSCREEN_KDED) << "found a fixed config, will use " << file.fileName(); } else { - file.setFileName(configFileName(id)); + file.setFileName(s_dirPath % fileName); } if (!file.open(QIODevice::ReadOnly)) { qCDebug(KSCREEN_KDED) << "failed to open file" << file.fileName(); - return KScreen::ConfigPtr(); + return nullptr; } KScreen::OutputList outputList = config->outputs(); @@ -97,7 +127,7 @@ QSize screenSize; Q_FOREACH(const QVariant &info, outputs) { - KScreen::OutputPtr output = Serializer::findOutput(config, info.toMap()); + KScreen::OutputPtr output = findOutput(config, info.toMap()); if (!output) { continue; } @@ -118,16 +148,57 @@ config->setOutputs(outputList); config->screen()->setCurrentSize(screenSize); + if (!canBeApplied(config)) { + return nullptr; + } + auto cfg = std::unique_ptr(new Config(config)); + cfg->setValidityFlags(m_validityFlags); + return cfg; +} + +bool Config::canBeApplied() const +{ + return canBeApplied(m_data); +} - return config; +bool Config::canBeApplied(KScreen::ConfigPtr config) const +{ +#ifdef KDED_UNIT_TEST + Q_UNUSED(config); + return true; +#else + return KScreen::Config::canBeApplied(config, m_validityFlags); +#endif +} + +bool Config::writeFile() +{ + return writeFile(filePath()); } -bool Serializer::saveConfig(const KScreen::ConfigPtr &config, const QString &configId) +bool Config::writeOpenLidFile() { - if (!config || configId.isEmpty()) { + return writeFile(filePath() % QStringLiteral("_lidOpened")); +} + +static QVariantMap metadata(const KScreen::OutputPtr &output) +{ + QVariantMap metadata; + metadata[QStringLiteral("name")] = output->name(); + if (!output->edid() || !output->edid()->isValid()) { + return metadata; + } + + metadata[QStringLiteral("fullname")] = output->edid()->deviceId(); + return metadata; +} + +bool Config::writeFile(const QString &filePath) +{ + if (!m_data) { return false; } - const KScreen::OutputList outputs = config->outputs(); + const KScreen::OutputList outputs = m_data->outputs(); QVariantList outputList; Q_FOREACH(const KScreen::OutputPtr &output, outputs) { @@ -166,43 +237,23 @@ info[QStringLiteral("mode")] = modeInfo; } - info[QStringLiteral("metadata")] = Serializer::metadata(output); + info[QStringLiteral("metadata")] = metadata(output); outputList.append(info); } - QFile file(configFileName(configId)); + QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { qCWarning(KSCREEN_KDED) << "Failed to open config file for writing! " << file.errorString(); return false; } - file.write(QJsonDocument::fromVariant(outputList).toJson()); qCDebug(KSCREEN_KDED) << "Config saved on: " << file.fileName(); return true; } -void Serializer::removeConfig(const QString &id) -{ - QFile::remove(configFileName(id)); -} - -bool Serializer::moveConfig(const QString &srcId, const QString &destId) -{ - const QFile srcFile(configFileName(srcId)); - if (srcFile.exists()) { - removeConfig(destId); - if (QFile::copy(configFileName(srcId), configFileName(destId))) { - removeConfig(srcId); - qCDebug(KSCREEN_KDED) << "Restored config" << srcId << "to" << destId; - return true; - } - } - return false; -} - -KScreen::OutputPtr Serializer::findOutput(const KScreen::ConfigPtr &config, const QVariantMap& info) +KScreen::OutputPtr Config::findOutput(const KScreen::ConfigPtr &config, const QVariantMap& info) { const KScreen::OutputList outputs = config->outputs(); // As individual outputs are indexed by a hash of their edid, which is not unique, // to be able to tell apart multiple identical outputs, these need special treatment @@ -293,14 +344,15 @@ return KScreen::OutputPtr(); } -QVariantMap Serializer::metadata(const KScreen::OutputPtr &output) +void Config::log() { - QVariantMap metadata; - metadata[QStringLiteral("name")] = output->name(); - if (!output->edid() || !output->edid()->isValid()) { - return metadata; + if (!m_data) { + return; + } + const auto outputs = m_data->outputs(); + for (const auto o : outputs) { + if (o->isConnected()) { + qCDebug(KSCREEN_KDED) << o; + } } - - metadata[QStringLiteral("fullname")] = output->edid()->deviceId(); - return metadata; } diff --git a/kded/daemon.h b/kded/daemon.h --- a/kded/daemon.h +++ b/kded/daemon.h @@ -26,6 +26,10 @@ #include +#include + +class Config; + namespace KScreen { class ConfigOperation; @@ -71,12 +75,14 @@ void applyOsdAction(KScreen::OsdAction::Action action); void doApplyConfig(const KScreen::ConfigPtr &config); + void doApplyConfig(std::unique_ptr config); + void refreshConfig(); void monitorConnectedChange(); - void disableOutput(KScreen::ConfigPtr &config, KScreen::OutputPtr &output); + void disableOutput(KScreen::OutputPtr &output); void showOsd(const QString &icon, const QString &text); - KScreen::ConfigPtr m_monitoredConfig; + std::unique_ptr m_monitoredConfig; bool m_monitoring; QTimer* m_changeCompressor; QTimer* m_saveTimer; diff --git a/kded/daemon.cpp b/kded/daemon.cpp --- a/kded/daemon.cpp +++ b/kded/daemon.cpp @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "daemon.h" -#include "serializer.h" +#include "config.h" #include "generator.h" #include "device.h" #include "kscreenadaptor.h" @@ -46,7 +46,6 @@ KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& ) : KDEDModule(parent) - , m_monitoredConfig(nullptr) , m_monitoring(false) , m_changeCompressor(new QTimer(this)) , m_saveTimer(nullptr) @@ -65,9 +64,10 @@ return; } - m_monitoredConfig = qobject_cast(op)->config(); - qCDebug(KSCREEN_KDED) << "Config" << m_monitoredConfig.data() << "is ready"; - KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig); + m_monitoredConfig = std::unique_ptr(new Config(qobject_cast(op)->config())); + m_monitoredConfig->setValidityFlags(KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); + qCDebug(KSCREEN_KDED) << "Config" << m_monitoredConfig->data().data() << "is ready"; + KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig->data()); init(); }); @@ -119,18 +119,31 @@ connect(Generator::self(), &Generator::ready, this, &KScreenDaemon::applyConfig); - Generator::self()->setCurrentConfig(m_monitoredConfig); + Generator::self()->setCurrentConfig(m_monitoredConfig->data()); monitorConnectedChange(); } void KScreenDaemon::doApplyConfig(const KScreen::ConfigPtr& config) { - qCDebug(KSCREEN_KDED) << "doApplyConfig()"; + qCDebug(KSCREEN_KDED) << "Do set and apply specific config"; + auto configWrapper = std::unique_ptr(new Config(config)); + configWrapper->setValidityFlags(KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); + doApplyConfig(std::move(configWrapper)); +} + +void KScreenDaemon::doApplyConfig(std::unique_ptr config) +{ + setMonitorForChanges(false); // TODO: remove? + m_monitoredConfig = std::move(config); + refreshConfig(); +} + +void KScreenDaemon::refreshConfig() +{ setMonitorForChanges(false); - m_monitoredConfig = config; - KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig); + KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig->data()); - connect(new KScreen::SetConfigOperation(config), &KScreen::SetConfigOperation::finished, this, + connect(new KScreen::SetConfigOperation(m_monitoredConfig->data()), &KScreen::SetConfigOperation::finished, this, [&]() { qCDebug(KSCREEN_KDED) << "Config applied"; setMonitorForChanges(true); @@ -140,31 +153,24 @@ void KScreenDaemon::applyConfig() { qCDebug(KSCREEN_KDED) << "Applying config"; - if (Serializer::configExists(m_monitoredConfig)) { + if (m_monitoredConfig->fileExists()) { applyKnownConfig(); return; } - applyIdealConfig(); } void KScreenDaemon::applyKnownConfig() { - const QString configId = Serializer::configId(m_monitoredConfig); - qCDebug(KSCREEN_KDED) << "Applying known config" << configId; + qCDebug(KSCREEN_KDED) << "Applying known config"; - // We may look for a config that has been set when the lid was closed, Bug: 353029 - if (Device::self()->isLaptop() && !Device::self()->isLidClosed()) { - Serializer::moveConfig(configId + QLatin1String("_lidOpened"), configId); - } - - KScreen::ConfigPtr config = Serializer::loadConfig(m_monitoredConfig, configId); - // It's possible that the Serializer returned a nullptr - if (!config || !KScreen::Config::canBeApplied(config, KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen)) { + std::unique_ptr readInConfig = m_monitoredConfig->readFile(); + if (readInConfig) { + doApplyConfig(std::move(readInConfig)); + } else { + // loading not succesful, fall back to ideal config applyIdealConfig(); - return; } - doApplyConfig(config); } void KScreenDaemon::applyLayoutPreset(const QString &presetName) @@ -213,44 +219,33 @@ void KScreenDaemon::applyIdealConfig() { - if (m_monitoredConfig->connectedOutputs().count() < 2) { + if (m_monitoredConfig->data()->connectedOutputs().count() < 2) { m_osdManager->hideOsd(); - doApplyConfig(Generator::self()->idealConfig(m_monitoredConfig)); + doApplyConfig(Generator::self()->idealConfig(m_monitoredConfig->data())); } else { qCDebug(KSCREEN_KDED) << "Getting ideal config from user via OSD..."; auto action = m_osdManager->showActionSelector(); connect(action, &KScreen::OsdAction::selected, this, &KScreenDaemon::applyOsdAction); } } -void logConfig(const KScreen::ConfigPtr &config) -{ - if (config) { - foreach (auto o, config->outputs()) { - if (o->isConnected()) { - qCDebug(KSCREEN_KDED) << o; - } - } - } -} - void KScreenDaemon::configChanged() { qCDebug(KSCREEN_KDED) << "Change detected"; - logConfig(m_monitoredConfig); + m_monitoredConfig->log(); // Modes may have changed, fix-up current mode id bool changed = false; - Q_FOREACH(const KScreen::OutputPtr &output, m_monitoredConfig->outputs()) { + Q_FOREACH(const KScreen::OutputPtr &output, m_monitoredConfig->data()->outputs()) { if (output->isConnected() && output->isEnabled() && (output->currentMode().isNull() || (output->followPreferredMode() && output->currentModeId() != output->preferredModeId()))) { qCDebug(KSCREEN_KDED) << "Current mode was" << output->currentModeId() << ", setting preferred mode" << output->preferredModeId(); output->setCurrentModeId(output->preferredModeId()); changed = true; } } if (changed) { - doApplyConfig(m_monitoredConfig); + refreshConfig(); } // Reset timer, delay the writeback @@ -270,13 +265,12 @@ // We assume the config is valid, since it's what we got, but we are interested // in the "at least one enabled screen" check - const bool valid = KScreen::Config::canBeApplied(m_monitoredConfig, KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); - if (valid) { - Serializer::saveConfig(m_monitoredConfig, Serializer::configId(m_monitoredConfig)); - logConfig(m_monitoredConfig); + if (m_monitoredConfig->canBeApplied()) { + m_monitoredConfig->writeFile(); + m_monitoredConfig->log(); } else { qCWarning(KSCREEN_KDED) << "Config does not have at least one screen enabled, WILL NOT save this config, this is not what user wants."; - logConfig(m_monitoredConfig); + m_monitoredConfig->log(); } } @@ -310,7 +304,7 @@ { // Ignore this when we don't have any external monitors, we can't turn off our // only screen - if (m_monitoredConfig->connectedOutputs().count() == 1) { + if (m_monitoredConfig->data()->connectedOutputs().count() == 1) { return; } @@ -326,13 +320,8 @@ // We should have a config with "_lidOpened" suffix lying around. If not, // then the configuration has changed while the lid was closed and we just // use applyConfig() and see what we can do ... - - const QString openConfigId = Serializer::configId(m_monitoredConfig) + QLatin1String("_lidOpened"); - if (Serializer::configExists(openConfigId)) { - const KScreen::ConfigPtr openedConfig = Serializer::loadConfig(m_monitoredConfig, openConfigId); - Serializer::removeConfig(openConfigId); - - doApplyConfig(openedConfig); + if (auto openCfg = m_monitoredConfig->readOpenLidFile()) { + doApplyConfig(std::move(openCfg)); } } } @@ -352,15 +341,14 @@ // and I'm not parsing PowerDevil's configs... qCDebug(KSCREEN_KDED) << "Lid closed without system going to suspend -> turning off the screen"; - for (KScreen::OutputPtr &output : m_monitoredConfig->outputs()) { + for (KScreen::OutputPtr &output : m_monitoredConfig->data()->outputs()) { if (output->type() == KScreen::Output::Panel) { if (output->isConnected() && output->isEnabled()) { // Save the current config with opened lid, just so that we know // how to restore it later - const QString configId = Serializer::configId(m_monitoredConfig) + QLatin1String("_lidOpened"); - Serializer::saveConfig(m_monitoredConfig, configId); - disableOutput(m_monitoredConfig, output); - doApplyConfig(m_monitoredConfig); + m_monitoredConfig->writeOpenLidFile(); + disableOutput(output); + refreshConfig(); return; } } @@ -380,21 +368,21 @@ if (output->isConnected()) { Q_EMIT outputConnected(output->name()); - if (!Serializer::configExists(m_monitoredConfig)) { + if (!m_monitoredConfig->fileExists()) { Q_EMIT unknownOutputConnected(output->name()); } } } void KScreenDaemon::monitorConnectedChange() { - KScreen::OutputList outputs = m_monitoredConfig->outputs(); + KScreen::OutputList outputs = m_monitoredConfig->data()->outputs(); Q_FOREACH(const KScreen::OutputPtr &output, outputs) { connect(output.data(), &KScreen::Output::isConnectedChanged, this, &KScreenDaemon::outputConnectedChanged, Qt::UniqueConnection); } - connect(m_monitoredConfig.data(), &KScreen::Config::outputAdded, this, + connect(m_monitoredConfig->data().data(), &KScreen::Config::outputAdded, this, [this] (const KScreen::OutputPtr output) { if (output->isConnected()) { m_changeCompressor->start(); @@ -404,7 +392,7 @@ Qt::UniqueConnection); }, Qt::UniqueConnection ); - connect(m_monitoredConfig.data(), &KScreen::Config::outputRemoved, + connect(m_monitoredConfig->data().data(), &KScreen::Config::outputRemoved, this, &KScreenDaemon::applyConfig, static_cast(Qt::QueuedConnection | Qt::UniqueConnection)); } @@ -426,13 +414,13 @@ } } -void KScreenDaemon::disableOutput(KScreen::ConfigPtr &config, KScreen::OutputPtr &output) +void KScreenDaemon::disableOutput(KScreen::OutputPtr &output) { const QRect geom = output->geometry(); qCDebug(KSCREEN_KDED) << "Laptop geometry:" << geom << output->pos() << (output->currentMode() ? output->currentMode()->size() : QSize()); // Move all outputs right from the @p output to left - for (KScreen::OutputPtr &otherOutput : config->outputs()) { + for (KScreen::OutputPtr &otherOutput : m_monitoredConfig->data()->outputs()) { if (otherOutput == output || !otherOutput->isConnected() || !otherOutput->isEnabled()) { continue; } diff --git a/kded/serializer.h b/kded/serializer.h deleted file mode 100644 --- a/kded/serializer.h +++ /dev/null @@ -1,50 +0,0 @@ -/************************************************************************************* - * Copyright (C) 2012 by Alejandro Fiestas Olivares * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * - *************************************************************************************/ - -#ifndef KDED_SERIALIZER_H -#define KDED_SERIALIZER_H - -#include -#include - -#include - -class Serializer -{ -public: - static QString configId(const KScreen::ConfigPtr &config); - static bool configExists(const KScreen::ConfigPtr &config); - static bool configExists(const QString& id); - static KScreen::ConfigPtr loadConfig(const KScreen::ConfigPtr ¤tConfig, const QString& id); - static bool saveConfig(const KScreen::ConfigPtr &config, const QString &configId); - static void removeConfig(const QString &id); - static bool moveConfig(const QString &srcId, const QString &destId); - - static KScreen::OutputPtr findOutput(const KScreen::ConfigPtr &config, const QVariantMap &info); - static QVariantMap metadata(const KScreen::OutputPtr &output); - - static void setConfigPath(const QString &path); -private: - friend class TestSerializer; - static QString configFileName(const QString &configId); - - static QString sConfigPath; - static QString sFixedConfig; -}; - -#endif //KDED_SERIALIZER_H diff --git a/tests/kded/CMakeLists.txt b/tests/kded/CMakeLists.txt --- a/tests/kded/CMakeLists.txt +++ b/tests/kded/CMakeLists.txt @@ -1,11 +1,13 @@ include_directories(${CMAKE_BINARY_DIR}) +add_definitions(-DKDED_UNIT_TEST) + macro(ADD_KDED_TEST testname) set(test_SRCS ${testname}.cpp ${CMAKE_SOURCE_DIR}/kded/generator.cpp ${CMAKE_SOURCE_DIR}/kded/device.cpp - ${CMAKE_SOURCE_DIR}/kded/serializer.cpp + ${CMAKE_SOURCE_DIR}/kded/config.cpp #${CMAKE_SOURCE_DIR}/kded/daemon.cpp ) ecm_qt_declare_logging_category(test_SRCS HEADER kscreen_daemon_debug.h IDENTIFIER KSCREEN_KDED CATEGORY_NAME kscreen.kded) @@ -24,5 +26,5 @@ endmacro() add_kded_test(testgenerator) -add_kded_test(serializertest) +add_kded_test(configtest) #add_kded_test(testdaemon) diff --git a/tests/kded/serializertest.cpp b/tests/kded/configtest.cpp rename from tests/kded/serializertest.cpp rename to tests/kded/configtest.cpp --- a/tests/kded/serializertest.cpp +++ b/tests/kded/configtest.cpp @@ -1,22 +1,21 @@ -/************************************************************************************* - * Copyright (C) 2015 by Daniel Vrátil * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * - *************************************************************************************/ - -#include "../../kded/serializer.h" +/******************************************************************** +Copyright 2015 Daniel Vrátil +Copyright 2018 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "../../kded/config.h" #include #include @@ -27,9 +26,9 @@ #include #include -using namespace KScreen; +#include -class TestSerializer : public QObject +class TestConfig : public QObject { Q_OBJECT @@ -50,10 +49,10 @@ void testFixedConfig(); private: - KScreen::ConfigPtr createConfig(bool output1Connected, bool output2Conected); + std::unique_ptr createConfig(bool output1Connected, bool output2Conected); }; -ConfigPtr TestSerializer::createConfig(bool output1Connected, bool output2Connected) +std::unique_ptr TestConfig::createConfig(bool output1Connected, bool output2Connected) { KScreen::ScreenPtr screen = KScreen::ScreenPtr::create(); screen->setCurrentSize(QSize(1920, 1080)); @@ -96,21 +95,24 @@ config->addOutput(output1); config->addOutput(output2); - return config; + auto configWrapper = std::unique_ptr(new Config(config)); + + return configWrapper; } -void TestSerializer::initTestCase() +void TestConfig::initTestCase() { qputenv("KSCREEN_LOGGING", "false"); - Serializer::setConfigPath(QStringLiteral(TEST_DATA "/serializerdata/")); + Config::setDirPath(QStringLiteral(TEST_DATA "serializerdata/")); } -void TestSerializer::testSimpleConfig() +void TestConfig::testSimpleConfig() { - KScreen::ConfigPtr config = createConfig(true, false); - config = Serializer::loadConfig(config, QStringLiteral("simpleConfig.json")); - QVERIFY(config); + auto configWrapper = createConfig(true, false); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("simpleConfig.json"))); + auto config = configWrapper->data(); + QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 1); auto output = config->connectedOutputs().first(); @@ -126,10 +128,12 @@ QCOMPARE(screen->currentSize(), QSize(1920, 1280)); } -void TestSerializer::testTwoScreenConfig() +void TestConfig::testTwoScreenConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("twoScreenConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("twoScreenConfig.json"))); + + auto config = configWrapper->data(); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); @@ -156,10 +160,12 @@ QCOMPARE(screen->currentSize(), QSize(3200, 1280)); } -void TestSerializer::testRotatedScreenConfig() +void TestConfig::testRotatedScreenConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("rotatedScreenConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("rotatedScreenConfig.json"))); + + auto config = configWrapper->data(); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); @@ -186,10 +192,12 @@ QCOMPARE(screen->currentSize(), QSize(2944, 1280)); } -void TestSerializer::testDisabledScreenConfig() +void TestConfig::testDisabledScreenConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("disabledScreenConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("disabledScreenConfig.json"))); + + auto config = configWrapper->data(); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); @@ -211,58 +219,64 @@ QCOMPARE(screen->currentSize(), QSize(1920, 1280)); } -void TestSerializer::testConfig404() +void TestConfig::testConfig404() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("filenotfoundConfig.json")); - QVERIFY(!config); - QVERIFY(config.isNull()); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("filenotfoundConfig.json"))); + + QVERIFY(!configWrapper); } -void TestSerializer::testCorruptConfig() +void TestConfig::testCorruptConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("corruptConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("corruptConfig.json"))); + auto config = configWrapper->data(); + QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } -void TestSerializer::testCorruptEmptyConfig() +void TestConfig::testCorruptEmptyConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("corruptEmptyConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("corruptEmptyConfig.json"))); + auto config = configWrapper->data(); + QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } -void TestSerializer::testCorruptUselessConfig() +void TestConfig::testCorruptUselessConfig() { - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("corruptUselessConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("corruptUselessConfig.json"))); + auto config = configWrapper->data(); + QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } -void TestSerializer::testNullConfig() +void TestConfig::testNullConfig() { - KScreen::ConfigPtr nullConfig; - QVERIFY(!nullConfig); + Config nullConfig(nullptr); + QVERIFY(!nullConfig.data()); // Null configs have empty configIds - QVERIFY(Serializer::configId(nullConfig).isEmpty()); + QVERIFY(nullConfig.id().isEmpty()); // Load config from a file not found results in a nullptr - KScreen::ConfigPtr config = createConfig(true, true); - QVERIFY(!Serializer::loadConfig(config, QString())); + auto config = createConfig(true, true); + QVERIFY(!config->readFile(QString())); // Wrong config file name should fail to save - QCOMPARE(Serializer::saveConfig(config, QString()), false); + QVERIFY(!config->writeFile(QString())); } -void TestSerializer::testIdenticalOutputs() +void TestConfig::testIdenticalOutputs() { // Test configuration of a video wall with 6 identical outputs connected // this is the autotest for https://bugs.kde.org/show_bug.cgi?id=325277 @@ -351,42 +365,49 @@ config->addOutput(output3); config->addOutput(output1); + Config configWrapper(config); + configWrapper.setDirPath(QStringLiteral(TEST_DATA "serializerdata/")); + QHash positions; positions[QStringLiteral("DisplayPort-0")] = QPoint(0, 1080); positions[QStringLiteral("DisplayPort-1")] = QPoint(2100, 30); positions[QStringLiteral("DisplayPort-2")] = QPoint(2100, 1080); positions[QStringLiteral("DisplayPort-3")] = QPoint(4020, 0); positions[QStringLiteral("DVI-0")] = QPoint(4020, 1080); positions[QStringLiteral("DVI-1")] = QPoint(0, 0); - config = Serializer::loadConfig(config, QStringLiteral("outputgrid_2x3.json")); - QVERIFY(config); + auto configWrapper2 = std::move(configWrapper.readFile(QStringLiteral("outputgrid_2x3.json"))); + KScreen::ConfigPtr config2 = configWrapper2->data(); + QVERIFY(config2); + QVERIFY(config != config2); - QCOMPARE(config->connectedOutputs().count(), 6); - Q_FOREACH (auto output, config->connectedOutputs()) { + QCOMPARE(config2->connectedOutputs().count(), 6); + Q_FOREACH (auto output, config2->connectedOutputs()) { QVERIFY(positions.keys().contains(output->name())); QVERIFY(output->name() != output->hash()); QCOMPARE(positions[output->name()], output->pos()); QCOMPARE(output->currentMode()->size(), QSize(1920, 1080)); QCOMPARE(output->currentMode()->refreshRate(), 60.0); QVERIFY(output->isEnabled()); } - QCOMPARE(config->screen()->currentSize(), QSize(5940, 2160)); + QCOMPARE(config2->screen()->currentSize(), QSize(5940, 2160)); } -void TestSerializer::testMoveConfig() +void TestConfig::testMoveConfig() { // Test if restoring a config using Serializer::moveConfig(src, dest) works // https://bugs.kde.org/show_bug.cgi?id=353029 // Load a dualhead config - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("twoScreenConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("twoScreenConfig.json"))); + + auto config = configWrapper->data(); QVERIFY(config); // Make sure we don't write into TEST_DATA QStandardPaths::setTestModeEnabled(true); - Serializer::setConfigPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); + configWrapper->setDirPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); // Basic assumptions for the remainder of our tests, this is the situation where the lid is opened QCOMPARE(config->connectedOutputs().count(), 2); @@ -402,35 +423,39 @@ QCOMPARE(output2->isPrimary(), false); // we fake the lid being closed, first save our current config to _lidOpened - Serializer::saveConfig(config, QStringLiteral("0xdeadbeef_lidOpened")); + configWrapper->writeOpenLidFile(); // ... then switch off the panel, set primary to the other output output->setEnabled(false); output->setPrimary(false); output2->setPrimary(true); // save config as the current one, this is the config we don't want restored, and which we'll overwrite - Serializer::saveConfig(config, QStringLiteral("0xdeadbeef")); + configWrapper->writeFile(); QCOMPARE(output->isEnabled(), false); QCOMPARE(output->isPrimary(), false); QCOMPARE(output2->isPrimary(), true); // Check if both files exist - QFile openCfg(Serializer::configFileName(QStringLiteral("0xdeadbeef_lidOpened"))); - QFile closedCfg(Serializer::configFileName(QStringLiteral("0xdeadbeef"))); + const QString closedPath = configWrapper->s_dirPath % configWrapper->id(); + const QString openedPath = closedPath % QStringLiteral("_lidOpened"); + + QFile openCfg(openedPath); + QFile closedCfg(closedPath); QVERIFY(openCfg.exists()); QVERIFY(closedCfg.exists()); - // Switcheroo... - QVERIFY(Serializer::moveConfig(QStringLiteral("0xdeadbeef_lidOpened"), QStringLiteral("0xdeadbeef"))); + // Switcheroolooloo... + configWrapper = std::move(configWrapper->readOpenLidFile()); + QVERIFY(configWrapper); // Check actual files, src should be gone, dest must exist QVERIFY(!openCfg.exists()); QVERIFY(closedCfg.exists()); - // Now load the resulting config and make sure the laptop panel is enabled and primary again - config = Serializer::loadConfig(config, QStringLiteral("0xdeadbeef")); + // Make sure the laptop panel is enabled and primary again + config = configWrapper->data(); output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); @@ -443,9 +468,8 @@ QCOMPARE(output2->isPrimary(), false); // Make sure we don't screw up when there's no _lidOpened config - QVERIFY(!Serializer::moveConfig(QStringLiteral("0xdeadbeef_lidOpened"), QStringLiteral("0xdeadbeef"))); - - config = Serializer::loadConfig(config, QStringLiteral("0xdeadbeef")); + configWrapper = std::move(configWrapper->readOpenLidFile()); + config = configWrapper->data(); output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); @@ -457,28 +481,31 @@ QCOMPARE(output2->isEnabled(), true); QCOMPARE(output2->isPrimary(), false); - Serializer::setConfigPath(QStringLiteral(TEST_DATA "/serializerdata/")); + configWrapper->setDirPath(QStringLiteral(TEST_DATA "/serializerdata/")); } -void TestSerializer::testFixedConfig() +void TestConfig::testFixedConfig() { // Load a dualhead config - KScreen::ConfigPtr config = createConfig(true, true); - config = Serializer::loadConfig(config, QStringLiteral("twoScreenConfig.json")); + auto configWrapper = createConfig(true, true); + configWrapper = std::move(configWrapper->readFile(QStringLiteral("twoScreenConfig.json"))); + auto config = configWrapper->data(); + QVERIFY(config); // Make sure we don't write into TEST_DATA QStandardPaths::setTestModeEnabled(true); - Serializer::setConfigPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); + configWrapper->setDirPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); + const auto fixedCfgPath = configWrapper->s_dirPath % configWrapper->s_fixedConfigFileName; // save config as the current one, this is the config we don't want restored, and which we'll overwrite - Serializer::saveConfig(config, Serializer::sFixedConfig); + configWrapper->writeFile(fixedCfgPath); // Check if both files exist - QFile fixedCfg(Serializer::configFileName(Serializer::sFixedConfig)); + QFile fixedCfg(fixedCfgPath); QVERIFY(fixedCfg.exists()); } -QTEST_MAIN(TestSerializer) +QTEST_MAIN(TestConfig) -#include "serializertest.moc" +#include "configtest.moc"