0//========================================================================
1// GLFW 3.4 Win32 - www.glfw.org
2//------------------------------------------------------------------------
3// Copyright (c) 2002-2006 Marcus Geelnard
4// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
5//
6// This software is provided 'as-is', without any express or implied
7// warranty. In no event will the authors be held liable for any damages
8// arising from the use of this software.
9//
10// Permission is granted to anyone to use this software for any purpose,
11// including commercial applications, and to alter it and redistribute it
12// freely, subject to the following restrictions:
13//
14// 1. The origin of this software must not be misrepresented; you must not
15// claim that you wrote the original software. If you use this software
16// in a product, an acknowledgment in the product documentation would
17// be appreciated but is not required.
18//
19// 2. Altered source versions must be plainly marked as such, and must not
20// be misrepresented as being the original software.
21//
22// 3. This notice may not be removed or altered from any source
23// distribution.
24//
25//========================================================================
27#include "internal.h"
29#if defined(_GLFW_WIN32)
31#include <stdlib.h>
32#include <string.h>
33#include <limits.h>
34#include <wchar.h>
37// Callback for EnumDisplayMonitors in createMonitor
38//
39static BOOL CALLBACK monitorCallback(HMONITOR handle,
40 HDC dc,
41 RECT* rect,
42 LPARAM data)
43{
44 MONITORINFOEXW mi;
45 ZeroMemory(&mi, sizeof(mi));
46 mi.cbSize = sizeof(mi);
48 if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
49 {
50 _GLFWmonitor* monitor = (_GLFWmonitor*) data;
51 if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
52 monitor->win32.handle = handle;
53 }
55 return TRUE;
56}
58// Create monitor from an adapter and (optionally) a display
59//
60static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
61 DISPLAY_DEVICEW* display)
62{
63 _GLFWmonitor* monitor;
64 int widthMM, heightMM;
65 char* name;
66 HDC dc;
67 DEVMODEW dm;
68 RECT rect;
70 if (display)
71 name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
72 else
73 name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
74 if (!name)
75 return NULL;
77 ZeroMemory(&dm, sizeof(dm));
78 dm.dmSize = sizeof(dm);
79 EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
81 dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
83 if (IsWindows8Point1OrGreater())
84 {
85 widthMM = GetDeviceCaps(dc, HORZSIZE);
86 heightMM = GetDeviceCaps(dc, VERTSIZE);
87 }
88 else
89 {
90 widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
91 heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
92 }
94 DeleteDC(dc);
96 monitor = _glfwAllocMonitor(name, widthMM, heightMM);
97 _glfw_free(name);
99 if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
100 monitor->win32.modesPruned = GLFW_TRUE;
102 wcscpy(monitor->win32.adapterName, adapter->DeviceName);
103 WideCharToMultiByte(CP_UTF8, 0,
104 adapter->DeviceName, -1,
105 monitor->win32.publicAdapterName,
106 sizeof(monitor->win32.publicAdapterName),
107 NULL, NULL);
109 if (display)
110 {
111 wcscpy(monitor->win32.displayName, display->DeviceName);
112 WideCharToMultiByte(CP_UTF8, 0,
113 display->DeviceName, -1,
114 monitor->win32.publicDisplayName,
115 sizeof(monitor->win32.publicDisplayName),
116 NULL, NULL);
117 }
119 rect.left = dm.dmPosition.x;
120 rect.top = dm.dmPosition.y;
121 rect.right = dm.dmPosition.x + dm.dmPelsWidth;
122 rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
124 EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
125 return monitor;
126}
129//////////////////////////////////////////////////////////////////////////
130////// GLFW internal API //////
131//////////////////////////////////////////////////////////////////////////
133// Poll for changes in the set of connected monitors
134//
135void _glfwPollMonitorsWin32(void)
136{
137 int i, disconnectedCount;
138 _GLFWmonitor** disconnected = NULL;
139 DWORD adapterIndex, displayIndex;
140 DISPLAY_DEVICEW adapter, display;
141 _GLFWmonitor* monitor;
143 disconnectedCount = _glfw.monitorCount;
144 if (disconnectedCount)
145 {
146 disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
147 memcpy(disconnected,
148 _glfw.monitors,
149 _glfw.monitorCount * sizeof(_GLFWmonitor*));
150 }
152 for (adapterIndex = 0; ; adapterIndex++)
153 {
154 int type = _GLFW_INSERT_LAST;
156 ZeroMemory(&adapter, sizeof(adapter));
157 adapter.cb = sizeof(adapter);
159 if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
160 break;
162 if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
163 continue;
165 if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
166 type = _GLFW_INSERT_FIRST;
168 for (displayIndex = 0; ; displayIndex++)
169 {
170 ZeroMemory(&display, sizeof(display));
171 display.cb = sizeof(display);
173 if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
174 break;
176 if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
177 continue;
179 for (i = 0; i < disconnectedCount; i++)
180 {
181 if (disconnected[i] &&
182 wcscmp(disconnected[i]->win32.displayName,
183 display.DeviceName) == 0)
184 {
185 disconnected[i] = NULL;
186 // handle may have changed, update
187 EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]);
188 break;
189 }
190 }
192 if (i < disconnectedCount)
193 continue;
195 monitor = createMonitor(&adapter, &display);
196 if (!monitor)
197 {
198 _glfw_free(disconnected);
199 return;
200 }
202 _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
204 type = _GLFW_INSERT_LAST;
205 }
207 // HACK: If an active adapter does not have any display devices
208 // (as sometimes happens), add it directly as a monitor
209 if (displayIndex == 0)
210 {
211 for (i = 0; i < disconnectedCount; i++)
212 {
213 if (disconnected[i] &&
214 wcscmp(disconnected[i]->win32.adapterName,
215 adapter.DeviceName) == 0)
216 {
217 disconnected[i] = NULL;
218 break;
219 }
220 }
222 if (i < disconnectedCount)
223 continue;
225 monitor = createMonitor(&adapter, NULL);
226 if (!monitor)
227 {
228 _glfw_free(disconnected);
229 return;
230 }
232 _glfwInputMonitor(monitor, GLFW_CONNECTED, type);
233 }
234 }
236 for (i = 0; i < disconnectedCount; i++)
237 {
238 if (disconnected[i])
239 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
240 }
242 _glfw_free(disconnected);
243}
245// Change the current video mode
246//
247void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
248{
249 GLFWvidmode current;
250 const GLFWvidmode* best;
251 DEVMODEW dm;
252 LONG result;
254 best = _glfwChooseVideoMode(monitor, desired);
255 _glfwGetVideoModeWin32(monitor, ¤t);
256 if (_glfwCompareVideoModes(¤t, best) == 0)
257 return;
259 ZeroMemory(&dm, sizeof(dm));
260 dm.dmSize = sizeof(dm);
261 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
262 DM_DISPLAYFREQUENCY;
263 dm.dmPelsWidth = best->width;
264 dm.dmPelsHeight = best->height;
265 dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
266 dm.dmDisplayFrequency = best->refreshRate;
268 if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
269 dm.dmBitsPerPel = 32;
271 result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
272 &dm,
273 NULL,
274 CDS_FULLSCREEN,
275 NULL);
276 if (result == DISP_CHANGE_SUCCESSFUL)
277 monitor->win32.modeChanged = GLFW_TRUE;
278 else
279 {
280 const char* description = "Unknown error";
282 if (result == DISP_CHANGE_BADDUALVIEW)
283 description = "The system uses DualView";
284 else if (result == DISP_CHANGE_BADFLAGS)
285 description = "Invalid flags";
286 else if (result == DISP_CHANGE_BADMODE)
287 description = "Graphics mode not supported";
288 else if (result == DISP_CHANGE_BADPARAM)
289 description = "Invalid parameter";
290 else if (result == DISP_CHANGE_FAILED)
291 description = "Graphics mode failed";
292 else if (result == DISP_CHANGE_NOTUPDATED)
293 description = "Failed to write to registry";
294 else if (result == DISP_CHANGE_RESTART)
295 description = "Computer restart required";
297 _glfwInputError(GLFW_PLATFORM_ERROR,
298 "Win32: Failed to set video mode: %s",
299 description);
300 }
301}
303// Restore the previously saved (original) video mode
304//
305void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
306{
307 if (monitor->win32.modeChanged)
308 {
309 ChangeDisplaySettingsExW(monitor->win32.adapterName,
310 NULL, NULL, CDS_FULLSCREEN, NULL);
311 monitor->win32.modeChanged = GLFW_FALSE;
312 }
313}
315void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
316{
317 UINT xdpi, ydpi;
319 if (xscale)
320 *xscale = 0.f;
321 if (yscale)
322 *yscale = 0.f;
324 if (IsWindows8Point1OrGreater())
325 {
326 if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK)
327 {
328 _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI");
329 return;
330 }
331 }
332 else
333 {
334 const HDC dc = GetDC(NULL);
335 xdpi = GetDeviceCaps(dc, LOGPIXELSX);
336 ydpi = GetDeviceCaps(dc, LOGPIXELSY);
337 ReleaseDC(NULL, dc);
338 }
340 if (xscale)
341 *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
342 if (yscale)
343 *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
344}
347//////////////////////////////////////////////////////////////////////////
348////// GLFW platform API //////
349//////////////////////////////////////////////////////////////////////////
351void _glfwFreeMonitorWin32(_GLFWmonitor* monitor)
352{
353}
355void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos)
356{
357 DEVMODEW dm;
358 ZeroMemory(&dm, sizeof(dm));
359 dm.dmSize = sizeof(dm);
361 EnumDisplaySettingsExW(monitor->win32.adapterName,
362 ENUM_CURRENT_SETTINGS,
363 &dm,
364 EDS_ROTATEDMODE);
366 if (xpos)
367 *xpos = dm.dmPosition.x;
368 if (ypos)
369 *ypos = dm.dmPosition.y;
370}
372void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor,
373 float* xscale, float* yscale)
374{
375 _glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale);
376}
378void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
379 int* xpos, int* ypos,
380 int* width, int* height)
381{
382 MONITORINFO mi = { sizeof(mi) };
383 GetMonitorInfoW(monitor->win32.handle, &mi);
385 if (xpos)
386 *xpos = mi.rcWork.left;
387 if (ypos)
388 *ypos = mi.rcWork.top;
389 if (width)
390 *width = mi.rcWork.right - mi.rcWork.left;
391 if (height)
392 *height = mi.rcWork.bottom - mi.rcWork.top;
393}
395GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count)
396{
397 int modeIndex = 0, size = 0;
398 GLFWvidmode* result = NULL;
400 *count = 0;
402 for (;;)
403 {
404 int i;
405 GLFWvidmode mode;
406 DEVMODEW dm;
408 ZeroMemory(&dm, sizeof(dm));
409 dm.dmSize = sizeof(dm);
411 if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
412 break;
414 modeIndex++;
416 // Skip modes with less than 15 BPP
417 if (dm.dmBitsPerPel < 15)
418 continue;
420 mode.width = dm.dmPelsWidth;
421 mode.height = dm.dmPelsHeight;
422 mode.refreshRate = dm.dmDisplayFrequency;
423 _glfwSplitBPP(dm.dmBitsPerPel,
424 &mode.redBits,
425 &mode.greenBits,
426 &mode.blueBits);
428 for (i = 0; i < *count; i++)
429 {
430 if (_glfwCompareVideoModes(result + i, &mode) == 0)
431 break;
432 }
434 // Skip duplicate modes
435 if (i < *count)
436 continue;
438 if (monitor->win32.modesPruned)
439 {
440 // Skip modes not supported by the connected displays
441 if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
442 &dm,
443 NULL,
444 CDS_TEST,
445 NULL) != DISP_CHANGE_SUCCESSFUL)
446 {
447 continue;
448 }
449 }
451 if (*count == size)
452 {
453 size += 128;
454 result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode));
455 }
457 (*count)++;
458 result[*count - 1] = mode;
459 }
461 if (!*count)
462 {
463 // HACK: Report the current mode if no valid modes were found
464 result = _glfw_calloc(1, sizeof(GLFWvidmode));
465 _glfwGetVideoModeWin32(monitor, result);
466 *count = 1;
467 }
469 return result;
470}
472GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode)
473{
474 DEVMODEW dm;
475 ZeroMemory(&dm, sizeof(dm));
476 dm.dmSize = sizeof(dm);
478 if (!EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm))
479 {
480 _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query display settings");
481 return GLFW_FALSE;
482 }
484 mode->width = dm.dmPelsWidth;
485 mode->height = dm.dmPelsHeight;
486 mode->refreshRate = dm.dmDisplayFrequency;
487 _glfwSplitBPP(dm.dmBitsPerPel,
488 &mode->redBits,
489 &mode->greenBits,
490 &mode->blueBits);
492 return GLFW_TRUE;
493}
495GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
496{
497 HDC dc;
498 WORD values[3][256];
500 dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
501 GetDeviceGammaRamp(dc, values);
502 DeleteDC(dc);
504 _glfwAllocGammaArrays(ramp, 256);
506 memcpy(ramp->red, values[0], sizeof(values[0]));
507 memcpy(ramp->green, values[1], sizeof(values[1]));
508 memcpy(ramp->blue, values[2], sizeof(values[2]));
510 return GLFW_TRUE;
511}
513void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
514{
515 HDC dc;
516 WORD values[3][256];
518 if (ramp->size != 256)
519 {
520 _glfwInputError(GLFW_PLATFORM_ERROR,
521 "Win32: Gamma ramp size must be 256");
522 return;
523 }
525 memcpy(values[0], ramp->red, sizeof(values[0]));
526 memcpy(values[1], ramp->green, sizeof(values[1]));
527 memcpy(values[2], ramp->blue, sizeof(values[2]));
529 dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
530 SetDeviceGammaRamp(dc, values);
531 DeleteDC(dc);
532}
535//////////////////////////////////////////////////////////////////////////
536////// GLFW native API //////
537//////////////////////////////////////////////////////////////////////////
539GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
540{
541 _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
542 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
544 if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
545 {
546 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized");
547 return NULL;
548 }
550 return monitor->win32.publicAdapterName;
551}
553GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
554{
555 _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
556 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
558 if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
559 {
560 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Win32: Platform not initialized");
561 return NULL;
562 }
564 return monitor->win32.publicDisplayName;
565}
567#endif // _GLFW_WIN32
index : raylib-jai
Bindings from https://solarium.technology