1 //========================================================================
2 // GLFW 3.3 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2016 Camilla Löwy <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 
89 // Notifies shared code of a monitor connection or disconnection
90 //
_glfwInputMonitor(_GLFWmonitor * monitor,int action,int placement)91 void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
92 {
93     if (action == GLFW_CONNECTED)
94     {
95         _glfw.monitorCount++;
96         _glfw.monitors =
97             realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount);
98 
99         if (placement == _GLFW_INSERT_FIRST)
100         {
101             memmove(_glfw.monitors + 1,
102                     _glfw.monitors,
103                     (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
104             _glfw.monitors[0] = monitor;
105         }
106         else
107             _glfw.monitors[_glfw.monitorCount - 1] = monitor;
108     }
109     else if (action == GLFW_DISCONNECTED)
110     {
111         int i;
112         _GLFWwindow* window;
113 
114         for (window = _glfw.windowListHead;  window;  window = window->next)
115         {
116             if (window->monitor == monitor)
117             {
118                 int width, height, xoff, yoff;
119                 _glfwPlatformGetWindowSize(window, &width, &height);
120                 _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
121                 _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL);
122                 _glfwPlatformSetWindowPos(window, xoff, yoff);
123             }
124         }
125 
126         for (i = 0;  i < _glfw.monitorCount;  i++)
127         {
128             if (_glfw.monitors[i] == monitor)
129             {
130                 _glfw.monitorCount--;
131                 memmove(_glfw.monitors + i,
132                         _glfw.monitors + i + 1,
133                         (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
134                 break;
135             }
136         }
137     }
138 
139     if (_glfw.callbacks.monitor)
140         _glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
141 
142     if (action == GLFW_DISCONNECTED)
143         _glfwFreeMonitor(monitor);
144 }
145 
146 // Notifies shared code that a full screen window has acquired or released
147 // a monitor
148 //
_glfwInputMonitorWindow(_GLFWmonitor * monitor,_GLFWwindow * window)149 void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
150 {
151     monitor->window = window;
152 }
153 
154 
155 //////////////////////////////////////////////////////////////////////////
156 //////                       GLFW internal API                      //////
157 //////////////////////////////////////////////////////////////////////////
158 
159 // Allocates and returns a monitor object with the specified name and dimensions
160 //
_glfwAllocMonitor(const char * name,int widthMM,int heightMM)161 _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
162 {
163     _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
164     monitor->widthMM = widthMM;
165     monitor->heightMM = heightMM;
166 
167     if (name)
168         monitor->name = _glfw_strdup(name);
169 
170     return monitor;
171 }
172 
173 // Frees a monitor object and any data associated with it
174 //
_glfwFreeMonitor(_GLFWmonitor * monitor)175 void _glfwFreeMonitor(_GLFWmonitor* monitor)
176 {
177     if (monitor == NULL)
178         return;
179 
180     _glfwPlatformFreeMonitor(monitor);
181 
182     _glfwFreeGammaArrays(&monitor->originalRamp);
183     _glfwFreeGammaArrays(&monitor->currentRamp);
184 
185     free(monitor->modes);
186     free(monitor->name);
187     free(monitor);
188 }
189 
190 // Allocates red, green and blue value arrays of the specified size
191 //
_glfwAllocGammaArrays(GLFWgammaramp * ramp,unsigned int size)192 void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
193 {
194     ramp->red = calloc(size, sizeof(unsigned short));
195     ramp->green = calloc(size, sizeof(unsigned short));
196     ramp->blue = calloc(size, sizeof(unsigned short));
197     ramp->size = size;
198 }
199 
200 // Frees the red, green and blue value arrays and clears the struct
201 //
_glfwFreeGammaArrays(GLFWgammaramp * ramp)202 void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
203 {
204     free(ramp->red);
205     free(ramp->green);
206     free(ramp->blue);
207 
208     memset(ramp, 0, sizeof(GLFWgammaramp));
209 }
210 
211 // Chooses the video mode most closely matching the desired one
212 //
_glfwChooseVideoMode(_GLFWmonitor * monitor,const GLFWvidmode * desired)213 const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
214                                         const GLFWvidmode* desired)
215 {
216     int i;
217     unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
218     unsigned int rateDiff, leastRateDiff = UINT_MAX;
219     unsigned int colorDiff, leastColorDiff = UINT_MAX;
220     const GLFWvidmode* current;
221     const GLFWvidmode* closest = NULL;
222 
223     if (!refreshVideoModes(monitor))
224         return NULL;
225 
226     for (i = 0;  i < monitor->modeCount;  i++)
227     {
228         current = monitor->modes + i;
229 
230         colorDiff = 0;
231 
232         if (desired->redBits != GLFW_DONT_CARE)
233             colorDiff += abs(current->redBits - desired->redBits);
234         if (desired->greenBits != GLFW_DONT_CARE)
235             colorDiff += abs(current->greenBits - desired->greenBits);
236         if (desired->blueBits != GLFW_DONT_CARE)
237             colorDiff += abs(current->blueBits - desired->blueBits);
238 
239         sizeDiff = abs((current->width - desired->width) *
240                        (current->width - desired->width) +
241                        (current->height - desired->height) *
242                        (current->height - desired->height));
243 
244         if (desired->refreshRate != GLFW_DONT_CARE)
245             rateDiff = abs(current->refreshRate - desired->refreshRate);
246         else
247             rateDiff = UINT_MAX - current->refreshRate;
248 
249         if ((colorDiff < leastColorDiff) ||
250             (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
251             (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
252         {
253             closest = current;
254             leastSizeDiff = sizeDiff;
255             leastRateDiff = rateDiff;
256             leastColorDiff = colorDiff;
257         }
258     }
259 
260     return closest;
261 }
262 
263 // Performs lexical comparison between two @ref GLFWvidmode structures
264 //
_glfwCompareVideoModes(const GLFWvidmode * fm,const GLFWvidmode * sm)265 int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
266 {
267     return compareVideoModes(fm, sm);
268 }
269 
270 // Splits a color depth into red, green and blue bit depths
271 //
_glfwSplitBPP(int bpp,int * red,int * green,int * blue)272 void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
273 {
274     int delta;
275 
276     // We assume that by 32 the user really meant 24
277     if (bpp == 32)
278         bpp = 24;
279 
280     // Convert "bits per pixel" to red, green & blue sizes
281 
282     *red = *green = *blue = bpp / 3;
283     delta = bpp - (*red * 3);
284     if (delta >= 1)
285         *green = *green + 1;
286 
287     if (delta == 2)
288         *red = *red + 1;
289 }
290 
291 
292 //////////////////////////////////////////////////////////////////////////
293 //////                        GLFW public API                       //////
294 //////////////////////////////////////////////////////////////////////////
295 
glfwGetMonitors(int * count)296 GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
297 {
298     assert(count != NULL);
299 
300     *count = 0;
301 
302     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
303 
304     *count = _glfw.monitorCount;
305     return (GLFWmonitor**) _glfw.monitors;
306 }
307 
glfwGetPrimaryMonitor(void)308 GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
309 {
310     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
311 
312     if (!_glfw.monitorCount)
313         return NULL;
314 
315     return (GLFWmonitor*) _glfw.monitors[0];
316 }
317 
glfwGetMonitorPos(GLFWmonitor * handle,int * xpos,int * ypos)318 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
319 {
320     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
321     assert(monitor != NULL);
322 
323     if (xpos)
324         *xpos = 0;
325     if (ypos)
326         *ypos = 0;
327 
328     _GLFW_REQUIRE_INIT();
329 
330     _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
331 }
332 
glfwGetMonitorPhysicalSize(GLFWmonitor * handle,int * widthMM,int * heightMM)333 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
334 {
335     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
336     assert(monitor != NULL);
337 
338     if (widthMM)
339         *widthMM = 0;
340     if (heightMM)
341         *heightMM = 0;
342 
343     _GLFW_REQUIRE_INIT();
344 
345     if (widthMM)
346         *widthMM = monitor->widthMM;
347     if (heightMM)
348         *heightMM = monitor->heightMM;
349 }
350 
glfwGetMonitorContentScale(GLFWmonitor * handle,float * xscale,float * yscale)351 GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
352                                         float* xscale, float* yscale)
353 {
354     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
355     assert(monitor != NULL);
356 
357     if (xscale)
358         *xscale = 0.f;
359     if (yscale)
360         *yscale = 0.f;
361 
362     _GLFW_REQUIRE_INIT();
363     _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
364 }
365 
glfwGetMonitorName(GLFWmonitor * handle)366 GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
367 {
368     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
369     assert(monitor != NULL);
370 
371     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
372     return monitor->name;
373 }
374 
glfwSetMonitorUserPointer(GLFWmonitor * handle,void * pointer)375 GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
376 {
377     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
378     assert(monitor != NULL);
379 
380     _GLFW_REQUIRE_INIT();
381     monitor->userPointer = pointer;
382 }
383 
glfwGetMonitorUserPointer(GLFWmonitor * handle)384 GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
385 {
386     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
387     assert(monitor != NULL);
388 
389     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
390     return monitor->userPointer;
391 }
392 
glfwSetMonitorCallback(GLFWmonitorfun cbfun)393 GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
394 {
395     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
396     _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
397     return cbfun;
398 }
399 
glfwGetVideoModes(GLFWmonitor * handle,int * count)400 GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
401 {
402     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
403     assert(monitor != NULL);
404     assert(count != NULL);
405 
406     *count = 0;
407 
408     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
409 
410     if (!refreshVideoModes(monitor))
411         return NULL;
412 
413     *count = monitor->modeCount;
414     return monitor->modes;
415 }
416 
glfwGetVideoMode(GLFWmonitor * handle)417 GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
418 {
419     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
420     assert(monitor != NULL);
421 
422     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
423 
424     _glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
425     return &monitor->currentMode;
426 }
427 
glfwSetGamma(GLFWmonitor * handle,float gamma)428 GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
429 {
430     int i;
431     unsigned short values[256];
432     GLFWgammaramp ramp;
433     assert(handle != NULL);
434     assert(gamma == gamma);
435     assert(gamma >= 0.f);
436     assert(gamma <= FLT_MAX);
437 
438     _GLFW_REQUIRE_INIT();
439 
440     if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
441     {
442         _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
443         return;
444     }
445 
446     for (i = 0;  i < 256;  i++)
447     {
448         float value;
449 
450         // Calculate intensity
451         value = i / 255.f;
452         // Apply gamma curve
453         value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
454 
455         // Clamp to value range
456         if (value > 65535.f)
457             value = 65535.f;
458 
459         values[i] = (unsigned short) value;
460     }
461 
462     ramp.red = values;
463     ramp.green = values;
464     ramp.blue = values;
465     ramp.size = 256;
466 
467     glfwSetGammaRamp(handle, &ramp);
468 }
469 
glfwGetGammaRamp(GLFWmonitor * handle)470 GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
471 {
472     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
473     assert(monitor != NULL);
474 
475     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
476 
477     _glfwFreeGammaArrays(&monitor->currentRamp);
478     _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
479 
480     return &monitor->currentRamp;
481 }
482 
glfwSetGammaRamp(GLFWmonitor * handle,const GLFWgammaramp * ramp)483 GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
484 {
485     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
486     assert(monitor != NULL);
487     assert(ramp != NULL);
488     assert(ramp->size > 0);
489     assert(ramp->red != NULL);
490     assert(ramp->green != NULL);
491     assert(ramp->blue != NULL);
492 
493     if (ramp->size <= 0)
494     {
495         _glfwInputError(GLFW_INVALID_VALUE,
496                         "Invalid gamma ramp size %i",
497                         ramp->size);
498         return;
499     }
500 
501     _GLFW_REQUIRE_INIT();
502 
503     if (!monitor->originalRamp.size)
504         _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
505 
506     _glfwPlatformSetGammaRamp(monitor, ramp);
507 }
508 
509