summaryrefslogtreecommitdiffstats
path: root/src/x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/x.cpp')
-rw-r--r--src/x.cpp796
1 files changed, 0 insertions, 796 deletions
diff --git a/src/x.cpp b/src/x.cpp
deleted file mode 100644
index ef43f08..0000000
--- a/src/x.cpp
+++ /dev/null
@@ -1,796 +0,0 @@
-#include "x.h"
-#include "cvt.h"
-#include <QDebug>
-
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-enum class Projector {
- No,
- Yes,
- Maybe
-};
-
-struct OutputInfo {
- OutputInfo(RROutput id, XRROutputInfo *output, XRRCrtcInfo *crtc, XRRModeInfo *mode)
- : output(output), crtc(crtc), mode(mode), id(id), position(-1), outputType(Projector::No) {}
- ~OutputInfo() {
- XRRFreeOutputInfo(output);
- }
- XRROutputInfo* output;
- XRRCrtcInfo* crtc;
- XRRModeInfo* mode;
- RROutput id;
- QString modelName;
- QString outputName;
- int position;
- Projector outputType;
-};
-
-ScreenInfo::ScreenInfo(const OutputInfo *oi, const ModeMap &om)
- : position(oi->position), name(oi->modelName), output(oi->outputName),
- isProjector(oi->outputType == Projector::Yes)
-{
- if (oi->mode != nullptr) {
- currentResolution = QSize(QSize(int(oi->mode->width), int(oi->mode->height)));
- }
- for (int i = 0; i < oi->output->nmode; ++i) {
- if (om.contains(oi->output->modes[i])) {
- auto m = om.value(oi->output->modes[i]);
- const QSize size(int(m->width), int(m->height));
- if (!modes.contains(size)) {
- modes.append(size);
- }
- if (i == 0 && oi->output->npreferred > 0) {
- preferredResolution = size;
- }
- }
- }
-}
-
-ScreenSetup * ScreenSetup::_instance = nullptr;
-
-ScreenSetup::ScreenSetup() : _screenResources(nullptr)
-{
- // Get initial data (to be freed)
- _display = XOpenDisplay(nullptr);
- if (_display == nullptr) {
- qFatal("Cannot open display");
- ::exit(1);
- }
- _EDID_ATOM = XInternAtom(_display, RR_PROPERTY_RANDR_EDID, False);
- /* Get informations about Xserver */
- updateScreenResources();
-
-}
-
-void ScreenSetup::freeResources()
-{
- freeCrtcBackup();
- // Clear the modemap (nothing to be freed, stored in screenResources)
- _modeMap.clear();
- _resolutions.clear();
-
- // Clear output info
- for (OutputInfo *output : _outputMap.values()) {
- delete output;
- }
- _outputMap.clear();
-
- // Clear crtc info
- for (XRRCrtcInfo *info : _crtcMap.values()) {
- XRRFreeCrtcInfo(info);
- }
- _crtcMap.clear();
-
- // Release resources
- if (_screenResources != nullptr) {
- XRRFreeScreenResources(_screenResources);
- _screenResources = nullptr;
- }
- XRRFreeScreenResources(_screenResources);
-}
-
-static bool xRectLessThan(const OutputInfo* const &a, const OutputInfo* const &b)
-{
- return a->crtc->x < b->crtc->x;
-}
-
-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
- */
-static QStringList initProjectorList()
-{
- QStringList list;
- list << "AT-HDVS-RX"; // Switchbox
- // TODO: Load from file
- return list;
-}
-
-static bool isProjectorName(const QString &name)
-{
- static QStringList projectors = initProjectorList();
- return projectors.contains(name);
-}
-
-//___________________________________________________________________________
-void ScreenSetup::updateScreenResources()
-{
- freeResources();
- _screenResources = XRRGetScreenResourcesCurrent(_display, DefaultRootWindow(_display));
- // Create the modemap
- qDebug() << "Modes";
- for (int i = 0; i < _screenResources->nmode; ++i) {
- _modeMap.insert(
- _screenResources->modes[i].id,
- &_screenResources->modes[i]);
- qDebug() << _screenResources->modes[i].id << "\t"
- << _screenResources->modes[i].width << "x"
- << _screenResources->modes[i].height;
- }
-
- /*
- int num = 0;
- XRRMonitorInfo *mi = XRRGetMonitors(_display, DefaultRootWindow(_display), True, &num);
- for (int i = 0; i < num; ++i) {
- char *name = XGetAtomName(_display, mi [i].name);
- if (name == nullptr)
- continue;
- qDebug() << "some monitor with name" << name << mi[i].primary;
- XFree(name);
- }
- */
-
- // Create crtcMap
- qDebug() << "CRTCs";
- for (int i = 0; i < _screenResources->ncrtc; ++i) {
- XRRCrtcInfo * info = XRRGetCrtcInfo(
- _display,
- _screenResources,
- _screenResources->crtcs[i]);
- if (info == nullptr) {
- qDebug() << "Error getting CRTC info for crtc" << i;
- continue;
- }
- qDebug() << _screenResources->crtcs[i] << "-- Outputs:" << info->noutput << "Possible:" << info->npossible;
- _crtcMap.insert(_screenResources->crtcs[i], info);
- }
-
- // Create outputmap and connectedOutputMap
- qDebug() << "Outputs";
- QHash<RROutput, QString> tempMap;
- QMap<Projector, int> typeCount;
- for (int i = 0; i < _screenResources->noutput; ++i) {
- XRROutputInfo* info = XRRGetOutputInfo(
- _display,
- _screenResources,
- _screenResources->outputs[i]);
- if (info == nullptr) {
- qDebug() << "Error getting info for output" << i;
- continue;
- }
- const QString outputName = QString::fromLocal8Bit(info->name, info->nameLen);
- tempMap.insert(_screenResources->outputs[i], outputName);
- if (info->connection == RR_Disconnected) {
- qDebug() << "Ignoring disconnected output" << outputName;
- XRRFreeOutputInfo(info);
- continue;
- }
- bool disconnected = false;
- if (info->crtc == None) {
- disconnected = true;
- qDebug() << "Connected output" << outputName << "has no CRTC -- trying to find free one";
- info->crtc = getFreeCrtc(info);
- }
- if (!_crtcMap.contains(info->crtc)) {
- qDebug() << "Have output" << outputName << "with no known crtc";
- XRRFreeOutputInfo(info);
- continue;
- }
- XRRCrtcInfo *crtc = _crtcMap.value(info->crtc);
- XRRModeInfo *mode = nullptr;
- if (!disconnected) {
- if (!_modeMap.contains(crtc->mode)) {
- qDebug() << "Have output" << outputName << " with crtc with no known mode -- offline?";
- } else {
- mode = _modeMap.value(crtc->mode);
- }
- }
- OutputInfo *oi = new OutputInfo(_screenResources->outputs[i], info, crtc, mode);
- oi->outputName = outputName;
- if (!this->readEdid(oi)) { // We have no EDID - take it as an indicator that there's a dumb output split/switch box
- oi->outputType = Projector::Maybe;
- } else if ((info->mm_height == 0 && info->mm_width == 0) || isProjectorName(oi->modelName)) {
- oi->outputType = Projector::Yes; // Screens with size 0x0 are projectors by convention
- } else if (info->mm_width > 500 && info->mm_height > 500) { // Big screen - probably should be handled like a projector
- oi->outputType = Projector::Yes;
- } else if (info->mm_width > 350 && info->mm_height > 350) { // Somewhere in-between
- oi->outputType = Projector::Maybe;
- }
- typeCount[oi->outputType]++;
- _outputMap.insert(_screenResources->outputs[i], oi);
- qDebug() << "Connected" << outputName << "-- Clones:" << info->nclone << "Modes:" << info->nmode << "Crtcs:" << info->ncrtc << "Preferred:" << info->npreferred;
- }
- // Final checks for projector
- if (typeCount[Projector::Yes] == 0) {
- // No definitive projector
- if (typeCount[Projector::Maybe] > 0 && typeCount[Projector::No] > 0) {
- // Potential projector(s) and normal screen, promote
- for (OutputInfo *info : _outputMap) {
- if (info->outputType == Projector::Maybe) {
- info->outputType = Projector::Yes;
- break;
- }
- }
- }
- }
- // Print mappings
- for (XRRCrtcInfo *info : _crtcMap) {
- qDebug() << info << ":";
- for (int i = 0; i < info->npossible; ++i) {
- qDebug() << "Possible:" << tempMap[info->possible[i]];
- }
- }
- // Determine each screen's position
- QList<OutputInfo*> screens = _outputMap.values();
- // Nothing connected?
- if (screens.isEmpty())
- return;
- qSort(screens.begin(), screens.end(), xRectLessThan);
- int endX = -0xffff;
- qDebug() << "From left to right";
- for (OutputInfo* output : screens) {
- if (output->mode == nullptr) {
- qDebug() << "(Ignoring" << output->outputName << "since it's disconnected)";
- }
- if (output->crtc->x >= endX) {
- QSize res(0, 0);
- if (_modeMap.contains(output->crtc->mode)) {
- auto mode = _modeMap.value(output->crtc->mode);
- res = QSize(int(mode->width), int(mode->height));
- }
- _resolutions.append(res);
- endX = -0xffff; // Reset
- }
- output->position = _resolutions.size() - 1;
- qDebug() << "Screen (" << output->crtc->x << "," << output->crtc->y << ") @" << output->crtc->width << "x" << output->crtc->height << "as screen" << output->position;
- if (output->crtc->x + int(output->crtc->width) > endX) {
- endX = output->crtc->x + int(output->crtc->width);
- }
- }
- qDebug() << "Loaded.";
-}
-
-QMap<QString, ScreenInfo> ScreenSetup::getScreenPositions() const
-{
- QMap<QString, ScreenInfo> ret;
- for (auto oi : _outputMap) {
- ret.insert(oi->outputName, ScreenInfo(oi, _modeMap));
- }
- return ret;
-}
-
-
-
-bool ScreenSetup::readEdid(OutputInfo* output)
-{
- int numProps = 0;
- bool found = false;
- Atom* properties = XRRListOutputProperties(_display, output->id, &numProps);
- for (int i = 0; i < numProps; ++i) {
- if (properties[i] == _EDID_ATOM) {
- found = true;
- break;
- }
- }
- XFree(properties);
- if (!found)
- return false;
-
- unsigned long nitems, bytes_after;
- unsigned char *prop;
- int actual_format;
- Atom actual_type;
- bool valid;
-
- XRRGetOutputProperty(_display, output->id, _EDID_ATOM,
- 0, 128, False, False,
- AnyPropertyType,
- &actual_type, &actual_format,
- &nitems, &bytes_after, &prop);
- valid = (actual_format == 8 && nitems >= 128);
-
- if (valid) {
- int idx;
- for (unsigned char *byte = prop + 54; byte < prop + 126; byte += 18) {
- if (byte[0] != 0 || byte[1] != 0 || byte[2] != 0)
- continue; // Not a text block
- if (byte[3] == 0xfc) { // Serial number
- output->modelName = QString::fromLatin1(reinterpret_cast<const char*>(byte) + 5, 13); // It's actually CP-437 but meh
- if ((idx = output->modelName.indexOf('\r')) != -1) {
- output->modelName.truncate(idx);
- }
- output->modelName = output->modelName.trimmed();
- qDebug() << "Display name:" << output->modelName;
- }
- }
- }
- XFree(prop);
- return valid;
-}
-
-/**
- * Create common modes and add them to all outputs.
- * Make sure every output has some variant of the most commonly
- * used modes.
- */
-void ScreenSetup::initModes()
-{
- // First copy typical resolutions to all outputs
-#define RES(x,y) (((y) << 16) | (x))
- QSet<quint32> wanted;
- wanted << RES(1280, 720) << RES(1280, 800) << RES(1920, 1080);
- for (XRRModeInfo *mode : _modeMap) {
- if (toVertRefresh(mode) < 58 || toVertRefresh(mode) > 61)
- continue; // Play it safe and consider only those for copying that are 60Hz
- wanted.remove(RES(mode->width, mode->height));
- // Make sure all outputs got it
- for (OutputInfo *info : _outputMap) {
- if (getOutputModeForResolution(info->output, mode->width, mode->height))
- continue;
- XRRAddOutputMode(_display, info->id, mode->id);
- }
- }
-#undef RES
- // Create those that no output supported
- for (auto res : wanted) {
- unsigned int x = res & 0xffff;
- unsigned int y = res >> 16;
- createMode(x, y, 60, QString::asprintf("%ux%u", x, y));
- }
- if (!wanted.isEmpty()) {
- updateScreenResources();
- }
- // Finally copy all those the projector supports to other outputs
- for (auto key : _outputMap.keys()) {
- OutputInfo *oi = _outputMap[key];
- if (oi->outputType == Projector::Yes) {
- copyModesToAll(key, oi->output->nmode);
- }
- }
- updateScreenResources();
-}
-
-XRRModeInfo* ScreenSetup::getPreferredMode(OutputInfo *oi) const
-{
- if (oi->output->nmode == 0) {
- qDebug() << "getPreferredMode: Output" << oi->outputName << "has no modes!?";
- return nullptr; // WTF!?
- }
- RRMode mode;
- if (oi->output->npreferred > 0) {
- mode = oi->output->modes[0];
- } else {
- mode = getOutputModeForResolution(oi->output, 1920, 1080);
- if (mode == None) {
- mode = getOutputModeForResolution(oi->output, 1280, 720);
- }
- if (mode == None) {
- mode = getOutputModeForResolution(oi->output, 1280, 800);
- }
- if (mode == None) {
- mode = oi->output->modes[0];
- }
- }
- if (!_modeMap.contains(mode))
- return nullptr;
- return _modeMap[mode];
-}
-
-QList<QSize> ScreenSetup::getTotalSize(const QList<OutputInfo*> &projectors, const QList<OutputInfo*> &screens) const
-{
- const int max = qMax(screens.size(), projectors.size());
- QList<QSize> modes;
- for (int i = 0; i < max; ++i) {
- XRRModeInfo *mode = nullptr;
- if (i < projectors.size()) {
- mode = getPreferredMode(projectors.at(i));
- }
- if (mode == nullptr && i < screens.size()) {
- mode = getPreferredMode(screens.at(i));
- }
- if (mode != nullptr) {
- modes.append(QSize(int(mode->width), int(mode->height)));
- }
- }
- return modes;
-}
-
-static QSize getTotalSizeHorz(const QList<QSize> &list)
-{
- QSize ret(0, 0);
- for (auto e : list) {
- ret.rwidth() += e.width();
- ret.rheight() = qMax(ret.height(), e.height());
- }
- return ret;
-}
-
-bool ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize &size, bool dryRun)
-{
- RRMode mode = getOutputModeForResolution(oi->output, size);
- if (mode == None) {
- 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];
- }
- if (!dryRun) {
- XRRSetCrtcConfig(_display,
- _screenResources,
- oi->output->crtc,
- CurrentTime,
- x, y, mode,
- RR_Rotate_0,
- &oi->id, 1);
- }
- qDebug() << "Set" << oi->outputName << "to" << _modeMap[mode]->width << "x" << _modeMap[mode]->height << "-- offset" << x << "/" << y;
- return true;
-}
-
-ScreenMode ScreenSetup::getCurrentMode()
-{
- bool notAtOrigin = false;
- for (auto oi : _outputMap) {
- if (oi->mode != nullptr) {
- if (oi->crtc->x != 0 || oi->crtc->y != 0) {
- notAtOrigin = true;
- }
- }
- }
- if (_outputMap.size() == 1)
- return ScreenMode::Single;
- if (_outputMap.size() > 2)
- return ScreenMode::Advanced;
- if (notAtOrigin)
- return ScreenMode::Dual;
- return ScreenMode::Clone;
-}
-
-ScreenMode ScreenSetup::setDefaultMode(bool dryRun)
-{
- if (_outputMap.size() == 1) // Only one output exists, do nothing
- return ScreenMode::Single;
- QMap<QString, OutputInfo*> screenMap;
- QMap<QString, OutputInfo*> projectorMap;
- for (auto o : _outputMap) {
- qDebug() << o->outputName << quint32(o->outputType);
- if (o->outputType == Projector::Yes) {
- projectorMap.insert(o->outputName, o);
- } else {
- screenMap.insert(o->outputName, o);
- }
- }
- auto projectors = projectorMap.values();
- auto screens = screenMap.values();
- qDebug() << projectors.size() << "projectors," << screens.size() << "screens.";
- QList<QSize> outputSizes = getTotalSize(projectors, screens);
- if (outputSizes.isEmpty())
- return ScreenMode::Advanced; // Dunno lol
- QSize screenSize = getTotalSizeHorz(outputSizes);
- if (!dryRun) {
- XGrabServer(_display);
- disconnectAllCrtcs();
- // Set new screen size
- setScreenSize(screenSize);
- }
-
- qDebug() << "Virtual size:" << screenSize << "with" << outputSizes.size() << "different screens.";
-
- int offset = 0;
- for (int i = 0; i < outputSizes.size(); ++i) {
- const QSize &size = outputSizes.at(i);
- if (i < projectors.size()) {
- setOutputResolution(projectors.at(i), offset, 0, size, dryRun);
- }
- if (i < screens.size()) {
- setOutputResolution(screens.at(i), offset, 0, size, dryRun);
- }
- offset += size.width();
- }
- if (!dryRun) {
- XUngrabServer(_display);
- XSync(_display, False);
- }
- updateScreenResources(); // Re-Read
- if (outputSizes.size() == 1) // One output size, at least 2 outputs in total -- clone mode
- return ScreenMode::Clone;
- if (outputSizes.size() == 2 && _outputMap.size() == 2) // Two outputs, two sizes -- extended
- return ScreenMode::Dual;
- return ScreenMode::Advanced; // Must be more than 2 outputs -> something more involved
-}
-
-/**
- * Copy first "num" modes from output to all other outputs if they
- * dont have a suitable mode yet.
- */
-void ScreenSetup::copyModesToAll(RROutput sourceId, int num)
-{
- const XRROutputInfo *outputInfo = _outputMap[sourceId]->output;
- for (int i = 0; i < num; ++i) {
- if (!_modeMap.contains(outputInfo->modes[i])) {
- qDebug() << "BUG: Mode" << outputInfo->modes[i] << "not found in copyModesToAll";
- continue;
- }
- const XRRModeInfo *mode = _modeMap[outputInfo->modes[i]];
- for (auto other : _outputMap.keys()) {
- if (other == sourceId)
- continue;
- const XRROutputInfo *otherInfo = _outputMap[other]->output;
- if (getOutputModeForResolution(otherInfo, mode->width, mode->height) != None)
- continue;
- XRRAddOutputMode(_display, other, outputInfo->modes[i]);
- }
- }
-}
-
-/**
- * Get the RRMode for the specified output 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.
- */
-RRMode ScreenSetup::getOutputModeForResolution(const XRROutputInfo *output, unsigned int width, unsigned int height) const
-{
- XRRModeInfo *retval = nullptr;
- 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;
- }
- }
- }
- return retval == nullptr ? None : retval->id;
-}
-
-RRMode ScreenSetup::getOutputModeForResolution(const XRROutputInfo *output, const QSize &resolution) const
-{
- return getOutputModeForResolution(output, static_cast<unsigned int>(resolution.width()), static_cast<unsigned int>(resolution.height()));
-}
-
-RRCrtc ScreenSetup::getFreeCrtc(const XRROutputInfo* output) const
-{
- for (int i = 0; i < output->ncrtc; ++i) {
- RRCrtc c = output->crtcs[i];
- if (!_crtcMap.contains(c)) {
- // Unknown CRTC!? Scan already known outputs
- qDebug() << "BUG: Output has unknown possible CRTC";
- for (auto oi : _outputMap) {
- if (oi->output->crtc == c)
- goto next;
- }
- } else {
- // Known CRTC -- see if free
- if (_crtcMap[c]->noutput > 0)
- goto next;
- }
- return c;
-next:;
- }
- return None;
-}
-
-//___________________________________________________________________________
-bool ScreenSetup::createMode(unsigned int resX, unsigned int resY, float refresh, QString name)
-{
- QByteArray ba = name.toLocal8Bit();
- mode *mode = vert_refresh(int(resX), int(resY), refresh, 0, 0, 0);
- if (mode == nullptr)
- return false;
- XRRModeInfo 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());
- free(mode);
-
- for (XRRModeInfo *mode : _modeMap) {
- if (mode->width == m.width && mode->height == m.height && mode->dotClock == m.dotClock)
- return true; // Already exists, return true?
- }
-
- RRMode xid = XRRCreateMode(_display, DefaultRootWindow(_display), &m);
- qDebug() << "Return value of create was" << xid;
- // Immediately add to all screens
- for (OutputInfo *info : _outputMap) {
- XRRAddOutputMode(_display, info->id, xid);
- }
- return true;
-}
-
-//___________________________________________________________________________
-ScreenSetup::~ScreenSetup()
-{
- freeResources();
- XCloseDisplay(_display);
-}
-
-void ScreenSetup::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 ScreenSetup::disconnectAllCrtcs()
-{
- // Disconnect everything
- for (auto crtc : _crtcMap.keys()) {
- XRRSetCrtcConfig(_display, _screenResources, crtc, CurrentTime,
- 0, 0, None, RR_Rotate_0, nullptr, 0);
- }
-}
-
-void ScreenSetup::freeCrtcBackup()
-{
- for (auto entry : _crtcBackup) {
- free(entry->outputs);
- free(entry);
- }
- _crtcBackup.clear();
- qDebug() << "CRTC freed";
-}
-
-void ScreenSetup::createCrtcBackup()
-{
- freeCrtcBackup();
- for (CrtcMap::iterator it = _crtcMap.begin(); it != _crtcMap.end(); ++it) {
- const auto src = it.value();
- XRRCrtcInfo *copy = static_cast<XRRCrtcInfo*>(calloc(1, sizeof(XRRCrtcInfo)));
- copy->outputs = static_cast<RROutput*>(calloc(size_t(src->noutput), sizeof(RROutput)));
- copy->x = src->x;
- copy->y = src->y;
- copy->mode = src->mode;
- copy->rotation = src->rotation;
- copy->noutput = src->noutput;
- for (int i = 0; i < src->noutput; ++i) {
- copy->outputs[i] = src->outputs[i];
- }
- _crtcBackup[it.key()] = copy;
- }
- qDebug() << "Created CRTC backup with entries:" << _crtcBackup.size();
-}
-
-bool ScreenSetup::setClone(const QSize &resolution)
-{
- createCrtcBackup();
- XGrabServer(_display);
- disconnectAllCrtcs();
- setScreenSize(resolution);
- bool ok = false;
- for (auto oi : _outputMap) {
- ok = setOutputResolution(oi, 0, 0, resolution) || ok;
- }
- XUngrabServer(_display);
- XSync(_display, False);
- return ok;
-}
-
-bool ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list)
-{
- QList<QSize> sizes;
- for (auto e : list) {
- if (e.second.isEmpty())
- continue;
- sizes.append(e.first);
- }
- if (sizes.isEmpty())
- return false;
- createCrtcBackup();
- auto screenSize = getTotalSizeHorz(sizes);
- if (screenSize.isEmpty())
- return false;
- XGrabServer(_display);
- disconnectAllCrtcs();
- setScreenSize(screenSize);
- int x = 0;
- bool ok = false;
- for (auto e : list) {
- if (e.second.isEmpty())
- continue;
- const QSize &res = e.first;
- for (auto outputName : e.second) {
- for (auto oi : _outputMap) {
- if (oi->outputName != outputName)
- continue;
- ok = setOutputResolution(oi, x, 0, res) || ok;
- }
- }
- x += res.width();
- }
- XUngrabServer(_display);
- XSync(_display, False);
- return ok;
-}
-
-void ScreenSetup::revertChanges()
-{
- if (_crtcBackup.isEmpty())
- return;
- qDebug() << "Starting revert";
- XGrabServer(_display);
- disconnectAllCrtcs();
- QSize screenSize;
- for (auto e : _crtcBackup) {
- if (e->mode == None || !_modeMap.contains(e->mode))
- continue;
- screenSize = screenSize.expandedTo(QSize(e->x + int(_modeMap[e->mode]->width), e->y + int(_modeMap[e->mode]->height)));
- }
- for (CrtcMap::iterator it = _crtcBackup.begin(); it != _crtcBackup.end(); ++it) {
- auto e = it.value();
- if (e->mode == None)
- continue;
- XRRSetCrtcConfig(_display, _screenResources, it.key(), CurrentTime,
- e->x, e->y, e->mode, e->rotation, e->outputs, e->noutput);
- }
- XUngrabServer(_display);
- XSync(_display, False);
-}
-
-static bool modeBiggerThan(const QSize &a, const QSize &b)
-{
- if (a.width() > b.width())
- return true;
- return a.width() == b.width() && a.height() > b.height();
-}
-
-ResolutionVector ScreenSetup::getCommonModes() const
-{
- QHash<QPair<quint32, quint32>, QSet<RROutput>> matches;
- for (auto oi : _outputMap) {
- for (int i = 0; i < oi->output->nmode; ++i) {
- if (!_modeMap.contains(oi->output->modes[i]))
- continue;
- const auto mode = _modeMap[oi->output->modes[i]];
- const QPair<quint32, quint32> pair = qMakePair(mode->width, mode->height);
- matches[pair].insert(oi->id);
- }
- }
- ResolutionVector ret;
- for (auto it = matches.begin(); it != matches.end(); ++it) {
- if (it.value().size() == _outputMap.size()) {
- ret.append(QSize(int(it.key().first), int(it.key().second)));
- }
- }
- qSort(ret.begin(), ret.end(), modeBiggerThan);
- return ret;
-}
-
-