• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.2 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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 
36 // Create monitor from an adapter and (optionally) a display
37 //
createMonitor(DISPLAY_DEVICEW * adapter,DISPLAY_DEVICEW * display)38 static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
39                                    DISPLAY_DEVICEW* display)
40 {
41     _GLFWmonitor* monitor;
42     char* name;
43     HDC dc;
44 
45     if (display)
46         name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
47     else
48         name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
49     if (!name)
50     {
51         _glfwInputError(GLFW_PLATFORM_ERROR,
52                         "Win32: Failed to convert string to UTF-8");
53         return NULL;
54     }
55 
56     dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
57 
58     monitor = _glfwAllocMonitor(name,
59                                 GetDeviceCaps(dc, HORZSIZE),
60                                 GetDeviceCaps(dc, VERTSIZE));
61 
62     DeleteDC(dc);
63     free(name);
64 
65     if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
66         monitor->win32.modesPruned = GLFW_TRUE;
67 
68     wcscpy(monitor->win32.adapterName, adapter->DeviceName);
69     WideCharToMultiByte(CP_UTF8, 0,
70                         adapter->DeviceName, -1,
71                         monitor->win32.publicAdapterName,
72                         sizeof(monitor->win32.publicAdapterName),
73                         NULL, NULL);
74 
75     if (display)
76     {
77         wcscpy(monitor->win32.displayName, display->DeviceName);
78         WideCharToMultiByte(CP_UTF8, 0,
79                             display->DeviceName, -1,
80                             monitor->win32.publicDisplayName,
81                             sizeof(monitor->win32.publicDisplayName),
82                             NULL, NULL);
83     }
84 
85     return monitor;
86 }
87 
88 
89 //////////////////////////////////////////////////////////////////////////
90 //////                       GLFW internal API                      //////
91 //////////////////////////////////////////////////////////////////////////
92 
93 // Change the current video mode
94 //
_glfwSetVideoModeWin32(_GLFWmonitor * monitor,const GLFWvidmode * desired)95 GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
96 {
97     GLFWvidmode current;
98     const GLFWvidmode* best;
99     DEVMODEW dm;
100 
101     best = _glfwChooseVideoMode(monitor, desired);
102     _glfwPlatformGetVideoMode(monitor, &current);
103     if (_glfwCompareVideoModes(&current, best) == 0)
104         return GLFW_TRUE;
105 
106     ZeroMemory(&dm, sizeof(dm));
107     dm.dmSize = sizeof(DEVMODEW);
108     dm.dmFields           = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
109                             DM_DISPLAYFREQUENCY;
110     dm.dmPelsWidth        = best->width;
111     dm.dmPelsHeight       = best->height;
112     dm.dmBitsPerPel       = best->redBits + best->greenBits + best->blueBits;
113     dm.dmDisplayFrequency = best->refreshRate;
114 
115     if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
116         dm.dmBitsPerPel = 32;
117 
118     if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
119                                  &dm,
120                                  NULL,
121                                  CDS_FULLSCREEN,
122                                  NULL) != DISP_CHANGE_SUCCESSFUL)
123     {
124         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
125         return GLFW_FALSE;
126     }
127 
128     monitor->win32.modeChanged = GLFW_TRUE;
129     return GLFW_TRUE;
130 }
131 
132 // Restore the previously saved (original) video mode
133 //
_glfwRestoreVideoModeWin32(_GLFWmonitor * monitor)134 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
135 {
136     if (monitor->win32.modeChanged)
137     {
138         ChangeDisplaySettingsExW(monitor->win32.adapterName,
139                                  NULL, NULL, CDS_FULLSCREEN, NULL);
140         monitor->win32.modeChanged = GLFW_FALSE;
141     }
142 }
143 
144 
145 //////////////////////////////////////////////////////////////////////////
146 //////                       GLFW platform API                      //////
147 //////////////////////////////////////////////////////////////////////////
148 
_glfwPlatformGetMonitors(int * count)149 _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
150 {
151     int found = 0;
152     DWORD adapterIndex, displayIndex, primaryIndex = 0;
153     DISPLAY_DEVICEW adapter, display;
154     GLFWbool hasDisplays = GLFW_FALSE;
155     _GLFWmonitor** monitors = NULL;
156 
157     *count = 0;
158 
159     // HACK: Check if any active adapters have connected displays
160     //       If not, this is a headless system or a VMware guest
161 
162     for (adapterIndex = 0;  ;  adapterIndex++)
163     {
164         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
165         adapter.cb = sizeof(DISPLAY_DEVICEW);
166 
167         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
168             break;
169 
170         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
171             continue;
172 
173         ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
174         display.cb = sizeof(DISPLAY_DEVICEW);
175 
176         if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0))
177         {
178             hasDisplays = GLFW_TRUE;
179             break;
180         }
181     }
182 
183     for (adapterIndex = 0;  ;  adapterIndex++)
184     {
185         ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
186         adapter.cb = sizeof(DISPLAY_DEVICEW);
187 
188         if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
189             break;
190 
191         if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
192             continue;
193 
194         if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
195             primaryIndex = found;
196 
197         if (hasDisplays)
198         {
199             for (displayIndex = 0;  ;  displayIndex++)
200             {
201                 ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
202                 display.cb = sizeof(DISPLAY_DEVICEW);
203 
204                 if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
205                     break;
206 
207                 found++;
208                 monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
209                 monitors[found - 1] = createMonitor(&adapter, &display);
210             }
211         }
212         else
213         {
214             found++;
215             monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
216             monitors[found - 1] = createMonitor(&adapter, NULL);
217         }
218     }
219 
220     _GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]);
221 
222     *count = found;
223     return monitors;
224 }
225 
_glfwPlatformIsSameMonitor(_GLFWmonitor * first,_GLFWmonitor * second)226 GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
227 {
228     if (wcslen(first->win32.displayName))
229         return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
230     else
231         return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0;
232 }
233 
_glfwPlatformGetMonitorPos(_GLFWmonitor * monitor,int * xpos,int * ypos)234 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
235 {
236     DEVMODEW settings;
237     ZeroMemory(&settings, sizeof(DEVMODEW));
238     settings.dmSize = sizeof(DEVMODEW);
239 
240     EnumDisplaySettingsExW(monitor->win32.adapterName,
241                            ENUM_CURRENT_SETTINGS,
242                            &settings,
243                            EDS_ROTATEDMODE);
244 
245     if (xpos)
246         *xpos = settings.dmPosition.x;
247     if (ypos)
248         *ypos = settings.dmPosition.y;
249 }
250 
_glfwPlatformGetVideoModes(_GLFWmonitor * monitor,int * count)251 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
252 {
253     int modeIndex = 0, size = 0;
254     GLFWvidmode* result = NULL;
255 
256     *count = 0;
257 
258     for (;;)
259     {
260         int i;
261         GLFWvidmode mode;
262         DEVMODEW dm;
263 
264         ZeroMemory(&dm, sizeof(DEVMODEW));
265         dm.dmSize = sizeof(DEVMODEW);
266 
267         if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
268             break;
269 
270         modeIndex++;
271 
272         // Skip modes with less than 15 BPP
273         if (dm.dmBitsPerPel < 15)
274             continue;
275 
276         mode.width  = dm.dmPelsWidth;
277         mode.height = dm.dmPelsHeight;
278         mode.refreshRate = dm.dmDisplayFrequency;
279         _glfwSplitBPP(dm.dmBitsPerPel,
280                       &mode.redBits,
281                       &mode.greenBits,
282                       &mode.blueBits);
283 
284         for (i = 0;  i < *count;  i++)
285         {
286             if (_glfwCompareVideoModes(result + i, &mode) == 0)
287                 break;
288         }
289 
290         // Skip duplicate modes
291         if (i < *count)
292             continue;
293 
294         if (monitor->win32.modesPruned)
295         {
296             // Skip modes not supported by the connected displays
297             if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
298                                          &dm,
299                                          NULL,
300                                          CDS_TEST,
301                                          NULL) != DISP_CHANGE_SUCCESSFUL)
302             {
303                 continue;
304             }
305         }
306 
307         if (*count == size)
308         {
309             size += 128;
310             result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
311         }
312 
313         (*count)++;
314         result[*count - 1] = mode;
315     }
316 
317     if (!*count)
318     {
319         // HACK: Report the current mode if no valid modes were found
320         result = calloc(1, sizeof(GLFWvidmode));
321         _glfwPlatformGetVideoMode(monitor, result);
322         *count = 1;
323     }
324 
325     return result;
326 }
327 
_glfwPlatformGetVideoMode(_GLFWmonitor * monitor,GLFWvidmode * mode)328 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
329 {
330     DEVMODEW dm;
331 
332     ZeroMemory(&dm, sizeof(DEVMODEW));
333     dm.dmSize = sizeof(DEVMODEW);
334 
335     EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
336 
337     mode->width  = dm.dmPelsWidth;
338     mode->height = dm.dmPelsHeight;
339     mode->refreshRate = dm.dmDisplayFrequency;
340     _glfwSplitBPP(dm.dmBitsPerPel,
341                   &mode->redBits,
342                   &mode->greenBits,
343                   &mode->blueBits);
344 }
345 
_glfwPlatformGetGammaRamp(_GLFWmonitor * monitor,GLFWgammaramp * ramp)346 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
347 {
348     HDC dc;
349     WORD values[768];
350 
351     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
352     GetDeviceGammaRamp(dc, values);
353     DeleteDC(dc);
354 
355     _glfwAllocGammaArrays(ramp, 256);
356 
357     memcpy(ramp->red,   values +   0, 256 * sizeof(unsigned short));
358     memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
359     memcpy(ramp->blue,  values + 512, 256 * sizeof(unsigned short));
360 }
361 
_glfwPlatformSetGammaRamp(_GLFWmonitor * monitor,const GLFWgammaramp * ramp)362 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
363 {
364     HDC dc;
365     WORD values[768];
366 
367     if (ramp->size != 256)
368     {
369         _glfwInputError(GLFW_PLATFORM_ERROR,
370                         "Win32: Gamma ramp size must be 256");
371         return;
372     }
373 
374     memcpy(values +   0, ramp->red,   256 * sizeof(unsigned short));
375     memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
376     memcpy(values + 512, ramp->blue,  256 * sizeof(unsigned short));
377 
378     dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
379     SetDeviceGammaRamp(dc, values);
380     DeleteDC(dc);
381 }
382 
383 
384 //////////////////////////////////////////////////////////////////////////
385 //////                        GLFW native API                       //////
386 //////////////////////////////////////////////////////////////////////////
387 
glfwGetWin32Adapter(GLFWmonitor * handle)388 GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
389 {
390     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
391     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
392     return monitor->win32.publicAdapterName;
393 }
394 
glfwGetWin32Monitor(GLFWmonitor * handle)395 GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
396 {
397     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
398     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
399     return monitor->win32.publicDisplayName;
400 }
401 
402