• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.2 - 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 <assert.h>
31 #include <math.h>
32 #include <float.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 
37 
38 // Lexically compare video modes, used by qsort
39 //
compareVideoModes(const void * fp,const void * sp)40 static int compareVideoModes(const void* fp, const void* sp)
41 {
42     const GLFWvidmode* fm = fp;
43     const GLFWvidmode* sm = sp;
44     const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
45     const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
46     const int farea = fm->width * fm->height;
47     const int sarea = sm->width * sm->height;
48 
49     // First sort on color bits per pixel
50     if (fbpp != sbpp)
51         return fbpp - sbpp;
52 
53     // Then sort on screen area
54     if (farea != sarea)
55         return farea - sarea;
56 
57     // Lastly sort on refresh rate
58     return fm->refreshRate - sm->refreshRate;
59 }
60 
61 // Retrieves the available modes for the specified monitor
62 //
refreshVideoModes(_GLFWmonitor * monitor)63 static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
64 {
65     int modeCount;
66     GLFWvidmode* modes;
67 
68     if (monitor->modes)
69         return GLFW_TRUE;
70 
71     modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
72     if (!modes)
73         return GLFW_FALSE;
74 
75     qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
76 
77     free(monitor->modes);
78     monitor->modes = modes;
79     monitor->modeCount = modeCount;
80 
81     return GLFW_TRUE;
82 }
83 
84 
85 //////////////////////////////////////////////////////////////////////////
86 //////                         GLFW event API                       //////
87 //////////////////////////////////////////////////////////////////////////
88 
_glfwInputMonitorChange(void)89 void _glfwInputMonitorChange(void)
90 {
91     int i, j, monitorCount = _glfw.monitorCount;
92     _GLFWmonitor** monitors = _glfw.monitors;
93 
94     _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
95 
96     // Re-use still connected monitor objects
97 
98     for (i = 0;  i < _glfw.monitorCount;  i++)
99     {
100         for (j = 0;  j < monitorCount;  j++)
101         {
102             if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j]))
103             {
104                 _glfwFreeMonitor(_glfw.monitors[i]);
105                 _glfw.monitors[i] = monitors[j];
106                 break;
107             }
108         }
109     }
110 
111     // Find and report disconnected monitors (not in the new list)
112 
113     for (i = 0;  i < monitorCount;  i++)
114     {
115         _GLFWwindow* window;
116 
117         for (j = 0;  j < _glfw.monitorCount;  j++)
118         {
119             if (monitors[i] == _glfw.monitors[j])
120                 break;
121         }
122 
123         if (j < _glfw.monitorCount)
124             continue;
125 
126         for (window = _glfw.windowListHead;  window;  window = window->next)
127         {
128             if (window->monitor == monitors[i])
129             {
130                 int width, height;
131                 _glfwPlatformGetWindowSize(window, &width, &height);
132                 _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
133             }
134         }
135 
136         if (_glfw.callbacks.monitor)
137             _glfw.callbacks.monitor((GLFWmonitor*) monitors[i], GLFW_DISCONNECTED);
138     }
139 
140     // Find and report newly connected monitors (not in the old list)
141     // Re-used monitor objects are then removed from the old list to avoid
142     // having them destroyed at the end of this function
143 
144     for (i = 0;  i < _glfw.monitorCount;  i++)
145     {
146         for (j = 0;  j < monitorCount;  j++)
147         {
148             if (_glfw.monitors[i] == monitors[j])
149             {
150                 monitors[j] = NULL;
151                 break;
152             }
153         }
154 
155         if (j < monitorCount)
156             continue;
157 
158         if (_glfw.callbacks.monitor)
159             _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED);
160     }
161 
162     _glfwFreeMonitors(monitors, monitorCount);
163 }
164 
_glfwInputMonitorWindowChange(_GLFWmonitor * monitor,_GLFWwindow * window)165 void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)
166 {
167     monitor->window = window;
168 }
169 
170 
171 //////////////////////////////////////////////////////////////////////////
172 //////                       GLFW internal API                      //////
173 //////////////////////////////////////////////////////////////////////////
174 
_glfwAllocMonitor(const char * name,int widthMM,int heightMM)175 _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
176 {
177     _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
178     monitor->name = strdup(name);
179     monitor->widthMM = widthMM;
180     monitor->heightMM = heightMM;
181 
182     return monitor;
183 }
184 
_glfwFreeMonitor(_GLFWmonitor * monitor)185 void _glfwFreeMonitor(_GLFWmonitor* monitor)
186 {
187     if (monitor == NULL)
188         return;
189 
190     _glfwFreeGammaArrays(&monitor->originalRamp);
191     _glfwFreeGammaArrays(&monitor->currentRamp);
192 
193     free(monitor->modes);
194     free(monitor->name);
195     free(monitor);
196 }
197 
_glfwAllocGammaArrays(GLFWgammaramp * ramp,unsigned int size)198 void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
199 {
200     ramp->red = calloc(size, sizeof(unsigned short));
201     ramp->green = calloc(size, sizeof(unsigned short));
202     ramp->blue = calloc(size, sizeof(unsigned short));
203     ramp->size = size;
204 }
205 
_glfwFreeGammaArrays(GLFWgammaramp * ramp)206 void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
207 {
208     free(ramp->red);
209     free(ramp->green);
210     free(ramp->blue);
211 
212     memset(ramp, 0, sizeof(GLFWgammaramp));
213 }
214 
_glfwFreeMonitors(_GLFWmonitor ** monitors,int count)215 void _glfwFreeMonitors(_GLFWmonitor** monitors, int count)
216 {
217     int i;
218 
219     for (i = 0;  i < count;  i++)
220         _glfwFreeMonitor(monitors[i]);
221 
222     free(monitors);
223 }
224 
_glfwChooseVideoMode(_GLFWmonitor * monitor,const GLFWvidmode * desired)225 const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
226                                         const GLFWvidmode* desired)
227 {
228     int i;
229     unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
230     unsigned int rateDiff, leastRateDiff = UINT_MAX;
231     unsigned int colorDiff, leastColorDiff = UINT_MAX;
232     const GLFWvidmode* current;
233     const GLFWvidmode* closest = NULL;
234 
235     if (!refreshVideoModes(monitor))
236         return NULL;
237 
238     for (i = 0;  i < monitor->modeCount;  i++)
239     {
240         current = monitor->modes + i;
241 
242         colorDiff = 0;
243 
244         if (desired->redBits != GLFW_DONT_CARE)
245             colorDiff += abs(current->redBits - desired->redBits);
246         if (desired->greenBits != GLFW_DONT_CARE)
247             colorDiff += abs(current->greenBits - desired->greenBits);
248         if (desired->blueBits != GLFW_DONT_CARE)
249             colorDiff += abs(current->blueBits - desired->blueBits);
250 
251         sizeDiff = abs((current->width - desired->width) *
252                        (current->width - desired->width) +
253                        (current->height - desired->height) *
254                        (current->height - desired->height));
255 
256         if (desired->refreshRate != GLFW_DONT_CARE)
257             rateDiff = abs(current->refreshRate - desired->refreshRate);
258         else
259             rateDiff = UINT_MAX - current->refreshRate;
260 
261         if ((colorDiff < leastColorDiff) ||
262             (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
263             (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
264         {
265             closest = current;
266             leastSizeDiff = sizeDiff;
267             leastRateDiff = rateDiff;
268             leastColorDiff = colorDiff;
269         }
270     }
271 
272     return closest;
273 }
274 
_glfwCompareVideoModes(const GLFWvidmode * fm,const GLFWvidmode * sm)275 int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
276 {
277     return compareVideoModes(fm, sm);
278 }
279 
_glfwSplitBPP(int bpp,int * red,int * green,int * blue)280 void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
281 {
282     int delta;
283 
284     // We assume that by 32 the user really meant 24
285     if (bpp == 32)
286         bpp = 24;
287 
288     // Convert "bits per pixel" to red, green & blue sizes
289 
290     *red = *green = *blue = bpp / 3;
291     delta = bpp - (*red * 3);
292     if (delta >= 1)
293         *green = *green + 1;
294 
295     if (delta == 2)
296         *red = *red + 1;
297 }
298 
299 
300 //////////////////////////////////////////////////////////////////////////
301 //////                        GLFW public API                       //////
302 //////////////////////////////////////////////////////////////////////////
303 
glfwGetMonitors(int * count)304 GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
305 {
306     assert(count != NULL);
307     *count = 0;
308 
309     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
310 
311     *count = _glfw.monitorCount;
312     return (GLFWmonitor**) _glfw.monitors;
313 }
314 
glfwGetPrimaryMonitor(void)315 GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
316 {
317     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
318 
319     if (!_glfw.monitorCount)
320         return NULL;
321 
322     return (GLFWmonitor*) _glfw.monitors[0];
323 }
324 
glfwGetMonitorPos(GLFWmonitor * handle,int * xpos,int * ypos)325 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
326 {
327     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
328     assert(monitor != NULL);
329 
330     if (xpos)
331         *xpos = 0;
332     if (ypos)
333         *ypos = 0;
334 
335     _GLFW_REQUIRE_INIT();
336 
337     _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
338 }
339 
glfwGetMonitorPhysicalSize(GLFWmonitor * handle,int * widthMM,int * heightMM)340 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
341 {
342     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
343     assert(monitor != NULL);
344 
345     if (widthMM)
346         *widthMM = 0;
347     if (heightMM)
348         *heightMM = 0;
349 
350     _GLFW_REQUIRE_INIT();
351 
352     if (widthMM)
353         *widthMM = monitor->widthMM;
354     if (heightMM)
355         *heightMM = monitor->heightMM;
356 }
357 
glfwGetMonitorName(GLFWmonitor * handle)358 GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
359 {
360     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
361     assert(monitor != NULL);
362 
363     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
364     return monitor->name;
365 }
366 
glfwSetMonitorCallback(GLFWmonitorfun cbfun)367 GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
368 {
369     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
370     _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
371     return cbfun;
372 }
373 
glfwGetVideoModes(GLFWmonitor * handle,int * count)374 GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
375 {
376     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
377     assert(monitor != NULL);
378     assert(count != NULL);
379 
380     *count = 0;
381 
382     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
383 
384     if (!refreshVideoModes(monitor))
385         return NULL;
386 
387     *count = monitor->modeCount;
388     return monitor->modes;
389 }
390 
glfwGetVideoMode(GLFWmonitor * handle)391 GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
392 {
393     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
394     assert(monitor != NULL);
395 
396     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
397 
398     _glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
399     return &monitor->currentMode;
400 }
401 
glfwSetGamma(GLFWmonitor * handle,float gamma)402 GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
403 {
404     int i;
405     unsigned short values[256];
406     GLFWgammaramp ramp;
407 
408     _GLFW_REQUIRE_INIT();
409 
410     if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
411     {
412         _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
413         return;
414     }
415 
416     for (i = 0;  i < 256;  i++)
417     {
418         double value;
419 
420         // Calculate intensity
421         value = i / 255.0;
422         // Apply gamma curve
423         value = pow(value, 1.0 / gamma) * 65535.0 + 0.5;
424 
425         // Clamp to value range
426         if (value > 65535.0)
427             value = 65535.0;
428 
429         values[i] = (unsigned short) value;
430     }
431 
432     ramp.red = values;
433     ramp.green = values;
434     ramp.blue = values;
435     ramp.size = 256;
436 
437     glfwSetGammaRamp(handle, &ramp);
438 }
439 
glfwGetGammaRamp(GLFWmonitor * handle)440 GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
441 {
442     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
443     assert(monitor != NULL);
444 
445     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
446 
447     _glfwFreeGammaArrays(&monitor->currentRamp);
448     _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
449 
450     return &monitor->currentRamp;
451 }
452 
glfwSetGammaRamp(GLFWmonitor * handle,const GLFWgammaramp * ramp)453 GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
454 {
455     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
456     assert(monitor != NULL);
457     assert(ramp != NULL);
458     assert(ramp->red != NULL);
459     assert(ramp->green != NULL);
460     assert(ramp->blue != NULL);
461 
462     if (ramp->size <= 0)
463     {
464         _glfwInputError(GLFW_INVALID_VALUE,
465                         "Invalid gamma ramp size %i",
466                         ramp->size);
467         return;
468     }
469 
470     _GLFW_REQUIRE_INIT();
471 
472     if (!monitor->originalRamp.size)
473         _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
474 
475     _glfwPlatformSetGammaRamp(monitor, ramp);
476 }
477 
478