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, ¤t);
58 if (_glfwCompareVideoModes(¤t, 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