Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
PhosphorIdentity::ScreenId Namespace Reference

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.
 

Detailed Description

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.

Function Documentation

◆ buildBaseId()

QString PhosphorIdentity::ScreenId::buildBaseId ( const QString &  manufacturer,
const QString &  model,
const QString &  serial 
)
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).

◆ buildScreenBaseId()

QString PhosphorIdentity::ScreenId::buildScreenBaseId ( const QString &  manufacturer,
const QString &  model,
const QString &  serialNumber,
const QString &  connectorName 
)
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.

◆ invalidateEdidCache()

void PhosphorIdentity::ScreenId::invalidateEdidCache ( const QString &  connectorName = QString())
inline

Drop cached EDID serial data.

Call on hotplug; pass an empty string to drop everything.

◆ normalizeHexSerial()

QString PhosphorIdentity::ScreenId::normalizeHexSerial ( const QString &  serial)
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.

◆ readEdidHeaderSerial()

QString PhosphorIdentity::ScreenId::readEdidHeaderSerial ( const QString &  connectorName)
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.