There are two common ways I observe how games get monitor name to display: 1. Registry key under Enum/Display (also present in EnumDisplayDevicesA result for monitors). On Windows this key is derived from edid as 'Manufacturer ID' (3 letters) combined with "Manufacturer product code" (4 hex digits). We currently have 'Default_Display' there for all the displays; 2. DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME). Windows sets friendlyNameFromEdid flag and returns a name from 'EDID Display Descriptor' with code 0xfc ("Display name"). As far as I could see by searching through the Windows registry this name doesn't seem to be explicitly present anywhere in registry (besides binary raw edid of course).
The first patch removes name from the gdi driver's display structure. Now none of the drivers set anything genuine there. x11 and winemac always end up with "Generic Non-Pnp Monitor" string, wineandroid sets NULL there and "Generic Non-Pnp Monitor" is set in win32u in this case. That "Generic Non-Pnp Monitor" goes to "DeviceDesc" registry value. While our value doesn't match Windows string exactly, Windows also doesn't have any meaningful name under DeviceDesc (and contains "Generic Non-Pnp Monitor" as a part of it). So this patch is essentially a no-op currently. Going forward my idea is that we just want to have edid from drivers. If the raw one is not available we can generate fallback one ourselves based on the info about the monitor we might have from elsewhere in the drivers. My motivation is: - EDID is sometimes queried by apps directly, and it is better to provide a true one or a synthetic one with as much of accurate info as possible / reasonable; - There is more info in EDID, e. g., colorimetry for HDR support in d3d. As far as I can tell, there is no documented way to query HDR info on Windows besides dxgi interfaces (which in case on Wine are based on gdi drivers for such things and can hardly become a genine source of such info in Wine) and WinRT interface (for which I don't know where it takes the info on Windows but we probably don't want to make it a lower level source of such info in Wine).
The alternative would be, instead of basing higher level win32u on EDID, parse EDID in drivers instead and add all the necessary info into gdi_monitor structure (instead of removing display name from there), but so far it seems less straightforward to me.
-- v3: win32u: Get friendly monitor name from EDID in NtUserDisplayConfigGetDeviceInfo(). win32u: Return edidManufactureId and edidProductCodeId from NtUserDisplayConfigGetDeviceInfo(). win32u: Store EDID info in monitors cache. win32u: Use monitor ID from EDID when available. win32u: Remove monitor name from gdi driver monitor info.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 8 +++----- dlls/winemac.drv/cocoa_display.m | 1 - dlls/winemac.drv/display.c | 3 --- dlls/winemac.drv/macdrv_cocoa.h | 2 -- dlls/winex11.drv/desktop.c | 4 ---- dlls/winex11.drv/display.c | 3 --- dlls/winex11.drv/xinerama.c | 4 ---- dlls/winex11.drv/xrandr.c | 7 ------- include/wine/gdi_driver.h | 1 - 9 files changed, 3 insertions(+), 30 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 2269193b7ff..aab148bbfe3 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1311,12 +1311,11 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) static const WCHAR default_monitorW[] = {'M','O','N','I','T','O','R','\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
- TRACE( "%s %s %s\n", debugstr_w(monitor->name), wine_dbgstr_rect(&monitor->rc_monitor), - wine_dbgstr_rect(&monitor->rc_work) ); - monitor_index = ctx->monitor_count++; output_index = ctx->output_count++;
+ TRACE( "%u %s %s\n", monitor_index, wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) ); + sprintf( buffer, "MonitorID%u", monitor_index ); sprintf( instance, "DISPLAY\Default_Monitor\%04X&%04X", ctx->video_count - 1, monitor_index ); set_reg_ascii_value( ctx->adapter_key, buffer, instance ); @@ -1327,8 +1326,7 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param )
link_device( bufferW, guid_devinterface_monitorW );
- lstrcpyW( bufferW, monitor->name ); - if (!bufferW[0]) asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" ); + asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" ); set_reg_value( hkey, device_descW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) );
set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) ); diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m index 04f6dda4481..b5096a39ca4 100644 --- a/dlls/winemac.drv/cocoa_display.m +++ b/dlls/winemac.drv/cocoa_display.m @@ -675,7 +675,6 @@ int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitor if (j == 0) primary_index = monitor_count;
- strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor"); monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE; monitors[monitor_count].rc_monitor = displays[j].frame; monitors[monitor_count].rc_work = displays[j].work_frame; diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index dab81cc8ffb..19ff72a7130 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -1192,9 +1192,6 @@ BOOL macdrv_UpdateDisplayDevices( const struct gdi_device_manager *device_manage .rc_work = rect_from_cgrect(monitor->rc_work), .state_flags = monitor->state_flags, }; - RtlUTF8ToUnicodeN(gdi_monitor.name, sizeof(gdi_monitor.name), &len, - monitor->name, strlen(monitor->name)); - TRACE("monitor: %s\n", debugstr_a(monitor->name)); device_manager->add_monitor( &gdi_monitor, param ); }
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6196032c08d..a82dd319330 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -291,8 +291,6 @@ struct macdrv_adapter /* Represent a monitor in EnumDisplayDevices context */ struct macdrv_monitor { - /* Name, in UTF-8 encoding */ - char name[128]; /* as RcMonitor in MONITORINFO struct after conversion by rect_from_cgrect */ CGRect rc_monitor; /* as RcWork in MONITORINFO struct after conversion by rect_from_cgrect */ diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index bb998543ae7..a0367d6ce50 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -287,15 +287,11 @@ static void X11DRV_desktop_free_adapters( struct gdi_adapter *adapters )
static BOOL X11DRV_desktop_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *monitor;
monitor = calloc( 1, sizeof(*monitor) ); if (!monitor) return FALSE;
- lstrcpyW( monitor->name, generic_nonpnp_monitorW ); SetRect( &monitor->rc_monitor, 0, 0, desktop_width, desktop_height ); SetRect( &monitor->rc_work, 0, 0, desktop_width, desktop_height ); query_desktop_work_area( &monitor->rc_work ); diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 34085c49543..78de6a6f88b 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -589,10 +589,7 @@ BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manage
/* Initialize monitors */ for (monitor = 0; monitor < monitor_count; monitor++) - { - TRACE("monitor: %#x %s\n", monitor, wine_dbgstr_w(monitors[monitor].name)); device_manager->add_monitor( &monitors[monitor], param ); - }
handler->free_monitors(monitors, monitor_count);
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c index 6835aa4a331..2691f9e9c5e 100644 --- a/dlls/winex11.drv/xinerama.c +++ b/dlls/winex11.drv/xinerama.c @@ -287,9 +287,6 @@ static void xinerama_free_adapters( struct gdi_adapter *adapters )
static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *monitor; INT first = (INT)adapter_id; INT monitor_count = 0; @@ -319,7 +316,6 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor ) && !IsRectEmpty( &monitors[first].rcMonitor ))) { - lstrcpyW( monitor[index].name, generic_nonpnp_monitorW ); monitor[index].rc_monitor = monitors[i].rcMonitor; monitor[index].rc_work = monitors[i].rcWork; /* Xinerama only reports monitors already attached */ diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 2b0ee253cea..7c32e683c5d 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -1027,9 +1027,6 @@ static void xrandr14_free_adapters( struct gdi_adapter *adapters )
static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *realloc_monitors, *monitors = NULL; XRRScreenResources *screen_resources = NULL; XRROutputInfo *output_info = NULL, *enum_output_info = NULL; @@ -1063,7 +1060,6 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne /* Inactive but attached monitor, no need to check for mirrored/replica monitors */ if (!output_info->crtc || !crtc_info->mode) { - lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW ); monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED; monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid ); monitor_count = 1; @@ -1108,9 +1104,6 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne enum_crtc_info->width == crtc_info->width && enum_crtc_info->height == crtc_info->height) { - /* FIXME: Read output EDID property and parse the data to get the correct name */ - lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW ); - SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height ); monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 3db3d0d6af3..3de7e20af9a 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -253,7 +253,6 @@ struct gdi_adapter
struct gdi_monitor { - WCHAR name[128]; /* name */ RECT rc_monitor; /* RcMonitor in MONITORINFO struct */ RECT rc_work; /* RcWork in MONITORINFO struct */ DWORD state_flags; /* StateFlags in DISPLAY_DEVICE struct */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 54 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index aab148bbfe3..2805f71311f 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -218,6 +218,14 @@ struct adapter DEVMODEW *modes; };
+#define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 +struct edid_monitor_info +{ + unsigned int flags; + /* MONITOR_INFO_HAS_MONITOR_ID */ + char monitor_id_string[8]; +}; + struct monitor { struct list entry; @@ -438,6 +446,30 @@ static void adapter_release( struct adapter *adapter )
C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94);
+static void get_monitor_info_from_edid( struct edid_monitor_info *info, const unsigned char *edid, unsigned int edid_len ) +{ + unsigned short w; + unsigned char d; + unsigned int i; + + info->flags = 0; + if (!edid || edid_len < 128) return; + + w = (edid[8] << 8) | edid[9]; /* Manufacturer ID, big endian. */ + for (i = 0; i < 3; ++i) + { + d = w & 0x1f; + if (!d || d - 1 > 'Z' - 'A') return; + info->monitor_id_string[2 - i] = 'A' + d - 1; + w >>= 5; + } + if (w) return; + w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + sprintf( info->monitor_id_string + 3, "%04X", w ); + info->flags = MONITOR_INFO_HAS_MONITOR_ID; + TRACE( "Monitor id %s.\n", info->monitor_id_string ); +} + static BOOL write_adapter_mode( HKEY adapter_key, UINT index, const DEVMODEW *mode ) { WCHAR bufferW[MAX_PATH] = {0}; @@ -871,7 +903,7 @@ static void prepare_devices(void) REG_OPTION_VOLATILE, NULL );
/* delete monitors */ - reg_empty_key( enum_key, "DISPLAY\DEFAULT_MONITOR" ); + reg_empty_key( enum_key, "DISPLAY" ); sprintf( buffer, "Class\%s", guid_devclass_monitorA ); hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL ); @@ -1305,19 +1337,25 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) struct device_manager_ctx *ctx = param; char buffer[MAX_PATH], instance[64]; unsigned int monitor_index, output_index; + struct edid_monitor_info monitor_info; + char monitor_id_string[16]; WCHAR bufferW[MAX_PATH]; HKEY hkey, subkey; - - static const WCHAR default_monitorW[] = - {'M','O','N','I','T','O','R','\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0}; + unsigned int len;
monitor_index = ctx->monitor_count++; output_index = ctx->output_count++;
TRACE( "%u %s %s\n", monitor_index, wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) );
+ get_monitor_info_from_edid( &monitor_info, monitor->edid, monitor->edid_len ); + if (monitor_info.flags & MONITOR_INFO_HAS_MONITOR_ID) + strcpy( monitor_id_string, monitor_info.monitor_id_string ); + else + strcpy( monitor_id_string, "Default_Monitor" ); + sprintf( buffer, "MonitorID%u", monitor_index ); - sprintf( instance, "DISPLAY\Default_Monitor\%04X&%04X", ctx->video_count - 1, monitor_index ); + sprintf( instance, "DISPLAY\%s\%04X&%04X", monitor_id_string, ctx->video_count - 1, monitor_index ); set_reg_ascii_value( ctx->adapter_key, buffer, instance );
hkey = reg_create_key( enum_key, bufferW, asciiz_to_unicode( bufferW, instance ) - sizeof(WCHAR), @@ -1333,7 +1371,11 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) sprintf( buffer, "%s\%04X", guid_devclass_monitorA, output_index ); set_reg_ascii_value( hkey, "Driver", buffer ); set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_monitorW, sizeof(guid_devclass_monitorW) ); - set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, default_monitorW, sizeof(default_monitorW) ); + + sprintf( buffer, "MONITOR\%s", monitor_id_string ); + len = asciiz_to_unicode( bufferW, buffer ); + bufferW[len / sizeof(WCHAR)] = 0; + set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, len + sizeof(WCHAR) );
if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL ))) {
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 2805f71311f..1ee2ad9b740 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -170,6 +170,7 @@ static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0}; static const WCHAR yesW[] = {'Y','e','s',0}; static const WCHAR noW[] = {'N','o',0}; static const WCHAR mode_countW[] = {'M','o','d','e','C','o','u','n','t',0}; +static const WCHAR edidW[] = {'E','D','I','D',0};
static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}"; static const WCHAR guid_devclass_displayW[] = @@ -238,6 +239,7 @@ struct monitor RECT rc_monitor; RECT rc_work; BOOL is_clone; + struct edid_monitor_info edid_info; };
static struct list adapters = LIST_INIT(adapters); @@ -749,7 +751,7 @@ static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct m char buffer[4096]; KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer; WCHAR *device_name, *value_str = (WCHAR *)value->Data, *ptr; - HKEY hkey; + HKEY hkey, subkey; DWORD size, len;
monitor->flags = adapter->id ? 0 : MONITORINFOF_PRIMARY; @@ -856,6 +858,14 @@ static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct m monitor->dev.device_id[size++] = '\'; lstrcpyW( monitor->dev.device_id + size, device_name );
+ /* EDID */ + if ((subkey = reg_open_key( hkey, device_parametersW, sizeof(device_parametersW) ))) + { + if (query_reg_value( subkey, edidW, value, sizeof(buffer) )) + get_monitor_info_from_edid( &monitor->edid_info, value->Data, value->DataLength ); + NtClose( subkey ); + } + NtClose( hkey ); return TRUE; } @@ -1380,7 +1390,6 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL ))) { static const WCHAR bad_edidW[] = {'B','A','D','_','E','D','I','D',0}; - static const WCHAR edidW[] = {'E','D','I','D',0};
if (monitor->edid_len) set_reg_value( subkey, edidW, REG_BINARY, monitor->edid, monitor->edid_len );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 1ee2ad9b740..db875e57201 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -224,6 +224,7 @@ struct edid_monitor_info { unsigned int flags; /* MONITOR_INFO_HAS_MONITOR_ID */ + unsigned short manufacturer, product_code; char monitor_id_string[8]; };
@@ -467,6 +468,8 @@ static void get_monitor_info_from_edid( struct edid_monitor_info *info, const un } if (w) return; w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + info->manufacturer = *(unsigned short *)(edid + 8); + info->product_code = w; sprintf( info->monitor_id_string + 3, "%04X", w ); info->flags = MONITOR_INFO_HAS_MONITOR_ID; TRACE( "Monitor id %s.\n", info->monitor_id_string ); @@ -5732,6 +5735,12 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD snprintf( buffer, ARRAY_SIZE(buffer), "Display%u", monitor->output_id + 1 ); asciiz_to_unicode( target_name->monitorFriendlyDeviceName, buffer ); lstrcpyW( target_name->monitorDevicePath, monitor->dev.interface_name ); + if (monitor->edid_info.flags & MONITOR_INFO_HAS_MONITOR_ID) + { + target_name->edidManufactureId = monitor->edid_info.manufacturer; + target_name->edidProductCodeId = monitor->edid_info.product_code; + target_name->flags.edidIdsValid = 1; + } ret = STATUS_SUCCESS; break; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index db875e57201..bcdb8c5103b 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -220,12 +220,15 @@ struct adapter };
#define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 +#define MONITOR_INFO_HAS_MONITOR_NAME 0x00000002 struct edid_monitor_info { unsigned int flags; /* MONITOR_INFO_HAS_MONITOR_ID */ unsigned short manufacturer, product_code; char monitor_id_string[8]; + /* MONITOR_INFO_HAS_MONITOR_NAME */ + WCHAR monitor_name[14]; };
struct monitor @@ -451,9 +454,10 @@ C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94);
static void get_monitor_info_from_edid( struct edid_monitor_info *info, const unsigned char *edid, unsigned int edid_len ) { + unsigned int i, j; unsigned short w; unsigned char d; - unsigned int i; + const char *s;
info->flags = 0; if (!edid || edid_len < 128) return; @@ -473,6 +477,19 @@ static void get_monitor_info_from_edid( struct edid_monitor_info *info, const un sprintf( info->monitor_id_string + 3, "%04X", w ); info->flags = MONITOR_INFO_HAS_MONITOR_ID; TRACE( "Monitor id %s.\n", info->monitor_id_string ); + + for (i = 0; i < 4; ++i) + { + if (edid[54 + i * 18 + 3] != 0xfc) continue; + /* "Display name" ASCII descriptor. */ + s = (const char *)&edid[54 + i * 18 + 5]; + for (j = 0; s[j] && j < 13; ++j) + info->monitor_name[j] = s[j]; + while (j && isspace(s[j - 1])) --j; + info->monitor_name[j] = 0; + info->flags |= MONITOR_INFO_HAS_MONITOR_NAME; + break; + } }
static BOOL write_adapter_mode( HKEY adapter_key, UINT index, const DEVMODEW *mode ) @@ -5731,7 +5748,6 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD continue;
target_name->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL; - /* FIXME: get real monitor name. */ snprintf( buffer, ARRAY_SIZE(buffer), "Display%u", monitor->output_id + 1 ); asciiz_to_unicode( target_name->monitorFriendlyDeviceName, buffer ); lstrcpyW( target_name->monitorDevicePath, monitor->dev.interface_name ); @@ -5741,6 +5757,11 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD target_name->edidProductCodeId = monitor->edid_info.product_code; target_name->flags.edidIdsValid = 1; } + if (monitor->edid_info.flags & MONITOR_INFO_HAS_MONITOR_NAME) + { + wcscpy( target_name->monitorFriendlyDeviceName, monitor->edid_info.monitor_name ); + target_name->flags.friendlyNameFromEdid = 1; + } ret = STATUS_SUCCESS; break; }
v2: - use a structure and single function to parse all the used edid info at once; - store info structure instead of raw edid in cache; - add monitor index to trace.
This merge request was approved by Zhiyi Zhang.
While our value doesn't match Windows string exactly, Windows also doesn't have any meaningful name under DeviceDesc (and contains "Generic Non-Pnp Monitor" as a part of it)
On my machine, DeviceDesc contains "27GN950(DP)" or "27GN950(HDMI)" and is shown in the DeviceString from EnumDisplayDevices(). So it's kind of arbitrary. I think you can use the EDID display name for DeviceDesc as well. It could be another patch.