#include "loginrpc.h" #include "cvt.h" #include #include #include #include #include LoginRpc::LoginRpc(int port, QObject *parent) : QObject(parent) { QTcpServer *srv = new QTcpServer(this); srv->listen(QHostAddress::Any, port); connect(srv, &QTcpServer::newConnection, [=] { while (srv->hasPendingConnections()) { QTcpSocket *sock = srv->nextPendingConnection(); handleIncoming(sock); } }); } void LoginRpc::handleIncoming(QTcpSocket *sock) { connect(sock, &QTcpSocket::readyRead, [=] { QByteArray ba = sock->readAll(); // XXX We assume everything arrives in one packet if (ba.length() < 2) { sock->deleteLater(); return; } int vers = (ba[0] << 8) + ba[1]; ba = ba.mid(2); ba = QByteArray::fromBase64(ba); if (vers == 1) { handleCommandV1(QString::fromUtf8(ba)); } else { qDebug() << "Ignoring unknown Login RPC version" << vers; } }); } void LoginRpc::handleCommandV1(const QString &command) { QStringList lines = command.split('\n'); while (lines.count() < 3) { lines.append(QString()); } QString res = lines[2]; QStringList parts = res.split("x"); qDebug() << "Got resolution" << res << "parsed to" << parts; if (parts.size() == 2) { int x = parts[0].toInt(); int y = parts[1].toInt(); qDebug() << "As int:" << x << y; if (x > 0 && y > 0) { x = (x / 8) * 8; y = (y / 8) * 8; // TODO: Configurable min max sizes if (x < 1024) x = 1024; if (y < 720) y = 720; if (x > 1920) x = 1920; if (y > 1080) y = 1080; QString name = QString("%1x%2").arg(x).arg(y); mode *mode = vert_refresh(x, y, 60, 0, 0, 0); QProcess p; QStringList newmode = QStringList() << "--verbose" << "--newmode" << name << QString::asprintf("%.2f", mode->pclk) << QString::number(mode->hr) << QString::number(mode->hss) << QString::number(mode->hse) << QString::number(mode->hfl) << QString::number(mode->vr) << QString::number(mode->vss) << QString::number(mode->vse) << QString::number(mode->vfl) << "-hsync" << "+vsync"; // Get all outputs QStringList setMode("--verbose"); p.setProcessChannelMode(QProcess::MergedChannels); p.start("xrandr"); p.waitForFinished(2000); QString out = QString::fromLocal8Bit(p.readAll()); QRegularExpression re("^(\\S+)\\s.*?(\\w+connected)", QRegularExpression::MultilineOption); QRegularExpressionMatchIterator it = re.globalMatch(out); QString disconnectedOut; QString virtOut; QStringList outputs; while (it.hasNext()) { QRegularExpressionMatch m = it.next(); QString output = m.captured(1); if (virtOut.isEmpty() && (output == QLatin1String("VIRTUAL1") || output == QLatin1String("VIRTUAL-1") || output == QLatin1String("Virtual1") || output == QLatin1String("Virtual-1") || output == QLatin1String("default"))) { virtOut = output; } else if (disconnectedOut.isEmpty() && m.captured(2) == "disconnected") { disconnectedOut = output; } else { outputs << output; } } if (virtOut.isEmpty() && !disconnectedOut.isEmpty()) { virtOut = disconnectedOut; disconnectedOut.clear(); } if (!disconnectedOut.isEmpty()) { outputs << disconnectedOut; } if (virtOut.isEmpty() && !outputs.isEmpty()) { virtOut = outputs.takeFirst(); } qDebug() << "Virtual output:" << virtOut << "unwanted additional outputs:" << outputs << "(First disconnected:" << disconnectedOut << ")"; p.kill(); if (!virtOut.isEmpty()) { setMode << "--output" << virtOut << "--mode" << name; for (auto output : outputs) { setMode << "--output" << output << "--off"; } qDebug() << "Setting mode" << newmode; p.setProcessChannelMode(QProcess::ForwardedChannels); // Create mode p.start("xrandr", newmode); p.waitForFinished(2000); p.kill(); // Add to virtual output p.start("xrandr", QStringList() << "--verbose" << "--addmode" << virtOut << name); p.waitForFinished(2000); p.kill(); // Set all outputs p.start("xrandr", setMode); p.waitForFinished(2000); p.kill(); } } } emit loginRequest(lines[0], lines[1], lines[2]); }