diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 2935ac28..02cc823c 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -37,6 +37,83 @@ #include +// If the returned pointer is valid (not NULL) the caller of this function is in charge of freeing the memory when he is done. +static char * tryGetMoreAccurateDisplayName(const WCHAR *deviceName) +{ + DISPLAYCONFIG_PATH_INFO *paths = NULL; + DISPLAYCONFIG_MODE_INFO *modes = NULL; + char *retval = NULL; + UINT32 pathCount = 0; + UINT32 modeCount = 0; + UINT32 i; + LONG rc; + + do { + rc = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount); + if (rc != ERROR_SUCCESS) { + goto WHEN_FAILURE; + } + + free(paths); + free(modes); + + paths = (DISPLAYCONFIG_PATH_INFO *) malloc(sizeof (DISPLAYCONFIG_PATH_INFO) * pathCount); + modes = (DISPLAYCONFIG_MODE_INFO *) malloc(sizeof (DISPLAYCONFIG_MODE_INFO) * modeCount); + if ((paths == NULL) || (modes == NULL)) { + goto WHEN_FAILURE; + } + + rc = QueryDisplayConfig(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; + + ZeroMemory(&sourceName, sizeof(sourceName)); + sourceName.header.adapterId = paths[i].targetInfo.adapterId; + sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + sourceName.header.size = sizeof (sourceName); + sourceName.header.id = paths[i].sourceInfo.id; + rc = DisplayConfigGetDeviceInfo(&sourceName.header); + if (rc != ERROR_SUCCESS) { + break; + } else if (wcscmp(deviceName, sourceName.viewGdiDeviceName) != 0) { + continue; + } + + ZeroMemory(&targetName, sizeof(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 = DisplayConfigGetDeviceInfo(&targetName.header); + if (rc == ERROR_SUCCESS) { + retval = _glfwCreateUTF8FromWideStringWin32(targetName.monitorFriendlyDeviceName); + /* if we got an empty string, treat it as failure so we'll fallback + to getting the generic name. */ + if (retval && (*retval == '\0')) { + free(retval); + retval = NULL; + } + } + break; + } + } + + free(paths); + free(modes); + return retval; + +WHEN_FAILURE: + free(retval); + free(paths); + free(modes); + return NULL; +} + + // Callback for EnumDisplayMonitors in createMonitor // static BOOL CALLBACK monitorCallback(HMONITOR handle, @@ -52,12 +129,22 @@ static BOOL CALLBACK monitorCallback(HMONITOR handle, { _GLFWmonitor* monitor = (_GLFWmonitor*) data; if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0) + { monitor->win32.handle = handle; + char *possibleBetterDisplayName = tryGetMoreAccurateDisplayName(mi.szDevice); + if(possibleBetterDisplayName != NULL) + { + strncpy(monitor->name, possibleBetterDisplayName, sizeof(monitor->name) - 1); + free(possibleBetterDisplayName); + possibleBetterDisplayName = NULL; + } + } } return TRUE; } + // Create monitor from an adapter and (optionally) a display // static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,