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