File indexing completed on 2024-04-28 16:49:40
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Alejandro Fiestas Olivares <afiestas@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "parser.h" 0008 #include "fake.h" 0009 0010 #include "config.h" 0011 #include "mode.h" 0012 #include "output.h" 0013 #include "screen.h" 0014 0015 #include <QFile> 0016 #include <QJsonArray> 0017 #include <QJsonDocument> 0018 #include <QJsonObject> 0019 #include <QLoggingCategory> 0020 #include <QMetaObject> 0021 #include <QMetaProperty> 0022 0023 using namespace KScreen; 0024 0025 ConfigPtr Parser::fromJson(const QByteArray &data) 0026 { 0027 ConfigPtr config(new Config); 0028 0029 const QJsonObject json = QJsonDocument::fromJson(data).object(); 0030 0031 ScreenPtr screen = Parser::screenFromJson(json[QStringLiteral("screen")].toObject().toVariantMap()); 0032 config->setScreen(screen); 0033 0034 const QVariantList outputs = json[QStringLiteral("outputs")].toArray().toVariantList(); 0035 if (outputs.isEmpty()) { 0036 return config; 0037 } 0038 0039 OutputList outputList; 0040 for (const QVariant &value : outputs) { 0041 const OutputPtr output = Parser::outputFromJson(value.toMap()); 0042 outputList.insert(output->id(), output); 0043 } 0044 0045 config->setOutputs(outputList); 0046 return config; 0047 } 0048 0049 ConfigPtr Parser::fromJson(const QString &path) 0050 { 0051 QFile file(path); 0052 if (!file.open(QIODevice::ReadOnly)) { 0053 qWarning() << file.errorString(); 0054 qWarning() << "File: " << path; 0055 return ConfigPtr(); 0056 } 0057 0058 return Parser::fromJson(file.readAll()); 0059 } 0060 0061 ScreenPtr Parser::screenFromJson(const QVariantMap &data) 0062 { 0063 ScreenPtr screen(new Screen); 0064 screen->setId(data[QStringLiteral("id")].toInt()); 0065 screen->setMinSize(Parser::sizeFromJson(data[QStringLiteral("minSize")].toMap())); 0066 screen->setMaxSize(Parser::sizeFromJson(data[QStringLiteral("maxSize")].toMap())); 0067 screen->setCurrentSize(Parser::sizeFromJson(data[QStringLiteral("currentSize")].toMap())); 0068 screen->setMaxActiveOutputsCount(data[QStringLiteral("maxActiveOutputsCount")].toInt()); 0069 0070 return screen; 0071 } 0072 0073 void Parser::qvariant2qobject(const QVariantMap &variant, QObject *object) 0074 { 0075 const QMetaObject *metaObject = object->metaObject(); 0076 for (QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter) { 0077 const int propertyIndex = metaObject->indexOfProperty(qPrintable(iter.key())); 0078 if (propertyIndex == -1) { 0079 // qWarning() << "Skipping non-existent property" << iter.key(); 0080 continue; 0081 } 0082 const QMetaProperty metaProperty = metaObject->property(propertyIndex); 0083 if (!metaProperty.isWritable()) { 0084 // qWarning() << "Skipping read-only property" << iter.key(); 0085 continue; 0086 } 0087 0088 const QVariant property = object->property(iter.key().toLatin1().constData()); 0089 Q_ASSERT(property.isValid()); 0090 if (property.isValid()) { 0091 QVariant value = iter.value(); 0092 if (value.canConvert(property.type())) { 0093 value.convert(property.type()); 0094 object->setProperty(iter.key().toLatin1().constData(), value); 0095 } else if (QLatin1String("QVariant") == QLatin1String(property.typeName())) { 0096 object->setProperty(iter.key().toLatin1().constData(), value); 0097 } 0098 } 0099 } 0100 } 0101 0102 OutputPtr Parser::outputFromJson(QMap<QString, QVariant> map) 0103 { 0104 OutputPtr output(new Output); 0105 output->setId(map[QStringLiteral("id")].toInt()); 0106 0107 QStringList preferredModes; 0108 const QVariantList prefModes = map[QStringLiteral("preferredModes")].toList(); 0109 for (const QVariant &mode : prefModes) { 0110 preferredModes.append(mode.toString()); 0111 } 0112 output->setPreferredModes(preferredModes); 0113 map.remove(QStringLiteral("preferredModes")); 0114 0115 ModeList modelist; 0116 const QVariantList modes = map[QStringLiteral("modes")].toList(); 0117 for (const QVariant &modeValue : modes) { 0118 const ModePtr mode = Parser::modeFromJson(modeValue); 0119 modelist.insert(mode->id(), mode); 0120 } 0121 output->setModes(modelist); 0122 map.remove(QStringLiteral("modes")); 0123 0124 if (map.contains(QStringLiteral("clones"))) { 0125 QList<int> clones; 0126 for (const QVariant &id : map[QStringLiteral("clones")].toList()) { 0127 clones.append(id.toInt()); 0128 } 0129 0130 output->setClones(clones); 0131 map.remove(QStringLiteral("clones")); 0132 } 0133 0134 const QByteArray type = map[QStringLiteral("type")].toByteArray().toUpper(); 0135 if (type.contains("LVDS") || type.contains("EDP") || type.contains("IDP") || type.contains("7")) { 0136 output->setType(Output::Panel); 0137 } else if (type.contains("VGA")) { 0138 output->setType(Output::VGA); 0139 } else if (type.contains("DVI")) { 0140 output->setType(Output::DVI); 0141 } else if (type.contains("DVI-I")) { 0142 output->setType(Output::DVII); 0143 } else if (type.contains("DVI-A")) { 0144 output->setType(Output::DVIA); 0145 } else if (type.contains("DVI-D")) { 0146 output->setType(Output::DVID); 0147 } else if (type.contains("HDMI") || type.contains("6")) { 0148 output->setType(Output::HDMI); 0149 } else if (type.contains("Panel")) { 0150 output->setType(Output::Panel); 0151 } else if (type.contains("TV")) { 0152 output->setType(Output::TV); 0153 } else if (type.contains("TV-Composite")) { 0154 output->setType(Output::TVComposite); 0155 } else if (type.contains("TV-SVideo")) { 0156 output->setType(Output::TVSVideo); 0157 } else if (type.contains("TV-Component")) { 0158 output->setType(Output::TVComponent); 0159 } else if (type.contains("TV-SCART")) { 0160 output->setType(Output::TVSCART); 0161 } else if (type.contains("TV-C4")) { 0162 output->setType(Output::TVC4); 0163 } else if (type.contains("DisplayPort") || type.contains("14")) { 0164 output->setType(Output::DisplayPort); 0165 } else if (type.contains("Unknown")) { 0166 output->setType(Output::Unknown); 0167 } else { 0168 qCWarning(KSCREEN_FAKE) << "Output Type not translated:" << type; 0169 } 0170 map.remove(QStringLiteral("type")); 0171 0172 if (map.contains(QStringLiteral("pos"))) { 0173 output->setPos(Parser::pointFromJson(map[QStringLiteral("pos")].toMap())); 0174 map.remove(QStringLiteral("pos")); 0175 } 0176 0177 if (map.contains(QStringLiteral("size"))) { 0178 output->setSize(Parser::sizeFromJson(map[QStringLiteral("size")].toMap())); 0179 map.remove(QStringLiteral("size")); 0180 } 0181 0182 // This is not supported in real configs; only set this value in fake test 0183 // configs and don't add logic to kscreen to set this data in real configs. 0184 if (map.contains(QStringLiteral("sizeMM"))) { 0185 output->setSizeMm(Parser::sizeFromJson(map[QStringLiteral("sizeMM")].toMap())); 0186 map.remove(QStringLiteral("sizeMM")); 0187 } 0188 0189 auto scale = QStringLiteral("scale"); 0190 if (map.contains(scale)) { 0191 qDebug() << "Scale found:" << map[scale].toReal(); 0192 output->setScale(map[scale].toReal()); 0193 map.remove(scale); 0194 } 0195 0196 // the deprecated "primary" property may exist for compatibility, but "priority" should override it whenever present. 0197 if (map.contains(QStringLiteral("primary"))) { 0198 output->setPriority(map[QStringLiteral("primary")].toBool() ? 1 : 2); 0199 map.remove(QStringLiteral("primary")); 0200 } 0201 if (map.contains(QStringLiteral("priority"))) { 0202 output->setPriority(map[QStringLiteral("priority")].toUInt()); 0203 map.remove(QStringLiteral("priority")); 0204 } 0205 0206 // Remove some extra properties that we do not want or need special treatment 0207 map.remove(QStringLiteral("edid")); 0208 0209 Parser::qvariant2qobject(map, output.data()); 0210 return output; 0211 } 0212 0213 ModePtr Parser::modeFromJson(const QVariant &data) 0214 { 0215 const QVariantMap map = data.toMap(); 0216 ModePtr mode(new Mode); 0217 Parser::qvariant2qobject(map, mode.data()); 0218 0219 mode->setSize(Parser::sizeFromJson(map[QStringLiteral("size")].toMap())); 0220 0221 return mode; 0222 } 0223 0224 QSize Parser::sizeFromJson(const QVariant &data) 0225 { 0226 const QVariantMap map = data.toMap(); 0227 0228 QSize size; 0229 size.setWidth(map[QStringLiteral("width")].toInt()); 0230 size.setHeight(map[QStringLiteral("height")].toInt()); 0231 0232 return size; 0233 } 0234 0235 QPoint Parser::pointFromJson(const QVariant &data) 0236 { 0237 const QVariantMap map = data.toMap(); 0238 0239 QPoint point; 0240 point.setX(map[QStringLiteral("x")].toInt()); 0241 point.setY(map[QStringLiteral("y")].toInt()); 0242 0243 return point; 0244 } 0245 0246 QRect Parser::rectFromJson(const QVariant &data) 0247 { 0248 QRect rect; 0249 rect.setSize(Parser::sizeFromJson(data)); 0250 rect.setBottomLeft(Parser::pointFromJson(data)); 0251 0252 return rect; 0253 } 0254 0255 bool Parser::validate(const QByteArray &data) 0256 { 0257 Q_UNUSED(data); 0258 return true; 0259 } 0260 0261 bool Parser::validate(const QString &data) 0262 { 0263 Q_UNUSED(data); 0264 return true; 0265 }