Compositor-agnostic EDID parsing and screen-ID construction. More...
Namespaces | |
| namespace | detail |
Functions | |
| QString | readEdidHeaderSerial (const QString &connectorName) |
| Read the EDID header serial from sysfs for a DRM connector. | |
| void | invalidateEdidCache (const QString &connectorName=QString()) |
| Drop cached EDID serial data. | |
| QString | normalizeHexSerial (const QString &serial) |
| Coerce a possibly-hex serial ("0x0001C1A3") to decimal ("115107"). | |
| QString | buildBaseId (const QString &manufacturer, const QString &model, const QString &serial) |
| Assemble a base identifier from EDID-style fields. | |
| 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. | |
Compositor-agnostic EDID parsing and screen-ID construction.
Owns the canonical "manufacturer:model:serial" wire format used by every Phosphor consumer that refers to a physical screen across processes. Daemon (via QScreen properties) and compositor plugins (via wlr_output / KWin::Output) feed in their own raw fields and get back byte-identical IDs.
EDID header format (VESA E-EDID 1.3+, sysfs blob /sys/class/drm/.../edid): Bytes 0-7 : magic header (00 FF FF FF FF FF FF 00) Bytes 8-9 : manufacturer ID Bytes 10-11 : product code Bytes 12-15 : serial number (little-endian uint32)
Threading: the sysfs cache is accessed without synchronisation; every function MUST be called from the GUI / main thread.
|
inline |
Assemble a base identifier from EDID-style fields.
"manuf:model:serial" when serial is available, "manuf:model" when only those are present, empty when no field is set (caller should fall back to the connector name).
|
inline |
Build a base ID from raw EDID fields, sysfs serial authoritative.
The per-connector sysfs EDID header serial is read FIRST and only falls back to QScreen::serialNumber() (via normalizeHexSerial) when sysfs yields nothing. Both decode the same EDID header field (bytes 12-15), so a correctly-paired monitor produces a byte-identical id either way — but the sysfs read is keyed by the real DRM connector and therefore cannot be mis-paired, whereas QScreen::serialNumber() can: KWin's Wayland QPA hands two IDENTICAL-model panels (same manuf+model, distinct serials) each other's serial, stamping the wrong serial onto each logical output. That swap flips left/right for every cross-output neighbour decision (a window "moved left" lands on the right monitor, the OSD arrow points the wrong way, the source monitor's reflow targets the wrong screen). Anchoring identity on the connector-keyed sysfs value aligns us with the kernel/KWin geometry pairing.
Returns the connector name as a final fallback so the result is always a non-empty stable string.
|
inline |
Drop cached EDID serial data.
Call on hotplug; pass an empty string to drop everything.
|
inline |
Coerce a possibly-hex serial ("0x0001C1A3") to decimal ("115107").
KWin on Wayland exposes the EDID header serial as hex via QScreen::serialNumber(). Both daemon and compositor must produce byte-identical IDs, so we normalise to decimal.
|
inline |
Read the EDID header serial from sysfs for a DRM connector.
Scans /sys/class/drm/card*-<connectorName>/edid, validates the EDID magic header, and extracts the serial number from bytes 12-15 (little-endian uint32, decimal-formatted).
Cached after the first successful read. After 3 consecutive misses the empty result is cached permanently to avoid unbounded sysfs I/O for virtual displays / embedded panels. Use invalidateEdidCache on hotplug.