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 }