File indexing completed on 2024-04-28 11:50:49
0001 /*************************************************************************** 0002 * Copyright (C) 2012-2016 by Daniel Nicoletti <dantti12@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; see the file COPYING. If not, write to * 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0017 * Boston, MA 02110-1301, USA. * 0018 ***************************************************************************/ 0019 0020 #include "Output.h" 0021 0022 #include <QGuiApplication> 0023 #include <QLoggingCategory> 0024 0025 #define RR_CONNECTOR_TYPE_PANEL "Panel" 0026 0027 Q_DECLARE_LOGGING_CATEGORY(COLORD) 0028 0029 Output::Output(RROutput output, XRRScreenResources *resources) 0030 : m_output(output) 0031 , m_resources(resources) 0032 { 0033 XRROutputInfo *info; 0034 info = XRRGetOutputInfo(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), m_resources, m_output); 0035 if (!info) { 0036 return; 0037 } 0038 0039 // store if RROutput is connected and active 0040 m_active = info->connection == RR_Connected && info->crtc != None; 0041 0042 // store output name 0043 m_name = info->name; 0044 0045 // store the crtc 0046 m_crtc = info->crtc; 0047 0048 XRRFreeOutputInfo(info); 0049 0050 // The ConnectorType property is present in RANDR 1.3 and greater 0051 if (connectorType() == QLatin1String(RR_CONNECTOR_TYPE_PANEL)) { 0052 m_isLaptop = true; 0053 } else if (m_name.contains(QLatin1String("lvds"), Qt::CaseInsensitive) || 0054 // Most drivers use an "LVDS" prefix... 0055 m_name.contains(QLatin1String("LCD"), Qt::CaseInsensitive) || 0056 // ... but fglrx uses "LCD" in some versions. Shoot me now, kthxbye. 0057 m_name.contains(QLatin1String("eDP"), Qt::CaseInsensitive) 0058 /* eDP is for internal laptop panel connections */) { 0059 // Older versions of RANDR - this is a best guess, 0060 // as @#$% RANDR doesn't have standard output names, 0061 // so drivers can use whatever they like. 0062 m_isLaptop = true; 0063 } 0064 } 0065 0066 Output::~Output() 0067 { 0068 delete m_interface; 0069 } 0070 0071 bool Output::isActive() const 0072 { 0073 return m_active; 0074 } 0075 0076 bool Output::isLaptop() const 0077 { 0078 return m_isLaptop; 0079 } 0080 0081 bool Output::isPrimary(bool hasXRandR13, Window root) const 0082 { 0083 if (hasXRandR13) { 0084 RROutput primary = XRRGetOutputPrimary(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), root); 0085 return primary == m_output; 0086 } 0087 return false; 0088 } 0089 0090 QString Output::name() const 0091 { 0092 return m_name; 0093 } 0094 0095 QString Output::id() const 0096 { 0097 return m_id; 0098 } 0099 0100 void Output::setPath(const QDBusObjectPath &path) 0101 { 0102 if (m_interface && m_interface->path() == path.path()) { 0103 return; 0104 } 0105 m_path = path; 0106 0107 delete m_interface; 0108 m_interface = new CdDeviceInterface(QStringLiteral("org.freedesktop.ColorManager"), path.path(), QDBusConnection::systemBus()); 0109 if (!m_interface->isValid()) { 0110 qCWarning(COLORD) << "Invalid interface" << path.path() << m_interface->lastError().message(); 0111 delete m_interface; 0112 m_interface = nullptr; 0113 } 0114 } 0115 0116 QDBusObjectPath Output::path() const 0117 { 0118 return m_path; 0119 } 0120 0121 CdDeviceInterface *Output::interface() 0122 { 0123 return m_interface; 0124 } 0125 0126 RRCrtc Output::crtc() const 0127 { 0128 return m_crtc; 0129 } 0130 0131 RROutput Output::output() const 0132 { 0133 return m_output; 0134 } 0135 0136 int Output::getGammaSize() const 0137 { 0138 // The gama size of this output 0139 return XRRGetCrtcGammaSize(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), m_crtc); 0140 } 0141 0142 void Output::setGamma(XRRCrtcGamma *gamma) 0143 { 0144 XRRSetCrtcGamma(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), m_crtc, gamma); 0145 } 0146 0147 Edid Output::readEdidData() 0148 { 0149 // get the EDID 0150 size_t size; 0151 const quint8 *data; 0152 data = readEdidData(size); 0153 if (data == nullptr) { 0154 qCWarning(COLORD) << "Unable to get EDID for output" << name(); 0155 Edid ret; 0156 m_id = ret.deviceId(name()); 0157 return ret; 0158 } 0159 0160 // With EDID data we can parse our info 0161 Edid edid(data, size); 0162 m_edidHash = edid.hash(); 0163 m_id = edid.deviceId(name()); 0164 delete[] data; 0165 0166 return edid; 0167 } 0168 0169 QString Output::edidHash() const 0170 { 0171 return m_edidHash; 0172 } 0173 0174 QString Output::connectorType() const 0175 { 0176 unsigned char *prop; 0177 int actual_format; 0178 unsigned long nitems, bytes_after; 0179 Atom actual_type; 0180 Atom connector_type; 0181 Atom connector_type_atom = XInternAtom(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), "ConnectorType", false); 0182 char *connector_type_str; 0183 QString result; 0184 0185 XRRGetOutputProperty(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), 0186 m_output, 0187 connector_type_atom, 0188 0, 0189 100, 0190 false, 0191 false, 0192 AnyPropertyType, 0193 &actual_type, 0194 &actual_format, 0195 &nitems, 0196 &bytes_after, 0197 &prop); 0198 if (!(actual_type == XA_ATOM && actual_format == 32 && nitems == 1)) { 0199 XFree(prop); 0200 return result; 0201 } 0202 0203 connector_type = *((Atom *)prop); 0204 0205 connector_type_str = XGetAtomName(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), connector_type); 0206 if (connector_type_str) { 0207 result = connector_type_str; 0208 XFree(connector_type_str); 0209 } 0210 0211 XFree(prop); 0212 0213 return result; 0214 } 0215 0216 /* This is what gnome-desktop does */ 0217 static quint8 *getProperty(Display *dpy, RROutput output, Atom atom, size_t &len) 0218 { 0219 unsigned char *prop; 0220 int actual_format; 0221 unsigned long nitems, bytes_after; 0222 Atom actual_type; 0223 quint8 *result; 0224 0225 XRRGetOutputProperty(dpy, output, atom, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); 0226 if (actual_type == XA_INTEGER && actual_format == 8) { 0227 result = new quint8[nitems]; 0228 memcpy(result, prop, nitems); 0229 len = nitems; 0230 } else { 0231 result = nullptr; 0232 } 0233 0234 XFree(prop); 0235 return result; 0236 } 0237 0238 quint8 *Output::readEdidData(size_t &len) 0239 { 0240 Atom edid_atom; 0241 quint8 *result; 0242 0243 edid_atom = XInternAtom(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), RR_PROPERTY_RANDR_EDID, false); 0244 result = getProperty(qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display(), m_output, edid_atom, len); 0245 0246 if (result) { 0247 if (len % 128 == 0) { 0248 return result; 0249 } else { 0250 len = 0; 0251 delete[] result; 0252 } 0253 } 0254 0255 return nullptr; 0256 } 0257 0258 bool Output::operator==(const Output &output) const 0259 { 0260 return m_output == output.output(); 0261 } 0262 0263 #include "moc_Output.cpp"