File indexing completed on 2024-11-10 04:55:34
0001 /* 0002 SPDX-FileCopyrightText: 2012 Alejandro Fiestas Olivares <afiestas@kde.org> 0003 SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "config.h" 0008 #include "../common/control.h" 0009 #include "device.h" 0010 #include "kscreen_daemon_debug.h" 0011 #include "output.h" 0012 0013 #include <QDir> 0014 #include <QFile> 0015 #include <QJsonDocument> 0016 #include <QRect> 0017 #include <QStandardPaths> 0018 #include <QStringBuilder> 0019 0020 #include <cstdint> 0021 0022 #include <kscreen/output.h> 0023 #include <kscreen/screen.h> 0024 0025 QString Config::s_fixedConfigFileName = QStringLiteral("fixed-config"); 0026 QString Config::s_configsDirName = QString(); 0027 /*QStringLiteral("configs");*/ // TODO: KDE6 - Replace QString w/ QStringLiteral move these files into the subfolder 0028 0029 QString Config::configsDirPath() 0030 { 0031 return Globals::dirPath() % s_configsDirName; 0032 } 0033 0034 Config::Config(KScreen::ConfigPtr config, QObject *parent) 0035 : QObject(parent) 0036 , m_data(config) 0037 , m_control(new ControlConfig(config, this)) 0038 { 0039 } 0040 0041 QString Config::filePath() const 0042 { 0043 if (!QDir().mkpath(configsDirPath())) { 0044 return QString(); 0045 } 0046 return configsDirPath() % id(); 0047 } 0048 0049 QString Config::id() const 0050 { 0051 if (!m_data) { 0052 return QString(); 0053 } 0054 return m_data->connectedOutputsHash(); 0055 } 0056 0057 void Config::activateControlWatching() 0058 { 0059 connect(m_control, &ControlConfig::changed, this, &Config::controlChanged); 0060 m_control->activateWatcher(); 0061 } 0062 0063 bool Config::fileExists() const 0064 { 0065 return (QFile::exists(configsDirPath() % id()) || QFile::exists(configsDirPath() % s_fixedConfigFileName)); 0066 } 0067 0068 std::unique_ptr<Config> Config::readFile() 0069 { 0070 if (Device::self()->isLaptop() && !Device::self()->isLidClosed()) { 0071 // We may look for a config that has been set when the lid was closed, Bug: 353029 0072 const QString lidOpenedFilePath(filePath() % QStringLiteral("_lidOpened")); 0073 const QFile srcFile(lidOpenedFilePath); 0074 0075 if (srcFile.exists()) { 0076 QFile::remove(filePath()); 0077 if (QFile::copy(lidOpenedFilePath, filePath())) { 0078 QFile::remove(lidOpenedFilePath); 0079 qCDebug(KSCREEN_KDED) << "Restored lid opened config to" << id(); 0080 } 0081 } 0082 } 0083 return readFile(id()); 0084 } 0085 0086 std::unique_ptr<Config> Config::readOpenLidFile() 0087 { 0088 const QString openLidFile = id() % QStringLiteral("_lidOpened"); 0089 auto config = readFile(openLidFile); 0090 QFile::remove(configsDirPath() % openLidFile); 0091 return config; 0092 } 0093 0094 std::unique_ptr<Config> Config::readFile(const QString &fileName) 0095 { 0096 if (!m_data) { 0097 return nullptr; 0098 } 0099 auto config = std::unique_ptr<Config>(new Config(m_data->clone())); 0100 config->setValidityFlags(m_validityFlags); 0101 0102 QFile file; 0103 if (QFile::exists(configsDirPath() % s_fixedConfigFileName)) { 0104 file.setFileName(configsDirPath() % s_fixedConfigFileName); 0105 qCDebug(KSCREEN_KDED) << "found a fixed config, will use " << file.fileName(); 0106 } else { 0107 file.setFileName(configsDirPath() % fileName); 0108 } 0109 if (!file.open(QIODevice::ReadOnly)) { 0110 qCDebug(KSCREEN_KDED) << "failed to open file" << file.fileName(); 0111 return nullptr; 0112 } 0113 0114 QJsonDocument parser; 0115 QVariantList outputs = parser.fromJson(file.readAll()).toVariant().toList(); 0116 Output::readInOutputs(config->data(), outputs); 0117 0118 QSize screenSize; 0119 const auto configOutputs = config->data()->outputs(); 0120 for (const auto &output : configOutputs) { 0121 if (!output->isPositionable()) { 0122 continue; 0123 } 0124 0125 output->setExplicitLogicalSize(config->data()->logicalSizeForOutput(*output)); 0126 0127 const QRect geom = output->geometry(); 0128 if (geom.x() + geom.width() > screenSize.width()) { 0129 screenSize.setWidth(geom.x() + geom.width()); 0130 } 0131 if (geom.y() + geom.height() > screenSize.height()) { 0132 screenSize.setHeight(geom.y() + geom.height()); 0133 } 0134 } 0135 config->data()->screen()->setCurrentSize(screenSize); 0136 0137 if (!canBeApplied(config->data())) { 0138 return nullptr; 0139 } 0140 return config; 0141 } 0142 0143 bool Config::canBeApplied() const 0144 { 0145 return canBeApplied(m_data); 0146 } 0147 0148 bool Config::canBeApplied(KScreen::ConfigPtr config) const 0149 { 0150 #ifdef KDED_UNIT_TEST 0151 Q_UNUSED(config); 0152 return true; 0153 #else 0154 return KScreen::Config::canBeApplied(config, m_validityFlags); 0155 #endif 0156 } 0157 0158 bool Config::writeFile() 0159 { 0160 return writeFile(filePath()); 0161 } 0162 0163 bool Config::writeOpenLidFile() 0164 { 0165 return writeFile(filePath() % QStringLiteral("_lidOpened")); 0166 } 0167 0168 bool Config::writeFile(const QString &filePath) 0169 { 0170 if (id().isEmpty()) { 0171 return false; 0172 } 0173 const KScreen::OutputList outputs = m_data->outputs(); 0174 0175 const auto oldConfig = readFile(); 0176 KScreen::OutputList oldOutputs; 0177 if (oldConfig) { 0178 oldOutputs = oldConfig->data()->outputs(); 0179 } 0180 0181 const auto hasDuplicate = [&outputs](const auto output) { 0182 return std::any_of(outputs.begin(), outputs.end(), [output](const auto &o) { 0183 return o != output && o->hashMd5() == output->hashMd5(); 0184 }); 0185 }; 0186 0187 QVariantList outputList; 0188 for (const KScreen::OutputPtr &output : outputs) { 0189 QVariantMap info; 0190 0191 const auto oldOutputIt = std::find_if(oldOutputs.constBegin(), oldOutputs.constEnd(), [output](const KScreen::OutputPtr &out) { 0192 return out->hashMd5() == output->hashMd5(); 0193 }); 0194 const KScreen::OutputPtr oldOutput = oldOutputIt != oldOutputs.constEnd() ? *oldOutputIt : nullptr; 0195 0196 if (!output->isConnected()) { 0197 continue; 0198 } 0199 0200 Output::writeGlobalPart(output, info, oldOutput); 0201 info[QStringLiteral("priority")] = output->priority(); 0202 info[QStringLiteral("enabled")] = output->isEnabled(); 0203 0204 auto setOutputConfigInfo = [&info](const KScreen::OutputPtr &out) { 0205 if (!out) { 0206 return; 0207 } 0208 0209 QVariantMap pos; 0210 pos[QStringLiteral("x")] = out->pos().x(); 0211 pos[QStringLiteral("y")] = out->pos().y(); 0212 info[QStringLiteral("pos")] = pos; 0213 }; 0214 setOutputConfigInfo(output->isEnabled() ? output : oldOutput); 0215 0216 if (output->isEnabled()) { 0217 // try to update global output data 0218 Output::writeGlobal(output, hasDuplicate(output)); 0219 } 0220 0221 outputList.append(info); 0222 } 0223 0224 QFile file(filePath); 0225 if (!file.open(QIODevice::WriteOnly)) { 0226 qCWarning(KSCREEN_KDED) << "Failed to open config file for writing! " << file.errorString(); 0227 return false; 0228 } 0229 file.write(QJsonDocument::fromVariant(outputList).toJson()); 0230 qCDebug(KSCREEN_KDED) << "Config saved on: " << file.fileName(); 0231 0232 return true; 0233 } 0234 0235 void Config::log() 0236 { 0237 if (!m_data) { 0238 return; 0239 } 0240 const auto outputs = m_data->outputs(); 0241 for (const auto &o : outputs) { 0242 if (o->isConnected()) { 0243 qCDebug(KSCREEN_KDED) << o; 0244 } 0245 } 0246 } 0247 0248 #include "moc_config.cpp"