summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-02-16 10:12:22 +0100
committerSimon Rettberg2020-02-16 10:12:22 +0100
commit6289a836449b67d2a3d54d38332343ec8335aa67 (patch)
treed44323911a3577ec0c7916d8a0a6cbffb28995b7
parentMake sure screen at (0, 0) is marked primary (diff)
downloadbeamergui-6289a836449b67d2a3d54d38332343ec8335aa67.tar.gz
beamergui-6289a836449b67d2a3d54d38332343ec8335aa67.tar.xz
beamergui-6289a836449b67d2a3d54d38332343ec8335aa67.zip
Use xrandr to actually set resolutions
Get rid of out own crap to try and figure out how to configure the outputs, crtcs, screens, whatever. xrandr probably is smarter here, so just build a command line and go.
-rw-r--r--src/main.cpp10
-rw-r--r--src/widget.cpp2
-rw-r--r--src/xprivate.cpp67
-rw-r--r--src/xprivate.h12
-rw-r--r--src/xx.cpp131
-rw-r--r--src/xx.h3
6 files changed, 89 insertions, 136 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 8df19e2..59c886b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -62,7 +62,7 @@ int main(int argc, char *argv[])
ScreenSetup::inst()->setCenteredClone();
} else if (CommandLine::autoSetup()) {
ScreenMode mode;
- ScreenSetup::inst()->setDefaultMode(CommandLine::testMode(), mode);
+ ScreenSetup::inst()->setDefaultMode(mode);
} else {
ScreenSetup::inst()->getCurrentMode();
}
@@ -98,12 +98,10 @@ static void parseCommandLine(const QCoreApplication &a)
QCommandLineOption oBackground(QStringList() << "b" << "background",
QCoreApplication::translate("main", "Keep running in background and show GUI when number of screens changes."));
parser.addOption(oBackground);
- /*
// Test mode -- pretend to do setup
QCommandLineOption oTest(QStringList() << "t" << "test",
QCoreApplication::translate("main", "Test mode, don't actually apply any changes."));
- parser.addOption(oTest); TODO Not fully implemented so disabled for now
- */
+ parser.addOption(oTest);
// Wakeup beamergui daemon via DBus connect
QCommandLineOption oWakeup(QStringList() << "w" << "wakeup",
QCoreApplication::translate("main", "Connect to system bus to trigger wakeup of wainting beamergui."));
@@ -113,10 +111,8 @@ static void parseCommandLine(const QCoreApplication &a)
QCoreApplication::translate("main", "Set all outputs to clone mode. If size differs, center outputs according to largest output."));
parser.addOption(oCenter);
// PARSE
- parser.process(a);
- /*
+ parser.process(a);
_testMode = parser.isSet(oTest);
- */
_autoSetup = parser.isSet(oAutoSetup);
_showGui = parser.isSet(oShowGui);
_backgroundMode = parser.isSet(oBackground);
diff --git a/src/widget.cpp b/src/widget.cpp
index 12bbfd1..6b231fa 100644
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -142,7 +142,7 @@ Widget::Widget(QWidget *parent) :
_lastScreenCount = currentCount;
ScreenSetup::inst()->initModes();
ScreenMode mode;
- auto ret = ScreenSetup::inst()->setDefaultMode(CommandLine::testMode(), mode);
+ auto ret = ScreenSetup::inst()->setDefaultMode(mode);
if (!ret.ok() || !keepResolution()) {
ret.revert();
}
diff --git a/src/xprivate.cpp b/src/xprivate.cpp
index b8f10b6..370c6f5 100644
--- a/src/xprivate.cpp
+++ b/src/xprivate.cpp
@@ -7,13 +7,6 @@
static Display* __display;
static XErrorHandler old_handler;
-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
*/
@@ -173,6 +166,7 @@ void XPrivate::updateScreenResources()
qDebug() << "updateScreenResources: Outputs";
QHash<RROutput, QString> tempMap;
QMap<Projector, int> typeCount;
+ _allOutputs.clear();
for (int i = 0; i < _screenResources->noutput; ++i) {
XRROutputInfo* info = XRRGetOutputInfo(
_display,
@@ -183,6 +177,7 @@ void XPrivate::updateScreenResources()
continue;
}
const QString outputName = QString::fromLocal8Bit(info->name, info->nameLen);
+ _allOutputs.append(outputName);
tempMap.insert(_screenResources->outputs[i], outputName);
if (info->connection == RR_Disconnected) {
qDebug() << "Ignoring disconnected output" << outputName;
@@ -446,26 +441,6 @@ void XPrivate::addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId
}
}
-void XPrivate::setScreenSize(const QSize &size)
-{
- XRRSetScreenSize(_display, DefaultRootWindow(_display),
- size.width(), size.height(),
- int(25.4 * size.width() / 96.0), // standard dpi that X uses
- int(25.4 * size.height() / 96.0)); // standard dpi that X uses
-}
-
-void XPrivate::disconnectAllCrtcs()
-{
- // Disconnect everything
- for (auto crtc : _crtcMap.keys()) {
- Status s = XRRSetCrtcConfig(_display, _screenResources, crtc, CurrentTime,
- 0, 0, None, RR_Rotate_0, nullptr, 0);
- if (s != RRSetConfigSuccess) {
- qDebug() << "Disconnecting CRTC" << crtc << "failed";
- }
- }
-}
-
/**
* Copy first "num" modes from output to all other outputs if they
* dont have a suitable mode yet.
@@ -514,6 +489,8 @@ QList<RRMode> XPrivate::getOutputModeForResolution(const XRROutputInfo *output,
}
// Sort others descending by dotClock
qSort(others.begin(), others.end(), [](const XRRModeInfo *a, const XRRModeInfo *b) {
+ if ((a->modeFlags & RR_DoubleScan) != (b->modeFlags & RR_DoubleScan))
+ return (a->modeFlags & RR_DoubleScan) == 0; // Prefer non-interlaced resolutions
return toVertRefresh(a) > toVertRefresh(b);
});
QList<RRMode> ret;
@@ -661,38 +638,22 @@ QList<QSize> XPrivate::getTotalSize(const QList<OutputInfo*> &projectors, const
return modes;
}
-bool XPrivate::setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun)
+void XPrivate::setOutputResolution(QStringList &args, OutputInfo *oi, int x, int y, const QSize &size)
{
QList<RRMode> modes = getOutputModeForResolution(oi->output, size);
- Status s = RRSetConfigSuccess;
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";
+ return;
+ qDebug() << "falling back to its default mode";
modes.append(oi->output->modes[0]);
}
- if (!dryRun) {
- 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) {
- if (x == 0 && y == 0) {
- XRRSetOutputPrimary(_display, DefaultRootWindow(_display), oi->id);
- }
- break;
- }
- }
- }
- qDebug() << (s != RRSetConfigSuccess ? "Failed to" : "") << "Set" << oi->outputName << "to" << size << "-- offset" << x << "/" << y;
- if (s == RRSetConfigSuccess) {
- return true;
+ // modes list is known to be sorted by preferred resolution/rate, then sorted by highest to lowest rate
+ // so we just pick the first one for now, as the GUI doesn't offer picking the rate
+ XRRModeInfo *best = _modeMap[modes.first()];
+ args << "--output" << oi->outputName << "--mode" << best->name << "--rate" << QString::number(toVertRefresh(best), 'f', 2);
+ args << "--x" << QString::number(x) << "--y" << QString::number(y);
+ if (x == 0 && y == 0 && !args.contains(QLatin1String("--primary"))) {
+ args.append("--primary");
}
- return false;
}
diff --git a/src/xprivate.h b/src/xprivate.h
index 2937442..d0f2d53 100644
--- a/src/xprivate.h
+++ b/src/xprivate.h
@@ -49,13 +49,11 @@ public:
bool readEdid(OutputInfo* output);
void addMissingModesFromExtBlock(XRRScreenResources *res, RROutput outputId, unsigned char *data);
void addMissingModesFromDtd(XRRScreenResources *res, RROutput outputId, unsigned char *data);
- void disconnectAllCrtcs();
XRRModeInfo* getPreferredMode(const OutputInfo *oi, XRRModeInfo *fallback = nullptr) const;
- void setScreenSize(const QSize &size);
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);
+ void 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);
@@ -65,7 +63,15 @@ public:
ModeMap _modeMap;
CrtcMap _crtcMap;
OutputMap _outputMap;
+ QStringList _allOutputs;
ResolutionVector _resolutions;
};
+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;
+}
+
#endif // XPRIVATE_H
diff --git a/src/xx.cpp b/src/xx.cpp
index 62bd353..b94e42e 100644
--- a/src/xx.cpp
+++ b/src/xx.cpp
@@ -1,9 +1,11 @@
#include "xx.h"
#include "xprivate.h"
#include "cvt.h"
+#include "main.h"
#include <QDebug>
#include <QSocketNotifier>
#include <QThread>
+#include <QProcess>
/*
* This clusterfuck exists because there are name clashes between X11/Xrandr headers
@@ -55,24 +57,24 @@ public:
if (map.isEmpty())
return;
qDebug() << "Starting revert";
- XGrabServer(x->_display);
- x->disconnectAllCrtcs();
+ QStringList cmd;
QSize screenSize;
for (auto e : map) {
if (e->mode == None || !x->_modeMap.contains(e->mode))
continue;
+ XRRModeInfo *mode = x->_modeMap[e->mode];
+ QString rate = QString::number(toVertRefresh(mode), 'f', 2);
+ for (int i = 0; i < e->noutput; ++i) {
+ auto *oi = x->_outputMap[e->outputs[i]];
+ cmd << "--output" << oi->outputName << "--mode" << mode->name << "--rate" << rate;
+ cmd << "--x" << QString::number(oi->crtc->x) << "--y" << QString::number(oi->crtc->y);
+ if (oi->crtc->x == 0 && oi->crtc->y == 0 && !cmd.contains("--primary")) {
+ cmd << "--primary";
+ }
+ }
screenSize = screenSize.expandedTo(QSize(e->x + int(x->_modeMap[e->mode]->width), e->y + int(x->_modeMap[e->mode]->height)));
}
- x->setScreenSize(screenSize);
- for (CrtcMap::iterator it = map.begin(); it != map.end(); ++it) {
- auto e = it.value();
- if (e->mode == None)
- continue;
- XRRSetCrtcConfig(x->_display, x->_screenResources, it.key(), CurrentTime,
- e->x, e->y, e->mode, e->rotation, e->outputs, e->noutput);
- }
- XUngrabServer(x->_display);
- XSync(x->_display, False);
+ ScreenSetup::inst()->runXrandr(cmd);
freeBackup();
}
};
@@ -220,13 +222,6 @@ ScreenSetup::ScreenSetup() : a(new XPrivate())
}
-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;
-}
-
void ScreenSetup::addMissingEdidResolutions()
{
a->addMissingEdidResolutions();
@@ -330,7 +325,7 @@ bool ScreenSetup::hasScreenWithoutEdid()
return false;
}
-ConfigBackup ScreenSetup::setDefaultMode(bool dryRun, ScreenMode &mode)
+ConfigBackup ScreenSetup::setDefaultMode(ScreenMode &mode)
{
ConfigBackup retval;
if (a->_outputMap.size() == 1) { // Only one output exists, do nothing
@@ -356,36 +351,24 @@ ConfigBackup ScreenSetup::setDefaultMode(bool dryRun, ScreenMode &mode)
mode = ScreenMode::Advanced; // Dunno lol
return retval;
}
- QSize screenSize = getTotalSizeHorz(outputSizes);
- if (!dryRun) {
- retval = createCrtcBackup();
- XGrabServer(a->_display);
- a->disconnectAllCrtcs();
- // Set new screen size
- a->setScreenSize(screenSize);
- }
+ QSize screenSize = getTotalSizeHorz(outputSizes);
+ QStringList cmd;
+ retval = createCrtcBackup();
qDebug() << "Virtual screen size:" << screenSize << "with" << outputSizes.size() << "different screens.";
int offset = 0;
- for (int i = 0; i < outputSizes.size(); ++i) {
- bool ok = false;
+ for (int i = 0; i < outputSizes.size(); ++i) {
const QSize &size = outputSizes.at(i);
if (i < projectors.size()) {
- ok = a->setOutputResolution(projectors.at(i), offset, 0, size, dryRun) || ok;
+ a->setOutputResolution(cmd, projectors.at(i), offset, 0, size);
}
if (i < screens.size()) {
- ok = a->setOutputResolution(screens.at(i), offset, 0, size, dryRun) || ok;
+ a->setOutputResolution(cmd, screens.at(i), offset, 0, size);
}
- offset += size.width();
- if (ok) {
- retval._ok = true;
- }
- }
- if (!dryRun) {
- XUngrabServer(a->_display);
- XSync(a->_display, False);
- }
+ offset += size.width();
+ }
+ retval._ok = runXrandr(cmd);
updateScreenResources(); // Re-Read
if (outputSizes.size() == 1) {
// One output size, at least 2 outputs in total -- clone mode
@@ -478,9 +461,8 @@ ConfigBackup ScreenSetup::setCenteredClone()
return retval;
break;
}
- XGrabServer(a->_display);
- a->disconnectAllCrtcs();
- QSize screenSize;
+ QStringList cmd;
+ QSize screenSize; // Currently unused
for (auto oi : a->_outputMap) {
auto mode = a->getPreferredMode(oi, fallback);
if (mode != nullptr) {
@@ -492,36 +474,28 @@ ConfigBackup ScreenSetup::setCenteredClone()
}
const int x = (screenSize.width() - int(mode->width)) / 2;
const int y = (screenSize.height() - int(mode->height)) / 2;
- if (a->setOutputResolution(oi, x, y, QSize(int(mode->width), int(mode->height)))) {
- retval._ok = true;
- }
- }
- }
- a->setScreenSize(screenSize);
- XUngrabServer(a->_display);
- XSync(a->_display, False);
+ a->setOutputResolution(cmd, oi, x, y, QSize(int(mode->width), int(mode->height)));
+ }
+ }
+ retval._ok = runXrandr(cmd);
return retval;
}
ConfigBackup ScreenSetup::setClone(const QSize &resolution)
{
+ QStringList cmd;
ConfigBackup retval = createCrtcBackup();
- XGrabServer(a->_display);
- a->disconnectAllCrtcs();
- a->setScreenSize(resolution);
for (auto oi : a->_outputMap) {
- if (a->setOutputResolution(oi, 0, 0, resolution)) {
- retval._ok = true;
- }
- }
- XUngrabServer(a->_display);
- XSync(a->_display, False);
+ a->setOutputResolution(cmd, oi, 0, 0, resolution);
+ }
+ retval._ok = runXrandr(cmd);
return retval;
}
ConfigBackup ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list)
{
ConfigBackup retval;
+ QStringList cmd;
QList<QSize> sizes;
for (auto e : list) {
if (e.second.isEmpty())
@@ -534,9 +508,6 @@ ConfigBackup ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &l
auto screenSize = getTotalSizeHorz(sizes);
if (screenSize.isEmpty())
return retval;
- XGrabServer(a->_display);
- a->disconnectAllCrtcs();
- a->setScreenSize(screenSize);
int x = 0;
for (auto e : list) {
if (e.second.isEmpty())
@@ -546,15 +517,12 @@ ConfigBackup ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &l
for (auto oi : a->_outputMap) {
if (oi->outputName != outputName)
continue;
- if (a->setOutputResolution(oi, x, 0, res)) {
- retval._ok = true;
- }
- }
+ a->setOutputResolution(cmd, oi, x, 0, res);
+ }
}
x += res.width();
- }
- XUngrabServer(a->_display);
- XSync(a->_display, False);
+ }
+ retval._ok = runXrandr(cmd);
return retval;
}
@@ -634,3 +602,24 @@ const ResolutionVector &ScreenSetup::getVirtualResolutions() const
{
return a->_resolutions;
}
+
+bool ScreenSetup::runXrandr(QStringList &cmd)
+{
+ QProcess proc;
+ // Sloppy: Turn off all outputs not found in argument list. Doesn't actually parse the
+ // command line, so if you have a mode that's called like an output, funny things might happen.
+ for (const auto &name : a->_allOutputs) {
+ if (!cmd.contains(name)) {
+ cmd << "--output" << name << "--off";
+ }
+ }
+ qDebug() << "XRANDR:" << cmd;
+ if (CommandLine::testMode())
+ return true;
+ proc.start("xrandr", cmd);
+ proc.waitForFinished(5000);
+ if (proc.state() == QProcess::Running) {
+ proc.kill();
+ }
+ return proc.exitCode() == 0;
+}
diff --git a/src/xx.h b/src/xx.h
index 53d3507..ce522d8 100644
--- a/src/xx.h
+++ b/src/xx.h
@@ -68,7 +68,7 @@ public:
void initModes();
ScreenMode getCurrentMode();
bool hasScreenWithoutEdid();
- ConfigBackup setDefaultMode(bool dryRun, ScreenMode &mode);
+ ConfigBackup setDefaultMode(ScreenMode &mode);
bool createMode(unsigned int resX, unsigned int resY, float refresh, QString name);
ConfigBackup setCenteredClone();
ConfigBackup setClone(const QSize &resolution);
@@ -78,6 +78,7 @@ public:
int queryCurrentOutputCount() const;
QMap<QString, ScreenInfo> getScreenPositions() const;
const ResolutionVector &getVirtualResolutions() const;
+ bool runXrandr(QStringList &cmd);
// Singleton
inline static ScreenSetup* inst() {