summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;