1 //========================================================================
2 // GLFW 3.1 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
6 //
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.
10 //
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:
14 //
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.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 //    be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 //    distribution.
25 //
26 //========================================================================
27 
28 #include "internal.h"
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <malloc.h>
34 
35 // These constants are missing on MinGW
36 #ifndef EDS_ROTATEDMODE
37  #define EDS_ROTATEDMODE 0x00000004
38 #endif
39 #ifndef DISPLAY_DEVICE_ACTIVE
40  #define DISPLAY_DEVICE_ACTIVE 0x00000001
41 #endif
42 
43 
44 //////////////////////////////////////////////////////////////////////////
45 //////                       GLFW internal API                      //////
46 //////////////////////////////////////////////////////////////////////////
47 
48 // Change the current video mode
49 //
_glfwSetVideoMode(_GLFWmonitor * monitor,const GLFWvidmode * desired)50 GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired)
51 {
52     GLFWvidmode current;
53     const GLFWvidmode* best;
54     DEVMODEW dm;
55 
56     best = _glfwChooseVideoMode(monitor, desired);
57     _glfwPlatformGetVideoMode(monitor, &current);
58     if (_glfwCompareVideoModes(&current, best) == 0)
59         return GL_TRUE;
60 
61     ZeroMemory(&dm, sizeof(dm));
62     dm.dmSize = sizeof(DEVMODEW);
63     dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
64                             DM_DISPLAYFREQUENCY;
65     dm.dmPelsWidth        = best->width;
66     dm.dmPelsHeight       = best->height;
67     dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
68     dm.dmDisplayFrequency = best->refreshRate;
69 
70     if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
71         dm.dmBitsPerPel = 32;
72 
73     if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
74                                  &dm,
75                                  NULL,
76                                  CDS_FULLSCREEN,
77                                  NULL) != DISP_CHANGE_SUCCESSFUL)
78     {
79         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
80         return GL_FALSE;
81     }
82 
83     monitor->win32.modeChanged = GL_TRUE;
84     return GL_TRUE;
85 }
86 
87 // Restore the previously saved (original) video mode
88 //
_glfwRestoreVideoMode(_GLFWmonitor * monitor)89 void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
90 {
91     if (monitor->win32.modeChanged)
92     {
93         ChangeDisplaySettingsExW(monitor->win32.adapterName,
94                                  NULL, NULL, CDS_FULLSCREEN, NULL);
95         monitor->win32.modeChanged = GL_FALSE;
96     }
97 }
98 
99 
100 //////////////////////////////////////////////////////////////////////////
101 //////                       GLFW platform API                      //////
102 //////////////////////////////////////////////////////////////////////////
103 
_glfwPlatformGetMonitors(int * count)104 _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
105 {
106     int found = 0;
107     _GLFWmonitor** monitors = NULL;
108     DWORD adapterIndex, displayIndex;
109 
110     *count = 0;
111 
112     for (adapterIndex = 0;  ;  adapterIndex++)
113     {
114         DISPLAY_DEVICEW adapter;
115 
116         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
117         adapter.cb = sizeof(DISPLAY_DEVICEW);
118 
119         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
120             break;
121 
122         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
123             continue;
124 
125         for (displayIndex = 0;  ;  displayIndex++)
126         {
127             DISPLAY_DEVICEW display;
128             _GLFWmonitor* monitor;
129             char* name;
130             HDC dc;
131 
132             ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
133             display.cb = sizeof(DISPLAY_DEVICEW);
134 
135             if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
136                 break;
137 
138             name = _glfwCreateUTF8FromWideString(display.DeviceString);
139             if (!name)
140             {
141                 _glfwInputError(GLFW_PLATFORM_ERROR,
142                                 "Win32: Failed to convert string to UTF-8");
143                 continue;
144             }
145 
146             dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL);
147 
148             monitor = _glfwAllocMonitor(name,
149                                         GetDeviceCaps(dc, HORZSIZE),
150                                         GetDeviceCaps(dc, VERTSIZE));
151 
152             DeleteDC(dc);
153             free(name);
154 
155             if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED)
156                 monitor->win32.modesPruned = GL_TRUE;
157 
158             wcscpy(monitor->win32.adapterName, adapter.DeviceName);
159             wcscpy(monitor->win32.displayName, display.DeviceName);
160 
161             WideCharToMultiByte(CP_UTF8, 0,
162                                 adapter.DeviceName, -1,
163                                 monitor->win32.publicAdapterName,
164                                 sizeof(monitor->win32.publicAdapterName),
165                                 NULL, NULL);
166 
167             WideCharToMultiByte(CP_UTF8, 0,
168                                 display.DeviceName, -1,
169                                 monitor->win32.publicDisplayName,
170                                 sizeof(monitor->win32.publicDisplayName),
171                                 NULL, NULL);
172 
173             found++;
174             monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
175             monitors[found - 1] = monitor;
176 
177             if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE &&
178                 displayIndex == 0)
179             {
180                 _GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
181             }
182         }
183     }
184 
185     *count = found;
186     return monitors;
187 }
188 
_glfwPlatformIsSameMonitor(_GLFWmonitor * first,_GLFWmonitor * second)189 GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
190 {
191     return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
192 }
193 
_glfwPlatformGetMonitorPos(_GLFWmonitor * monitor,int * xpos,int * ypos)194 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
195 {
196     DEVMODEW settings;
197     ZeroMemory(&settings, sizeof(DEVMODEW));
198     settings.dmSize = sizeof(DEVMODEW);
199 
200     EnumDisplaySettingsExW(monitor->win32.adapterName,
201                            ENUM_CURRENT_SETTINGS,
202                            &settings,
203                            EDS_ROTATEDMODE);
204 
205     if (xpos)
206         *xpos = settings.dmPosition.x;
207     if (ypos)
208         *ypos = settings.dmPosition.y;
209 }
210 
_glfwPlatformGetVideoModes(_GLFWmonitor * monitor,int * count)211 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
212 {
213     int modeIndex = 0, size = 0;
214     GLFWvidmode* result = NULL;
215 
216     *count = 0;
217 
218     for (;;)
219     {
220         int i;
221         GLFWvidmode mode;
222         DEVMODEW dm;
223 
224         ZeroMemory(&dm, sizeof(DEVMODEW));
225         dm.dmSize = sizeof(DEVMODEW);
226 
227         if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
228             break;
229 
230         modeIndex++;
231 
232         // Skip modes with less than 15 BPP
233         if (dm.dmBitsPerPel < 15)
234             continue;
235 
236         mode.width  = dm.dmPelsWidth;
237         mode.height = dm.dmPelsHeight;
238         mode.refreshRate = dm.dmDisplayFrequency;
239         _glfwSplitBPP(dm.dmBitsPerPel,
240                       &mode.redBits,
241                       &mode.greenBits,
242                       &mode.blueBits);
243 
244         for (i = 0;  i < *count;  i++)
245         {
246             if (_glfwCompareVideoModes(result + i, &mode) == 0)
247                 break;
248         }
249 
250         // Skip duplicate modes
251         if (i < *count)
252             continue;
253 
254         if (monitor->win32.modesPruned)
255         {
256             // Skip modes not supported by the connected displays
257             if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
258                                          &dm,
259                                          NULL,
260                                          CDS_TEST,
261                                          NULL) != DISP_CHANGE_SUCCESSFUL)
262             {
263                 continue;
264             }
265         }
266 
267         if (*count == size)
268         {
269             if (*count)
270                 size *= 2;
271             else
272                 size = 128;
273 
274             result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
275         }
276 
277         (*count)++;
278         result[*count - 1] = mode;
279     }
280 
281     return result;
282 }
283 
_glfwPlatformGetVideoMode(_GLFWmonitor * monitor,GLFWvidmode * mode)284 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
285 {
286     DEVMODEW dm;
287 
288     ZeroMemory(&dm, sizeof(DEVMODEW));
289     dm.dmSize = sizeof(DEVMODEW);
290 
291     EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
292 
293     mode->width  = dm.dmPelsWidth;
294     mode->height = dm.dmPelsHeight;
295     mode->refreshRate = dm.dmDisplayFrequency;
296     _glfwSplitBPP(dm.dmBitsPerPel,
297                   &mode->redBits,
298                   &mode->greenBits,
299                   &mode->blueBits);
300 }
301 
_glfwPlatformGetGammaRamp(_GLFWmonitor * monitor,GLFWgammaramp * ramp)302 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
303 {
304     HDC dc;
305     WORD values[768];
306 
307     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
308     GetDeviceGammaRamp(dc, values);
309     DeleteDC(dc);
310 
311     _glfwAllocGammaArrays(ramp, 256);
312 
313     memcpy(ramp->red,   values +   0, 256 * sizeof(unsigned short));
314     memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
315     memcpy(ramp->blue,  values + 512, 256 * sizeof(unsigned short));
316 }
317 
_glfwPlatformSetGammaRamp(_GLFWmonitor * monitor,const GLFWgammaramp * ramp)318 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
319 {
320     HDC dc;
321     WORD values[768];
322 
323     if (ramp->size != 256)
324     {
325         _glfwInputError(GLFW_PLATFORM_ERROR,
326                         "Win32: Gamma ramp size must be 256");
327         return;
328     }
329 
330     memcpy(values +   0, ramp->red,   256 * sizeof(unsigned short));
331     memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
332     memcpy(values + 512, ramp->blue,  256 * sizeof(unsigned short));
333 
334     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
335     SetDeviceGammaRamp(dc, values);
336     DeleteDC(dc);
337 }
338 
339 
340 //////////////////////////////////////////////////////////////////////////
341 //////                        GLFW native API                       //////
342 //////////////////////////////////////////////////////////////////////////
343 
glfwGetWin32Adapter(GLFWmonitor * handle)344 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
345 {
346     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
347     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
348     return monitor->win32.publicAdapterName;
349 }
350 
glfwGetWin32Monitor(GLFWmonitor * handle)351 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
352 {
353     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
354     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
355     return monitor->win32.publicDisplayName;
356 }
357 
358