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 "waylandtestserver.h"
0008 
0009 #include "waylandconfigreader.h"
0010 
0011 #include <QFile>
0012 #include <QJsonArray>
0013 #include <QJsonDocument>
0014 #include <QJsonObject>
0015 #include <QLoggingCategory>
0016 #include <QStandardPaths>
0017 
0018 #include <utility>
0019 
0020 #include "../src/edid.h"
0021 
0022 Q_LOGGING_CATEGORY(KSCREEN_WAYLAND_TESTSERVER, "kscreen.kwayland.testserver")
0023 
0024 using namespace KScreen;
0025 using namespace KWayland::Server;
0026 
0027 WaylandTestServer::WaylandTestServer(QObject *parent)
0028     : QObject(parent)
0029     , m_configFile(QLatin1String(TEST_DATA) + QLatin1String("default.json"))
0030     , m_display(nullptr)
0031     , m_outputManagement(nullptr)
0032     , m_dpmsManager(nullptr)
0033     , m_suspendChanges(false)
0034     , m_waiting(nullptr)
0035 {
0036 }
0037 
0038 WaylandTestServer::~WaylandTestServer()
0039 {
0040     stop();
0041     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Wayland server shut down.";
0042 }
0043 
0044 void WaylandTestServer::start()
0045 {
0046     using namespace KWayland::Server;
0047     delete m_display;
0048     m_display = new KWayland::Server::Display(this);
0049     if (qgetenv("WAYLAND_DISPLAY").isEmpty()) {
0050         m_display->setSocketName(s_socketName);
0051     } else {
0052         m_display->setSocketName(QString::fromLatin1(qgetenv("WAYLAND_DISPLAY")));
0053     }
0054     m_display->start();
0055 
0056     auto manager = m_display->createDpmsManager();
0057     manager->create();
0058 
0059     m_outputManagement = m_display->createOutputManagement();
0060     m_outputManagement->create();
0061     connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested, this, &WaylandTestServer::configurationChangeRequested);
0062 
0063     KScreen::WaylandConfigReader::outputsFromConfig(m_configFile, m_display, m_outputs);
0064     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << QStringLiteral("export WAYLAND_DISPLAY=") + m_display->socketName();
0065     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << QStringLiteral("You can specify the WAYLAND_DISPLAY for this server by exporting it in the environment");
0066     // showOutputs();
0067 }
0068 
0069 void WaylandTestServer::stop()
0070 {
0071     qDeleteAll(m_outputs);
0072     m_outputs.clear();
0073     // actually stop the Wayland server
0074     delete m_display;
0075     m_display = nullptr;
0076 }
0077 
0078 KWayland::Server::Display *WaylandTestServer::display()
0079 {
0080     return m_display;
0081 }
0082 
0083 void WaylandTestServer::setConfig(const QString &configfile)
0084 {
0085     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Creating Wayland server from " << configfile;
0086     m_configFile = configfile;
0087 }
0088 
0089 int WaylandTestServer::outputCount() const
0090 {
0091     return m_outputs.count();
0092 }
0093 QList<KWayland::Server::OutputDeviceInterface *> WaylandTestServer::outputs() const
0094 {
0095     return m_outputs;
0096 }
0097 
0098 void WaylandTestServer::suspendChanges(bool suspend)
0099 {
0100     if (m_suspendChanges == suspend) {
0101         return;
0102     }
0103     m_suspendChanges = suspend;
0104     if (!suspend && m_waiting) {
0105         m_waiting->setApplied();
0106         m_waiting = nullptr;
0107         Q_EMIT configChanged();
0108     }
0109 }
0110 
0111 void WaylandTestServer::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *configurationInterface)
0112 {
0113     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server received change request, changes:" << configurationInterface->changes().count();
0114     Q_EMIT configReceived();
0115 
0116     auto changes = configurationInterface->changes();
0117     for (auto it = changes.constBegin(); it != changes.constEnd(); ++it) {
0118         auto outputdevice = it.key();
0119         auto c = it.value();
0120         if (c->enabledChanged()) {
0121             qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting enabled:";
0122             outputdevice->setEnabled(c->enabled());
0123         }
0124         if (c->modeChanged()) {
0125             qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting new mode:" << c->mode() << modeString(outputdevice, c->mode());
0126             outputdevice->setCurrentMode(c->mode());
0127         }
0128         if (c->transformChanged()) {
0129             qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server setting transform: " << (int)(c->transform());
0130             outputdevice->setTransform(c->transform());
0131         }
0132         if (c->positionChanged()) {
0133             qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server setting position: " << c->position();
0134             outputdevice->setGlobalPosition(c->position());
0135         }
0136         if (c->scaleChanged()) {
0137             qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting scale:" << c->scaleF();
0138             outputdevice->setScaleF(c->scaleF());
0139         }
0140     }
0141 
0142     if (m_suspendChanges) {
0143         Q_ASSERT(!m_waiting);
0144         m_waiting = configurationInterface;
0145         return;
0146     }
0147 
0148     configurationInterface->setApplied();
0149     // showOutputs();
0150     Q_EMIT configChanged();
0151 }
0152 
0153 void WaylandTestServer::showOutputs()
0154 {
0155     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "******** Wayland server running: " << m_outputs.count() << " outputs. ********";
0156     for (const auto &o : std::as_const(m_outputs)) {
0157         bool enabled = (o->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Enabled);
0158         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "  * Output id: " << o->uuid();
0159         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "      Enabled: " << (enabled ? "enabled" : "disabled");
0160         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "         Name: " << QStringLiteral("%2-%3").arg(o->manufacturer(), o->model());
0161         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "         Mode: " << modeString(o, o->currentModeId());
0162         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "          Pos: " << o->globalPosition();
0163         qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "         Edid: " << o->edid();
0164         // << o->currentMode().size();
0165     }
0166     qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "******************************************************";
0167 }
0168 
0169 QString WaylandTestServer::modeString(KWayland::Server::OutputDeviceInterface *outputdevice, int mid)
0170 {
0171     QString s;
0172     QString ids;
0173     int _i = 0;
0174     for (const auto &_m : outputdevice->modes()) {
0175         _i++;
0176         if (_i < 6) {
0177             ids.append(QString::number(_m.id) + QLatin1String(", "));
0178         } else {
0179             ids.append(QLatin1Char('.'));
0180         }
0181         if (_m.id == mid) {
0182             s = QStringLiteral("%1x%2 @%3").arg(QString::number(_m.size.width()), QString::number(_m.size.height()), QString::number(_m.refreshRate));
0183         }
0184     }
0185     return QStringLiteral("[%1] %2 (%4 modes: %3)").arg(QString::number(mid), s, ids, QString::number(outputdevice->modes().count()));
0186 }