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.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 6 ++---- 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, 2 insertions(+), 29 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 2269193b7ff..5e7b04905b8 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1311,8 +1311,7 @@ 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) ); + TRACE( "%s %s\n", wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) );
monitor_index = ctx->monitor_count++; output_index = ctx->output_count++; @@ -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/user32/tests/monitor.c | 8 ++++++++ dlls/win32u/sysparams.c | 41 +++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 1dff85b9621..5a717d30360 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -191,6 +191,9 @@ static void test_enumdisplaydevices_monitor(int monitor_index, const char *adapt ok(device->StateFlags <= (DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE), "#%d wrong state %#lx\n", monitor_index, device->StateFlags);
+ trace("DeviceName %s, DeviceString %s, DeviceID %s, DeviceKey %s.\n", + debugstr_a(device->DeviceName), debugstr_a(device->DeviceString), debugstr_a(device->DeviceID), debugstr_a(device->DeviceKey)); + /* DeviceID */ CharLowerA(device->DeviceID); if (flags & EDD_GET_DEVICE_INTERFACE_NAME) @@ -1721,6 +1724,7 @@ static void test_QueryDisplayConfig_result(UINT32 flags, ret = pDisplayConfigGetDeviceInfo(&target_name.header); ok(!ret, "Expected 0, got %ld\n", ret); check_device_path(target_name.monitorDevicePath, &target_name.header.adapterId, target_name.header.id); + trace("flags %#lx, edidManufactureId %#x, edidProductCodeId %#x, friendlyName %s.\n", target_name.flags, target_name.edidManufactureId, target_name.edidProductCodeId, debugstr_w(target_name.monitorFriendlyDeviceName));
todo_wine { preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; @@ -2618,6 +2622,10 @@ START_TEST(monitor) return; }
+test_display_config(); +test_enumdisplaydevices(); +return; + test_enumdisplaydevices(); test_ChangeDisplaySettingsEx(); test_DisplayConfigSetDeviceInfo(); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 5e7b04905b8..8ca12d4f808 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -871,7 +871,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 ); @@ -1300,24 +1300,49 @@ static void add_adapter( const struct gdi_adapter *adapter, void *param ) sizeof(adapter->state_flags) ); }
+static BOOL get_monitor_id_from_edid( char monitor_id_string[16], const unsigned char *edid, unsigned int edid_len ) +{ + unsigned short w; + unsigned char d; + unsigned int i; + + if (!edid || edid_len < 128) return FALSE; + + 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 FALSE; + monitor_id_string[2 - i] = 'A' + d - 1; + w >>= 5; + } + if (w) return FALSE; + w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + sprintf( monitor_id_string + 3, "%04X", w ); + TRACE( "Monitor id %s.\n", monitor_id_string ); + return TRUE; +} + 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; + 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;
TRACE( "%s %s\n", wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) );
monitor_index = ctx->monitor_count++; output_index = ctx->output_count++;
+ if (!get_monitor_id_from_edid( monitor_id_string, monitor->edid, monitor->edid_len )) + 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 +1358,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 | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 8ca12d4f808..283d40e2e29 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[] = @@ -230,6 +231,8 @@ struct monitor RECT rc_monitor; RECT rc_work; BOOL is_clone; + unsigned char *edid; + unsigned int edid_len; };
static struct list adapters = LIST_INIT(adapters); @@ -717,7 +720,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; @@ -824,6 +827,17 @@ 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) ) && (monitor->edid = malloc( value->DataLength ))) + { + monitor->edid_len = value->DataLength; + memcpy( monitor->edid, value->Data, monitor->edid_len ); + } + NtClose( subkey ); + } + NtClose( hkey ); return TRUE; } @@ -1367,7 +1381,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 ); @@ -1500,6 +1513,7 @@ static void clear_display_devices(void) monitor = LIST_ENTRY( list_head( &monitors ), struct monitor, entry ); adapter_release( monitor->adapter ); list_remove( &monitor->entry ); + free( monitor->edid ); free( monitor ); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 283d40e2e29..c98c288e72c 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1314,7 +1314,8 @@ static void add_adapter( const struct gdi_adapter *adapter, void *param ) sizeof(adapter->state_flags) ); }
-static BOOL get_monitor_id_from_edid( char monitor_id_string[16], const unsigned char *edid, unsigned int edid_len ) +static BOOL get_monitor_id_from_edid( char monitor_id_string[16], unsigned short *man_id, unsigned short *prod_code, + const unsigned char *edid, unsigned int edid_len ) { unsigned short w; unsigned char d; @@ -1327,11 +1328,17 @@ static BOOL get_monitor_id_from_edid( char monitor_id_string[16], const unsigned { d = w & 0x1f; if (!d || d - 1 > 'Z' - 'A') return FALSE; - monitor_id_string[2 - i] = 'A' + d - 1; + if (monitor_id_string) monitor_id_string[2 - i] = 'A' + d - 1; w >>= 5; } if (w) return FALSE; w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + if (man_id) + { + *man_id = *(unsigned short *)(edid + 8); + *prod_code = w; + return TRUE; + } sprintf( monitor_id_string + 3, "%04X", w ); TRACE( "Monitor id %s.\n", monitor_id_string ); return TRUE; @@ -1352,7 +1359,7 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) monitor_index = ctx->monitor_count++; output_index = ctx->output_count++;
- if (!get_monitor_id_from_edid( monitor_id_string, monitor->edid, monitor->edid_len )) + if (!get_monitor_id_from_edid( monitor_id_string, NULL, NULL, monitor->edid, monitor->edid_len )) strcpy( monitor_id_string, "Default_Monitor" );
sprintf( buffer, "MonitorID%u", monitor_index ); @@ -5724,6 +5731,9 @@ 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 (get_monitor_id_from_edid( NULL, &target_name->edidManufactureId, &target_name->edidProductCodeId, + monitor->edid, monitor->edid_len )) + target_name->flags.edidIdsValid = 1; ret = STATUS_SUCCESS; break; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/win32u/sysparams.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index c98c288e72c..64c0af66c3d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5708,7 +5708,10 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD { DISPLAYCONFIG_TARGET_DEVICE_NAME *target_name = (DISPLAYCONFIG_TARGET_DEVICE_NAME *)packet; char buffer[ARRAY_SIZE(target_name->monitorFriendlyDeviceName)]; + const unsigned char *edid; struct monitor *monitor; + unsigned int i, j; + const char *s;
TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n" );
@@ -5727,13 +5730,26 @@ 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 ); + edid = monitor->edid; if (get_monitor_id_from_edid( NULL, &target_name->edidManufactureId, &target_name->edidProductCodeId, - monitor->edid, monitor->edid_len )) + edid, monitor->edid_len )) + { target_name->flags.edidIdsValid = 1; + 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) + target_name->monitorFriendlyDeviceName[j] = s[j]; + while (j && isspace(s[j - 1])) --j; + target_name->monitorFriendlyDeviceName[j] = 0; + target_name->flags.friendlyNameFromEdid = 1; + } + } ret = STATUS_SUCCESS; break; }