File indexing completed on 2024-05-05 09:51:11
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Daniel Vratil <dvratil@redhat.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 * 0006 */ 0007 0008 #include "configserializer_p.h" 0009 0010 #include "config.h" 0011 #include "kscreen_debug.h" 0012 #include "mode.h" 0013 #include "output.h" 0014 #include "screen.h" 0015 0016 #include <QDBusArgument> 0017 #include <QFile> 0018 #include <QJsonDocument> 0019 #include <QRect> 0020 0021 #include <cstdint> 0022 #include <optional> 0023 0024 using namespace KScreen; 0025 0026 QJsonObject ConfigSerializer::serializePoint(const QPoint &point) 0027 { 0028 QJsonObject obj; 0029 obj[QLatin1String("x")] = point.x(); 0030 obj[QLatin1String("y")] = point.y(); 0031 return obj; 0032 } 0033 0034 QJsonObject ConfigSerializer::serializeSize(const QSize &size) 0035 { 0036 QJsonObject obj; 0037 obj[QLatin1String("width")] = size.width(); 0038 obj[QLatin1String("height")] = size.height(); 0039 return obj; 0040 } 0041 0042 QJsonObject ConfigSerializer::serializeConfig(const ConfigPtr &config) 0043 { 0044 QJsonObject obj; 0045 0046 if (!config) { 0047 return obj; 0048 } 0049 0050 obj[QLatin1String("features")] = static_cast<int>(config->supportedFeatures()); 0051 0052 QJsonArray outputs; 0053 for (const OutputPtr &output : config->outputs()) { 0054 outputs.append(serializeOutput(output)); 0055 } 0056 obj[QLatin1String("outputs")] = outputs; 0057 if (config->screen()) { 0058 obj[QLatin1String("screen")] = serializeScreen(config->screen()); 0059 } 0060 0061 obj[QLatin1String("tabletModeAvailable")] = config->tabletModeAvailable(); 0062 obj[QLatin1String("tabletModeEngaged")] = config->tabletModeEngaged(); 0063 0064 return obj; 0065 } 0066 0067 QJsonObject ConfigSerializer::serializeOutput(const OutputPtr &output) 0068 { 0069 QJsonObject obj; 0070 0071 obj[QLatin1String("id")] = output->id(); 0072 obj[QLatin1String("name")] = output->name(); 0073 obj[QLatin1String("type")] = static_cast<int>(output->type()); 0074 obj[QLatin1String("icon")] = output->icon(); 0075 obj[QLatin1String("pos")] = serializePoint(output->pos()); 0076 obj[QLatin1String("scale")] = output->scale(); 0077 obj[QLatin1String("size")] = serializeSize(output->size()); 0078 obj[QLatin1String("rotation")] = static_cast<int>(output->rotation()); 0079 obj[QLatin1String("currentModeId")] = output->currentModeId(); 0080 obj[QLatin1String("preferredModes")] = serializeList(output->preferredModes()); 0081 obj[QLatin1String("connected")] = output->isConnected(); 0082 obj[QLatin1String("followPreferredMode")] = output->followPreferredMode(); 0083 obj[QLatin1String("enabled")] = output->isEnabled(); 0084 obj[QLatin1String("priority")] = static_cast<int>(output->priority()); 0085 obj[QLatin1String("clones")] = serializeList(output->clones()); 0086 // obj[QLatin1String("edid")] = output->edid()->raw(); 0087 obj[QLatin1String("sizeMM")] = serializeSize(output->sizeMm()); 0088 obj[QLatin1String("replicationSource")] = output->replicationSource(); 0089 0090 QJsonArray modes; 0091 for (const ModePtr &mode : output->modes()) { 0092 modes.append(serializeMode(mode)); 0093 } 0094 obj[QLatin1String("modes")] = modes; 0095 0096 if (output->capabilities() & Output::Capability::Overscan) { 0097 obj[QLatin1String("overscan")] = static_cast<int>(output->overscan()); 0098 } 0099 0100 if (output->capabilities() & Output::Capability::Vrr) { 0101 obj[QLatin1String("vrrPolicy")] = static_cast<int>(output->vrrPolicy()); 0102 } 0103 0104 if (output->capabilities() & Output::Capability::RgbRange) { 0105 obj[QLatin1String("rgbRange")] = static_cast<int>(output->rgbRange()); 0106 } 0107 0108 if (output->capabilities() & Output::Capability::HighDynamicRange) { 0109 obj[QLatin1String("hdr")] = output->isHdrEnabled(); 0110 } 0111 0112 if (output->capabilities() & Output::Capability::HighDynamicRange) { 0113 obj[QLatin1String("sdr-brightness")] = static_cast<int>(output->sdrBrightness()); 0114 } 0115 0116 if (output->capabilities() & Output::Capability::WideColorGamut) { 0117 obj[QLatin1String("wcg")] = output->isWcgEnabled(); 0118 } 0119 0120 return obj; 0121 } 0122 0123 QJsonObject ConfigSerializer::serializeMode(const ModePtr &mode) 0124 { 0125 QJsonObject obj; 0126 0127 obj[QLatin1String("id")] = mode->id(); 0128 obj[QLatin1String("name")] = mode->name(); 0129 obj[QLatin1String("size")] = serializeSize(mode->size()); 0130 obj[QLatin1String("refreshRate")] = mode->refreshRate(); 0131 0132 return obj; 0133 } 0134 0135 QJsonObject ConfigSerializer::serializeScreen(const ScreenPtr &screen) 0136 { 0137 QJsonObject obj; 0138 0139 obj[QLatin1String("id")] = screen->id(); 0140 obj[QLatin1String("currentSize")] = serializeSize(screen->currentSize()); 0141 obj[QLatin1String("maxSize")] = serializeSize(screen->maxSize()); 0142 obj[QLatin1String("minSize")] = serializeSize(screen->minSize()); 0143 obj[QLatin1String("maxActiveOutputsCount")] = screen->maxActiveOutputsCount(); 0144 0145 return obj; 0146 } 0147 0148 QPoint ConfigSerializer::deserializePoint(const QDBusArgument &arg) 0149 { 0150 int x = 0, y = 0; 0151 arg.beginMap(); 0152 while (!arg.atEnd()) { 0153 QString key; 0154 QVariant value; 0155 arg.beginMapEntry(); 0156 arg >> key >> value; 0157 if (key == QLatin1Char('x')) { 0158 x = value.toInt(); 0159 } else if (key == QLatin1Char('y')) { 0160 y = value.toInt(); 0161 } else { 0162 qCWarning(KSCREEN) << "Invalid key in Point map: " << key; 0163 return QPoint(); 0164 } 0165 arg.endMapEntry(); 0166 } 0167 arg.endMap(); 0168 return QPoint(x, y); 0169 } 0170 0171 QSize ConfigSerializer::deserializeSize(const QDBusArgument &arg) 0172 { 0173 int w = 0, h = 0; 0174 arg.beginMap(); 0175 while (!arg.atEnd()) { 0176 QString key; 0177 QVariant value; 0178 arg.beginMapEntry(); 0179 arg >> key >> value; 0180 if (key == QLatin1String("width")) { 0181 w = value.toInt(); 0182 } else if (key == QLatin1String("height")) { 0183 h = value.toInt(); 0184 } else { 0185 qCWarning(KSCREEN) << "Invalid key in size struct: " << key; 0186 return QSize(); 0187 } 0188 arg.endMapEntry(); 0189 } 0190 arg.endMap(); 0191 0192 return QSize(w, h); 0193 } 0194 0195 ConfigPtr ConfigSerializer::deserializeConfig(const QVariantMap &map) 0196 { 0197 ConfigPtr config(new Config); 0198 0199 if (map.contains(QLatin1String("features"))) { 0200 config->setSupportedFeatures(static_cast<Config::Features>(map[QStringLiteral("features")].toInt())); 0201 } 0202 0203 if (map.contains(QLatin1String("tabletModeAvailable"))) { 0204 config->setTabletModeAvailable(map[QStringLiteral("tabletModeAvailable")].toBool()); 0205 } 0206 if (map.contains(QLatin1String("tabletModeEngaged"))) { 0207 config->setTabletModeEngaged(map[QStringLiteral("tabletModeEngaged")].toBool()); 0208 } 0209 0210 if (map.contains(QLatin1String("outputs"))) { 0211 const QDBusArgument &outputsArg = map[QStringLiteral("outputs")].value<QDBusArgument>(); 0212 outputsArg.beginArray(); 0213 OutputList outputs; 0214 while (!outputsArg.atEnd()) { 0215 QVariant value; 0216 outputsArg >> value; 0217 const KScreen::OutputPtr output = deserializeOutput(value.value<QDBusArgument>()); 0218 if (!output) { 0219 return ConfigPtr(); 0220 } 0221 outputs.insert(output->id(), output); 0222 } 0223 outputsArg.endArray(); 0224 config->setOutputs(outputs); 0225 } 0226 0227 if (map.contains(QLatin1String("screen"))) { 0228 const QDBusArgument &screenArg = map[QStringLiteral("screen")].value<QDBusArgument>(); 0229 const KScreen::ScreenPtr screen = deserializeScreen(screenArg); 0230 if (!screen) { 0231 return ConfigPtr(); 0232 } 0233 config->setScreen(screen); 0234 } 0235 0236 return config; 0237 } 0238 0239 OutputPtr ConfigSerializer::deserializeOutput(const QDBusArgument &arg) 0240 { 0241 OutputPtr output(new Output); 0242 std::optional<bool> primary = std::nullopt; 0243 std::optional<uint32_t> priority = std::nullopt; 0244 0245 arg.beginMap(); 0246 while (!arg.atEnd()) { 0247 QString key; 0248 QVariant value; 0249 arg.beginMapEntry(); 0250 arg >> key >> value; 0251 if (key == QLatin1String("id")) { 0252 output->setId(value.toInt()); 0253 } else if (key == QLatin1String("name")) { 0254 output->setName(value.toString()); 0255 } else if (key == QLatin1String("type")) { 0256 output->setType(static_cast<Output::Type>(value.toInt())); 0257 } else if (key == QLatin1String("icon")) { 0258 output->setIcon(value.toString()); 0259 } else if (key == QLatin1String("pos")) { 0260 output->setPos(deserializePoint(value.value<QDBusArgument>())); 0261 } else if (key == QLatin1String("scale")) { 0262 output->setScale(value.toDouble()); 0263 } else if (key == QLatin1String("size")) { 0264 output->setSize(deserializeSize(value.value<QDBusArgument>())); 0265 } else if (key == QLatin1String("rotation")) { 0266 output->setRotation(static_cast<Output::Rotation>(value.toInt())); 0267 } else if (key == QLatin1String("currentModeId")) { 0268 output->setCurrentModeId(value.toString()); 0269 } else if (key == QLatin1String("preferredModes")) { 0270 output->setPreferredModes(deserializeList<QString>(value.value<QDBusArgument>())); 0271 } else if (key == QLatin1String("connected")) { 0272 output->setConnected(value.toBool()); 0273 } else if (key == QLatin1String("followPreferredMode")) { 0274 output->setFollowPreferredMode(value.toBool()); 0275 } else if (key == QLatin1String("enabled")) { 0276 output->setEnabled(value.toBool()); 0277 } else if (key == QLatin1String("primary")) { 0278 // primary is deprecated, but if it appears in config for compatibility reason. 0279 primary = value.toBool(); 0280 } else if (key == QLatin1String("priority")) { 0281 // "priority" takes precedence over "primary", but we need to 0282 // check it after the loop, otherwise it may come before the 0283 // primary and get overridden. 0284 priority = value.toUInt(); 0285 } else if (key == QLatin1String("clones")) { 0286 output->setClones(deserializeList<int>(value.value<QDBusArgument>())); 0287 } else if (key == QLatin1String("replicationSource")) { 0288 output->setReplicationSource(value.toInt()); 0289 } else if (key == QLatin1String("sizeMM")) { 0290 output->setSizeMm(deserializeSize(value.value<QDBusArgument>())); 0291 } else if (key == QLatin1String("modes")) { 0292 const QDBusArgument arg = value.value<QDBusArgument>(); 0293 ModeList modes; 0294 arg.beginArray(); 0295 while (!arg.atEnd()) { 0296 QVariant value; 0297 arg >> value; 0298 const KScreen::ModePtr mode = deserializeMode(value.value<QDBusArgument>()); 0299 if (!mode) { 0300 return OutputPtr(); 0301 } 0302 modes.insert(mode->id(), mode); 0303 } 0304 arg.endArray(); 0305 output->setModes(modes); 0306 } else if (key == QLatin1String("overscan")) { 0307 output->setOverscan(value.toUInt()); 0308 } else if (key == QLatin1String("vrrPolicy")) { 0309 output->setVrrPolicy(static_cast<Output::VrrPolicy>(value.toInt())); 0310 } else if (key == QLatin1String("rgbRange")) { 0311 output->setRgbRange(static_cast<Output::RgbRange>(value.toInt())); 0312 } else { 0313 qCWarning(KSCREEN) << "Invalid key in Output map: " << key; 0314 return OutputPtr(); 0315 } 0316 arg.endMapEntry(); 0317 } 0318 arg.endMap(); 0319 if (primary.has_value()) { 0320 output->setPriority(output->isEnabled() ? (primary.value() ? 1 : 2) : 0); 0321 } 0322 if (priority.has_value()) { 0323 output->setPriority(priority.value()); 0324 } 0325 return output; 0326 } 0327 0328 ModePtr ConfigSerializer::deserializeMode(const QDBusArgument &arg) 0329 { 0330 ModePtr mode(new Mode); 0331 0332 arg.beginMap(); 0333 while (!arg.atEnd()) { 0334 QString key; 0335 QVariant value; 0336 arg.beginMapEntry(); 0337 arg >> key >> value; 0338 0339 if (key == QLatin1String("id")) { 0340 mode->setId(value.toString()); 0341 } else if (key == QLatin1String("name")) { 0342 mode->setName(value.toString()); 0343 } else if (key == QLatin1String("size")) { 0344 mode->setSize(deserializeSize(value.value<QDBusArgument>())); 0345 } else if (key == QLatin1String("refreshRate")) { 0346 mode->setRefreshRate(value.toFloat()); 0347 } else { 0348 qCWarning(KSCREEN) << "Invalid key in Mode map: " << key; 0349 return ModePtr(); 0350 } 0351 arg.endMapEntry(); 0352 } 0353 arg.endMap(); 0354 return mode; 0355 } 0356 0357 ScreenPtr ConfigSerializer::deserializeScreen(const QDBusArgument &arg) 0358 { 0359 ScreenPtr screen(new Screen); 0360 0361 arg.beginMap(); 0362 QString key; 0363 QVariant value; 0364 while (!arg.atEnd()) { 0365 arg.beginMapEntry(); 0366 arg >> key >> value; 0367 if (key == QLatin1String("id")) { 0368 screen->setId(value.toInt()); 0369 } else if (key == QLatin1String("maxActiveOutputsCount")) { 0370 screen->setMaxActiveOutputsCount(value.toInt()); 0371 } else if (key == QLatin1String("currentSize")) { 0372 screen->setCurrentSize(deserializeSize(value.value<QDBusArgument>())); 0373 } else if (key == QLatin1String("maxSize")) { 0374 screen->setMaxSize(deserializeSize(value.value<QDBusArgument>())); 0375 } else if (key == QLatin1String("minSize")) { 0376 screen->setMinSize(deserializeSize(value.value<QDBusArgument>())); 0377 } else { 0378 qCWarning(KSCREEN) << "Invalid key in Screen map:" << key; 0379 return ScreenPtr(); 0380 } 0381 arg.endMapEntry(); 0382 } 0383 arg.endMap(); 0384 return screen; 0385 }