summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-07-02 14:55:32 +0200
committerSimon Rettberg2019-07-02 14:55:32 +0200
commit17f21da18d0b356e0981b23f1654df99be4e4b66 (patch)
tree0671d709e55485937c35ec1c966a0ba00019b900
parentFix warning about defunct -t option (diff)
downloadbeamergui-17f21da18d0b356e0981b23f1654df99be4e4b66.tar.gz
beamergui-17f21da18d0b356e0981b23f1654df99be4e4b66.tar.xz
beamergui-17f21da18d0b356e0981b23f1654df99be4e4b66.zip
Try all possible modes for a given resolution
-rw-r--r--src/xprivate.cpp101
-rw-r--r--src/xprivate.h4
-rw-r--r--src/xx.cpp2
3 files changed, 72 insertions, 35 deletions
diff --git a/src/xprivate.cpp b/src/xprivate.cpp
index 62a4895..1273e1e 100644
--- a/src/xprivate.cpp
+++ b/src/xprivate.cpp
@@ -3,6 +3,13 @@
#include <QDebug>
#include <QRegularExpression>
+static double toVertRefresh(const XRRModeInfo *mode)
+{
+ if (mode->hTotal > 0 && mode->vTotal > 0)
+ return (double(mode->dotClock) / (double(mode->hTotal) * double(mode->vTotal)));
+ return 0;
+}
+
/**
* Check list of known model names that falsely report a screen size or similar
*/
@@ -52,6 +59,14 @@ static int modeEqual(const XRRModeInfo *a, const XRRModeInfo *b)
a->modeFlags == b->modeFlags);
}
+static int errorHandler(Display *dpy, XErrorEvent *err)
+{
+ char buf[1000];
+ XGetErrorText(dpy, err->error_code, buf, 1000);
+ qDebug() << "**X11 error**" << buf;
+ return 0;
+}
+
/*
* Class members
*/
@@ -65,6 +80,7 @@ XPrivate::XPrivate()
qFatal("Cannot open display");
::exit(1);
}
+ XSetErrorHandler(errorHandler);
_EDID_ATOM = XInternAtom(_display, RR_PROPERTY_RANDR_EDID, False);
}
@@ -452,7 +468,7 @@ void XPrivate::copyModesToAll(RROutput sourceId, int num)
if (other == sourceId)
continue;
const XRROutputInfo *otherInfo = _outputMap[other]->output;
- if (getOutputModeForResolution(otherInfo, mode->width, mode->height) != None)
+ if (!getOutputModeForResolution(otherInfo, mode->width, mode->height).isEmpty())
continue;
XRRAddOutputMode(_display, other, outputInfo->modes[i]);
}
@@ -460,32 +476,42 @@ void XPrivate::copyModesToAll(RROutput sourceId, int num)
}
/**
- * Get the RRMode for the specified output matching the given resolution.
+ * Get all known modes matching the given resolution.
* If multiple modes match the given resolution, the function will
- * return the first matching preferred mode. If no preferred
- * mode matches, the non-preferred mode with the highest refresh rate
- * will be returned.
- * Otherwise, None will be returned.
+ * put the preferred resolution first, then all others sorted by
+ * dotClock, descending.
*/
-RRMode XPrivate::getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const
+QList<RRMode> XPrivate::getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const
{
- XRRModeInfo *retval = nullptr;
+ XRRModeInfo *pref = nullptr;
+ QList<XRRModeInfo*> others;
for (int i = 0; i < output->nmode; ++i) {
- if (!_modeMap.contains(output->modes[i]))
- continue;
- XRRModeInfo *info = _modeMap[output->modes[i]];
- if (info->width == width && info->height == height) {
- if (i < output->npreferred)
- return output->modes[i];
- if (retval == nullptr || retval->dotClock < info->dotClock) {
- retval = info;
- }
+ if (!_modeMap.contains(output->modes[i]))
+ continue;
+ XRRModeInfo *info = _modeMap[output->modes[i]];
+ if (info->width == width && info->height == height) {
+ if (i < output->npreferred && pref == nullptr) {
+ pref = info;
+ } else {
+ others.append(info);
}
+ }
+ }
+ // Sort others descending by dotClock
+ qSort(others.begin(), others.end(), [](const XRRModeInfo *a, const XRRModeInfo *b) {
+ return toVertRefresh(a) > toVertRefresh(b);
+ });
+ QList<RRMode> ret;
+ if (pref != nullptr) {
+ ret.append(pref->id);
+ }
+ for (auto e : others) {
+ ret.append(e->id);
}
- return retval == nullptr ? None : retval->id;
+ return ret;
}
-RRMode XPrivate::getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const
+QList<RRMode> XPrivate::getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const
{
return getOutputModeForResolution(output, static_cast<unsigned int>(resolution.width()), static_cast<unsigned int>(resolution.height()));
}
@@ -563,14 +589,20 @@ XRRModeInfo* XPrivate::getPreferredMode(const OutputInfo *oi, XRRModeInfo *fallb
if (fallback != nullptr) {
maxX = int(fallback->width);
maxY = int(fallback->height);
- mode = getOutputModeForResolution(oi->output, fallback->width, fallback->height);
+ auto list = getOutputModeForResolution(oi->output, fallback->width, fallback->height);
+ if (!list.isEmpty()) {
+ mode = list.first();
+ }
}
static const std::vector<QSize> wanted = {QSize(1920, 1080), QSize(1280, 800), QSize(1280, 720), QSize(1152, 864), QSize(1024, 768)};
for (const QSize s : wanted) {
if (mode != None)
break;
if (s.width() <= maxX && s.height() <= maxY) {
- mode = getOutputModeForResolution(oi->output, s.width(), s.height());
+ auto list = getOutputModeForResolution(oi->output, s.width(), s.height());
+ if (!list.isEmpty()) {
+ mode = list.first();
+ }
}
}
if (mode == None) {
@@ -616,25 +648,30 @@ QList<QSize> XPrivate::getTotalSize(const QList<OutputInfo*> &projectors, const
bool XPrivate::setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun)
{
- RRMode mode = getOutputModeForResolution(oi->output, size);
+ QList<RRMode> modes = getOutputModeForResolution(oi->output, size);
Status s = RRSetConfigSuccess;
- if (mode == None) {
+ if (modes.isEmpty()) {
qDebug() << "Cannot set" << oi->outputName << "to" << size << " since it's not supported";
if (oi->output->nmode == 0)
return false;
qDebug() << "falling back to its default";
- mode = oi->output->modes[0];
+ modes.append(oi->output->modes[0]);
}
if (!dryRun) {
- s = XRRSetCrtcConfig(_display,
- _screenResources,
- oi->output->crtc,
- CurrentTime,
- x, y, mode,
- RR_Rotate_0,
- &oi->id, 1);
+ for (RRMode mode : modes) {
+ qDebug() << "Trying" << toVertRefresh(_modeMap[mode]) << "Hz";
+ s = XRRSetCrtcConfig(_display,
+ _screenResources,
+ oi->output->crtc,
+ CurrentTime,
+ x, y, mode,
+ RR_Rotate_0,
+ &oi->id, 1);
+ if (s == RRSetConfigSuccess)
+ break;
+ }
}
- qDebug() << (s != RRSetConfigSuccess ? "Failed to" : "") << "Set" << oi->outputName << "to" << _modeMap[mode]->width << "x" << _modeMap[mode]->height << "-- offset" << x << "/" << y;
+ qDebug() << (s != RRSetConfigSuccess ? "Failed to" : "") << "Set" << oi->outputName << "to" << size << "-- offset" << x << "/" << y;
if (s == RRSetConfigSuccess) {
return true;
}
diff --git a/src/xprivate.h b/src/xprivate.h
index c7ef29b..2937442 100644
--- a/src/xprivate.h
+++ b/src/xprivate.h
@@ -52,8 +52,8 @@ public:
void disconnectAllCrtcs();
XRRModeInfo* getPreferredMode(const OutputInfo *oi, XRRModeInfo *fallback = nullptr) const;
void setScreenSize(const QSize &size);
- RRMode getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const;
- RRMode getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const;
+ QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const;
+ QList<RRMode> getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const;
RRCrtc getFreeCrtc(const XRROutputInfo* output) const;
bool setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun = false);
QList<QSize> getTotalSize(const QList<OutputInfo*> &projectors, const QList<OutputInfo*> &screens) const;
diff --git a/src/xx.cpp b/src/xx.cpp
index 0b91161..62bd353 100644
--- a/src/xx.cpp
+++ b/src/xx.cpp
@@ -265,7 +265,7 @@ void ScreenSetup::initModes()
continue; // Is not a wanted resolution
// Make sure all outputs got it
for (OutputInfo *info : a->_outputMap) {
- if (a->getOutputModeForResolution(info->output, mode->width, mode->height) != None)
+ if (!a->getOutputModeForResolution(info->output, mode->width, mode->height).isEmpty())
continue;
XRRAddOutputMode(a->_display, info->id, mode->id);
}