diff --git a/screen/common/control.cpp b/screen/common/control.cpp deleted file mode 100644 index 67170ad..0000000 --- a/screen/common/control.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/******************************************************************** -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 "control.h" -#include "globals.h" - -#include -#include -#include -#include -#include - -#include -#include - -QString Control::s_dirName = QStringLiteral("control/"); - -Control::Control(QObject *parent) - : QObject(parent) -{ -} - -void Control::activateWatcher() -{ - if (m_watcher) { - return; - } - m_watcher = new KDirWatch(this); - m_watcher->addFile(filePath()); - connect(m_watcher, &KDirWatch::dirty, this, [this]() { - readFile(); - Q_EMIT changed(); - }); -} - -KDirWatch *Control::watcher() const -{ - return m_watcher; -} - -bool Control::writeFile() -{ - const QString path = filePath(); - const auto infoMap = constInfo(); - - if (infoMap.isEmpty()) { - // Nothing to write. Default control. Remove file if it exists. - QFile::remove(path); - return true; - } - if (!QDir().mkpath(dirPath())) { - return false; - } - - // write updated data to file - QFile file(path); - if (!file.open(QIODevice::WriteOnly)) { - return false; - } - file.write(QJsonDocument::fromVariant(infoMap).toJson()); - return true; -} - -QString Control::dirPath() const -{ - return Globals::dirPath() % s_dirName; -} - -void Control::readFile() -{ - QFile file(filePath()); - if (file.open(QIODevice::ReadOnly)) { - // This might not be reached, bus this is ok. The control file will - // eventually be created on first write later on. - QJsonDocument parser; - m_info = parser.fromJson(file.readAll()).toVariant().toMap(); - } -} - -QString Control::filePathFromHash(const QString &hash) const -{ - return dirPath() % hash; -} - -QVariantMap &Control::info() -{ - return m_info; -} - -const QVariantMap &Control::constInfo() const -{ - return m_info; -} - -Control::OutputRetention Control::convertVariantToOutputRetention(QVariant variant) -{ - if (variant.canConvert()) { - const auto retention = variant.toInt(); - if (retention == (int)OutputRetention::Global) { - return OutputRetention::Global; - } - if (retention == (int)OutputRetention::Individual) { - return OutputRetention::Individual; - } - } - return OutputRetention::Undefined; -} - -ControlConfig::ControlConfig(KScreen::ConfigPtr config, QObject *parent) - : Control(parent) - , m_config(config) -{ - // qDebug() << "Looking for control file:" << config->connectedOutputsHash(); - readFile(); - - // TODO: use a file watcher in case of changes to the control file while - // object exists? - - // As global 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 - QStringList allIds; - const auto outputs = config->outputs(); - allIds.reserve(outputs.count()); - for (const KScreen::OutputPtr &output : outputs) { - const auto outputId = output->hashMd5(); - if (allIds.contains(outputId) && !m_duplicateOutputIds.contains(outputId)) { - m_duplicateOutputIds << outputId; - } - allIds << outputId; - } - - for (auto output : outputs) { - m_outputsControls << new ControlOutput(output, this); - } - - // TODO: this is same in Output::readInOutputs of the daemon. Combine? - - // TODO: connect to outputs added/removed signals and reevaluate duplicate ids - // in case of such a change while object exists? -} - -void ControlConfig::activateWatcher() -{ - if (watcher()) { - // Watcher was already activated. - return; - } - for (auto *output : m_outputsControls) { - output->activateWatcher(); - connect(output, &ControlOutput::changed, this, &ControlConfig::changed); - } -} - -QString ControlConfig::dirPath() const -{ - return Control::dirPath() % QStringLiteral("configs/"); -} - -QString ControlConfig::filePath() const -{ - if (!m_config) { - return QString(); - } - return filePathFromHash(m_config->connectedOutputsHash()); -} - -bool ControlConfig::writeFile() -{ - bool success = true; - for (auto *outputControl : m_outputsControls) { - if (getOutputRetention(outputControl->id(), outputControl->name()) == OutputRetention::Individual) { - continue; - } - success &= outputControl->writeFile(); - } - return success && Control::writeFile(); -} - -bool ControlConfig::infoIsOutput(const QVariantMap &info, const QString &outputId, const QString &outputName) const -{ - const QString outputIdInfo = info[QStringLiteral("id")].toString(); - if (outputIdInfo.isEmpty()) { - return false; - } - if (outputId != outputIdInfo) { - return false; - } - - if (!outputName.isEmpty() && m_duplicateOutputIds.contains(outputId)) { - // We may have identical outputs connected, these will have the same id in the config - // in order to find the right one, also check the output's name (usually the connector) - const auto metadata = info[QStringLiteral("metadata")].toMap(); - const auto outputNameInfo = metadata[QStringLiteral("name")].toString(); - if (outputName != outputNameInfo) { - // was a duplicate id, but info not for this output - return false; - } - } - return true; -} - -Control::OutputRetention ControlConfig::getOutputRetention(const KScreen::OutputPtr &output) const -{ - return getOutputRetention(output->hashMd5(), output->name()); -} - -Control::OutputRetention ControlConfig::getOutputRetention(const QString &outputId, const QString &outputName) const -{ - const QVariantList outputsInfo = getOutputs(); - for (const auto &variantInfo : outputsInfo) { - const QVariantMap info = variantInfo.toMap(); - if (!infoIsOutput(info, outputId, outputName)) { - continue; - } - return convertVariantToOutputRetention(info[QStringLiteral("retention")]); - } - // info for output not found - return OutputRetention::Undefined; -} - -static QVariantMap metadata(const QString &outputName) -{ - QVariantMap metadata; - metadata[QStringLiteral("name")] = outputName; - return metadata; -} - -QVariantMap createOutputInfo(const QString &outputId, const QString &outputName) -{ - QVariantMap outputInfo; - outputInfo[QStringLiteral("id")] = outputId; - outputInfo[QStringLiteral("metadata")] = metadata(outputName); - return outputInfo; -} - -void ControlConfig::setOutputRetention(const KScreen::OutputPtr &output, OutputRetention value) -{ - setOutputRetention(output->hashMd5(), output->name(), value); -} - -void ControlConfig::setOutputRetention(const QString &outputId, const QString &outputName, OutputRetention value) -{ - QList::iterator it; - QVariantList outputsInfo = getOutputs(); - - for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) { - QVariantMap outputInfo = (*it).toMap(); - if (!infoIsOutput(outputInfo, outputId, outputName)) { - continue; - } - outputInfo[QStringLiteral("retention")] = (int)value; - *it = outputInfo; - setOutputs(outputsInfo); - return; - } - // no entry yet, create one - auto outputInfo = createOutputInfo(outputId, outputName); - outputInfo[QStringLiteral("retention")] = (int)value; - - outputsInfo << outputInfo; - setOutputs(outputsInfo); -} - -qreal ControlConfig::getScale(const KScreen::OutputPtr &output) const -{ - return getScale(output->hashMd5(), output->name()); -} - -qreal ControlConfig::getScale(const QString &outputId, const QString &outputName) const -{ - const auto retention = getOutputRetention(outputId, outputName); - if (retention == OutputRetention::Individual) { - const QVariantList outputsInfo = getOutputs(); - for (const auto &variantInfo : outputsInfo) { - const QVariantMap info = variantInfo.toMap(); - if (!infoIsOutput(info, outputId, outputName)) { - continue; - } - const auto val = info[QStringLiteral("scale")]; - return val.canConvert() ? val.toReal() : -1; - } - } - // Retention is global or info for output not in config control file. - if (auto *outputControl = getOutputControl(outputId, outputName)) { - return outputControl->getScale(); - } - - // Info for output not found. - return -1; -} - -void ControlConfig::setScale(const KScreen::OutputPtr &output, qreal value) -{ - setScale(output->hashMd5(), output->name(), value); -} - -// TODO: combine methods (templated functions) -void ControlConfig::setScale(const QString &outputId, const QString &outputName, qreal value) -{ - QList::iterator it; - QVariantList outputsInfo = getOutputs(); - - auto setOutputScale = [&outputId, &outputName, value, this]() { - if (auto *control = getOutputControl(outputId, outputName)) { - control->setScale(value); - } - }; - - for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) { - QVariantMap outputInfo = (*it).toMap(); - if (!infoIsOutput(outputInfo, outputId, outputName)) { - continue; - } - outputInfo[QStringLiteral("scale")] = value; - *it = outputInfo; - setOutputs(outputsInfo); - setOutputScale(); - return; - } - // no entry yet, create one - auto outputInfo = createOutputInfo(outputId, outputName); - outputInfo[QStringLiteral("scale")] = value; - - outputsInfo << outputInfo; - setOutputs(outputsInfo); - setOutputScale(); -} - -bool ControlConfig::getAutoRotate(const KScreen::OutputPtr &output) const -{ - return getAutoRotate(output->hashMd5(), output->name()); -} - -bool ControlConfig::getAutoRotate(const QString &outputId, const QString &outputName) const -{ - const auto retention = getOutputRetention(outputId, outputName); - if (retention == OutputRetention::Individual) { - const QVariantList outputsInfo = getOutputs(); - for (const auto &variantInfo : outputsInfo) { - const QVariantMap info = variantInfo.toMap(); - if (!infoIsOutput(info, outputId, outputName)) { - continue; - } - const auto val = info[QStringLiteral("autorotate")]; - return !val.canConvert() || val.toBool(); - } - } - // Retention is global or info for output not in config control file. - if (auto *outputControl = getOutputControl(outputId, outputName)) { - return outputControl->getAutoRotate(); - } - - // Info for output not found. - return true; -} - -void ControlConfig::setAutoRotate(const KScreen::OutputPtr &output, bool value) -{ - setAutoRotate(output->hashMd5(), output->name(), value); -} - -// TODO: combine methods (templated functions) -void ControlConfig::setAutoRotate(const QString &outputId, const QString &outputName, bool value) -{ - QList::iterator it; - QVariantList outputsInfo = getOutputs(); - - auto setOutputAutoRotate = [&outputId, &outputName, value, this]() { - if (auto *control = getOutputControl(outputId, outputName)) { - control->setAutoRotate(value); - } - }; - - for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) { - QVariantMap outputInfo = (*it).toMap(); - if (!infoIsOutput(outputInfo, outputId, outputName)) { - continue; - } - outputInfo[QStringLiteral("autorotate")] = value; - *it = outputInfo; - setOutputs(outputsInfo); - setOutputAutoRotate(); - return; - } - // no entry yet, create one - auto outputInfo = createOutputInfo(outputId, outputName); - outputInfo[QStringLiteral("autorotate")] = value; - - outputsInfo << outputInfo; - setOutputs(outputsInfo); - setOutputAutoRotate(); -} - -bool ControlConfig::getAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const -{ - return getAutoRotateOnlyInTabletMode(output->hashMd5(), output->name()); -} - -bool ControlConfig::getAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName) const -{ - const auto retention = getOutputRetention(outputId, outputName); - if (retention == OutputRetention::Individual) { - const QVariantList outputsInfo = getOutputs(); - for (const auto &variantInfo : outputsInfo) { - const QVariantMap info = variantInfo.toMap(); - if (!infoIsOutput(info, outputId, outputName)) { - continue; - } - const auto val = info[QStringLiteral("autorotate-tablet-only")]; - return !val.canConvert() || val.toBool(); - } - } - // Retention is global or info for output not in config control file. - if (auto *outputControl = getOutputControl(outputId, outputName)) { - return outputControl->getAutoRotateOnlyInTabletMode(); - } - - // Info for output not found. - return true; -} - -void ControlConfig::setAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output, bool value) -{ - setAutoRotateOnlyInTabletMode(output->hashMd5(), output->name(), value); -} - -// TODO: combine methods (templated functions) -void ControlConfig::setAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName, bool value) -{ - QList::iterator it; - QVariantList outputsInfo = getOutputs(); - - auto setOutputAutoRotateOnlyInTabletMode = [&outputId, &outputName, value, this]() { - if (auto *control = getOutputControl(outputId, outputName)) { - control->setAutoRotateOnlyInTabletMode(value); - } - }; - - for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) { - QVariantMap outputInfo = (*it).toMap(); - if (!infoIsOutput(outputInfo, outputId, outputName)) { - continue; - } - outputInfo[QStringLiteral("autorotate-tablet-only")] = value; - *it = outputInfo; - setOutputs(outputsInfo); - setOutputAutoRotateOnlyInTabletMode(); - return; - } - // no entry yet, create one - auto outputInfo = createOutputInfo(outputId, outputName); - outputInfo[QStringLiteral("autorotate-tablet-only")] = value; - - outputsInfo << outputInfo; - setOutputs(outputsInfo); - setOutputAutoRotateOnlyInTabletMode(); -} - -KScreen::OutputPtr ControlConfig::getReplicationSource(const KScreen::OutputPtr &output) const -{ - return getReplicationSource(output->hashMd5(), output->name()); -} - -KScreen::OutputPtr ControlConfig::getReplicationSource(const QString &outputId, const QString &outputName) const -{ - const QVariantList outputsInfo = getOutputs(); - for (const auto &variantInfo : outputsInfo) { - const QVariantMap info = variantInfo.toMap(); - if (!infoIsOutput(info, outputId, outputName)) { - continue; - } - const QString sourceHash = info[QStringLiteral("replicate-hash")].toString(); - const QString sourceName = info[QStringLiteral("replicate-name")].toString(); - - if (sourceHash.isEmpty() && sourceName.isEmpty()) { - // Common case when the replication source has been unset. - return nullptr; - } - - for (const auto &output : m_config->outputs()) { - if (output->hashMd5() == sourceHash && output->name() == sourceName) { - return output; - } - } - // No match. - return nullptr; - } - // Info for output not found. - return nullptr; -} - -void ControlConfig::setReplicationSource(const KScreen::OutputPtr &output, const KScreen::OutputPtr &source) -{ - setReplicationSource(output->hashMd5(), output->name(), source); -} - -void ControlConfig::setReplicationSource(const QString &outputId, const QString &outputName, const KScreen::OutputPtr &source) -{ - QList::iterator it; - QVariantList outputsInfo = getOutputs(); - const QString sourceHash = source ? source->hashMd5() : QStringLiteral(""); - const QString sourceName = source ? source->name() : QStringLiteral(""); - - for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) { - QVariantMap outputInfo = (*it).toMap(); - if (!infoIsOutput(outputInfo, outputId, outputName)) { - continue; - } - outputInfo[QStringLiteral("replicate-hash")] = sourceHash; - outputInfo[QStringLiteral("replicate-name")] = sourceName; - *it = outputInfo; - setOutputs(outputsInfo); - // TODO: shall we set this information also as new global value (like with auto-rotate)? - return; - } - // no entry yet, create one - auto outputInfo = createOutputInfo(outputId, outputName); - outputInfo[QStringLiteral("replicate-hash")] = sourceHash; - outputInfo[QStringLiteral("replicate-name")] = sourceName; - - outputsInfo << outputInfo; - setOutputs(outputsInfo); - // TODO: shall we set this information also as new global value (like with auto-rotate)? -} - -QVariantList ControlConfig::getOutputs() const -{ - return constInfo()[QStringLiteral("outputs")].toList(); -} - -void ControlConfig::setOutputs(QVariantList outputsInfo) -{ - auto &infoMap = info(); - infoMap[QStringLiteral("outputs")] = outputsInfo; -} -ControlOutput *ControlConfig::getOutputControl(const QString &outputId, const QString &outputName) const -{ - for (auto *control : m_outputsControls) { - if (control->id() == outputId && control->name() == outputName) { - return control; - } - } - return nullptr; -} - -ControlOutput::ControlOutput(KScreen::OutputPtr output, QObject *parent) - : Control(parent) - , m_output(output) -{ - readFile(); -} - -QString ControlOutput::id() const -{ - return m_output->hashMd5(); -} - -QString ControlOutput::name() const -{ - return m_output->name(); -} - -QString ControlOutput::dirPath() const -{ - return Control::dirPath() % QStringLiteral("outputs/"); -} - -QString ControlOutput::filePath() const -{ - if (!m_output) { - return QString(); - } - return filePathFromHash(m_output->hashMd5()); -} - -qreal ControlOutput::getScale() const -{ - const auto val = constInfo()[QStringLiteral("scale")]; - return val.canConvert() ? val.toReal() : -1; -} - -void ControlOutput::setScale(qreal value) -{ - auto &infoMap = info(); - if (infoMap.isEmpty()) { - infoMap = createOutputInfo(m_output->hashMd5(), m_output->name()); - } - infoMap[QStringLiteral("scale")] = value; -} - -bool ControlOutput::getAutoRotate() const -{ - const auto val = constInfo()[QStringLiteral("autorotate")]; - return !val.canConvert() || val.toBool(); -} - -void ControlOutput::setAutoRotate(bool value) -{ - auto &infoMap = info(); - if (infoMap.isEmpty()) { - infoMap = createOutputInfo(m_output->hashMd5(), m_output->name()); - } - infoMap[QStringLiteral("autorotate")] = value; -} - -bool ControlOutput::getAutoRotateOnlyInTabletMode() const -{ - const auto val = constInfo()[QStringLiteral("autorotate-tablet-only")]; - return !val.canConvert() || val.toBool(); -} - -void ControlOutput::setAutoRotateOnlyInTabletMode(bool value) -{ - auto &infoMap = info(); - if (infoMap.isEmpty()) { - infoMap = createOutputInfo(m_output->hashMd5(), m_output->name()); - } - infoMap[QStringLiteral("autorotate-tablet-only")] = value; -} diff --git a/screen/common/control.h b/screen/common/control.h deleted file mode 100644 index 75f2038..0000000 --- a/screen/common/control.h +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************** -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 COMMON_CONTROL_H -#define COMMON_CONTROL_H - -#include - -#include -#include -#include - -class KDirWatch; - -class Control : public QObject -{ - Q_OBJECT -public: - enum class OutputRetention { - Undefined = -1, - Global = 0, - Individual = 1, - }; - Q_ENUM(OutputRetention) - - explicit Control(QObject *parent = nullptr); - - ~Control() override = default; - - virtual bool writeFile(); - virtual void activateWatcher(); - -Q_SIGNALS: - void changed(); - -protected: - virtual QString dirPath() const; - virtual QString filePath() const = 0; - QString filePathFromHash(const QString &hash) const; - void readFile(); - QVariantMap &info(); - const QVariantMap &constInfo() const; - KDirWatch *watcher() const; - - static OutputRetention convertVariantToOutputRetention(QVariant variant); - -private: - static QString s_dirName; - QVariantMap m_info; - KDirWatch *m_watcher = nullptr; -}; - -class ControlOutput; - -class ControlConfig : public Control -{ - Q_OBJECT -public: - explicit ControlConfig(KScreen::ConfigPtr config, QObject *parent = nullptr); - - OutputRetention getOutputRetention(const KScreen::OutputPtr &output) const; - OutputRetention getOutputRetention(const QString &outputId, const QString &outputName) const; - void setOutputRetention(const KScreen::OutputPtr &output, OutputRetention value); - void setOutputRetention(const QString &outputId, const QString &outputName, OutputRetention value); - - qreal getScale(const KScreen::OutputPtr &output) const; - qreal getScale(const QString &outputId, const QString &outputName) const; - void setScale(const KScreen::OutputPtr &output, qreal value); - void setScale(const QString &outputId, const QString &outputName, qreal value); - - bool getAutoRotate(const KScreen::OutputPtr &output) const; - bool getAutoRotate(const QString &outputId, const QString &outputName) const; - void setAutoRotate(const KScreen::OutputPtr &output, bool value); - void setAutoRotate(const QString &outputId, const QString &outputName, bool value); - - bool getAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const; - bool getAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName) const; - void setAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output, bool value); - void setAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName, bool value); - - KScreen::OutputPtr getReplicationSource(const KScreen::OutputPtr &output) const; - KScreen::OutputPtr getReplicationSource(const QString &outputId, const QString &outputName) const; - void setReplicationSource(const KScreen::OutputPtr &output, const KScreen::OutputPtr &source); - void setReplicationSource(const QString &outputId, const QString &outputName, const KScreen::OutputPtr &source); - - QString dirPath() const override; - QString filePath() const override; - - bool writeFile() override; - void activateWatcher() override; - -private: - QVariantList getOutputs() const; - void setOutputs(QVariantList outputsInfo); - bool infoIsOutput(const QVariantMap &info, const QString &outputId, const QString &outputName) const; - ControlOutput *getOutputControl(const QString &outputId, const QString &outputName) const; - - KScreen::ConfigPtr m_config; - QStringList m_duplicateOutputIds; - QVector m_outputsControls; -}; - -class ControlOutput : public Control -{ - Q_OBJECT -public: - explicit ControlOutput(KScreen::OutputPtr output, QObject *parent = nullptr); - - QString id() const; - QString name() const; - - // TODO: scale auto value - - qreal getScale() const; - void setScale(qreal value); - - bool getAutoRotate() const; - void setAutoRotate(bool value); - - bool getAutoRotateOnlyInTabletMode() const; - void setAutoRotateOnlyInTabletMode(bool value); - - QString dirPath() const override; - QString filePath() const override; - -private: - KScreen::OutputPtr m_output; -}; - -#endif diff --git a/screen/common/globals.cpp b/screen/common/globals.cpp deleted file mode 100644 index 6a3675f..0000000 --- a/screen/common/globals.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************** -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 "globals.h" - -#include -#include - -namespace Globals -{ - -QString s_dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % - QStringLiteral("/kscreen/"); - -QString dirPath() { - return s_dirPath; -} - -void setDirPath(const QString &path) -{ - s_dirPath = path; - if (!s_dirPath.endsWith(QLatin1Char('/'))) { - s_dirPath += QLatin1Char('/'); - } -} - -} diff --git a/screen/common/globals.h b/screen/common/globals.h deleted file mode 100644 index 142598e..0000000 --- a/screen/common/globals.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************** -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 . -*********************************************************************/ -#ifndef COMMON_GLOBALS_H -#define COMMON_GLOBALS_H - -#include - -namespace Globals -{ - void setDirPath(const QString &path); - QString dirPath(); -} - -#endif diff --git a/screen/common/orientation_sensor.cpp b/screen/common/orientation_sensor.cpp deleted file mode 100644 index 0cc456e..0000000 --- a/screen/common/orientation_sensor.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************** -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 "orientation_sensor.h" - -#include - -OrientationSensor::OrientationSensor(QObject *parent) - : QObject(parent) - , m_sensor(new QOrientationSensor(this)) -{ - connect(m_sensor, &QOrientationSensor::activeChanged, this, &OrientationSensor::refresh); -} - -OrientationSensor::~OrientationSensor() = default; - -void OrientationSensor::updateState() -{ - const auto orientation = m_sensor->reading()->orientation(); - if (m_value != orientation) { - m_value = orientation; - Q_EMIT valueChanged(orientation); - } -} - -void OrientationSensor::refresh() -{ - if (m_sensor->isActive()) { - if (m_enabled) { - updateState(); - } - Q_EMIT availableChanged(true); - } else { - Q_EMIT availableChanged(false); - } -} - -QOrientationReading::Orientation OrientationSensor::value() const -{ - return m_value; -} - -bool OrientationSensor::available() const -{ - return m_sensor->connectToBackend(); -} - -bool OrientationSensor::enabled() const -{ - return m_sensor->isActive(); -} - -void OrientationSensor::setEnabled(bool enable) -{ - if (m_enabled == enable) { - return; - } - m_enabled = enable; - - if (enable) { - connect(m_sensor, &QOrientationSensor::readingChanged, this, &OrientationSensor::updateState); - m_sensor->start(); - } else { - disconnect(m_sensor, &QOrientationSensor::readingChanged, this, &OrientationSensor::updateState); - m_value = QOrientationReading::Undefined; - } - Q_EMIT enabledChanged(enable); -} diff --git a/screen/common/orientation_sensor.h b/screen/common/orientation_sensor.h deleted file mode 100644 index 6aace60..0000000 --- a/screen/common/orientation_sensor.h +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************** -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 . -*********************************************************************/ -#pragma once - -#include -#include - -class OrientationSensor final : public QObject -{ - Q_OBJECT -public: - explicit OrientationSensor(QObject *parent = nullptr); - ~OrientationSensor() override final; - - QOrientationReading::Orientation value() const; - bool available() const; - bool enabled() const; - - void setEnabled(bool enable); - -Q_SIGNALS: - void valueChanged(QOrientationReading::Orientation orientation); - void availableChanged(bool available); - void enabledChanged(bool enabled); - -private: - void refresh(); - void updateState(); - - QOrientationSensor *m_sensor; - QOrientationReading::Orientation m_value = QOrientationReading::Undefined; - bool m_enabled = false; -}; diff --git a/screen/common/utils.cpp b/screen/common/utils.cpp deleted file mode 100644 index 182c59a..0000000 --- a/screen/common/utils.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * 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 "utils.h" - -#include -#include - -QString Utils::outputName(const KScreen::OutputPtr& output) -{ - return outputName(output.data()); -} - -QString Utils::outputName(const KScreen::Output *output) -{ - if (output->type() == KScreen::Output::Panel) { - return QObject::tr("Laptop Screen"); - } - - if (output->edid()) { - // The name will be "VendorName ModelName (ConnectorName)", - // but some components may be empty. - QString name; - if (!(output->edid()->vendor().isEmpty())) { - name = output->edid()->vendor() + QLatin1Char(' '); - } - if (!output->edid()->name().isEmpty()) { - name += output->edid()->name() + QLatin1Char(' '); - } - if (!name.trimmed().isEmpty()) { - return name + QLatin1Char('(') + output->name() + QLatin1Char(')'); - } - } - return output->name(); -} - -QString Utils::sizeToString(const QSize &size) -{ - return QStringLiteral("%1x%2").arg(size.width()).arg(size.height()); -} - diff --git a/screen/common/utils.h b/screen/common/utils.h deleted file mode 100644 index f59c832..0000000 --- a/screen/common/utils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * 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 KSCREEN_KCM_UTILS_H -#define KSCREEN_KCM_UTILS_H - -#include -#include - -#include -#include - -namespace Utils -{ - - QString outputName(const KScreen::Output *output); - QString outputName(const KScreen::OutputPtr &output); - - QString sizeToString(const QSize &size); -} - -#endif diff --git a/screen/confighandler.cpp b/screen/confighandler.cpp deleted file mode 100644 index 96d24d8..0000000 --- a/screen/confighandler.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/******************************************************************** -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 "confighandler.h" - -#include "outputmodel.h" - -#include -#include -#include - -#include -#include - -using namespace KScreen; - -ConfigHandler::ConfigHandler(QObject *parent) - : QObject(parent) -{ -} - -void ConfigHandler::setConfig(KScreen::ConfigPtr config) -{ - m_config = config; - m_initialConfig = m_config->clone(); - m_initialControl.reset(new ControlConfig(m_initialConfig)); - - KScreen::ConfigMonitor::instance()->addConfig(m_config); - m_control.reset(new ControlConfig(config)); - - m_outputs = new OutputModel(this); - connect(m_outputs, &OutputModel::positionChanged, this, &ConfigHandler::checkScreenNormalization); - connect(m_outputs, &OutputModel::sizeChanged, this, &ConfigHandler::checkScreenNormalization); - - for (const KScreen::OutputPtr &output : config->outputs()) { - initOutput(output); - } - m_lastNormalizedScreenSize = screenSize(); - - // TODO: put this into m_initialControl - m_initialRetention = getRetention(); - Q_EMIT retentionChanged(); - - connect(m_outputs, &OutputModel::changed, this, [this]() { - checkNeedsSave(); - Q_EMIT changed(); - }); - connect(m_config.data(), &KScreen::Config::outputAdded, this, [this]() { - Q_EMIT outputConnect(true); - }); - connect(m_config.data(), &KScreen::Config::outputRemoved, this, [this]() { - Q_EMIT outputConnect(false); - }); - // connect(m_config.data(), &KScreen::Config::primaryOutputChanged, this, &ConfigHandler::primaryOutputChanged); - - Q_EMIT outputModelChanged(); -} - -void ConfigHandler::resetScale(const KScreen::OutputPtr &output) -{ - // Load scale control (either not set, same or windowing system does not transmit scale). - const qreal scale = m_control->getScale(output); - if (scale > 0) { - output->setScale(scale); - for (auto initialOutput : m_initialConfig->outputs()) { - if (initialOutput->id() == output->id()) { - initialOutput->setScale(scale); - break; - } - } - } -} - -void ConfigHandler::initOutput(const KScreen::OutputPtr &output) -{ - if (output->isConnected()) { - resetScale(output); - m_outputs->add(output); - } - connect(output.data(), &KScreen::Output::isConnectedChanged, this, [this, output]() { - Q_EMIT outputConnect(output->isConnected()); - }); -} - -void ConfigHandler::updateInitialData() -{ - m_initialRetention = getRetention(); - connect(new GetConfigOperation(), &GetConfigOperation::finished, this, [this](ConfigOperation *op) { - if (op->hasError()) { - return; - } - m_initialConfig = qobject_cast(op)->config(); - for (auto output : m_config->outputs()) { - resetScale(output); - } - m_initialControl.reset(new ControlConfig(m_initialConfig)); - checkNeedsSave(); - }); -} - -void ConfigHandler::checkNeedsSave() -{ - if (m_config->supportedFeatures() & KScreen::Config::Feature::PrimaryDisplay) { - if (m_config->primaryOutput() && m_initialConfig->primaryOutput()) { - if (m_config->primaryOutput()->hashMd5() != m_initialConfig->primaryOutput()->hashMd5()) { - Q_EMIT needsSaveChecked(true); - return; - } - } else if ((bool)m_config->primaryOutput() != (bool)m_initialConfig->primaryOutput()) { - Q_EMIT needsSaveChecked(true); - return; - } - } - - if (m_initialRetention != getRetention()) { - Q_EMIT needsSaveChecked(true); - return; - } - - for (const auto &output : m_config->connectedOutputs()) { - const QString hash = output->hashMd5(); - for (const auto &initialOutput : m_initialConfig->outputs()) { - if (hash != initialOutput->hashMd5()) { - continue; - } - bool needsSave = false; - if (output->isEnabled() != initialOutput->isEnabled()) { - needsSave = true; - } - // clang-format off - if (output->isEnabled()) { - needsSave |= output->currentModeId() != - initialOutput->currentModeId() - || output->pos() != initialOutput->pos() - || output->scale() != initialOutput->scale() - || output->rotation() != initialOutput->rotation() - || output->replicationSource() != initialOutput->replicationSource() - || autoRotate(output) != m_initialControl->getAutoRotate(output) - || autoRotateOnlyInTabletMode(output) - != m_initialControl->getAutoRotateOnlyInTabletMode(output); - } - // clang-format on - if (needsSave) { - Q_EMIT needsSaveChecked(true); - return; - } - break; - } - } - Q_EMIT needsSaveChecked(false); -} - -QSize ConfigHandler::screenSize() const -{ - int width = 0, height = 0; - QSize size; - - for (const auto &output : m_config->connectedOutputs()) { - if (!output->isPositionable()) { - continue; - } - const int outputRight = output->geometry().right(); - const int outputBottom = output->geometry().bottom(); - - if (outputRight > width) { - width = outputRight; - } - if (outputBottom > height) { - height = outputBottom; - } - } - if (width > 0 && height > 0) { - size = QSize(width, height); - } else { - size = QSize(); - } - return size; -} - -QSize ConfigHandler::normalizeScreen() -{ - if (!m_config) { - return QSize(); - } - bool changed = m_outputs->normalizePositions(); - - const auto currentScreenSize = screenSize(); - changed |= m_lastNormalizedScreenSize != currentScreenSize; - m_lastNormalizedScreenSize = currentScreenSize; - - Q_EMIT screenNormalizationUpdate(true); - return currentScreenSize; -} - -void ConfigHandler::checkScreenNormalization() -{ - const bool normalized = !m_config || (m_lastNormalizedScreenSize == screenSize() && m_outputs->positionsNormalized()); - - Q_EMIT screenNormalizationUpdate(normalized); -} - -void ConfigHandler::primaryOutputSelected(int index) -{ - Q_UNUSED(index) - // TODO -} - -void ConfigHandler::primaryOutputChanged(const KScreen::OutputPtr &output) -{ - Q_UNUSED(output) -} - -Control::OutputRetention ConfigHandler::getRetention() const -{ - using Retention = Control::OutputRetention; - - auto ret = Retention::Undefined; - if (!m_control) { - return ret; - } - const auto outputs = m_config->connectedOutputs(); - if (outputs.isEmpty()) { - return ret; - } - ret = m_control->getOutputRetention(outputs.first()); - - for (const auto &output : outputs) { - const auto outputRet = m_control->getOutputRetention(output); - if (ret != outputRet) { - // Control file with different retention values per output. - return Retention::Undefined; - } - } - - if (ret == Retention::Undefined) { - // If all outputs have undefined retention, - // this should be displayed as global retention. - return Retention::Global; - } - return ret; -} - -int ConfigHandler::retention() const -{ - return static_cast(getRetention()); -} - -void ConfigHandler::setRetention(int retention) -{ - using Retention = Control::OutputRetention; - - if (!m_control) { - return; - } - if (retention != static_cast(Retention::Global) && retention != static_cast(Retention::Individual)) { - // We only allow setting to global or individual retention. - return; - } - if (retention == ConfigHandler::retention()) { - return; - } - auto ret = static_cast(retention); - for (const auto &output : m_config->connectedOutputs()) { - m_control->setOutputRetention(output, ret); - } - checkNeedsSave(); - Q_EMIT retentionChanged(); - Q_EMIT changed(); -} - -qreal ConfigHandler::scale(const KScreen::OutputPtr &output) const -{ - return m_control->getScale(output); -} - -void ConfigHandler::setScale(KScreen::OutputPtr &output, qreal scale) -{ - m_control->setScale(output, scale); -} - -KScreen::OutputPtr ConfigHandler::replicationSource(const KScreen::OutputPtr &output) const -{ - return m_control->getReplicationSource(output); -} - -void ConfigHandler::setReplicationSource(KScreen::OutputPtr &output, const KScreen::OutputPtr &source) -{ - m_control->setReplicationSource(output, source); -} - -bool ConfigHandler::autoRotate(const KScreen::OutputPtr &output) const -{ - return m_control->getAutoRotate(output); -} - -void ConfigHandler::setAutoRotate(KScreen::OutputPtr &output, bool autoRotate) -{ - m_control->setAutoRotate(output, autoRotate); -} - -bool ConfigHandler::autoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const -{ - return m_control->getAutoRotateOnlyInTabletMode(output); -} - -void ConfigHandler::setAutoRotateOnlyInTabletMode(KScreen::OutputPtr &output, bool value) -{ - m_control->setAutoRotateOnlyInTabletMode(output, value); -} - -void ConfigHandler::writeControl() -{ - if (!m_control) { - return; - } - m_control->writeFile(); -} diff --git a/screen/confighandler.h b/screen/confighandler.h deleted file mode 100644 index cc6956a..0000000 --- a/screen/confighandler.h +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************** -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 CONFIGHANDLER_H -#define CONFIGHANDLER_H - -#include "./common/control.h" - -#include - -#include - -class OutputModel; - -class ConfigHandler : public QObject -{ - Q_OBJECT -public: - explicit ConfigHandler(QObject *parent = nullptr); - ~ConfigHandler() override = default; - - void setConfig(KScreen::ConfigPtr config); - void updateInitialData(); - - OutputModel *outputModel() const - { - return m_outputs; - } - - QSize normalizeScreen(); - - KScreen::ConfigPtr config() const - { - return m_config; - } - - KScreen::ConfigPtr initialConfig() const - { - return m_initialConfig; - } - - int retention() const; - void setRetention(int retention); - - qreal scale(const KScreen::OutputPtr &output) const; - void setScale(KScreen::OutputPtr &output, qreal scale); - - KScreen::OutputPtr replicationSource(const KScreen::OutputPtr &output) const; - void setReplicationSource(KScreen::OutputPtr &output, const KScreen::OutputPtr &source); - - bool autoRotate(const KScreen::OutputPtr &output) const; - void setAutoRotate(KScreen::OutputPtr &output, bool autoRotate); - bool autoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const; - void setAutoRotateOnlyInTabletMode(KScreen::OutputPtr &output, bool value); - - void writeControl(); - - void checkNeedsSave(); - -Q_SIGNALS: - void outputModelChanged(); - void changed(); - void screenNormalizationUpdate(bool normalized); - void needsSaveChecked(bool need); - void retentionChanged(); - void outputConnect(bool connected); - -private: - void checkScreenNormalization(); - QSize screenSize() const; - Control::OutputRetention getRetention() const; - void primaryOutputSelected(int index); - void primaryOutputChanged(const KScreen::OutputPtr &output); - void initOutput(const KScreen::OutputPtr &output); - void resetScale(const KScreen::OutputPtr &output); - - KScreen::ConfigPtr m_config = nullptr; - KScreen::ConfigPtr m_initialConfig; - OutputModel *m_outputs = nullptr; - - std::unique_ptr m_control; - std::unique_ptr m_initialControl; - Control::OutputRetention m_initialRetention = Control::OutputRetention::Undefined; - QSize m_lastNormalizedScreenSize; -}; - -#endif diff --git a/screen/outputmodel.cpp b/screen/outputmodel.cpp deleted file mode 100644 index 4e16013..0000000 --- a/screen/outputmodel.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/******************************************************************** -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 "outputmodel.h" - -#include "./common/utils.h" - -#include "confighandler.h" - -#include - -OutputModel::OutputModel(ConfigHandler *configHandler) - : QAbstractListModel(configHandler) - , m_config(configHandler) -{ - connect(this, &OutputModel::dataChanged, this, &OutputModel::changed); -} - -int OutputModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return m_outputs.count(); -} - -QVariant OutputModel::data(const QModelIndex &index, int role) const -{ - if (index.row() < 0 || index.row() >= m_outputs.count()) { - return QVariant(); - } - - const KScreen::OutputPtr &output = m_outputs[index.row()].ptr; - switch (role) { - case Qt::DisplayRole: - return Utils::outputName(output); - case EnabledRole: - return output->isEnabled(); - case InternalRole: - return output->type() == KScreen::Output::Type::Panel; - case PrimaryRole: - return output->isPrimary(); - case SizeRole: - return output->geometry().size(); - case PositionRole: - return m_outputs[index.row()].pos; - case NormalizedPositionRole: - return output->geometry().topLeft(); - case AutoRotateRole: - return m_config->autoRotate(output); - case AutoRotateOnlyInTabletModeRole: - return m_config->autoRotateOnlyInTabletMode(output); - case RotationRole: - return output->rotation(); - case ScaleRole: - return output->scale(); - case ResolutionIndexRole: - return resolutionIndex(output); - case ResolutionsRole: - return resolutionsStrings(output); - case RefreshRateIndexRole: - return refreshRateIndex(output); - case ReplicationSourceModelRole: - return replicationSourceModel(output); - case ReplicationSourceIndexRole: - return replicationSourceIndex(index.row()); - case ReplicasModelRole: - return replicasModel(output); - case RefreshRatesRole: - QVariantList ret; - for (const auto rate : refreshRates(output)) { - ret << QString("%1 Hz").arg(int(rate + 0.5)); - } - return ret; - } - return QVariant(); -} - -bool OutputModel::setData(const QModelIndex &index, - const QVariant &value, int role) -{ - if (index.row() < 0 || index.row() >= m_outputs.count()) { - return false; - } - - Output &output = m_outputs[index.row()]; - switch (role) { - case PositionRole: - if (value.canConvert()) { - QPoint val = value.toPoint(); - if (output.pos == val) { - return false; - } - - snap(output, val); - m_outputs[index.row()].pos = val; - updatePositions(); - Q_EMIT positionChanged(); - Q_EMIT dataChanged(index, index, {role}); - return true; - } - break; - case EnabledRole: - if (value.canConvert()) { - return setEnabled(index.row(), value.toBool()); - } - break; - case PrimaryRole: - if (value.canConvert()) { - bool primary = value.toBool(); - if (output.ptr->isPrimary() == primary) { - return false; - } - m_config->config()->setPrimaryOutput(output.ptr); - Q_EMIT dataChanged(index, index, {role}); - return true; - } - break; - case ResolutionIndexRole: - if (value.canConvert()) { - return setResolution(index.row(), value.toInt()); - } - break; - case RefreshRateIndexRole: - if (value.canConvert()) { - return setRefreshRate(index.row(), value.toInt()); - } - break; - case AutoRotateRole: - if (value.canConvert()) { - return setAutoRotate(index.row(), value.value()); - } - break; - case AutoRotateOnlyInTabletModeRole: - if (value.canConvert()) { - return setAutoRotateOnlyInTabletMode(index.row(), value.value()); - } - break; - case RotationRole: - if (value.canConvert()) { - return setRotation(index.row(), - value.value()); - } - break; - case ReplicationSourceIndexRole: - if (value.canConvert()) { - return setReplicationSourceIndex(index.row(), value.toInt() - 1); - } - break; - case ScaleRole: - bool ok; - const qreal scale = value.toReal(&ok); - if (ok && !qFuzzyCompare(output.ptr->scale(), scale)) { - output.ptr->setScale(scale); - m_config->setScale(output.ptr, scale); - Q_EMIT sizeChanged(); - Q_EMIT dataChanged(index, index, {role, SizeRole}); - return true; - } - break; - } - return false; -} - -QHash OutputModel::roleNames() const -{ - QHash roles = QAbstractItemModel::roleNames(); - roles[EnabledRole] = "enabled"; - roles[InternalRole] = "internal"; - roles[PrimaryRole] = "primary"; - roles[SizeRole] = "size"; - roles[PositionRole] = "position"; - roles[NormalizedPositionRole] = "normalizedPosition"; - roles[AutoRotateRole] = "autoRotate"; - roles[AutoRotateOnlyInTabletModeRole] = "autoRotateOnlyInTabletMode"; - roles[RotationRole] = "rotation"; - roles[ScaleRole] = "scale"; - roles[ResolutionIndexRole] = "resolutionIndex"; - roles[ResolutionsRole] = "resolutions"; - roles[RefreshRateIndexRole] = "refreshRateIndex"; - roles[RefreshRatesRole] = "refreshRates"; - roles[ReplicationSourceModelRole] = "replicationSourceModel"; - roles[ReplicationSourceIndexRole] = "replicationSourceIndex"; - roles[ReplicasModelRole] = "replicasModel"; - return roles; -} - -void OutputModel::add(const KScreen::OutputPtr &output) -{ - const int insertPos = m_outputs.count(); - Q_EMIT beginInsertRows(QModelIndex(), insertPos, insertPos); - - int i = 0; - while (i < m_outputs.size()) { - const QPoint pos = m_outputs[i].ptr->pos(); - if (output->pos().x() < pos.x()) { - break; - } - if (output->pos().x() == pos.x() && - output->pos().y() < pos.y()) { - break; - } - i++; - } - // Set the initial non-normalized position to be the normalized - // position plus the current delta. - QPoint pos = output->pos(); - if (!m_outputs.isEmpty()) { - const QPoint delta = m_outputs[0].pos - m_outputs[0].ptr->pos(); - pos = output->pos() + delta; - } - m_outputs.insert(i, Output(output, pos)); - - connect(output.data(), &KScreen::Output::priorityChanged, - this, [this, output](){ - roleChanged(output->id(), PrimaryRole); - }); - Q_EMIT endInsertRows(); - - // Update replications. - for (int j = 0; j < m_outputs.size(); j++) { - if (i == j) { - continue; - } - QModelIndex index = createIndex(j, 0); - // Calling this directly ignores possible optimization when the - // refresh rate hasn't changed in fact. But that's ok. - Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, - ReplicationSourceIndexRole}); - } -} - -void OutputModel::remove(int outputId) -{ - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [outputId](const Output &output) { - return output.ptr->id() == outputId; - }); - if (it != m_outputs.end()) { - const int index = it - m_outputs.begin(); - Q_EMIT beginRemoveRows(QModelIndex(), index, index); - m_outputs.erase(it); - Q_EMIT endRemoveRows(); - } -} - -void OutputModel::resetPosition(const Output &output) -{ - if (output.posReset.x() < 0) { - // KCM was closed in between. - for (const Output &out : m_outputs) { - if (out.ptr->id() == output.ptr->id()) { - continue; - } - if (out.ptr->geometry().right() > output.ptr->pos().x()) { - output.ptr->setPos(out.ptr->geometry().topRight()); - } - } - } else { - output.ptr->setPos(/*output.ptr->pos() - */output.posReset); - } -} - -bool OutputModel::setEnabled(int outputIndex, bool enable) -{ - Output &output = m_outputs[outputIndex]; - - if (output.ptr->isEnabled() == enable) { - return false; - } - - output.ptr->setEnabled(enable); - - if (enable) { - resetPosition(output); - - setResolution(outputIndex, resolutionIndex(output.ptr)); - reposition(); - } else { - output.posReset = output.ptr->pos(); - } - - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {EnabledRole}); - return true; -} - -inline bool refreshRateCompare(float rate1, float rate2) -{ - return qAbs(rate1 - rate2) < 0.5; -} - -bool OutputModel::setResolution(int outputIndex, int resIndex) -{ - const Output &output = m_outputs[outputIndex]; - const auto resolutionList = resolutions(output.ptr); - if (resIndex < 0 || resIndex >= resolutionList.size()) { - return false; - } - const QSize size = resolutionList[resIndex]; - - const float oldRate = output.ptr->currentMode() ? output.ptr->currentMode()->refreshRate() : - -1; - const auto modes = output.ptr->modes(); - - auto modeIt = std::find_if(modes.begin(), modes.end(), - [size, oldRate](const KScreen::ModePtr &mode) { - // TODO: we don't want to compare against old refresh rate if - // refresh rate selection is auto. - return mode->size() == size && - refreshRateCompare(mode->refreshRate(), oldRate); - }); - - if (modeIt == modes.end()) { - // New resolution does not support previous refresh rate. - // Get the highest one instead. - float bestRefreshRate = 0; - auto it = modes.begin(); - while (it != modes.end()) { - if ((*it)->size() == size && (*it)->refreshRate() > bestRefreshRate) { - modeIt = it; - } - it++; - } - } - Q_ASSERT(modeIt != modes.end()); - - const auto id = (*modeIt)->id(); - if (output.ptr->currentModeId() == id) { - return false; - } - output.ptr->setCurrentModeId(id); - - QModelIndex index = createIndex(outputIndex, 0); - // Calling this directly ignores possible optimization when the - // refresh rate hasn't changed in fact. But that's ok. - Q_EMIT dataChanged(index, index, {ResolutionIndexRole, - SizeRole, - RefreshRateIndexRole}); - Q_EMIT sizeChanged(); - return true; -} - -bool OutputModel::setRefreshRate(int outputIndex, int refIndex) -{ - const Output &output = m_outputs[outputIndex]; - const auto rates = refreshRates(output.ptr); - if (refIndex < 0 || refIndex >= rates.size()) { - return false; - } - const float refreshRate = rates[refIndex]; - - const auto modes = output.ptr->modes(); - const auto oldMode = output.ptr->currentMode(); - - auto modeIt = std::find_if(modes.begin(), modes.end(), - [oldMode, refreshRate](const KScreen::ModePtr &mode) { - // TODO: we don't want to compare against old refresh rate if - // refresh rate selection is auto. - return mode->size() == oldMode->size() && - refreshRateCompare(mode->refreshRate(), refreshRate); - }); - Q_ASSERT(modeIt != modes.end()); - - if (refreshRateCompare(oldMode->refreshRate(), (*modeIt)->refreshRate())) { - // no change - return false; - } - output.ptr->setCurrentModeId((*modeIt)->id()); - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {RefreshRateIndexRole}); - return true; -} - -bool OutputModel::setAutoRotate(int outputIndex, bool value) -{ - Output &output = m_outputs[outputIndex]; - - if (m_config->autoRotate(output.ptr) == value) { - return false; - } - m_config->setAutoRotate(output.ptr, value); - - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {AutoRotateRole}); - return true; -} - -bool OutputModel::setAutoRotateOnlyInTabletMode(int outputIndex, bool value) -{ - Output &output = m_outputs[outputIndex]; - - if (m_config->autoRotateOnlyInTabletMode(output.ptr) == value) { - return false; - } - m_config->setAutoRotateOnlyInTabletMode(output.ptr, value); - - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {AutoRotateOnlyInTabletModeRole}); - return true; -} - -bool OutputModel::setRotation(int outputIndex, KScreen::Output::Rotation rotation) -{ - const Output &output = m_outputs[outputIndex]; - - if (rotation != KScreen::Output::None - && rotation != KScreen::Output::Left - && rotation != KScreen::Output::Inverted - && rotation != KScreen::Output::Right) { - return false; - } - if (output.ptr->rotation() == rotation) { - return false; - } - output.ptr->setRotation(rotation); - - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {RotationRole, SizeRole}); - Q_EMIT sizeChanged(); - return true; - -} - -int OutputModel::resolutionIndex(const KScreen::OutputPtr &output) const -{ - const QSize currentResolution = output->enforcedModeSize(); - - if (!currentResolution.isValid()) { - return 0; - } - - const auto sizes = resolutions(output); - - const auto it = std::find_if(sizes.begin(), - sizes.end(), - [currentResolution](const QSize &size) { - return size == currentResolution; - }); - if (it == sizes.end()) { - return -1; - } - return it - sizes.begin(); -} - -int OutputModel::refreshRateIndex(const KScreen::OutputPtr &output) const -{ - if (!output->currentMode()) { - return 0; - } - const auto rates = refreshRates(output); - const float currentRate = output->currentMode()->refreshRate(); - - const auto it = std::find_if(rates.begin(), - rates.end(), - [currentRate](float rate) { - return refreshRateCompare(rate, currentRate); - }); - if (it == rates.end()) { - return 0; - } - return it - rates.begin(); -} - -static int greatestCommonDivisor(int a, int b) { - if (b == 0) { - return a; - } - return greatestCommonDivisor(b, a % b); -} - -QVariantList OutputModel::resolutionsStrings(const KScreen::OutputPtr &output) const -{ - QVariantList ret; - - for (const QSize &size : resolutions(output)) { - int divisor = greatestCommonDivisor(size.width(), size.height()); - - // Prefer "16:10" over "8:5" - if (size.height() / divisor == 5) { - divisor /= 2; - } - - const QString text = QString("%1x%2").arg(QString::number(size.width())) - .arg(QString::number(size.height())); - - ret << text; - } - - return ret; -} - -QVector OutputModel::resolutions(const KScreen::OutputPtr &output) const -{ - QVector hits; - - for (const auto &mode : output->modes()) { - const QSize size = mode->size(); - if (!hits.contains(size)) { - hits << size; - } - } - std::sort(hits.begin(), hits.end(), [](const QSize &a, const QSize &b) { - if (a.width() > b.width()) { - return true; - } - if (a.width() == b.width() && a.height() > b.height()) { - return true; - } - return false; - }); - return hits; -} - -QVector OutputModel::refreshRates(const KScreen::OutputPtr - &output) const -{ - QVector hits; - - QSize baseSize; - if (output->currentMode()) { - baseSize = output->currentMode()->size(); - } else if (output->preferredMode()) { - baseSize = output->preferredMode()->size(); - } - if (!baseSize.isValid()) { - return hits; - } - - for (const auto &mode : output->modes()) { - if (mode->size() != baseSize) { - continue; - } - const float rate = mode->refreshRate(); - if (std::find_if(hits.begin(), hits.end(), - [rate](float r) { - return refreshRateCompare(r, rate); - }) != hits.end()) { - continue; - } - hits << rate; - } - return hits; -} - -int OutputModel::replicationSourceId(const Output &output) const -{ - const KScreen::OutputPtr source = m_config->replicationSource(output.ptr); - if (!source) { - return 0; - } - return source->id(); -} - -QStringList OutputModel::replicationSourceModel(const KScreen::OutputPtr &output) const -{ - QStringList ret = { QObject::tr("None") }; - - for (const auto &out : m_outputs) { - if (out.ptr->id() != output->id()) { - const int outSourceId = replicationSourceId(out); - if (outSourceId == output->id()) { - // 'output' is already source for replication, can't be replica itself - return { QObject::tr("Replicated by other output") }; - } - if (outSourceId) { - // This 'out' is a replica. Can't be a replication source. - continue; - } - ret.append(Utils::outputName(out.ptr)); - } - } - return ret; -} - -bool OutputModel::setReplicationSourceIndex(int outputIndex, int sourceIndex) -{ - if (outputIndex <= sourceIndex) { - sourceIndex++; - } - if (sourceIndex >= m_outputs.count()) { - return false; - } - - Output &output = m_outputs[outputIndex]; - const int oldSourceId = replicationSourceId(output); - - if (sourceIndex < 0) { - if (oldSourceId == 0) { - // no change - return false; - } - m_config->setReplicationSource(output.ptr, nullptr); - output.ptr->setExplicitLogicalSize(QSizeF()); - resetPosition(output); - } else { - const auto source = m_outputs[sourceIndex].ptr; - if (oldSourceId == source->id()) { - // no change - return false; - } - m_config->setReplicationSource(output.ptr, source); - output.posReset = output.ptr->pos(); - output.ptr->setPos(source->pos()); - output.ptr->setExplicitLogicalSize(source->explicitLogicalSize()); - } - - reposition(); - - QModelIndex index = createIndex(outputIndex, 0); - Q_EMIT dataChanged(index, index, {ReplicationSourceIndexRole}); - - if (oldSourceId != 0) { - auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [oldSourceId](const Output &out) { - return out.ptr->id() == oldSourceId; - }); - if (it != m_outputs.end()) { - QModelIndex index = createIndex(it - m_outputs.begin(), 0); - Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicasModelRole}); - } - } - if (sourceIndex >= 0) { - QModelIndex index = createIndex(sourceIndex, 0); - Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicasModelRole}); - } - return true; -} - -int OutputModel::replicationSourceIndex(int outputIndex) const -{ - const int sourceId = replicationSourceId(m_outputs[outputIndex]); - if (!sourceId) { - return 0; - } - for (int i = 0; i < m_outputs.size(); i++) { - const Output &output = m_outputs[i]; - if (output.ptr->id() == sourceId) { - return i + (outputIndex > i ? 1 : 0); - } - } - return 0; -} - -QVariantList OutputModel::replicasModel(const KScreen::OutputPtr &output) const -{ - QVariantList ret; - for (int i = 0; i < m_outputs.size(); i++) { - const Output &out = m_outputs[i]; - if (out.ptr->id() != output->id()) { - if (replicationSourceId(out) == output->id()) { - ret << i; - } - } - } - return ret; -} - -void OutputModel::roleChanged(int outputId, OutputRoles role) -{ - for (int i = 0; i < m_outputs.size(); i++) { - Output &output = m_outputs[i]; - if (output.ptr->id() == outputId) { - QModelIndex index = createIndex(i, 0); - Q_EMIT dataChanged(index, index, {role}); - return; - } - } -} - -bool OutputModel::positionable(const Output &output) const -{ - return output.ptr->isPositionable(); -} - -void OutputModel::reposition() -{ - int x = 0; - int y = 0; - - // Find first valid output. - for (const auto &out : m_outputs) { - if (positionable(out)) { - x = out.ptr->pos().x(); - y = out.ptr->pos().y(); - break; - } - } - - for (int i = 0; i < m_outputs.size(); i++) { - if (!positionable(m_outputs[i])) { - continue; - } - const QPoint &cmp = m_outputs[i].ptr->pos(); - - if (cmp.x() < x) { - x = cmp.x(); - } - if (cmp.y() < y) { - y = cmp.y(); - } - } - - if (x == 0 && y == 0) { - return; - } - - for (int i = 0; i < m_outputs.size(); i++) { - auto &out = m_outputs[i]; - out.ptr->setPos(out.ptr->pos() - QPoint(x, y)); - QModelIndex index = createIndex(i, 0); - Q_EMIT dataChanged(index, index, {NormalizedPositionRole}); - } - m_config->normalizeScreen(); -} - -QPoint OutputModel::originDelta() const -{ - int x = 0; - int y = 0; - - // Find first valid output. - for (const auto &out : m_outputs) { - if (positionable(out)) { - x = out.pos.x(); - y = out.pos.y(); - break; - } - } - - for (int i = 1; i < m_outputs.size(); i++) { - if (!positionable(m_outputs[i])) { - continue; - } - const QPoint &cmp = m_outputs[i].pos; - - if (cmp.x() < x) { - x = cmp.x(); - } - if (cmp.y() < y) { - y = cmp.y(); - } - } - return QPoint(x, y); -} - -void OutputModel::updatePositions() -{ - const QPoint delta = originDelta(); - for (int i = 0; i < m_outputs.size(); i++) { - const auto &out = m_outputs[i]; - if (!positionable(out)) { - continue; - } - const QPoint set = out.pos - delta; - if (out.ptr->pos() != set) { - out.ptr->setPos(set); - QModelIndex index = createIndex(i, 0); - Q_EMIT dataChanged(index, index, {NormalizedPositionRole}); - } - } - updateOrder(); -} - -void OutputModel::updateOrder() -{ - auto order = m_outputs; - std::sort(order.begin(), order.end(), [](const Output &a, const Output &b) { - const int xDiff = b.ptr->pos().x() - a.ptr->pos().x(); - const int yDiff = b.ptr->pos().y() - a.ptr->pos().y(); - if (xDiff > 0) { - return true; - } - if (xDiff == 0 && yDiff > 0) { - return true; - } - return false; - }); - - for (int i = 0; i < order.size(); i++) { - for (int j = 0; j < m_outputs.size(); j++) { - if (order[i].ptr->id() != m_outputs[j].ptr->id()) { - continue; - } - if (i != j) { - beginMoveRows(QModelIndex(), j, j, QModelIndex(), i); - m_outputs.remove(j); - m_outputs.insert(i, order[i]); - endMoveRows(); - } - break; - } - } - - // TODO: Could this be optimized by only outputs updating where replica indices changed? - for (int i = 0; i < m_outputs.size(); i++) { - QModelIndex index = createIndex(i, 0); - Q_EMIT dataChanged(index, index, { ReplicasModelRole }); - } -} - -bool OutputModel::normalizePositions() -{ - bool changed = false; - for (int i = 0; i < m_outputs.size(); i++) { - auto &output = m_outputs[i]; - if (output.pos == output.ptr->pos()) { - continue; - } - if (!positionable(output)) { - continue; - } - changed = true; - auto index = createIndex(i, 0); - output.pos = output.ptr->pos(); - Q_EMIT dataChanged(index, index, {PositionRole}); - } - return changed; -} - -bool OutputModel::positionsNormalized() const -{ - // There might be slight deviations because of snapping. - return originDelta().manhattanLength() < 5; -} - -const int s_snapArea = 80; - -bool isVerticalClose(const QRect &rect1, const QRect &rect2) -{ - if (rect2.top() - rect1.bottom() > s_snapArea ) { - return false; - } - if (rect1.top() - rect2.bottom() > s_snapArea ) { - return false; - } - return true; -} - -bool snapToRight(const QRect &target, - const QSize &size, - QPoint &dest) -{ - if (qAbs(target.right() - dest.x()) < s_snapArea) { - // In snap zone for left to right snap. - dest.setX(target.right() + 1); - return true; - } - if (qAbs(target.right() - (dest.x() + size.width())) < s_snapArea) { - // In snap zone for right to right snap. - dest.setX(target.right() - size.width()); - return true; - } - return false; -} - -bool snapToLeft(const QRect &target, - const QSize &size, - QPoint &dest) -{ - if (qAbs(target.left() - dest.x()) < s_snapArea) { - // In snap zone for left to left snap. - dest.setX(target.left()); - return true; - } - if (qAbs(target.left() - (dest.x() + size.width())) < s_snapArea) { - // In snap zone for right to left snap. - dest.setX(target.left() - size.width()); - return true; - } - return false; -} - -bool snapToMiddle(const QRect &target, - const QSize &size, - QPoint &dest) -{ - const int outputMid = dest.y() + size.height() / 2; - const int targetMid = target.top() + target.height() / 2; - if (qAbs(targetMid - outputMid) < s_snapArea) { - // In snap zone for middle to middle snap. - dest.setY(targetMid - size.height() / 2); - return true; - } - return false; -} - -bool snapToTop(const QRect &target, - const QSize &size, - QPoint &dest) -{ - if (qAbs(target.top() - dest.y()) < s_snapArea) { - // In snap zone for bottom to top snap. - dest.setY(target.top()); - return true; - } - if (qAbs(target.top() - (dest.y() + size.height())) < s_snapArea) { - // In snap zone for top to top snap. - dest.setY(target.top() - size.height()); - return true; - } - return false; -} - -bool snapToBottom(const QRect &target, - const QSize &size, - QPoint &dest) -{ - if (qAbs(target.bottom() - dest.y()) < s_snapArea) { - // In snap zone for top to bottom snap. - dest.setY(target.bottom() + 1); - return true; - } - if (qAbs(target.bottom() - (dest.y() + size.height())) < s_snapArea) { - // In snap zone for bottom to bottom snap. - dest.setY(target.bottom() - size.height() + 1); - return true; - } - return false; -} - -bool snapVertical(const QRect &target, - const QSize &size, - QPoint &dest) -{ - if (snapToMiddle(target, size, dest)) { - return true; - } - if (snapToBottom(target, size, dest)) { - return true; - } - if (snapToTop(target, size, dest)) { - return true; - } - return false; -} - -void OutputModel::snap(const Output &output, QPoint &dest) -{ - const QSize size = output.ptr->geometry().size(); - for (const Output &out : m_outputs) { - if (out.ptr->id() == output.ptr->id()) { - // Can not snap to itself. - continue; - } - if (!positionable(out)) { - continue; - } - - const QRect target(out.pos, out.ptr->geometry().size()); - - if (!isVerticalClose(target, QRect(dest, size))) { - continue; - } - - // try snap left to right first - if (snapToRight(target, size, dest)) { - snapVertical(target, size, dest); - continue; - } - if (snapToLeft(target, size, dest)) { - snapVertical(target, size, dest); - continue; - } - if (snapVertical(target, size, dest)) { - continue; - } - } -} diff --git a/screen/outputmodel.h b/screen/outputmodel.h deleted file mode 100644 index 49cd5bb..0000000 --- a/screen/outputmodel.h +++ /dev/null @@ -1,154 +0,0 @@ -/******************************************************************** -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 OUTPUTMODEL_H -#define OUTPUTMODEL_H - -#include -#include - -#include -#include - -class ConfigHandler; - -class OutputModel : public QAbstractListModel -{ - Q_OBJECT - -public: - enum OutputRoles { - EnabledRole = Qt::UserRole + 1, - InternalRole, - PrimaryRole, - SizeRole, - /** Position in the graphical view relative to some arbitrary but fixed origin. */ - PositionRole, - /** Position for backend relative to most northwest display corner. */ - NormalizedPositionRole, - AutoRotateRole, - AutoRotateOnlyInTabletModeRole, - RotationRole, - ScaleRole, - ResolutionIndexRole, - ResolutionsRole, - RefreshRateIndexRole, - RefreshRatesRole, - ReplicationSourceModelRole, - ReplicationSourceIndexRole, - ReplicasModelRole - }; - - explicit OutputModel(ConfigHandler *configHandler); - ~OutputModel() override = default; - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, - int role = Qt::DisplayRole) const override; - bool setData(const QModelIndex &index, - const QVariant &value, - int role = Qt::EditRole) override; - - void add(const KScreen::OutputPtr &output); - void remove(int outputId); - - /** - * Resets the origin for calculation of positions to the most northwest display corner - * while keeping the normalized positions untouched. - * - * @return true if some (unnormalized) output position changed on this call, otherwise false. - */ - bool normalizePositions(); - bool positionsNormalized() const; - -Q_SIGNALS: - void positionChanged(); - void sizeChanged(); - void changed(); - -protected: - QHash roleNames() const override; - -private: - struct Output { - Output() {} - Output(const Output &output) - : ptr(output.ptr) - , pos(output.pos) - {} - Output(Output &&) noexcept = default; - Output(KScreen::OutputPtr _ptr, const QPoint &_pos) - : ptr(_ptr) - , pos(_pos) - {} - Output &operator=(const Output &output) { - ptr = output.ptr; - pos = output.pos; - posReset = QPoint(-1, -1); - return *this; - } - Output &operator=(Output &&) noexcept = default; - - KScreen::OutputPtr ptr; - QPoint pos; - QPoint posReset = QPoint(-1, -1); - }; - - void roleChanged(int outputId, OutputRoles role); - - void resetPosition(const Output &output); - void reposition(); - void updatePositions(); - void updateOrder(); - QPoint originDelta() const; - - /** - * @brief Snaps moved output to others - * @param output the moved output - * @param dest the desired destination to be adjusted by snapping - */ - void snap(const Output &output, QPoint &dest); - - bool setEnabled(int outputIndex, bool enable); - - bool setResolution(int outputIndex, int resIndex); - bool setRefreshRate(int outputIndex, int refIndex); - bool setRotation(int outputIndex, KScreen::Output::Rotation rotation); - bool setAutoRotate(int outputIndex, bool value); - bool setAutoRotateOnlyInTabletMode(int outputIndex, bool value); - - int resolutionIndex(const KScreen::OutputPtr &output) const; - int refreshRateIndex(const KScreen::OutputPtr &output) const; - QVariantList resolutionsStrings(const KScreen::OutputPtr &output) const; - QVector resolutions(const KScreen::OutputPtr &output) const; - QVector refreshRates(const KScreen::OutputPtr &output) const; - - bool positionable(const Output &output) const; - - QStringList replicationSourceModel(const KScreen::OutputPtr &output) const; - bool setReplicationSourceIndex(int outputIndex, int sourceIndex); - int replicationSourceIndex(int outputIndex) const; - int replicationSourceId(const Output &output) const; - - QVariantList replicasModel(const KScreen::OutputPtr &output) const; - - QVector m_outputs; - - ConfigHandler *m_config; -}; - -#endif \ No newline at end of file diff --git a/screen/plugin.cpp b/screen/plugin.cpp deleted file mode 100644 index d377dca..0000000 --- a/screen/plugin.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -#include "outputmodel.h" -#include "screen.h" - -class QmlPlugins : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") - -public: - void registerTypes(const char * uri) override { - // qmlRegisterType(uri, 1, 0, "OutputModel"); - qmlRegisterType(uri, 1, 0, "Screen"); - qmlRegisterType(uri, 1, 0, "Output"); - } -}; - -#include "plugin.moc" \ No newline at end of file diff --git a/screen/screen.cpp b/screen/screen.cpp deleted file mode 100644 index 52b5aa8..0000000 --- a/screen/screen.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "screen.h" -#include "outputmodel.h" - -#include - -#include -#include - -Screen::Screen(QObject *parent) - : QObject(parent) -{ - qmlRegisterType(); - load(); -} - -void Screen::load() -{ - // Don't pull away the outputModel under QML's feet - // signal its disappearance first before deleting and replacing it. - // We take the m_config pointer so outputModel() will return null, - // gracefully cleaning up the QML side and only then we will delete it. - auto *oldConfig = m_config.release(); - if (oldConfig) { - emit outputModelChanged(); - delete oldConfig; - } - - m_config.reset(new ConfigHandler(this)); - connect(m_config.get(), &ConfigHandler::outputModelChanged, this, &Screen::outputModelChanged); - - connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, &Screen::configReady); -} - -void Screen::save() -{ - if (!m_config) - return; - - auto config = m_config->config(); - bool atLeastOneEnabledOutput = false; - - for (const KScreen::OutputPtr &output : config->outputs()) { - KScreen::ModePtr mode = output->currentMode(); - atLeastOneEnabledOutput |= output->isEnabled(); - } - - m_config->writeControl(); - - auto *op = new KScreen::SetConfigOperation(config); - op->exec(); -} - -OutputModel *Screen::outputModel() const -{ - if (!m_config) { - return nullptr; - } - - return m_config->outputModel(); -} - -void Screen::configReady(KScreen::ConfigOperation *op) -{ - if (op->hasError()) { - m_config.reset(); - return; - } - - KScreen::ConfigPtr config = qobject_cast(op)->config(); - // const bool autoRotationSupported = config->supportedFeatures() & (KScreen::Config::Feature::AutoRotation | KScreen::Config::Feature::TabletMode); - - m_config->setConfig(config); -} diff --git a/screen/screen.h b/screen/screen.h deleted file mode 100644 index 0f79913..0000000 --- a/screen/screen.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "confighandler.h" -#include "outputmodel.h" - -class ConfigHandler; -class OutputModel; -class Screen : public QObject -{ - Q_OBJECT - Q_PROPERTY(OutputModel *outputModel READ outputModel NOTIFY outputModelChanged) - -public: - explicit Screen(QObject *parent = nullptr); - - OutputModel *outputModel() const; - - void load(); - Q_INVOKABLE void save(); - -private: - void configReady(KScreen::ConfigOperation *op); - -Q_SIGNALS: - void outputModelChanged(); - -private: - std::unique_ptr m_config; -}; \ No newline at end of file