summaryrefslogtreecommitdiffstats
path: root/src/xprivate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xprivate.cpp')
-rw-r--r--src/xprivate.cpp222
1 files changed, 179 insertions, 43 deletions
diff --git a/src/xprivate.cpp b/src/xprivate.cpp
index 7667b9e..4be7098 100644
--- a/src/xprivate.cpp
+++ b/src/xprivate.cpp
@@ -37,6 +37,21 @@ static bool xRectLessThan(const OutputInfo* const &a, const OutputInfo* const &b
return a->crtc->x < b->crtc->x;
}
+static int modeEqual(const XRRModeInfo *a, const XRRModeInfo *b)
+{
+ return (a->width == b->width &&
+ a->height == b->height &&
+ a->dotClock / 10 == b->dotClock / 10 &&
+ a->hSyncStart == b->hSyncStart &&
+ a->hSyncEnd == b->hSyncEnd &&
+ a->hTotal == b->hTotal &&
+ a->hSkew == b->hSkew &&
+ a->vSyncStart == b->vSyncStart &&
+ a->vSyncEnd == b->vSyncEnd &&
+ a->vTotal == b->vTotal &&
+ a->modeFlags == b->modeFlags);
+}
+
/*
* Class members
*/
@@ -224,51 +239,172 @@ void XPrivate::updateScreenResources()
qDebug() << "Loaded.";
}
+void XPrivate::addMissingEdidResolutions()
+{
+ XRRScreenResources *resptr = XRRGetScreenResourcesCurrent(_display, DefaultRootWindow(_display));
+ for (int i = 0; i < resptr->noutput; ++i) {
+ unsigned char prop[512];
+ unsigned long edidLen = 512;
+ if (!getEdid(resptr->outputs[i], prop, &edidLen))
+ continue;
+ if (edidLen < 256)
+ continue;
+ for (unsigned int j = 128; j < edidLen - 127; j += 128) {
+ addMissingModesFromEdid(resptr, resptr->outputs[i], prop + j);
+ }
+ }
+ XRRFreeScreenResources(resptr);
+}
+
+bool XPrivate::getEdid(RROutput outputId, unsigned char *buffer, unsigned long *size)
+{
+ int numProps = 0;
+ bool found = false;
+ Atom* properties = XRRListOutputProperties(_display, outputId, &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 = nullptr;
+ int actual_format;
+ Atom actual_type;
+ bool valid;
+
+ XRRGetOutputProperty(_display, outputId, _EDID_ATOM,
+ 0, long(size), False, False,
+ AnyPropertyType,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop);
+ valid = (actual_format == 8 && nitems >= 128 && prop != nullptr);
+ if (valid) {
+ memcpy(buffer, prop, qMin(*size, nitems));
+ *size = qMin(nitems, *size);
+ } else {
+ *size = 0;
+ }
+ if (prop != nullptr) {
+ XFree(prop);
+ }
+ return valid;
+}
+
bool XPrivate::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;
+ unsigned char prop[512];
+ unsigned long edidLen = 512;
+
+ if (!getEdid(output->id, prop, &edidLen))
+ return false;
+
+ 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;
+ }
+ }
+ return true;
+}
+
+void XPrivate::addMissingModesFromEdid(XRRScreenResources *res, RROutput outputId, unsigned char *data)
+{
+ if (data[0] != 2) // Not type 2, skip
+ return;
+ if (data[2] == 0) // Empty block
+ return;
+ int dtdOffset = data[2];
+ if (dtdOffset < 4) // No DTD blocks
+ return;
+ if (dtdOffset > 128) {
+ dtdOffset = 128;
+ }
+
+ int hactive, vactive, pixclk, hsyncoff, hsyncwidth, hblank, vsyncoff, vsyncwidth, vblank;
+ for (int i = dtdOffset; i < 128 - 17; i += 18) {
+ if (data[i] == 0 && data[i + 1] == 0)
+ continue;
+ hactive = data[i+2] + ((data[i+4] & 0xf0) << 4);
+ hblank = data[i+3] + ((data[i+4] & 0x0f) << 8);
+ vactive = data[i+5] + ((data[i+7] & 0xf0) << 4);
+ vblank = data[i+6] + ((data[i+7] & 0x0f) << 8);
+ pixclk = (data[i+1] << 8) | (data[i]); // 10kHz
+ hsyncoff = data[i+8] | ((data[i+11] & 0xC0) << 2);
+ hsyncwidth = data[i+9] | ((data[i+11] & 0x30) << 4);
+ vsyncoff = ((data[i+10] & 0xf0) >> 4) | ((data[i+11] & 0x0C) << 2);
+ vsyncwidth = (data[i+10] & 0x0f) | ((data[i+11] & 0x03) << 4);
+ char buf[100];
+ XRRModeInfo m;
+ memset(&m, 0, sizeof(m));
+ m.width = static_cast<unsigned int>(hactive);
+ m.height = static_cast<unsigned int>(vactive);
+ m.dotClock = static_cast<unsigned long>(pixclk) * 10ul * 1000ul;
+ m.hSyncStart= static_cast<unsigned int>(hactive + hsyncoff);
+ m.hSyncEnd = static_cast<unsigned int>(hactive + hsyncoff + hsyncwidth);
+ m.hTotal = static_cast<unsigned int>(hactive + hblank);
+ m.hSkew = 0;
+ m.vSyncStart= static_cast<unsigned int>(vactive + vsyncoff);
+ m.vSyncEnd = static_cast<unsigned int>(vactive + vsyncoff + vsyncwidth);
+ m.vTotal = static_cast<unsigned int>(vactive + vblank);
+ m.id = 0;
+ m.name = buf;
+ m.nameLength = static_cast<unsigned int>(snprintf(buf, sizeof(buf), "%dx%d_%d", hactive, vactive, static_cast<int>(m.dotClock / (m.hTotal * m.vTotal))));
+ if (m.nameLength > sizeof(buf)) {
+ m.nameLength = sizeof(buf);
+ }
+ if ((data[i+17] & 0x18) == 0x18) {
+ // Digital Separate
+ if (data[i+17] & 0x04) {
+ m.modeFlags |= RR_VSyncPositive;
+ } else {
+ m.modeFlags |= RR_VSyncNegative;
+ }
+ if (data[i+17] & 0x02) {
+ m.modeFlags |= RR_HSyncPositive;
+ } else {
+ m.modeFlags |= RR_HSyncNegative;
+ }
+ } else if ((data[i+17] & 0x18) == 0x10) {
+ // Digital Composite
+ if (data[i+17] & 0x02) {
+ m.modeFlags |= RR_HSyncPositive;
+ } else {
+ m.modeFlags |= RR_HSyncNegative;
+ }
+ m.modeFlags |= RR_VSyncNegative; // Default? Clarify...
+ } else {
+ m.modeFlags |= RR_VSyncNegative | RR_HSyncNegative; // ...
+ }
+ if (data[i+17] & 0x80) {
+ m.modeFlags |= RR_Interlace;
+ }
+ // See if we should add this mode
+ RRMode modeId = 0;
+ for (int mode = 0; mode < res->nmode; ++mode) {
+ if (modeEqual(&res->modes[mode], &m)) {
+ modeId = res->modes[mode].id;
+ break;
+ }
+ }
+ if (modeId == 0) {
+ modeId = XRRCreateMode(_display, DefaultRootWindow(_display), &m);
+ }
+ if (modeId != 0) {
+ XRRAddOutputMode(_display, outputId, modeId);
+ }
+ }
}
void XPrivate::setScreenSize(const QSize &size)