summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/loginrpc.cpp165
1 files changed, 114 insertions, 51 deletions
diff --git a/src/loginrpc.cpp b/src/loginrpc.cpp
index 86bfe07..3d6092b 100644
--- a/src/loginrpc.cpp
+++ b/src/loginrpc.cpp
@@ -4,9 +4,18 @@
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QDebug>
+#include <QSize>
#include <QProcess>
#include <QRegularExpression>
+static int setMode(const QString &virtOut, const QString &name, const QStringList &allOutputs);
+
+static int sizeDiff(const QSize &a, const QSize &b)
+{
+ return qAbs((a.width() * a.width()) - (b.width() * b.width()))
+ + qAbs((a.height() * a.height()) - (b.height() * b.height()));
+}
+
LoginRpc::LoginRpc(int port, QObject *parent)
: QObject(parent)
{
@@ -48,6 +57,11 @@ void LoginRpc::handleCommandV1(const QString &command)
QStringList parts = res.split("x");
qDebug() << "Got resolution" << res << "parsed to" << parts;
if (parts.size() == 2) {
+ struct {
+ QString output;
+ QString modeName;
+ QSize size;
+ } bestConMode, bestDisconMode, *currentReadMode = nullptr;
int x = parts[0].toInt();
int y = parts[1].toInt();
qDebug() << "As int:" << x << y;
@@ -59,11 +73,17 @@ void LoginRpc::handleCommandV1(const QString &command)
if (y < 720) y = 720;
if (x > 1920) x = 1920;
if (y > 1080) y = 1080;
- QString name = QString("%1x%2_30").arg(x).arg(y);
- mode *mode = vert_refresh(x, y, 30, 0, 0, 0);
+ QString name = QString("%1x%2_60").arg(x).arg(y);
+ mode *mode = vert_refresh(x, y, 60, 0, 0, 0);
QProcess p;
+ // Fetch xrandr default output once
p.setProcessChannelMode(QProcess::MergedChannels);
+ p.start("xrandr", QStringList());
+ p.waitForFinished(2000);
+ p.kill();
+ QString xrandrOutput = QString::fromLocal8Bit(p.readAll());
qDebug() << "Creating new mode via xrandr";
+ p.setProcessChannelMode(QProcess::ForwardedChannels);
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)
@@ -71,15 +91,49 @@ void LoginRpc::handleCommandV1(const QString &command)
// Create mode
p.start("xrandr", newmode);
p.waitForFinished(2000);
- //bool lowResFallback = p.exitCode() != 0;
+ qDebug() << "Exit code" << p.exitCode();
+ bool lowResFallback = p.exitCode() != 0;
p.kill();
+ do {
+ // Find best match among existing modes in case --newmode failed, or --addmode fails later
+ QSize wantedSize(x, y);
+ QStringList lines = xrandrOutput.split(QRegularExpression("[\r\n]+"));
+ QString curScreen;
+ bool curConnected = false;
+ QRegularExpression scr("^([A-Za-z0-9_-]+)\\s+(connected|disconnected)\\s+");
+ QRegularExpression mode("^\\s+([0-9]+)x([0-9]+)(\\S*)\\s+\\d");
+ for (const auto &line : lines) {
+ //qDebug() << "Line" << line;
+ auto m = scr.match(line);
+ if (m.hasMatch()) {
+ // Is a line that starts a new screen section
+ curScreen = m.captured(1);
+ curConnected = m.captured(2) == QStringLiteral("connected");
+ currentReadMode = curConnected ? &bestConMode : &bestDisconMode;
+ //qDebug() << "Output" << curScreen << curConnected;
+ continue;
+ }
+ if (currentReadMode != nullptr) {
+ m = mode.match(line);
+ if (m.hasMatch()) {
+ // Is a resolution/mode
+ QSize s(m.captured(1).toInt(), m.captured(2).toInt());
+ //qDebug() << "Matched resolution" << m.captured() << s;
+ //qDebug() << "Current:" << sizeDiff(currentReadMode->size, wantedSize) << ", This: " << sizeDiff(s, wantedSize);
+ if (s.width() > 1000 && s.height() > 700 && sizeDiff(currentReadMode->size, wantedSize) > sizeDiff(s, wantedSize)) {
+ // Better
+ qDebug() << s << "is better than" << currentReadMode->size << "on" << curScreen << curConnected;
+ currentReadMode->output = curScreen;
+ currentReadMode->modeName = m.captured(1) + "x" + m.captured(2) + m.captured(3);
+ currentReadMode->size = s;
+ }
+ }
+ }
+ }
+ } while(0);
// Get all outputs
- QStringList setMode("--verbose");
- p.start("xrandr", QStringList());
- p.waitForFinished(2000);
- QString out = QString::fromLocal8Bit(p.readAll());
QRegularExpression re("^(\\S+)\\s.*?(\\w*connected)", QRegularExpression::MultilineOption);
- QRegularExpressionMatchIterator it = re.globalMatch(out);
+ QRegularExpressionMatchIterator it = re.globalMatch(xrandrOutput);
QString virtOut, evdiOut;
QStringList allOutputs, disconnectedOutputs, connectedOutputs;
while (it.hasNext()) {
@@ -106,32 +160,35 @@ void LoginRpc::handleCommandV1(const QString &command)
allOutputs << evdiOut;
}
qDebug() << "Virtual output:" << virtOut << "unwanted additional outputs:" << allOutputs;
- p.kill();
int ret = -1;
+ // Always try virtual output first, even if --newmode failed. Might have to be re-evaluated in the future
if (!virtOut.isEmpty()) {
- setMode << "--output" << virtOut << "--mode" << name;
- for (auto output : allOutputs) {
- setMode << "--output" << output << "--off";
- }
- qDebug() << "Setting mode" << setMode;
- p.setProcessChannelMode(QProcess::ForwardedChannels);
// 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);
- ret = p.exitCode();
- p.kill();
+ ret = setMode(virtOut, name, allOutputs);
if (ret != 0) {
allOutputs << virtOut;
}
}
+ // Overridden, because --newmode failed?
+ if (lowResFallback) {
+ if (ret != 0 && !bestDisconMode.modeName.isEmpty()) {
+ qDebug() << "Ret" << ret << "- Trying to enable best disconnected screen (1)";
+ ret = setMode(bestDisconMode.output, bestDisconMode.modeName, allOutputs);
+ bestDisconMode.modeName.clear();
+ }
+ if (ret != 0 && !bestConMode.modeName.isEmpty()) {
+ qDebug() << "Ret" << ret << "- Trying to enable best connected screen (1)";
+ ret = setMode(bestConMode.output, bestConMode.modeName, allOutputs);
+ bestConMode.modeName.clear();
+ }
+ }
// Either -1 if we didn't have a virtual one, or != 0 if xrandr setting failed
// Now as fallback, try enabling a disconnected output only
if (ret != 0 && !disconnectedOutputs.isEmpty()) {
- qDebug() << "Ret:" << ret << "- Trying to enable one disconnected output";
+ qDebug() << "Ret:" << ret << "- Trying to enable one random disconnected output";
QRegularExpression re("\\d+$");
QString dis;
int used[10] = {};
@@ -157,49 +214,55 @@ void LoginRpc::handleCommandV1(const QString &command)
if (dis.isEmpty()) {
dis = disconnectedOutputs.first();
}
- setMode.clear();
- setMode << "--verbose" << "--output" << dis << "--mode" << name;
- for (auto s : allOutputs) {
- if (s == dis)
- continue; // Not the one we need
- setMode << "--output" << s << "--off";
- }
- qDebug() << "Setting mode" << setMode;
- p.setProcessChannelMode(QProcess::ForwardedChannels);
// Add to output
p.start("xrandr", QStringList() << "--verbose" << "--addmode" << dis << name);
p.waitForFinished(2000);
p.kill();
- // Set
- p.start("xrandr", setMode);
- p.waitForFinished(2000);
- ret = p.exitCode();
- p.kill();
+ ret = setMode(dis, name, allOutputs);
+ }
+ // Try this stuff again in case --newmode succeeded but --addmode now didn't (NVIDIA)
+ if (ret != 0 && !bestDisconMode.modeName.isEmpty()) {
+ qDebug() << "Ret" << ret << "- Trying to enable best disconnected screen (2)";
+ ret = setMode(bestDisconMode.output, bestDisconMode.modeName, allOutputs);
+ bestDisconMode.modeName.clear();
}
// Now as fallback, try enabling just one connected output
- if (ret != 0) {
- qDebug() << "Ret:" << ret << "- Trying to enable one connected output";
+ if (ret != 0 && !connectedOutputs.isEmpty()) {
+ qDebug() << "Ret:" << ret << "- Trying to enable one random connected output";
QString conn = connectedOutputs.first();
- setMode.clear();
- setMode << "--verbose" << "--output" << conn << "--mode" << name;
- for (auto s : allOutputs) {
- if (s == conn)
- continue; // Not the one we need
- setMode << "--output" << s << "--off";
- }
- qDebug() << "Setting mode" << setMode;
- p.setProcessChannelMode(QProcess::ForwardedChannels);
// Add to output
p.start("xrandr", QStringList() << "--verbose" << "--addmode" << conn << name);
p.waitForFinished(2000);
p.kill();
- // Set
- p.start("xrandr", setMode);
- p.waitForFinished(2000);
- ret = p.exitCode();
- p.kill();
+ ret = setMode(conn, name, allOutputs);
+ }
+ // Try this stuff again in case --newmode succeeded but --addmode now didn't (NVIDIA)
+ if (ret != 0 && !bestConMode.modeName.isEmpty()) {
+ qDebug() << "Ret" << ret << "- Trying to enable best connected screen (2)";
+ ret = setMode(bestConMode.output, bestConMode.modeName, allOutputs);
+ bestConMode.modeName.clear();
}
}
}
emit loginRequest(lines[0], lines[1], lines[2]);
}
+
+static int setMode(const QString &virtOut, const QString &name, const QStringList &allOutputs)
+{
+ QStringList setMode(QStringLiteral("--verbose"));
+ QProcess p;
+ p.setProcessChannelMode(QProcess::ForwardedChannels);
+ for (auto output : allOutputs) {
+ if (output == virtOut)
+ continue; // Skip self
+ setMode << "--output" << output << "--off";
+ }
+ setMode << "--output" << virtOut << "--mode" << name;
+ // Set all outputs
+ qDebug() << setMode;
+ p.start("xrandr", setMode);
+ p.waitForFinished(2000);
+ int ret = p.exitCode();
+ p.kill();
+ return ret;
+}