windows: Get better name for the physical display, for Vista and later.

Fixes #5321.
This commit is contained in:
Ryan C. Gordon 2022-06-12 15:28:49 -04:00
parent 1963cccce1
commit 9a0367675f
No known key found for this signature in database
GPG Key ID: FA148B892AB48044
2 changed files with 300 additions and 4 deletions

View File

@ -196,6 +196,100 @@ WIN_GetDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode * mod
return SDL_TRUE;
}
/* The win32 API calls in this function require Windows Vista or later. */
/* these are normally WINAPI but VS2017 is saying "warning C4229: anachronism used: modifiers on data are ignored" */
typedef LONG (*SDL_WIN32PROC_GetDisplayConfigBufferSizes)(UINT32 flags, UINT32* numPathArrayElements, UINT32* numModeInfoArrayElements);
typedef LONG (*SDL_WIN32PROC_QueryDisplayConfig)(UINT32 flags, UINT32* numPathArrayElements, DISPLAYCONFIG_PATH_INFO* pathArray, UINT32* numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO* modeInfoArray, DISPLAYCONFIG_TOPOLOGY_ID* currentTopologyId);
typedef LONG (*SDL_WIN32PROC_DisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket);
static char *
WIN_GetDisplayNameVista(const WCHAR *deviceName)
{
void *dll;
SDL_WIN32PROC_GetDisplayConfigBufferSizes pGetDisplayConfigBufferSizes;
SDL_WIN32PROC_QueryDisplayConfig pQueryDisplayConfig;
SDL_WIN32PROC_DisplayConfigGetDeviceInfo pDisplayConfigGetDeviceInfo;
DISPLAYCONFIG_PATH_INFO *paths = NULL;
DISPLAYCONFIG_MODE_INFO *modes = NULL;
char *retval = NULL;
UINT32 pathCount = 0;
UINT32 modeCount = 0;
UINT32 i;
LONG rc;
dll = SDL_LoadObject("USER32.DLL");
if (!dll) {
return NULL;
}
pGetDisplayConfigBufferSizes = (SDL_WIN32PROC_GetDisplayConfigBufferSizes) SDL_LoadFunction(dll, "GetDisplayConfigBufferSizes");
pQueryDisplayConfig = (SDL_WIN32PROC_QueryDisplayConfig) SDL_LoadFunction(dll, "QueryDisplayConfig");
pDisplayConfigGetDeviceInfo = (SDL_WIN32PROC_DisplayConfigGetDeviceInfo) SDL_LoadFunction(dll, "DisplayConfigGetDeviceInfo");
if (!pGetDisplayConfigBufferSizes || !pQueryDisplayConfig || !pDisplayConfigGetDeviceInfo) {
goto WIN_GetDisplayNameVista_failed;
}
do {
rc = pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount);
if (rc != ERROR_SUCCESS) {
goto WIN_GetDisplayNameVista_failed;
}
SDL_free(paths);
SDL_free(modes);
paths = (DISPLAYCONFIG_PATH_INFO *) SDL_malloc(sizeof (DISPLAYCONFIG_PATH_INFO) * pathCount);
modes = (DISPLAYCONFIG_MODE_INFO *) SDL_malloc(sizeof (DISPLAYCONFIG_MODE_INFO) * modeCount);
if ((paths == NULL) || (modes == NULL)) {
goto WIN_GetDisplayNameVista_failed;
}
rc = pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths, &modeCount, modes, 0);
} while (rc == ERROR_INSUFFICIENT_BUFFER);
if (rc == ERROR_SUCCESS) {
for (i = 0; i < pathCount; i++) {
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
DISPLAYCONFIG_TARGET_DEVICE_NAME targetName;
SDL_zero(sourceName);
sourceName.header.adapterId = paths[i].targetInfo.adapterId;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof (sourceName);
rc = pDisplayConfigGetDeviceInfo(&sourceName.header);
if (rc != ERROR_SUCCESS) {
break;
} else if (SDL_wcscmp(deviceName, sourceName.viewGdiDeviceName) != 0) {
continue;
}
SDL_zero(targetName);
targetName.header.adapterId = paths[i].targetInfo.adapterId;
targetName.header.id = paths[i].targetInfo.id;
targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = sizeof (targetName);
rc = pDisplayConfigGetDeviceInfo(&targetName.header);
if (rc == ERROR_SUCCESS) {
retval = WIN_StringToUTF8W(targetName.monitorFriendlyDeviceName);
}
break;
}
}
SDL_free(paths);
SDL_free(modes);
SDL_UnloadObject(dll);
return retval;
WIN_GetDisplayNameVista_failed:
SDL_free(retval);
SDL_free(paths);
SDL_free(modes);
SDL_UnloadObject(dll);
return NULL;
}
static SDL_bool
WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool send_event)
{
@ -204,7 +298,6 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
SDL_DisplayOrientation orientation;
DISPLAY_DEVICEW device;
#ifdef DEBUG_MODES
SDL_Log("Display: %s\n", WIN_StringToUTF8W(info->szDevice));
@ -243,10 +336,16 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
displaydata->IsValid = SDL_TRUE;
SDL_zero(display);
device.cb = sizeof(device);
if (EnumDisplayDevicesW(info->szDevice, 0, &device, 0)) {
display.name = WIN_StringToUTF8W(device.DeviceString);
display.name = WIN_GetDisplayNameVista(info->szDevice);
if (display.name == NULL) {
DISPLAY_DEVICEW device;
SDL_zero(device);
device.cb = sizeof (device);
if (EnumDisplayDevicesW(info->szDevice, 0, &device, 0)) {
display.name = WIN_StringToUTF8W(device.DeviceString);
}
}
display.desktop_mode = mode;
display.current_mode = mode;
display.orientation = orientation;

View File

@ -75,6 +75,203 @@ typedef struct _TOUCHINPUT {
DWORD cyContact;
} TOUCHINPUT, *PTOUCHINPUT;
/* More-robust display information in Vista... */
/* This is a huge amount of data to be stuffing into three API calls. :( */
typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
LUID adapterId;
UINT32 id;
union
{
UINT32 modeInfoIdx;
struct
{
UINT32 cloneGroupId : 16;
UINT32 sourceModeInfoIdx : 16;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
UINT32 statusFlags;
} DISPLAYCONFIG_PATH_SOURCE_INFO;
typedef struct DISPLAYCONFIG_RATIONAL
{
UINT32 Numerator;
UINT32 Denominator;
} DISPLAYCONFIG_RATIONAL;
typedef struct DISPLAYCONFIG_PATH_TARGET_INFO
{
LUID adapterId;
UINT32 id;
union
{
UINT32 modeInfoIdx;
struct
{
UINT32 desktopModeInfoIdx : 16;
UINT32 targetModeInfoIdx : 16;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
UINT32 /*DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY*/ outputTechnology;
UINT32 /*DISPLAYCONFIG_ROTATION*/ rotation;
UINT32 /*DISPLAYCONFIG_SCALING*/ scaling;
DISPLAYCONFIG_RATIONAL refreshRate;
UINT32 /*DISPLAYCONFIG_SCANLINE_ORDERING*/ scanLineOrdering;
BOOL targetAvailable;
UINT32 statusFlags;
} DISPLAYCONFIG_PATH_TARGET_INFO;
typedef struct DISPLAYCONFIG_PATH_INFO
{
DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
UINT32 flags;
} DISPLAYCONFIG_PATH_INFO;
typedef enum
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_MODE_INFO_TYPE;
typedef struct DISPLAYCONFIG_2DREGION
{
UINT32 cx;
UINT32 cy;
} DISPLAYCONFIG_2DREGION;
typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
UINT64 pixelRate;
DISPLAYCONFIG_RATIONAL hSyncFreq;
DISPLAYCONFIG_RATIONAL vSyncFreq;
DISPLAYCONFIG_2DREGION activeSize;
DISPLAYCONFIG_2DREGION totalSize;
union
{
struct
{
UINT32 videoStandard : 16;
// Vertical refresh frequency divider
UINT32 vSyncFreqDivider : 6;
UINT32 reserved : 10;
} AdditionalSignalInfo;
UINT32 videoStandard;
} DUMMYUNIONNAME;
// Scan line ordering (e.g. progressive, interlaced).
UINT32 /*DISPLAYCONFIG_SCANLINE_ORDERING*/ scanLineOrdering;
} DISPLAYCONFIG_VIDEO_SIGNAL_INFO;
typedef struct DISPLAYCONFIG_SOURCE_MODE
{
UINT32 width;
UINT32 height;
UINT32 /*DISPLAYCONFIG_PIXELFORMAT*/ pixelFormat;
POINTL position;
} DISPLAYCONFIG_SOURCE_MODE;
typedef struct DISPLAYCONFIG_TARGET_MODE
{
DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
} DISPLAYCONFIG_TARGET_MODE;
typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
{
POINTL PathSourceSize;
RECTL DesktopImageRegion;
RECTL DesktopImageClip;
} DISPLAYCONFIG_DESKTOP_IMAGE_INFO;
typedef struct DISPLAYCONFIG_MODE_INFO
{
DISPLAYCONFIG_MODE_INFO_TYPE infoType;
UINT32 id;
LUID adapterId;
union
{
DISPLAYCONFIG_TARGET_MODE targetMode;
DISPLAYCONFIG_SOURCE_MODE sourceMode;
DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
} DUMMYUNIONNAME;
} DISPLAYCONFIG_MODE_INFO;
typedef enum DISPLAYCONFIG_TOPOLOGY_ID
{
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_TOPOLOGY_ID;
typedef enum
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_DEVICE_INFO_TYPE;
typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
DISPLAYCONFIG_DEVICE_INFO_TYPE type;
UINT32 size;
LUID adapterId;
UINT32 id;
} DISPLAYCONFIG_DEVICE_INFO_HEADER;
typedef struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
{
DISPLAYCONFIG_DEVICE_INFO_HEADER header;
WCHAR viewGdiDeviceName[CCHDEVICENAME];
} DISPLAYCONFIG_SOURCE_DEVICE_NAME;
typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
union
{
struct
{
UINT32 friendlyNameFromEdid : 1;
UINT32 friendlyNameForced : 1;
UINT32 edidIdsValid : 1;
UINT32 reserved : 29;
} DUMMYSTRUCTNAME;
UINT32 value;
} DUMMYUNIONNAME;
} DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS;
typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
DISPLAYCONFIG_DEVICE_INFO_HEADER header;
DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
UINT32 /*DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY*/ outputTechnology;
UINT16 edidManufactureId;
UINT16 edidProductCodeId;
UINT32 connectorInstance;
WCHAR monitorFriendlyDeviceName[64];
WCHAR monitorDevicePath[128];
} DISPLAYCONFIG_TARGET_DEVICE_NAME;
#define QDC_ONLY_ACTIVE_PATHS 0x00000002
#endif /* WINVER < 0x0601 */
#if WINVER < 0x0603