From f43d344aa39e0872449840690ea2981f46bc67cb Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 6 Aug 2019 09:16:01 +0300 Subject: [PATCH] gdk: x11: Fill GdkMonitor manufacturer with PNP id from EDID Previously, the manufacturer property of the GdkMonitor was NULL, and having at least PNP id at GdkMonitor.manufacturer makes it possible to distinguish between different monitors programmatically. --- gdk/gdkmonitor.c | 7 +++++- gdk/x11/gdkscreen-x11.c | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/gdk/gdkmonitor.c b/gdk/gdkmonitor.c index 2d27c29972..37e2c872eb 100644 --- a/gdk/gdkmonitor.c +++ b/gdk/gdkmonitor.c @@ -401,7 +401,12 @@ gdk_monitor_get_connector (GdkMonitor *monitor) * gdk_monitor_get_manufacturer: * @monitor: a #GdkMonitor * - * Gets the name of the monitor's manufacturer, if available. + * Gets the name or PNP ID of the monitor's manufacturer, if available. + * + * Note that this value might also vary depending on actual + * display backend. + * + * PNP ID registry is located at https://uefi.org/pnp_id_list * * Returns: (transfer none) (nullable): the name of the manufacturer, or %NULL */ diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c index cda654f04e..ffba0708f7 100644 --- a/gdk/x11/gdkscreen-x11.c +++ b/gdk/x11/gdkscreen-x11.c @@ -354,6 +354,7 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed) GdkRectangle geometry; GdkRectangle newgeo; char *name; + char *manufacturer = NULL; int refresh_rate = 0; gdk_x11_display_error_trap_push (display); @@ -405,6 +406,50 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed) g_ptr_array_add (x11_display->monitors, monitor); } + /* Fetch minimal manufacturer information (PNP ID) from EDID */ + { + #define EDID_LENGTH 128 + Atom actual_type, edid_atom; + char tmp[3]; + int actual_format; + unsigned char *prop; + unsigned long nbytes, bytes_left; + Display *disp = GDK_DISPLAY_XDISPLAY (x11_display); + + edid_atom = XInternAtom (disp, RR_PROPERTY_RANDR_EDID, FALSE); + + XRRGetOutputProperty (disp, output, + edid_atom, + 0, + EDID_LENGTH, + FALSE, + FALSE, + AnyPropertyType, + &actual_type, + &actual_format, + &nbytes, + &bytes_left, + &prop); + + // Check partial EDID header (whole header: 00 ff ff ff ff ff ff 00) + if (nbytes >= EDID_LENGTH && prop[0] == 0x00 && prop[1] == 0xff) + { + /* decode the Vendor ID from three 5 bit words packed into 2 bytes + * /--08--\/--09--\ + * 7654321076543210 + * |\---/\---/\---/ + * R C1 C2 C3 */ + tmp[0] = 'A' + ((prop[8] & 0x7c) / 4) - 1; + tmp[1] = 'A' + ((prop[8] & 0x3) * 8) + ((prop[9] & 0xe0) / 32) - 1; + tmp[2] = 'A' + (prop[9] & 0x1f) - 1; + + manufacturer = g_strndup (tmp, sizeof (tmp)); + } + + XFree(prop); + #undef EDID_LENGTH + } + gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry); name = g_strndup (output_info->name, output_info->nameLen); @@ -433,6 +478,8 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed) gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->surface_scale); gdk_monitor_set_model (GDK_MONITOR (monitor), name); gdk_monitor_set_connector (GDK_MONITOR (monitor), name); + gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), manufacturer); + g_free (manufacturer); g_free (name); if (rr_monitors[i].primary)