summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-09-17 15:17:01 +0200
committerSimon Rettberg2020-09-17 15:17:01 +0200
commit2901482b60f53ba9846db779601297838ad9f622 (patch)
treece76febf8c2cf3b229a9fc3280cc0f0605d63cb4
parentAdd more debug info (diff)
downloadbeamergui-2901482b60f53ba9846db779601297838ad9f622.tar.gz
beamergui-2901482b60f53ba9846db779601297838ad9f622.tar.xz
beamergui-2901482b60f53ba9846db779601297838ad9f622.zip
Force-Add resolutions when using --resolutions option
If the user explicitly passes desired resolutions on the command line, assume they know what they're doing, and go ahead and force things the way they were requested. Also add more debug spam to relevant code, so we can track down where/why things fail.
-rw-r--r--src/xprivate.cpp60
-rw-r--r--src/xprivate.h1
-rw-r--r--src/xx.cpp43
3 files changed, 96 insertions, 8 deletions
diff --git a/src/xprivate.cpp b/src/xprivate.cpp
index 7cb0949..53059e4 100644
--- a/src/xprivate.cpp
+++ b/src/xprivate.cpp
@@ -1,4 +1,5 @@
#include "xprivate.h"
+#include "cvt.h"
#include <QDebug>
#include <QRegularExpression>
@@ -658,3 +659,62 @@ XRRModeInfo* XPrivate::setOutputResolution(QStringList &args, OutputInfo *oi, in
}
return best;
}
+
+/**
+ * !! oi pointer might be invalid after calling this !!
+ * @return true if updateScreenResources() should be called later
+ */
+bool XPrivate::addResolutionToOutput(OutputInfo *oi, const QSize &res)
+{
+ if (!getOutputModeForResolution(oi->output, res).empty())
+ return false; // Nothing to do
+ XRRModeInfo *bestMode = nullptr;
+ for (auto *mode : _modeMap) {
+ if (int(mode->width) != res.width() || int(mode->height) != res.height())
+ continue;
+ if (toVertRefresh(mode) < 59 || toVertRefresh(mode) > 70)
+ continue; // Play it safe
+ if (bestMode == nullptr || abs(toVertRefresh(bestMode) - 60) > abs(toVertRefresh(mode) - 60)) {
+ bestMode = mode; // As close to 60 as possible
+ }
+ }
+ if (bestMode != nullptr) {
+ qDebug() << "Adding existing mode" << res.width() << 'x' << res.height() << "to" << oi->outputName;
+ XRRAddOutputMode(_display, oi->id, bestMode->id);
+ return true;
+ } else {
+ // From scratch
+ qDebug() << "Creating requested mode" << res.width() << 'x' << res.height() << "from scratch";
+ QByteArray ba = QString::asprintf("%dx%d_BG", res.width(), res.height()).toLocal8Bit();
+ mode *mode = vert_refresh(res.width(), res.height(), 60, 0, 0, 0);
+ if (mode == nullptr)
+ return false; // Failed
+ XRRModeInfo m;
+ memset(&m, 0, sizeof(m));
+ m.width = static_cast<unsigned int>(mode->hr);
+ m.height = static_cast<unsigned int>(mode->vr);
+ m.dotClock = static_cast<unsigned long>(mode->pclk) * 1000ul * 1000ul;
+ m.hSyncStart= static_cast<unsigned int>(mode->hss);
+ m.hSyncEnd = static_cast<unsigned int>(mode->hse);
+ m.hTotal = static_cast<unsigned int>(mode->hfl);
+ m.hSkew = 0;
+ m.vSyncStart= static_cast<unsigned int>(mode->vss);
+ m.vSyncEnd = static_cast<unsigned int>(mode->vse);
+ m.vTotal = static_cast<unsigned int>(mode->vfl);
+ m.id = 0;
+ m.name = ba.data();
+ m.nameLength= static_cast<unsigned int>(ba.length());
+ m.modeFlags = RR_VSyncPositive | RR_HSyncNegative;
+ free(mode);
+ RRMode xid = XRRCreateMode(_display, DefaultRootWindow(_display), &m);
+ if (xid <= 0) {
+ qDebug() << "Creating mode failed";
+ return false;
+ }
+ qDebug() << "Adding created mode to" << oi->outputName;
+ XRRAddOutputMode(_display, oi->id, xid);
+ // Stuff changed, update now in case other screens want the same resolution
+ updateScreenResources();
+ return false; // We just updated ourselves, don't signal "update required"
+ }
+}
diff --git a/src/xprivate.h b/src/xprivate.h
index 0152fb1..bc8791e 100644
--- a/src/xprivate.h
+++ b/src/xprivate.h
@@ -56,6 +56,7 @@ public:
XRRModeInfo* setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size);
QList<QSize> getTotalSize(const QList<OutputInfo*> &projectors, const QList<OutputInfo*> &screens) const;
void copyModesToAll(RROutput id, int num);
+ bool addResolutionToOutput(OutputInfo *oi, const QSize &res);
Display* _display;
Atom _EDID_ATOM;
diff --git a/src/xx.cpp b/src/xx.cpp
index 179d286..d4a4608 100644
--- a/src/xx.cpp
+++ b/src/xx.cpp
@@ -267,6 +267,7 @@ void ScreenSetup::initModes()
if (!a->getOutputModeForResolution(info->output, mode->width, mode->height).isEmpty())
continue;
XRRAddOutputMode(a->_display, info->id, mode->id);
+ qDebug() << "Adding mode" << mode->width << 'x' << mode->height << "to" << info->outputName;
}
}
#undef RES
@@ -274,6 +275,7 @@ void ScreenSetup::initModes()
for (auto res : wanted) {
unsigned int x = res & 0xffff;
unsigned int y = res >> 16;
+ qDebug() << "Creating missing wanted resolution of" << x << "x" << y;
createMode(x, y, 60, QString::asprintf("%ux%u", x, y));
}
if (!wanted.isEmpty()) { // Modes were added, update for final loop below
@@ -282,7 +284,8 @@ void ScreenSetup::initModes()
// Finally copy all those the projector supports to other outputs
for (auto key : a->_outputMap.keys()) {
OutputInfo *oi = a->_outputMap[key];
- if (oi->outputType == Projector::Yes) {
+ if (oi->outputType == Projector::Yes && oi->output->npreferred > 0) { // Only if has edid
+ qDebug() << "Copying" << oi->output->nmode << "modes to all from" << oi->outputName;
a->copyModesToAll(key, oi->output->nmode);
}
}
@@ -497,7 +500,10 @@ bool ScreenSetup::createMode(unsigned int resX, unsigned int resY, float refresh
}
RRMode xid = XRRCreateMode(a->_display, DefaultRootWindow(a->_display), &m);
- qDebug() << "Return value of create was" << xid;
+ if (xid <= 0) {
+ qDebug() << "Return value of create mode was" << xid << "(" << resX << 'x' << resY << ")";
+ return false;
+ }
// Immediately add to all screens
for (OutputInfo *info : a->_outputMap) {
XRRAddOutputMode(a->_display, info->id, xid);
@@ -591,21 +597,42 @@ ConfigBackup ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &l
retval = createCrtcBackup();
auto screenSize = getTotalSizeHorz(sizes);
if (screenSize.isEmpty())
- return retval;
- int x = 0;
+ return retval;
+ // Make sure desired resolutions exist on outputs
+ bool reload = false;
+ for (auto e : list) {
+ if (e.second.isEmpty())
+ continue;
+ const QSize &res = e.first;
+ for (auto outputName : e.second) {
+ for (auto oi : a->_outputMap) {
+ if (oi->outputName != outputName)
+ continue;
+ // Now add resolution if not found
+ if (a->addResolutionToOutput(oi, res)) {
+ reload = true;
+ }
+ }
+ }
+ }
+ if (reload) {
+ updateScreenResources();
+ }
+ int x = 0;
for (auto e : list) {
if (e.second.isEmpty())
continue;
const QSize &res = e.first;
unsigned int w = 0;
+ // Find according output, apply resolution
for (auto outputName : e.second) {
for (auto oi : a->_outputMap) {
if (oi->outputName != outputName)
continue;
- auto *mode = a->setOutputResolution(cmd, oi, x, 0, res);
- if (mode != nullptr && mode->width > w) {
- w = mode->width;
- }
+ auto *mode = a->setOutputResolution(cmd, oi, x, 0, res);
+ if (mode != nullptr && mode->width > w) {
+ w = mode->width;
+ }
}
}
x += w;