1 //========================================================================
2 // GLFW 3.4 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
15 // 1. The origin of this software must not be misrepresented; you must not
16 // claim that you wrote the original software. If you use this software
17 // in a product, an acknowledgment in the product documentation would
18 // be appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
26 //========================================================================
27 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
39 // Callback for EnumDisplayMonitors in createMonitor
41 static BOOL CALLBACK monitorCallback(HMONITOR handle,
47 ZeroMemory(&mi, sizeof(mi));
48 mi.cbSize = sizeof(mi);
50 if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
52 _GLFWmonitor* monitor = (_GLFWmonitor*) data;
53 if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
54 monitor->win32.handle = handle;
60 // Create monitor from an adapter and (optionally) a display
62 static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
63 DISPLAY_DEVICEW* display)
65 _GLFWmonitor* monitor;
66 int widthMM, heightMM;
73 name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
75 name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
79 ZeroMemory(&dm, sizeof(dm));
80 dm.dmSize = sizeof(dm);
81 EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
83 dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
85 if (IsWindows8Point1OrGreater())
87 widthMM = GetDeviceCaps(dc, HORZSIZE);
88 heightMM = GetDeviceCaps(dc, VERTSIZE);
92 widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
93 heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
98 monitor = _glfwAllocMonitor(name, widthMM, heightMM);
101 if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
102 monitor->win32.modesPruned = GLFW_TRUE;
104 wcscpy(monitor->win32.adapterName, adapter->DeviceName);
105 WideCharToMultiByte(CP_UTF8, 0,
106 adapter->DeviceName, -1,
107 monitor->win32.publicAdapterName,
108 sizeof(monitor->win32.publicAdapterName),
113 wcscpy(monitor->win32.displayName, display->DeviceName);
114 WideCharToMultiByte(CP_UTF8, 0,
115 display->DeviceName, -1,
116 monitor->win32.publicDisplayName,
117 sizeof(monitor->win32.publicDisplayName),
121 rect.left = dm.dmPosition.x;
122 rect.top = dm.dmPosition.y;
123 rect.right = dm.dmPosition.x + dm.dmPelsWidth;
124 rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
126 EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
131 //////////////////////////////////////////////////////////////////////////
132 ////// GLFW internal API //////
133 //////////////////////////////////////////////////////////////////////////
135 // Poll for changes in the set of connected monitors
137 void _glfwPollMonitorsWin32(void)
139 int i, disconnectedCount;
140 _GLFWmonitor** disconnected = NULL;
141 DWORD adapterIndex, displayIndex;
142 DISPLAY_DEVICEW adapter, display;
143 _GLFWmonitor* monitor;
145 disconnectedCount = _glfw.monitorCount;
146 if (disconnectedCount)
148 disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
151 _glfw.monitorCount * sizeof(_GLFWmonitor*));
154 for (adapterIndex = 0; ; adapterIndex++)
156 int type = _GLFW_INSERT_LAST;
158 ZeroMemory(&adapter, sizeof(adapter));
159 adapter.cb = sizeof(adapter);
161 if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
164 if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
167 if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
168 type = _GLFW_INSERT_FIRST;
170 for (displayIndex = 0; ; displayIndex++)
172 ZeroMemory(&display, sizeof(display));
173 display.cb = sizeof(display);
175 if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
178 if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
181 for (i = 0; i < disconnectedCount; i++)
183 if (disconnected[i] &&
184 wcscmp(disconnected[i]->win32.displayName,
185 display.DeviceName) == 0)
187 disconnected[i] = NULL;
188 // handle may have changed, update
189 EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]);
194 if (i < disconnectedCount)
197 monitor = createMonitor(&adapter, &display);
204 _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
206 type = _GLFW_INSERT_LAST;
209 // HACK: If an active adapter does not have any display devices
210 // (as sometimes happens), add it directly as a monitor
211 if (displayIndex == 0)
213 for (i = 0; i < disconnectedCount; i++)
215 if (disconnected[i] &&
216 wcscmp(disconnected[i]->win32.adapterName,
217 adapter.DeviceName) == 0)
219 disconnected[i] = NULL;
224 if (i < disconnectedCount)
227 monitor = createMonitor(&adapter, NULL);
234 _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
238 for (i = 0; i < disconnectedCount; i++)
241 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
247 // Change the current video mode
249 void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
252 const GLFWvidmode* best;
256 best = _glfwChooseVideoMode(monitor, desired);
257 _glfwPlatformGetVideoMode(monitor, ¤t);
258 if (_glfwCompareVideoModes(¤t, best) == 0)
261 ZeroMemory(&dm, sizeof(dm));
262 dm.dmSize = sizeof(dm);
263 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
265 dm.dmPelsWidth = best->width;
266 dm.dmPelsHeight = best->height;
267 dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
268 dm.dmDisplayFrequency = best->refreshRate;
270 if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
271 dm.dmBitsPerPel = 32;
273 result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
278 if (result == DISP_CHANGE_SUCCESSFUL)
279 monitor->win32.modeChanged = GLFW_TRUE;
282 const char* description = "Unknown error";
284 if (result == DISP_CHANGE_BADDUALVIEW)
285 description = "The system uses DualView";
286 else if (result == DISP_CHANGE_BADFLAGS)
287 description = "Invalid flags";
288 else if (result == DISP_CHANGE_BADMODE)
289 description = "Graphics mode not supported";
290 else if (result == DISP_CHANGE_BADPARAM)
291 description = "Invalid parameter";
292 else if (result == DISP_CHANGE_FAILED)
293 description = "Graphics mode failed";
294 else if (result == DISP_CHANGE_NOTUPDATED)
295 description = "Failed to write to registry";
296 else if (result == DISP_CHANGE_RESTART)
297 description = "Computer restart required";
299 _glfwInputError(GLFW_PLATFORM_ERROR,
300 "Win32: Failed to set video mode: %s",
305 // Restore the previously saved (original) video mode
307 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
309 if (monitor->win32.modeChanged)
311 ChangeDisplaySettingsExW(monitor->win32.adapterName,
312 NULL, NULL, CDS_FULLSCREEN, NULL);
313 monitor->win32.modeChanged = GLFW_FALSE;
317 void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
321 if (IsWindows8Point1OrGreater())
322 GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
325 const HDC dc = GetDC(NULL);
326 xdpi = GetDeviceCaps(dc, LOGPIXELSX);
327 ydpi = GetDeviceCaps(dc, LOGPIXELSY);
332 *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
334 *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
338 //////////////////////////////////////////////////////////////////////////
339 ////// GLFW platform API //////
340 //////////////////////////////////////////////////////////////////////////
342 void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
346 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
349 ZeroMemory(&dm, sizeof(dm));
350 dm.dmSize = sizeof(dm);
352 EnumDisplaySettingsExW(monitor->win32.adapterName,
353 ENUM_CURRENT_SETTINGS,
358 *xpos = dm.dmPosition.x;
360 *ypos = dm.dmPosition.y;
363 void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
364 float* xscale, float* yscale)
366 _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale);
369 void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
370 int* xpos, int* ypos,
371 int* width, int* height)
373 MONITORINFO mi = { sizeof(mi) };
374 GetMonitorInfo(monitor->win32.handle, &mi);
377 *xpos = mi.rcWork.left;
379 *ypos = mi.rcWork.top;
381 *width = mi.rcWork.right - mi.rcWork.left;
383 *height = mi.rcWork.bottom - mi.rcWork.top;
386 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
388 int modeIndex = 0, size = 0;
389 GLFWvidmode* result = NULL;
399 ZeroMemory(&dm, sizeof(dm));
400 dm.dmSize = sizeof(dm);
402 if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
407 // Skip modes with less than 15 BPP
408 if (dm.dmBitsPerPel < 15)
411 mode.width = dm.dmPelsWidth;
412 mode.height = dm.dmPelsHeight;
413 mode.refreshRate = dm.dmDisplayFrequency;
414 _glfwSplitBPP(dm.dmBitsPerPel,
419 for (i = 0; i < *count; i++)
421 if (_glfwCompareVideoModes(result + i, &mode) == 0)
425 // Skip duplicate modes
429 if (monitor->win32.modesPruned)
431 // Skip modes not supported by the connected displays
432 if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
436 NULL) != DISP_CHANGE_SUCCESSFUL)
445 result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
449 result[*count - 1] = mode;
454 // HACK: Report the current mode if no valid modes were found
455 result = calloc(1, sizeof(GLFWvidmode));
456 _glfwPlatformGetVideoMode(monitor, result);
463 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
466 ZeroMemory(&dm, sizeof(dm));
467 dm.dmSize = sizeof(dm);
469 EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
471 mode->width = dm.dmPelsWidth;
472 mode->height = dm.dmPelsHeight;
473 mode->refreshRate = dm.dmDisplayFrequency;
474 _glfwSplitBPP(dm.dmBitsPerPel,
480 GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
485 dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
486 GetDeviceGammaRamp(dc, values);
489 _glfwAllocGammaArrays(ramp, 256);
491 memcpy(ramp->red, values[0], sizeof(values[0]));
492 memcpy(ramp->green, values[1], sizeof(values[1]));
493 memcpy(ramp->blue, values[2], sizeof(values[2]));
498 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
503 if (ramp->size != 256)
505 _glfwInputError(GLFW_PLATFORM_ERROR,
506 "Win32: Gamma ramp size must be 256");
510 memcpy(values[0], ramp->red, sizeof(values[0]));
511 memcpy(values[1], ramp->green, sizeof(values[1]));
512 memcpy(values[2], ramp->blue, sizeof(values[2]));
514 dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
515 SetDeviceGammaRamp(dc, values);
520 //////////////////////////////////////////////////////////////////////////
521 ////// GLFW native API //////
522 //////////////////////////////////////////////////////////////////////////
524 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
526 _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
527 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
528 return monitor->win32.publicAdapterName;
531 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
533 _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
534 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
535 return monitor->win32.publicDisplayName;