/* Copyright (C) 2014 P.L. Lucas Copyright (C) 2014 Hong Jen Yee (PCMan) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "xrandr.h" #include #include #include #include #include #include static QByteArray indentString(QByteArray line) { QByteArray s; int length = line.size(); char ch; for(int indent=0; indent < length; indent++ ) { ch = line[indent]; if( ch == ' ' || ch == '\t' ) s.append(ch); else break; } return s; } static int indentLevel(QByteArray line) { int indent = 0; while(indent < line.size() && ( line[indent] == ' ' || line[indent] == '\t' ) ) ++indent; return indent; } // new parsing code using xrandr --verbose QList XRandRBackend::getMonitorsInfo() { QList monitors; // execute xrandr command and read its output QProcess process; // set locale to "C" guarantee English output of xrandr process.processEnvironment().insert("LC_ALL", "c"); process.start("xrandr --verbose"); //process.start("cat pruebas.txt"); process.waitForFinished(-1); if(process.exitCode() != 0) return monitors; QList lines = process.readAllStandardOutput().split('\n'); // start parsing the output QRegExp regMonitorLine("([\\w-]+) +connected +(primary)? *(\\d+x\\d+\\+(\\d+)\\+(\\d+))?.*"); QRegExp regModeLine("\\s+(\\d+x\\d+).*"); QRegExp regRateLine("\\s+([vh]):.* clock\\s+([\\d.]+).?Hz.*"); QRegExp regKeyValue("\\s*(\\w[\\w ]*)\\s*:\\s*(\\S.*)?"); bool hasError = false; MonitorInfo* monitor = NULL; QList::iterator it = lines.begin(); bool readingModes = false; // currently, we only support one X screen, that is screen 0 while(it != lines.end() && !hasError) { QByteArray& line = *it; if(!monitor) { if(regMonitorLine.exactMatch(line)) { // format: VGA-0 connected 1280x1024+1024+0 (0x55) normal... monitor = new MonitorInfo(); monitor->name = regMonitorLine.cap(1); if(regMonitorLine.cap(2) == "primary") { // is primary monitor monitor->primaryOk = true; } if(!regMonitorLine.cap(3).isEmpty()) // mode+xpos+ypos monitor->enabledOk = true; monitor->xPos = regMonitorLine.cap(4).toInt(); monitor->yPos = regMonitorLine.cap(5).toInt(); } } else { // reading properties of this monitor if(regModeLine.exactMatch(line)) { // this is a mode line // sample: 1280x1024 (0x55) 108.000MHz +HSync +VSync *current +preferred readingModes = true; QString mode = regModeLine.cap(1); QString rate; bool isCurrent = line.contains("current"); bool isPreferred = line.contains("preferred"); ++it; while(it != lines.end()) { line = *it; if(regRateLine.exactMatch(line)) { // sample: // h: width 1280 start 1328 end 1440 total 1688 skew 0 clock 63.98KHz // v: height 1024 start 1025 end 1028 total 1066 clock 60.02Hz if(regRateLine.cap(1) == QLatin1String("v")) rate = regRateLine.cap(2); ++it; } else { --it; break; // rate lines ended for this mode } } if(!mode.isEmpty() && !rate.isEmpty()) { if(!monitor->modes.contains(mode)) monitor->modes.append(mode); if(!monitor->modeLines.contains(mode)) monitor->modeLines[mode] = QStringList(); monitor->modeLines[mode].append(rate); if(isPreferred) { monitor->preferredMode = mode; monitor->preferredRate = rate; } if(isCurrent) { monitor->currentMode = mode; monitor->currentRate = rate; } } } else { // this is not a mode line, read other properties if(readingModes) { // mode lines ended, so the whole monitor info is read monitors.append(monitor); monitor = NULL; readingModes = false; continue; } if(regKeyValue.exactMatch(line)) { // format: : QString key = regKeyValue.cap(1); QString value = regKeyValue.cap(2); QByteArray lineStringStart = indentString(line); int propertyIndentLevel = indentLevel(line); ++it; while( it != lines.end() ) { QByteArray& line = *it; int actualIndentLevel = indentLevel(line); if( actualIndentLevel>propertyIndentLevel && line.startsWith(lineStringStart) ) { value += "\n" + line.trimmed(); ++it; } else break; } qDebug() << key << "=" << value; if(key == "Gamma") { monitor->gamma = value; } else if(key == "Brightness") { monitor->brightness = value; } else if(key == "EDID") { monitor->edid = value ; // Get vendor QString hex = value.replace("\n","").replace(" ","").toLower(); int vendorPosStart = hex.indexOf("fc00"); if(vendorPosStart>0) { int vendorPosEnd = hex.indexOf("00", vendorPosStart+4); QString vendorHex = hex.mid(vendorPosStart+4, vendorPosEnd-vendorPosStart-4); QByteArray vendor; //vendor = QByteArray::fromHex(vendorHex.toLocal8Bit()).trimmed(); //qDebug() << "VendorHex:" << vendorHex << "Vendor" << vendor ; // QByteArray::fromHex sometimes fails. This a trick vendor=""; for(int i=1; ivendor = vendor; } } else if(key == "Backlight") { QRegExp rx("(\\d+)"); QStringList list; int pos = 0; while ((pos = rx.indexIn(value, pos)) != -1) { list << rx.cap(1); pos += rx.matchedLength(); } if(list.length()==3) { monitor->backlight=list[0]; monitor->backlightMin=list[1]; monitor->backlightMax=list[2]; } } continue; } // End format: : else { // this line is not key:value } } } if( it != lines.end() ) ++it; } if(monitor) // this should not happen unless a parsing error happens delete monitor; return monitors; } bool XRandRBackend::setMonitorsSettings(const QList monitors) { QString cmd = getCommand(monitors); qDebug() << cmd; // return true; QProcess process; process.start(cmd); process.waitForFinished(); return process.exitCode() == 0; } QString XRandRBackend::getCommand(const QList monitors) { QByteArray cmd = "xrandr"; foreach(MonitorSettings * monitor, monitors) { cmd += " --output "; cmd.append(monitor->name); cmd.append(' '); // if the monitor is turned on if(monitor->enabledOk) { QString sel_res = monitor->currentMode; QString sel_rate = monitor->currentRate; if(sel_res == QObject::tr("Auto")) // auto resolution cmd.append("--auto"); else { cmd.append("--mode "); cmd.append(sel_res); if(sel_rate != QObject::tr("Auto")) { // not auto refresh rate cmd.append(" --rate "); cmd.append(sel_rate); } } if(monitor->position == MonitorSettings::Manual) { // Manual position cmd.append(QString(" --pos %1x%2").arg(monitor->xPos).arg(monitor->yPos)); } else // Unify output cmd.append(QString(" --pos 0x0")); if(monitor->primaryOk) cmd.append(" --primary"); cmd.append(" --brightness "); cmd.append(monitor->brightness); cmd.append(" --gamma "); cmd.append(monitor->gamma); if( !monitor->backlight.isEmpty() ) { cmd.append(" --set Backlight "); cmd.append(monitor->backlight); } } else // turn off cmd.append("--off"); } qDebug() << "cmd:" << cmd; return cmd; }