15#include <QCoreApplication>
21#include <QLatin1String>
54 static QHash<QString, QString> s_cache;
60 static QHash<QString, int> s_counter;
70 Q_ASSERT(!QCoreApplication::instance() || QThread::currentThread() == QCoreApplication::instance()->thread());
91 auto cacheIt = cache.constFind(connectorName);
92 if (cacheIt != cache.constEnd()) {
98 QDir drmDir(QStringLiteral(
"/sys/class/drm"));
99 if (drmDir.exists()) {
100 const QStringList entries = drmDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
101 for (
const QString& entry : entries) {
102 int dashPos = entry.indexOf(QLatin1Char(
'-'));
106 if (entry.mid(dashPos + 1) != connectorName) {
109 QFile edidFile(drmDir.filePath(entry) + QStringLiteral(
"/edid"));
110 if (!edidFile.open(QIODevice::ReadOnly)) {
113 QByteArray header = edidFile.read(16);
114 if (header.size() < 16) {
117 const auto* data =
reinterpret_cast<const uint8_t*
>(header.constData());
118 if (data[0] != 0x00 || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || data[4] != 0xFF
119 || data[5] != 0xFF || data[6] != 0xFF || data[7] != 0x00) {
122 uint32_t serial = data[12] | (
static_cast<uint32_t
>(data[13]) << 8)
123 | (
static_cast<uint32_t
>(data[14]) << 16) | (
static_cast<uint32_t
>(data[15]) << 24);
125 result = QString::number(serial);
131 if (!result.isEmpty()) {
132 cache.insert(connectorName, result);
135 constexpr int maxRetries = 3;
138 if (misses >= maxRetries) {
139 cache.insert(connectorName, result);
152 if (connectorName.isEmpty()) {
170 if (!serial.isEmpty() && serial.startsWith(QLatin1String(
"0x"), Qt::CaseInsensitive)) {
172 uint32_t numericSerial = serial.toUInt(&ok, 16);
173 if (ok && numericSerial != 0) {
174 return QString::number(numericSerial);
187inline QString
buildBaseId(
const QString& manufacturer,
const QString& model,
const QString& serial)
189 if (!serial.isEmpty()) {
190 return manufacturer + QLatin1Char(
':') + model + QLatin1Char(
':') + serial;
192 if (!manufacturer.isEmpty() || !model.isEmpty()) {
193 return manufacturer + QLatin1Char(
':') + model;
217inline QString
buildScreenBaseId(
const QString& manufacturer,
const QString& model,
const QString& serialNumber,
218 const QString& connectorName)
221 if (serial.isEmpty()) {
224 QString baseId =
buildBaseId(manufacturer, model, serial);
225 return baseId.isEmpty() ? connectorName : baseId;
QHash< QString, QString > & edidSerialCache()
Definition ScreenId.h:52
void assertMainThread()
Debug-build enforcement of the documented single-thread contract: the function-local-static caches ar...
Definition ScreenId.h:68
QHash< QString, int > & edidMissCounter()
Definition ScreenId.h:58
QString readEdidHeaderSerial(const QString &connectorName)
Read the EDID header serial from sysfs for a DRM connector.
Definition ScreenId.h:87
QString normalizeHexSerial(const QString &serial)
Coerce a possibly-hex serial ("0x0001C1A3") to decimal ("115107").
Definition ScreenId.h:168
QString buildScreenBaseId(const QString &manufacturer, const QString &model, const QString &serialNumber, const QString &connectorName)
Build a base ID from raw EDID fields, sysfs serial authoritative.
Definition ScreenId.h:217
void invalidateEdidCache(const QString &connectorName=QString())
Drop cached EDID serial data.
Definition ScreenId.h:149
QString buildBaseId(const QString &manufacturer, const QString &model, const QString &serial)
Assemble a base identifier from EDID-style fields.
Definition ScreenId.h:187