File indexing completed on 2024-05-05 17:39:43
0001 /* 0002 * SPDX-FileCopyrightText: 2014-2015 Sebastian Kügler <sebas@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "waylandconfigreader.h" 0008 0009 #include <QDebug> 0010 0011 #include <QFile> 0012 #include <QJsonArray> 0013 #include <QJsonDocument> 0014 #include <QJsonObject> 0015 #include <QUuid> 0016 0017 #include "edid.h" 0018 0019 using namespace KScreen; 0020 0021 static QList<int> s_outputIds; 0022 0023 void WaylandConfigReader::outputsFromConfig(const QString &configfile, 0024 KWayland::Server::Display *display, 0025 QList<KWayland::Server::OutputDeviceInterface *> &outputs) 0026 { 0027 qDebug() << "Loading server from" << configfile; 0028 QFile file(configfile); 0029 file.open(QIODevice::ReadOnly); 0030 0031 QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll()); 0032 QJsonObject json = jsonDoc.object(); 0033 0034 QJsonArray omap = json[QStringLiteral("outputs")].toArray(); 0035 for (const QJsonValue &value : omap) { 0036 const QVariantMap &output = value.toObject().toVariantMap(); 0037 if (output[QStringLiteral("connected")].toBool()) { 0038 outputs << createOutputDevice(output, display); 0039 // qDebug() << "new Output created: " << output["name"].toString(); 0040 } else { 0041 // qDebug() << "disconnected Output" << output["name"].toString(); 0042 } 0043 } 0044 auto outpus = WaylandConfigReader::createOutputs(display, outputs); 0045 s_outputIds.clear(); 0046 } 0047 0048 OutputDeviceInterface *WaylandConfigReader::createOutputDevice(const QVariantMap &outputConfig, KWayland::Server::Display *display) 0049 { 0050 KWayland::Server::OutputDeviceInterface *outputdevice = display->createOutputDevice(display); 0051 0052 QByteArray data = QByteArray::fromBase64(outputConfig[QStringLiteral("edid")].toByteArray()); 0053 outputdevice->setEdid(data); 0054 Edid edid(data, display); 0055 0056 // qDebug() << "EDID Info: "; 0057 if (edid.isValid()) { 0058 // qDebug() << "\tDevice ID: " << edid.deviceId(); 0059 // qDebug() << "\tName: " << edid.name(); 0060 // qDebug() << "\tVendor: " << edid.vendor(); 0061 // qDebug() << "\tSerial: " << edid.serial(); 0062 // qDebug() << "\tEISA ID: " << edid.eisaId(); 0063 // qDebug() << "\tHash: " << edid.hash(); 0064 // qDebug() << "\tWidth (mm): " << edid.width(); 0065 // qDebug() << "\tHeight (mm): " << edid.height(); 0066 // qDebug() << "\tGamma: " << edid.gamma(); 0067 // qDebug() << "\tRed: " << edid.red(); 0068 // qDebug() << "\tGreen: " << edid.green(); 0069 // qDebug() << "\tBlue: " << edid.blue(); 0070 // qDebug() << "\tWhite: " << edid.white(); 0071 outputdevice->setPhysicalSize(QSize(edid.width() * 10, edid.height() * 10)); 0072 outputdevice->setManufacturer(edid.vendor()); 0073 outputdevice->setModel(edid.name()); 0074 } else { 0075 outputdevice->setPhysicalSize(sizeFromJson(outputConfig[QStringLiteral("sizeMM")])); 0076 outputdevice->setManufacturer(outputConfig[QStringLiteral("manufacturer")].toString()); 0077 outputdevice->setModel(outputConfig[QStringLiteral("model")].toString()); 0078 } 0079 auto uuid = QUuid::createUuid().toByteArray(); 0080 auto _id = outputConfig[QStringLiteral("id")].toInt(); 0081 if (_id) { 0082 uuid = QString::number(_id).toLocal8Bit(); 0083 } 0084 outputdevice->setUuid(uuid); 0085 0086 const QMap<int, KWayland::Server::OutputDeviceInterface::Transform> transformMap = {{0, KWayland::Server::OutputDeviceInterface::Transform::Normal}, 0087 {1, KWayland::Server::OutputDeviceInterface::Transform::Normal}, 0088 {2, KWayland::Server::OutputDeviceInterface::Transform::Rotated270}, 0089 {3, KWayland::Server::OutputDeviceInterface::Transform::Rotated180}, 0090 {4, KWayland::Server::OutputDeviceInterface::Transform::Rotated90}}; 0091 0092 outputdevice->setTransform(transformMap[outputConfig[QStringLiteral("rotation")].toInt()]); 0093 int currentModeId = outputConfig[QStringLiteral("currentModeId")].toInt(); 0094 QVariantList preferredModes = outputConfig[QStringLiteral("preferredModes")].toList(); 0095 0096 int mode_id = 0; 0097 for (const QVariant &_mode : outputConfig[QStringLiteral("modes")].toList()) { 0098 mode_id++; 0099 const QVariantMap &mode = _mode.toMap(); 0100 OutputDeviceInterface::Mode m0; 0101 const QSize _size = sizeFromJson(mode[QStringLiteral("size")]); 0102 0103 auto refreshRateIt = mode.constFind(QStringLiteral("refreshRate")); 0104 if (refreshRateIt != mode.constEnd()) { 0105 m0.refreshRate = qRound(refreshRateIt->toReal() * 1000); // config has it in Hz 0106 } 0107 bool isCurrent = currentModeId == mode[QStringLiteral("id")].toInt(); 0108 bool isPreferred = preferredModes.contains(mode[QStringLiteral("id")]); 0109 0110 OutputDeviceInterface::ModeFlags flags; 0111 if (isCurrent && isPreferred) { 0112 flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Current | OutputDeviceInterface::ModeFlag::Preferred); 0113 } else if (isCurrent) { 0114 flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Current); 0115 } else if (isPreferred) { 0116 flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Preferred); 0117 } 0118 0119 auto idIt = mode.constFind(QStringLiteral("id")); 0120 if (idIt != mode.constEnd()) { 0121 m0.id = idIt->toInt(); 0122 } else { 0123 m0.id = mode_id; 0124 } 0125 m0.size = _size; 0126 m0.flags = flags; 0127 outputdevice->addMode(m0); 0128 0129 if (isCurrent) { 0130 outputdevice->setCurrentMode(m0.id); 0131 } 0132 } 0133 0134 outputdevice->setGlobalPosition(pointFromJson(outputConfig[QStringLiteral("pos")])); 0135 outputdevice->setEnabled(outputConfig[QStringLiteral("enabled")].toBool() ? OutputDeviceInterface::Enablement::Enabled 0136 : OutputDeviceInterface::Enablement::Disabled); 0137 outputdevice->create(); 0138 0139 return outputdevice; 0140 } 0141 0142 QList<KWayland::Server::OutputInterface *> KScreen::WaylandConfigReader::createOutputs(KWayland::Server::Display *display, 0143 QList<KWayland::Server::OutputDeviceInterface *> &outputdevices) 0144 { 0145 const QMap<KWayland::Server::OutputDeviceInterface::Transform, KWayland::Server::OutputInterface::Transform> transformMap = { 0146 {KWayland::Server::OutputDeviceInterface::Transform::Normal, KWayland::Server::OutputInterface::Transform::Normal}, 0147 {KWayland::Server::OutputDeviceInterface::Transform::Rotated270, KWayland::Server::OutputInterface::Transform::Rotated270}, 0148 {KWayland::Server::OutputDeviceInterface::Transform::Rotated180, KWayland::Server::OutputInterface::Transform::Rotated180}, 0149 {KWayland::Server::OutputDeviceInterface::Transform::Rotated90, KWayland::Server::OutputInterface::Transform::Rotated90}, 0150 }; 0151 0152 QList<KWayland::Server::OutputInterface *> outputs; 0153 for (const auto outputdevice : outputdevices) { 0154 qDebug() << "New Output!"; 0155 KWayland::Server::OutputInterface *output = display->createOutput(display); 0156 0157 // Sync properties from outputdevice to the newly created output interface 0158 output->setManufacturer(outputdevice->manufacturer()); 0159 output->setModel(outputdevice->model()); 0160 // output->setUuid(outputdevice->uuid()); 0161 0162 for (const auto mode : outputdevice->modes()) { 0163 bool isCurrent = mode.flags.testFlag(OutputDeviceInterface::ModeFlag::Current); 0164 bool isPreferred = mode.flags.testFlag(OutputDeviceInterface::ModeFlag::Current); 0165 OutputInterface::ModeFlags flags; 0166 if (isPreferred && isCurrent) { 0167 flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Current | OutputInterface::ModeFlag::Preferred); 0168 } else if (isCurrent) { 0169 flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Current); 0170 } else if (isPreferred) { 0171 flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Preferred); 0172 } 0173 0174 OutputInterface::Mode m0; 0175 0176 m0.size = mode.size; 0177 output->addMode(m0.size, m0.flags, m0.refreshRate); 0178 0179 if (isCurrent) { 0180 output->setCurrentMode(m0.size, m0.refreshRate); 0181 } 0182 // qDebug() << "mode added:" << m0.size << m0.refreshRate << isCurrent; 0183 } 0184 0185 output->setGlobalPosition(outputdevice->globalPosition()); 0186 output->setPhysicalSize(outputdevice->physicalSize()); 0187 output->setTransform(transformMap.value(outputdevice->transform())); 0188 0189 output->setDpmsSupported(true); 0190 output->setDpmsMode(OutputInterface::DpmsMode::On); 0191 QObject::connect(output, &OutputInterface::dpmsModeRequested, [](KWayland::Server::OutputInterface::DpmsMode requestedMode) { 0192 Q_UNUSED(requestedMode); 0193 // FIXME: make sure this happens in the scope of an object! 0194 qDebug() << "DPMS Mode change requested"; 0195 }); 0196 output->create(); 0197 outputs << output; 0198 } 0199 return outputs; 0200 } 0201 0202 QSize WaylandConfigReader::sizeFromJson(const QVariant &data) 0203 { 0204 QVariantMap map = data.toMap(); 0205 0206 QSize size; 0207 size.setWidth(map[QStringLiteral("width")].toInt()); 0208 size.setHeight(map[QStringLiteral("height")].toInt()); 0209 0210 return size; 0211 } 0212 0213 QPoint WaylandConfigReader::pointFromJson(const QVariant &data) 0214 { 0215 QVariantMap map = data.toMap(); 0216 0217 QPoint point; 0218 point.setX(map[QStringLiteral("x")].toInt()); 0219 point.setY(map[QStringLiteral("y")].toInt()); 0220 0221 return point; 0222 } 0223 0224 QRect WaylandConfigReader::rectFromJson(const QVariant &data) 0225 { 0226 QRect rect; 0227 rect.setSize(WaylandConfigReader::sizeFromJson(data)); 0228 rect.setBottomLeft(WaylandConfigReader::pointFromJson(data)); 0229 0230 return rect; 0231 }