File indexing completed on 2024-04-21 16:17:33
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 return obj; 0108 } 0109 0110 QJsonObject ConfigSerializer::serializeMode(const ModePtr &mode) 0111 { 0112 QJsonObject obj; 0113 0114 obj[QLatin1String("id")] = mode->id(); 0115 obj[QLatin1String("name")] = mode->name(); 0116 obj[QLatin1String("size")] = serializeSize(mode->size()); 0117 obj[QLatin1String("refreshRate")] = mode->refreshRate(); 0118 0119 return obj; 0120 } 0121 0122 QJsonObject ConfigSerializer::serializeScreen(const ScreenPtr &screen) 0123 { 0124 QJsonObject obj; 0125 0126 obj[QLatin1String("id")] = screen->id(); 0127 obj[QLatin1String("currentSize")] = serializeSize(screen->currentSize()); 0128 obj[QLatin1String("maxSize")] = serializeSize(screen->maxSize()); 0129 obj[QLatin1String("minSize")] = serializeSize(screen->minSize()); 0130 obj[QLatin1String("maxActiveOutputsCount")] = screen->maxActiveOutputsCount(); 0131 0132 return obj; 0133 } 0134 0135 QPoint ConfigSerializer::deserializePoint(const QDBusArgument &arg) 0136 { 0137 int x = 0, y = 0; 0138 arg.beginMap(); 0139 while (!arg.atEnd()) { 0140 QString key; 0141 QVariant value; 0142 arg.beginMapEntry(); 0143 arg >> key >> value; 0144 if (key == QLatin1Char('x')) { 0145 x = value.toInt(); 0146 } else if (key == QLatin1Char('y')) { 0147 y = value.toInt(); 0148 } else { 0149 qCWarning(KSCREEN) << "Invalid key in Point map: " << key; 0150 return QPoint(); 0151 } 0152 arg.endMapEntry(); 0153 } 0154 arg.endMap(); 0155 return QPoint(x, y); 0156 } 0157 0158 QSize ConfigSerializer::deserializeSize(const QDBusArgument &arg) 0159 { 0160 int w = 0, h = 0; 0161 arg.beginMap(); 0162 while (!arg.atEnd()) { 0163 QString key; 0164 QVariant value; 0165 arg.beginMapEntry(); 0166 arg >> key >> value; 0167 if (key == QLatin1String("width")) { 0168 w = value.toInt(); 0169 } else if (key == QLatin1String("height")) { 0170 h = value.toInt(); 0171 } else { 0172 qCWarning(KSCREEN) << "Invalid key in size struct: " << key; 0173 return QSize(); 0174 } 0175 arg.endMapEntry(); 0176 } 0177 arg.endMap(); 0178 0179 return QSize(w, h); 0180 } 0181 0182 ConfigPtr ConfigSerializer::deserializeConfig(const QVariantMap &map) 0183 { 0184 ConfigPtr config(new Config); 0185 0186 if (map.contains(QLatin1String("features"))) { 0187 config->setSupportedFeatures(static_cast<Config::Features>(map[QStringLiteral("features")].toInt())); 0188 } 0189 0190 if (map.contains(QLatin1String("tabletModeAvailable"))) { 0191 config->setTabletModeAvailable(map[QStringLiteral("tabletModeAvailable")].toBool()); 0192 } 0193 if (map.contains(QLatin1String("tabletModeEngaged"))) { 0194 config->setTabletModeEngaged(map[QStringLiteral("tabletModeEngaged")].toBool()); 0195 } 0196 0197 if (map.contains(QLatin1String("outputs"))) { 0198 const QDBusArgument &outputsArg = map[QStringLiteral("outputs")].value<QDBusArgument>(); 0199 outputsArg.beginArray(); 0200 OutputList outputs; 0201 while (!outputsArg.atEnd()) { 0202 QVariant value; 0203 outputsArg >> value; 0204 const KScreen::OutputPtr output = deserializeOutput(value.value<QDBusArgument>()); 0205 if (!output) { 0206 return ConfigPtr(); 0207 } 0208 outputs.insert(output->id(), output); 0209 } 0210 outputsArg.endArray(); 0211 config->setOutputs(outputs); 0212 } 0213 0214 if (map.contains(QLatin1String("screen"))) { 0215 const QDBusArgument &screenArg = map[QStringLiteral("screen")].value<QDBusArgument>(); 0216 const KScreen::ScreenPtr screen = deserializeScreen(screenArg); 0217 if (!screen) { 0218 return ConfigPtr(); 0219 } 0220 config->setScreen(screen); 0221 } 0222 0223 return config; 0224 } 0225 0226 OutputPtr ConfigSerializer::deserializeOutput(const QDBusArgument &arg) 0227 { 0228 OutputPtr output(new Output); 0229 std::optional<bool> primary = std::nullopt; 0230 std::optional<uint32_t> priority = std::nullopt; 0231 0232 arg.beginMap(); 0233 while (!arg.atEnd()) { 0234 QString key; 0235 QVariant value; 0236 arg.beginMapEntry(); 0237 arg >> key >> value; 0238 if (key == QLatin1String("id")) { 0239 output->setId(value.toInt()); 0240 } else if (key == QLatin1String("name")) { 0241 output->setName(value.toString()); 0242 } else if (key == QLatin1String("type")) { 0243 output->setType(static_cast<Output::Type>(value.toInt())); 0244 } else if (key == QLatin1String("icon")) { 0245 output->setIcon(value.toString()); 0246 } else if (key == QLatin1String("pos")) { 0247 output->setPos(deserializePoint(value.value<QDBusArgument>())); 0248 } else if (key == QLatin1String("scale")) { 0249 output->setScale(value.toDouble()); 0250 } else if (key == QLatin1String("size")) { 0251 output->setSize(deserializeSize(value.value<QDBusArgument>())); 0252 } else if (key == QLatin1String("rotation")) { 0253 output->setRotation(static_cast<Output::Rotation>(value.toInt())); 0254 } else if (key == QLatin1String("currentModeId")) { 0255 output->setCurrentModeId(value.toString()); 0256 } else if (key == QLatin1String("preferredModes")) { 0257 output->setPreferredModes(deserializeList<QString>(value.value<QDBusArgument>())); 0258 } else if (key == QLatin1String("connected")) { 0259 output->setConnected(value.toBool()); 0260 } else if (key == QLatin1String("followPreferredMode")) { 0261 output->setFollowPreferredMode(value.toBool()); 0262 } else if (key == QLatin1String("enabled")) { 0263 output->setEnabled(value.toBool()); 0264 } else if (key == QLatin1String("primary")) { 0265 // primary is deprecated, but if it appears in config for compatibility reason. 0266 primary = value.toBool(); 0267 } else if (key == QLatin1String("priority")) { 0268 // "priority" takes precedence over "primary", but we need to 0269 // check it after the loop, otherwise it may come before the 0270 // primary and get overridden. 0271 priority = value.toUInt(); 0272 } else if (key == QLatin1String("clones")) { 0273 output->setClones(deserializeList<int>(value.value<QDBusArgument>())); 0274 } else if (key == QLatin1String("replicationSource")) { 0275 output->setReplicationSource(value.toInt()); 0276 } else if (key == QLatin1String("sizeMM")) { 0277 output->setSizeMm(deserializeSize(value.value<QDBusArgument>())); 0278 } else if (key == QLatin1String("modes")) { 0279 const QDBusArgument arg = value.value<QDBusArgument>(); 0280 ModeList modes; 0281 arg.beginArray(); 0282 while (!arg.atEnd()) { 0283 QVariant value; 0284 arg >> value; 0285 const KScreen::ModePtr mode = deserializeMode(value.value<QDBusArgument>()); 0286 if (!mode) { 0287 return OutputPtr(); 0288 } 0289 modes.insert(mode->id(), mode); 0290 } 0291 arg.endArray(); 0292 output->setModes(modes); 0293 } else if (key == QLatin1String("overscan")) { 0294 output->setOverscan(value.toUInt()); 0295 } else if (key == QLatin1String("vrrPolicy")) { 0296 output->setVrrPolicy(static_cast<Output::VrrPolicy>(value.toInt())); 0297 } else if (key == QLatin1String("rgbRange")) { 0298 output->setRgbRange(static_cast<Output::RgbRange>(value.toInt())); 0299 } else { 0300 qCWarning(KSCREEN) << "Invalid key in Output map: " << key; 0301 return OutputPtr(); 0302 } 0303 arg.endMapEntry(); 0304 } 0305 arg.endMap(); 0306 if (primary.has_value()) { 0307 output->setPriority(output->isEnabled() ? (primary.value() ? 1 : 2) : 0); 0308 } 0309 if (priority.has_value()) { 0310 output->setPriority(priority.value()); 0311 } 0312 return output; 0313 } 0314 0315 ModePtr ConfigSerializer::deserializeMode(const QDBusArgument &arg) 0316 { 0317 ModePtr mode(new Mode); 0318 0319 arg.beginMap(); 0320 while (!arg.atEnd()) { 0321 QString key; 0322 QVariant value; 0323 arg.beginMapEntry(); 0324 arg >> key >> value; 0325 0326 if (key == QLatin1String("id")) { 0327 mode->setId(value.toString()); 0328 } else if (key == QLatin1String("name")) { 0329 mode->setName(value.toString()); 0330 } else if (key == QLatin1String("size")) { 0331 mode->setSize(deserializeSize(value.value<QDBusArgument>())); 0332 } else if (key == QLatin1String("refreshRate")) { 0333 mode->setRefreshRate(value.toFloat()); 0334 } else { 0335 qCWarning(KSCREEN) << "Invalid key in Mode map: " << key; 0336 return ModePtr(); 0337 } 0338 arg.endMapEntry(); 0339 } 0340 arg.endMap(); 0341 return mode; 0342 } 0343 0344 ScreenPtr ConfigSerializer::deserializeScreen(const QDBusArgument &arg) 0345 { 0346 ScreenPtr screen(new Screen); 0347 0348 arg.beginMap(); 0349 QString key; 0350 QVariant value; 0351 while (!arg.atEnd()) { 0352 arg.beginMapEntry(); 0353 arg >> key >> value; 0354 if (key == QLatin1String("id")) { 0355 screen->setId(value.toInt()); 0356 } else if (key == QLatin1String("maxActiveOutputsCount")) { 0357 screen->setMaxActiveOutputsCount(value.toInt()); 0358 } else if (key == QLatin1String("currentSize")) { 0359 screen->setCurrentSize(deserializeSize(value.value<QDBusArgument>())); 0360 } else if (key == QLatin1String("maxSize")) { 0361 screen->setMaxSize(deserializeSize(value.value<QDBusArgument>())); 0362 } else if (key == QLatin1String("minSize")) { 0363 screen->setMinSize(deserializeSize(value.value<QDBusArgument>())); 0364 } else { 0365 qCWarning(KSCREEN) << "Invalid key in Screen map:" << key; 0366 return ScreenPtr(); 0367 } 0368 arg.endMapEntry(); 0369 } 0370 arg.endMap(); 0371 return screen; 0372 }