From 4b63f702856297746dc827f4cfa1a1b9770d684b Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 19 Oct 2015 00:46:26 +0200 Subject: [PATCH] Fix no monitors found on VMware Windows guest Monitor enumeration now switches to adapters if no displays are connected to active adapters. This should provide usable monitor objects on headless and VMware guest systems. Fixes #441. Fixes #556. Fixes #594. --- README.md | 1 + src/win32_monitor.c | 166 ++++++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 9d9001b3..38bec8fa 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ does not find Doxygen, the documentation will not be generated. when no windows existed - [Win32] Bugfix: Activating or deactivating displays in software did not trigger monitor callback + - [Win32] Bugfix: No monitors were listed on headless and VMware guest systems - [Cocoa] Removed support for OS X 10.6 - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault diff --git a/src/win32_monitor.c b/src/win32_monitor.c index 0341c26a..a6eeeb1e 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -33,6 +33,59 @@ #include +// Create monitor from an adapter and (optionally) a display +// +static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, + DISPLAY_DEVICEW* display) +{ + _GLFWmonitor* monitor; + char* name; + HDC dc; + + if (display) + name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString); + else + name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString); + if (!name) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert string to UTF-8"); + return NULL; + } + + dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL); + + monitor = _glfwAllocMonitor(name, + GetDeviceCaps(dc, HORZSIZE), + GetDeviceCaps(dc, VERTSIZE)); + + DeleteDC(dc); + free(name); + + if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) + monitor->win32.modesPruned = GLFW_TRUE; + + wcscpy(monitor->win32.adapterName, adapter->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + adapter->DeviceName, -1, + monitor->win32.publicAdapterName, + sizeof(monitor->win32.publicAdapterName), + NULL, NULL); + + if (display) + { + wcscpy(monitor->win32.displayName, display->DeviceName); + WideCharToMultiByte(CP_UTF8, 0, + display->DeviceName, -1, + monitor->win32.publicDisplayName, + sizeof(monitor->win32.publicDisplayName), + NULL, NULL); + } + + return monitor; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -96,17 +149,18 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { int found = 0; + DWORD adapterIndex, displayIndex, primaryIndex = 0; + DISPLAY_DEVICEW adapter, display; + GLFWbool hasDisplays = GLFW_FALSE; _GLFWmonitor** monitors = NULL; - DWORD adapterIndex, displayIndex; *count = 0; + // HACK: Check if any active adapters have connected displays + // If not, this is a headless system or a VMware guest + for (adapterIndex = 0; ; adapterIndex++) { - DISPLAY_DEVICEW adapter; - int widthMM, heightMM; - HDC dc; - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); adapter.cb = sizeof(DISPLAY_DEVICEW); @@ -116,71 +170,65 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; - dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL); - widthMM = GetDeviceCaps(dc, HORZSIZE); - heightMM = GetDeviceCaps(dc, VERTSIZE); - DeleteDC(dc); + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); - for (displayIndex = 0; ; displayIndex++) + if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0)) { - DISPLAY_DEVICEW display; - _GLFWmonitor* monitor; - char* name; - - ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); - display.cb = sizeof(DISPLAY_DEVICEW); - - if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) - break; - - name = _glfwCreateUTF8FromWideStringWin32(display.DeviceString); - if (!name) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to convert string to UTF-8"); - continue; - } - - monitor = _glfwAllocMonitor(name, widthMM, heightMM); - free(name); - - if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED) - monitor->win32.modesPruned = GLFW_TRUE; - - wcscpy(monitor->win32.adapterName, adapter.DeviceName); - wcscpy(monitor->win32.displayName, display.DeviceName); - - WideCharToMultiByte(CP_UTF8, 0, - adapter.DeviceName, -1, - monitor->win32.publicAdapterName, - sizeof(monitor->win32.publicAdapterName), - NULL, NULL); - - WideCharToMultiByte(CP_UTF8, 0, - display.DeviceName, -1, - monitor->win32.publicDisplayName, - sizeof(monitor->win32.publicDisplayName), - NULL, NULL); - - found++; - monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); - monitors[found - 1] = monitor; - - if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE && - displayIndex == 0) - { - _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]); - } + hasDisplays = GLFW_TRUE; + break; } } + for (adapterIndex = 0; ; adapterIndex++) + { + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) + break; + + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + primaryIndex = found; + + if (hasDisplays) + { + for (displayIndex = 0; ; displayIndex++) + { + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, &display); + } + } + else + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[found - 1] = createMonitor(&adapter, NULL); + } + } + + _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]); + *count = found; return monitors; } GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) { - return wcscmp(first->win32.displayName, second->win32.displayName) == 0; + if (wcslen(first->win32.displayName)) + return wcscmp(first->win32.displayName, second->win32.displayName) == 0; + else + return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0; } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)