summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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() {