| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- //========================================================================
- // GLFW 3.4 Win32 - www.glfw.org
- //------------------------------------------------------------------------
- // Copyright (c) 2002-2006 Marcus Geelnard
- // Copyright (c) 2006-2019 Camilla Löwy <[email protected]>
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would
- // be appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not
- // be misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source
- // distribution.
- //
- //========================================================================
- // Please use C89 style variable declarations in this file because VS 2010
- //========================================================================
- #include "internal.h"
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include <malloc.h>
- #include <wchar.h>
- // Callback for EnumDisplayMonitors in createMonitor
- //
- static BOOL CALLBACK monitorCallback(HMONITOR handle,
- HDC dc,
- RECT* rect,
- LPARAM data)
- {
- MONITORINFOEXW mi;
- ZeroMemory(&mi, sizeof(mi));
- mi.cbSize = sizeof(mi);
- if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
- {
- _GLFWmonitor* monitor = (_GLFWmonitor*) data;
- if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
- monitor->win32.handle = handle;
- }
- return TRUE;
- }
- // Create monitor from an adapter and (optionally) a display
- //
- static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
- DISPLAY_DEVICEW* display)
- {
- _GLFWmonitor* monitor;
- int widthMM, heightMM;
- char* name;
- HDC dc;
- DEVMODEW dm;
- RECT rect;
- if (display)
- name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
- else
- name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
- if (!name)
- return NULL;
- ZeroMemory(&dm, sizeof(dm));
- dm.dmSize = sizeof(dm);
- EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
- dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
- if (IsWindows8Point1OrGreater())
- {
- widthMM = GetDeviceCaps(dc, HORZSIZE);
- heightMM = GetDeviceCaps(dc, VERTSIZE);
- }
- else
- {
- widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
- heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
- }
- DeleteDC(dc);
- monitor = _glfwAllocMonitor(name, widthMM, heightMM);
- 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);
- }
- rect.left = dm.dmPosition.x;
- rect.top = dm.dmPosition.y;
- rect.right = dm.dmPosition.x + dm.dmPelsWidth;
- rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
- EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
- return monitor;
- }
- //////////////////////////////////////////////////////////////////////////
- ////// GLFW internal API //////
- //////////////////////////////////////////////////////////////////////////
- // Poll for changes in the set of connected monitors
- //
- void _glfwPollMonitorsWin32(void)
- {
- int i, disconnectedCount;
- _GLFWmonitor** disconnected = NULL;
- DWORD adapterIndex, displayIndex;
- DISPLAY_DEVICEW adapter, display;
- _GLFWmonitor* monitor;
- disconnectedCount = _glfw.monitorCount;
- if (disconnectedCount)
- {
- disconnected = (_GLFWmonitor**)calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
- memcpy(disconnected,
- _glfw.monitors,
- _glfw.monitorCount * sizeof(_GLFWmonitor*));
- }
- for (adapterIndex = 0; ; adapterIndex++)
- {
- int type = _GLFW_INSERT_LAST;
- ZeroMemory(&adapter, sizeof(adapter));
- adapter.cb = sizeof(adapter);
- if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
- break;
- if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
- continue;
- if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
- type = _GLFW_INSERT_FIRST;
- for (displayIndex = 0; ; displayIndex++)
- {
- ZeroMemory(&display, sizeof(display));
- display.cb = sizeof(display);
- if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
- break;
- if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
- continue;
- for (i = 0; i < disconnectedCount; i++)
- {
- if (disconnected[i] &&
- wcscmp(disconnected[i]->win32.displayName,
- display.DeviceName) == 0)
- {
- disconnected[i] = NULL;
- break;
- }
- }
- if (i < disconnectedCount)
- continue;
- monitor = createMonitor(&adapter, &display);
- if (!monitor)
- {
- free(disconnected);
- return;
- }
- _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
- type = _GLFW_INSERT_LAST;
- }
- // HACK: If an active adapter does not have any display devices
- // (as sometimes happens), add it directly as a monitor
- if (displayIndex == 0)
- {
- for (i = 0; i < disconnectedCount; i++)
- {
- if (disconnected[i] &&
- wcscmp(disconnected[i]->win32.adapterName,
- adapter.DeviceName) == 0)
- {
- disconnected[i] = NULL;
- break;
- }
- }
- if (i < disconnectedCount)
- continue;
- monitor = createMonitor(&adapter, NULL);
- if (!monitor)
- {
- free(disconnected);
- return;
- }
- _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
- }
- }
- for (i = 0; i < disconnectedCount; i++)
- {
- if (disconnected[i])
- _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
- }
- free(disconnected);
- }
- // Change the current video mode
- //
- void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
- {
- GLFWvidmode current;
- const GLFWvidmode* best;
- DEVMODEW dm;
- LONG result;
- best = _glfwChooseVideoMode(monitor, desired);
- _glfwPlatformGetVideoMode(monitor, ¤t);
- if (_glfwCompareVideoModes(¤t, best) == 0)
- return;
- ZeroMemory(&dm, sizeof(dm));
- dm.dmSize = sizeof(dm);
- dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
- DM_DISPLAYFREQUENCY;
- dm.dmPelsWidth = best->width;
- dm.dmPelsHeight = best->height;
- dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
- dm.dmDisplayFrequency = best->refreshRate;
- if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
- dm.dmBitsPerPel = 32;
- result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
- &dm,
- NULL,
- CDS_FULLSCREEN,
- NULL);
- if (result == DISP_CHANGE_SUCCESSFUL)
- monitor->win32.modeChanged = GLFW_TRUE;
- else
- {
- const char* description = "Unknown error";
- if (result == DISP_CHANGE_BADDUALVIEW)
- description = "The system uses DualView";
- else if (result == DISP_CHANGE_BADFLAGS)
- description = "Invalid flags";
- else if (result == DISP_CHANGE_BADMODE)
- description = "Graphics mode not supported";
- else if (result == DISP_CHANGE_BADPARAM)
- description = "Invalid parameter";
- else if (result == DISP_CHANGE_FAILED)
- description = "Graphics mode failed";
- else if (result == DISP_CHANGE_NOTUPDATED)
- description = "Failed to write to registry";
- else if (result == DISP_CHANGE_RESTART)
- description = "Computer restart required";
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Win32: Failed to set video mode: %s",
- description);
- }
- }
- // Restore the previously saved (original) video mode
- //
- void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
- {
- if (monitor->win32.modeChanged)
- {
- ChangeDisplaySettingsExW(monitor->win32.adapterName,
- NULL, NULL, CDS_FULLSCREEN, NULL);
- monitor->win32.modeChanged = GLFW_FALSE;
- }
- }
- void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
- {
- UINT xdpi, ydpi;
- if (IsWindows8Point1OrGreater())
- GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
- else
- {
- const HDC dc = GetDC(NULL);
- xdpi = GetDeviceCaps(dc, LOGPIXELSX);
- ydpi = GetDeviceCaps(dc, LOGPIXELSY);
- ReleaseDC(NULL, dc);
- }
- if (xscale)
- *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
- if (yscale)
- *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
- }
- //////////////////////////////////////////////////////////////////////////
- ////// GLFW platform API //////
- //////////////////////////////////////////////////////////////////////////
- void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
- {
- }
- void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
- {
- DEVMODEW dm;
- ZeroMemory(&dm, sizeof(dm));
- dm.dmSize = sizeof(dm);
- EnumDisplaySettingsExW(monitor->win32.adapterName,
- ENUM_CURRENT_SETTINGS,
- &dm,
- EDS_ROTATEDMODE);
- if (xpos)
- *xpos = dm.dmPosition.x;
- if (ypos)
- *ypos = dm.dmPosition.y;
- }
- void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
- float* xscale, float* yscale)
- {
- _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale);
- }
- void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
- int* xpos, int* ypos,
- int* width, int* height)
- {
- MONITORINFO mi = { sizeof(mi) };
- GetMonitorInfo(monitor->win32.handle, &mi);
- if (xpos)
- *xpos = mi.rcWork.left;
- if (ypos)
- *ypos = mi.rcWork.top;
- if (width)
- *width = mi.rcWork.right - mi.rcWork.left;
- if (height)
- *height = mi.rcWork.bottom - mi.rcWork.top;
- }
- GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
- {
- int modeIndex = 0, size = 0;
- GLFWvidmode* result = NULL;
- *count = 0;
- for (;;)
- {
- int i;
- GLFWvidmode mode;
- DEVMODEW dm;
- ZeroMemory(&dm, sizeof(dm));
- dm.dmSize = sizeof(dm);
- if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
- break;
- modeIndex++;
- // Skip modes with less than 15 BPP
- if (dm.dmBitsPerPel < 15)
- continue;
- mode.width = dm.dmPelsWidth;
- mode.height = dm.dmPelsHeight;
- mode.refreshRate = dm.dmDisplayFrequency;
- _glfwSplitBPP(dm.dmBitsPerPel,
- &mode.redBits,
- &mode.greenBits,
- &mode.blueBits);
- for (i = 0; i < *count; i++)
- {
- if (_glfwCompareVideoModes(result + i, &mode) == 0)
- break;
- }
- // Skip duplicate modes
- if (i < *count)
- continue;
- if (monitor->win32.modesPruned)
- {
- // Skip modes not supported by the connected displays
- if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
- &dm,
- NULL,
- CDS_TEST,
- NULL) != DISP_CHANGE_SUCCESSFUL)
- {
- continue;
- }
- }
- if (*count == size)
- {
- size += 128;
- result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
- }
- (*count)++;
- result[*count - 1] = mode;
- }
- if (!*count)
- {
- // HACK: Report the current mode if no valid modes were found
- result = (GLFWvidmode*)calloc(1, sizeof(GLFWvidmode));
- _glfwPlatformGetVideoMode(monitor, result);
- *count = 1;
- }
- return result;
- }
- void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
- {
- DEVMODEW dm;
- ZeroMemory(&dm, sizeof(dm));
- dm.dmSize = sizeof(dm);
- EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
- mode->width = dm.dmPelsWidth;
- mode->height = dm.dmPelsHeight;
- mode->refreshRate = dm.dmDisplayFrequency;
- _glfwSplitBPP(dm.dmBitsPerPel,
- &mode->redBits,
- &mode->greenBits,
- &mode->blueBits);
- }
- GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
- {
- HDC dc;
- WORD values[3][256];
- dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
- GetDeviceGammaRamp(dc, values);
- DeleteDC(dc);
- _glfwAllocGammaArrays(ramp, 256);
- memcpy(ramp->red, values[0], sizeof(values[0]));
- memcpy(ramp->green, values[1], sizeof(values[1]));
- memcpy(ramp->blue, values[2], sizeof(values[2]));
- return GLFW_TRUE;
- }
- void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
- {
- HDC dc;
- WORD values[3][256];
- if (ramp->size != 256)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Win32: Gamma ramp size must be 256");
- return;
- }
- memcpy(values[0], ramp->red, sizeof(values[0]));
- memcpy(values[1], ramp->green, sizeof(values[1]));
- memcpy(values[2], ramp->blue, sizeof(values[2]));
- dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
- SetDeviceGammaRamp(dc, values);
- DeleteDC(dc);
- }
- //////////////////////////////////////////////////////////////////////////
- ////// GLFW native API //////
- //////////////////////////////////////////////////////////////////////////
- GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
- {
- _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
- _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
- return monitor->win32.publicAdapterName;
- }
- GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
- {
- _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
- _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
- return monitor->win32.publicDisplayName;
- }
|