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.
This commit is contained in:
Camilla Berglund 2015-10-19 00:46:26 +02:00
parent 239ede725d
commit 4b63f70285
2 changed files with 108 additions and 59 deletions

View File

@ -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

View File

@ -33,6 +33,59 @@
#include <malloc.h>
// 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)