1 /// Translated from C to D
2 module glfw3.monitor;
3 
4 extern(C): @nogc: nothrow: __gshared:
5 //========================================================================
6 // GLFW 3.3 - www.glfw.org
7 //------------------------------------------------------------------------
8 // Copyright (c) 2002-2006 Marcus Geelnard
9 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
10 //
11 // This software is provided 'as-is', without any express or implied
12 // warranty. In no event will the authors be held liable for any damages
13 // arising from the use of this software.
14 //
15 // Permission is granted to anyone to use this software for any purpose,
16 // including commercial applications, and to alter it and redistribute it
17 // freely, subject to the following restrictions:
18 //
19 // 1. The origin of this software must not be misrepresented; you must not
20 //    claim that you wrote the original software. If you use this software
21 //    in a product, an acknowledgment in the product documentation would
22 //    be appreciated but is not required.
23 //
24 // 2. Altered source versions must be plainly marked as such, and must not
25 //    be misrepresented as being the original software.
26 //
27 // 3. This notice may not be removed or altered from any source
28 //    distribution.
29 //
30 //========================================================================
31 // Please use C89 style variable declarations in this file because VS 2010
32 //========================================================================
33 
34 import glfw3.internal;
35 
36 import core.stdc.assert_;
37 import core.stdc.math;
38 import core.stdc.string;
39 import core.stdc.stdlib;
40 import core.stdc.limits;
41 
42 // Lexically compare video modes, used by qsort
43 //
44 private int compareVideoModes(const(void)* fp, const(void)* sp) {
45     auto fm = cast(const(GLFWvidmode)*) fp;
46     auto sm = cast(const(GLFWvidmode)*) sp;
47     const(int) fbpp = fm.redBits + fm.greenBits + fm.blueBits;
48     const(int) sbpp = sm.redBits + sm.greenBits + sm.blueBits;
49     const(int) farea = fm.width * fm.height;
50     const(int) sarea = sm.width * sm.height;
51 
52     // First sort on color bits per pixel
53     if (fbpp != sbpp)
54         return fbpp - sbpp;
55 
56     // Then sort on screen area
57     if (farea != sarea)
58         return farea - sarea;
59 
60     // Then sort on width
61     if (fm.width != sm.width)
62         return fm.width - sm.width;
63 
64     // Lastly sort on refresh rate
65     return fm.refreshRate - sm.refreshRate;
66 }
67 
68 // Retrieves the available modes for the specified monitor
69 //
70 private GLFWbool refreshVideoModes(_GLFWmonitor* monitor) {
71     int modeCount;
72     GLFWvidmode* modes;
73 
74     if (monitor.modes)
75         return GLFW_TRUE;
76 
77     modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
78     if (!modes)
79         return GLFW_FALSE;
80 
81     qsort(modes, modeCount, GLFWvidmode.sizeof, &compareVideoModes);
82 
83     free(monitor.modes);
84     monitor.modes = modes;
85     monitor.modeCount = modeCount;
86 
87     return GLFW_TRUE;
88 }
89 
90 
91 //////////////////////////////////////////////////////////////////////////
92 //////                         GLFW event API                       //////
93 //////////////////////////////////////////////////////////////////////////
94 
95 // Notifies shared code of a monitor connection or disconnection
96 //
97 void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) {
98     if (action == GLFW_CONNECTED)
99     {
100         _glfw.monitorCount++;
101         _glfw.monitors =
102             cast(_GLFWmonitor**) realloc(_glfw.monitors, (_GLFWmonitor*).sizeof * _glfw.monitorCount);
103 
104         if (placement == _GLFW_INSERT_FIRST)
105         {
106             memmove(_glfw.monitors + 1,
107                     _glfw.monitors,
108                     (cast(size_t) _glfw.monitorCount - 1) * (_GLFWmonitor*).sizeof);
109             _glfw.monitors[0] = monitor;
110         }
111         else
112             _glfw.monitors[_glfw.monitorCount - 1] = monitor;
113     }
114     else if (action == GLFW_DISCONNECTED)
115     {
116         int i;
117         _GLFWwindow* window;
118 
119         for (window = _glfw.windowListHead;  window;  window = window.next)
120         {
121             if (window.monitor == monitor)
122             {
123                 int width;int height;int xoff;int yoff;
124                 _glfwPlatformGetWindowSize(window, &width, &height);
125                 _glfwPlatformSetWindowMonitor(window, null, 0, 0, width, height, 0);
126                 _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, null, null);
127                 _glfwPlatformSetWindowPos(window, xoff, yoff);
128             }
129         }
130 
131         for (i = 0;  i < _glfw.monitorCount;  i++)
132         {
133             if (_glfw.monitors[i] == monitor)
134             {
135                 _glfw.monitorCount--;
136                 memmove(_glfw.monitors + i,
137                         _glfw.monitors + i + 1,
138                         (cast(size_t) _glfw.monitorCount - i) * (_GLFWmonitor*).sizeof);
139                 break;
140             }
141         }
142     }
143 
144     if (_glfw.callbacks.monitor)
145         _glfw.callbacks.monitor(cast(GLFWmonitor*) monitor, action);
146 
147     if (action == GLFW_DISCONNECTED)
148         _glfwFreeMonitor(monitor);
149 }
150 
151 // Notifies shared code that a full screen window has acquired or released
152 // a monitor
153 //
154 void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) {
155     monitor.window = window;
156 }
157 
158 
159 //////////////////////////////////////////////////////////////////////////
160 //////                       GLFW internal API                      //////
161 //////////////////////////////////////////////////////////////////////////
162 
163 // Allocates and returns a monitor object with the specified name and dimensions
164 //
165 _GLFWmonitor* _glfwAllocMonitor(const(char)* name, int widthMM, int heightMM) {
166     auto monitor = cast(_GLFWmonitor*) calloc(1, _GLFWmonitor.sizeof);
167     monitor.widthMM = widthMM;
168     monitor.heightMM = heightMM;
169 
170     if (name)
171         monitor.name = _glfw_strdup(name);
172 
173     return monitor;
174 }
175 
176 // Frees a monitor object and any data associated with it
177 //
178 void _glfwFreeMonitor(_GLFWmonitor* monitor) {
179     if (monitor == null)
180         return;
181 
182     _glfwPlatformFreeMonitor(monitor);
183 
184     _glfwFreeGammaArrays(&monitor.originalRamp);
185     _glfwFreeGammaArrays(&monitor.currentRamp);
186 
187     free(monitor.modes);
188     free(monitor.name);
189     free(monitor);
190 }
191 
192 // Allocates red, green and blue value arrays of the specified size
193 //
194 void _glfwAllocGammaArrays(GLFWgammaramp* ramp, uint size) {
195     ramp.red =   cast(ushort*) calloc(size, ushort.sizeof);
196     ramp.green = cast(ushort*) calloc(size, ushort.sizeof);
197     ramp.blue =  cast(ushort*) calloc(size, ushort.sizeof);
198     ramp.size = size;
199 }
200 
201 // Frees the red, green and blue value arrays and clears the struct
202 //
203 void _glfwFreeGammaArrays(GLFWgammaramp* ramp) {
204     free(ramp.red);
205     free(ramp.green);
206     free(ramp.blue);
207 
208     memset(ramp, 0, GLFWgammaramp.sizeof);
209 }
210 
211 // Chooses the video mode most closely matching the desired one
212 //
213 const(GLFWvidmode)* _glfwChooseVideoMode(_GLFWmonitor* monitor, const(GLFWvidmode)* desired) {
214     int i;
215     uint sizeDiff;uint leastSizeDiff = UINT_MAX;
216     uint rateDiff;uint leastRateDiff = UINT_MAX;
217     uint colorDiff;uint leastColorDiff = UINT_MAX;
218     const(GLFWvidmode)* current;
219     const(GLFWvidmode)* closest = null;
220 
221     if (!refreshVideoModes(monitor))
222         return null;
223 
224     for (i = 0;  i < monitor.modeCount;  i++)
225     {
226         current = monitor.modes + i;
227 
228         colorDiff = 0;
229 
230         if (desired.redBits != GLFW_DONT_CARE)
231             colorDiff += abs(current.redBits - desired.redBits);
232         if (desired.greenBits != GLFW_DONT_CARE)
233             colorDiff += abs(current.greenBits - desired.greenBits);
234         if (desired.blueBits != GLFW_DONT_CARE)
235             colorDiff += abs(current.blueBits - desired.blueBits);
236 
237         sizeDiff = abs((current.width - desired.width) *
238                        (current.width - desired.width) +
239                        (current.height - desired.height) *
240                        (current.height - desired.height));
241 
242         if (desired.refreshRate != GLFW_DONT_CARE)
243             rateDiff = abs(current.refreshRate - desired.refreshRate);
244         else
245             rateDiff = UINT_MAX - current.refreshRate;
246 
247         if ((colorDiff < leastColorDiff) ||
248             (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
249             (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
250         {
251             closest = current;
252             leastSizeDiff = sizeDiff;
253             leastRateDiff = rateDiff;
254             leastColorDiff = colorDiff;
255         }
256     }
257 
258     return closest;
259 }
260 
261 // Performs lexical comparison between two @ref GLFWvidmode structures
262 //
263 int _glfwCompareVideoModes(const(GLFWvidmode)* fm, const(GLFWvidmode)* sm) {
264     return compareVideoModes(fm, sm);
265 }
266 
267 // Splits a color depth into red, green and blue bit depths
268 //
269 void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) {
270     int delta;
271 
272     // We assume that by 32 the user really meant 24
273     if (bpp == 32)
274         bpp = 24;
275 
276     // Convert "bits per pixel" to red, green & blue sizes
277 
278     *red = *green = *blue = bpp / 3;
279     delta = bpp - (*red * 3);
280     if (delta >= 1)
281         *green = *green + 1;
282 
283     if (delta == 2)
284         *red = *red + 1;
285 }
286 
287 
288 //////////////////////////////////////////////////////////////////////////
289 //////                        GLFW public API                       //////
290 //////////////////////////////////////////////////////////////////////////
291 
292 GLFWmonitor** glfwGetMonitors(int* count) {
293     assert(count != null);
294 
295     *count = 0;
296 
297     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
298 
299     *count = _glfw.monitorCount;
300     return cast(GLFWmonitor**) _glfw.monitors;
301 }
302 
303 GLFWmonitor* glfwGetPrimaryMonitor() {
304     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
305 
306     if (!_glfw.monitorCount)
307         return null;
308 
309     return cast(GLFWmonitor*) _glfw.monitors[0];
310 }
311 
312 void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) {
313     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
314     assert(monitor != null);
315 
316     if (xpos)
317         *xpos = 0;
318     if (ypos)
319         *ypos = 0;
320 
321     mixin(_GLFW_REQUIRE_INIT);
322 
323     _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
324 }
325 
326 void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, int* width, int* height) {
327     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
328     assert(monitor != null);
329 
330     if (xpos)
331         *xpos = 0;
332     if (ypos)
333         *ypos = 0;
334     if (width)
335         *width = 0;
336     if (height)
337         *height = 0;
338 
339     mixin(_GLFW_REQUIRE_INIT);
340 
341     _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height);
342 }
343 
344 void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) {
345     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
346     assert(monitor != null);
347 
348     if (widthMM)
349         *widthMM = 0;
350     if (heightMM)
351         *heightMM = 0;
352 
353     mixin(_GLFW_REQUIRE_INIT);
354 
355     if (widthMM)
356         *widthMM = monitor.widthMM;
357     if (heightMM)
358         *heightMM = monitor.heightMM;
359 }
360 
361 void glfwGetMonitorContentScale(GLFWmonitor* handle, float* xscale, float* yscale) {
362     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
363     assert(monitor != null);
364 
365     if (xscale)
366         *xscale = 0.0f;
367     if (yscale)
368         *yscale = 0.0f;
369 
370     mixin(_GLFW_REQUIRE_INIT);
371     _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
372 }
373 
374 const(char)* glfwGetMonitorName(GLFWmonitor* handle) {
375     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
376     assert(monitor != null);
377 
378     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
379     return monitor.name;
380 }
381 
382 void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer) {
383     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
384     assert(monitor != null);
385 
386     mixin(_GLFW_REQUIRE_INIT);
387     monitor.userPointer = pointer;
388 }
389 
390 void* glfwGetMonitorUserPointer(GLFWmonitor* handle) {
391     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
392     assert(monitor != null);
393 
394     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
395     return monitor.userPointer;
396 }
397 
398 GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) {
399     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
400     _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
401     return cbfun;
402 }
403 
404 const(GLFWvidmode)* glfwGetVideoModes(GLFWmonitor* handle, int* count) {
405     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
406     assert(monitor != null);
407     assert(count != null);
408 
409     *count = 0;
410 
411     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
412 
413     if (!refreshVideoModes(monitor))
414         return null;
415 
416     *count = monitor.modeCount;
417     return monitor.modes;
418 }
419 
420 const(GLFWvidmode)* glfwGetVideoMode(GLFWmonitor* handle) {
421     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
422     assert(monitor != null);
423 
424     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
425 
426     _glfwPlatformGetVideoMode(monitor, &monitor.currentMode);
427     return &monitor.currentMode;
428 }
429 
430 void glfwSetGamma(GLFWmonitor* handle, float gamma) {
431     uint i;
432     ushort* values;
433     GLFWgammaramp ramp;
434     const(GLFWgammaramp)* original;
435     assert(handle != null);
436     assert(gamma > 0.0f);
437     assert(gamma <= float.max);
438 
439     mixin(_GLFW_REQUIRE_INIT);
440 
441     if (gamma != gamma || gamma <= 0.0f || gamma > float.max)
442     {
443         _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
444         return;
445     }
446 
447     original = glfwGetGammaRamp(handle);
448     if (!original)
449         return;
450 
451     values = cast(ushort*) calloc(original.size, ushort.sizeof);
452 
453     for (i = 0;  i < original.size;  i++)
454     {
455         float value;
456 
457         // Calculate intensity
458         value = i / cast(float) (original.size - 1);
459         // Apply gamma curve
460         value = powf(value, 1.0f / gamma) * 65535.0f + 0.5f;
461         // Clamp to value range
462         value = _glfw_fminf(value, 65535.0f);
463 
464         values[i] = cast(ushort) value;
465     }
466 
467     ramp.red = values;
468     ramp.green = values;
469     ramp.blue = values;
470     ramp.size = original.size;
471 
472     glfwSetGammaRamp(handle, &ramp);
473     free(values);
474 }
475 
476 const(GLFWgammaramp)* glfwGetGammaRamp(GLFWmonitor* handle) {
477     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
478     assert(monitor != null);
479 
480     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
481 
482     _glfwFreeGammaArrays(&monitor.currentRamp);
483     if (!_glfwPlatformGetGammaRamp(monitor, &monitor.currentRamp))
484         return null;
485 
486     return &monitor.currentRamp;
487 }
488 
489 void glfwSetGammaRamp(GLFWmonitor* handle, const(GLFWgammaramp)* ramp) {
490     _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle;
491     assert(monitor != null);
492     assert(ramp != null);
493     assert(ramp.size > 0);
494     assert(ramp.red != null);
495     assert(ramp.green != null);
496     assert(ramp.blue != null);
497 
498     if (ramp.size <= 0)
499     {
500         _glfwInputError(GLFW_INVALID_VALUE,
501                         "Invalid gamma ramp size %i",
502                         ramp.size);
503         return;
504     }
505 
506     mixin(_GLFW_REQUIRE_INIT);
507 
508     if (!monitor.originalRamp.size)
509     {
510         if (!_glfwPlatformGetGammaRamp(monitor, &monitor.originalRamp))
511             return;
512     }
513 
514     _glfwPlatformSetGammaRamp(monitor, ramp);
515 }