Atlas - x11_monitor.c
Home / ext / glfw / src Lines: 1 | Size: 20331 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1//======================================================================== 2// GLFW 3.5 X11 - www.glfw.org 3//------------------------------------------------------------------------ 4// Copyright (c) 2002-2006 Marcus Geelnard 5// Copyright (c) 2006-2019 Camilla Löwy <[email protected]> 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#if defined(_GLFW_X11) 31 32#include <limits.h> 33#include <stdlib.h> 34#include <string.h> 35#include <math.h> 36#include <assert.h> 37 38 39// Check whether the display mode should be included in enumeration 40// 41static GLFWbool modeIsGood(const XRRModeInfo* mi) 42{ 43 return (mi->modeFlags & RR_Interlace) == 0; 44} 45 46// Calculates the refresh rate, in Hz, from the specified RandR mode info 47// 48static int calculateRefreshRate(const XRRModeInfo* mi) 49{ 50 if (mi->hTotal && mi->vTotal) 51 return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); 52 else 53 return 0; 54} 55 56// Returns the mode info for a RandR mode XID 57// 58static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) 59{ 60 for (int i = 0; i < sr->nmode; i++) 61 { 62 if (sr->modes[i].id == id) 63 return sr->modes + i; 64 } 65 66 return NULL; 67} 68 69// Convert RandR mode info to GLFW video mode 70// 71static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, 72 const XRRCrtcInfo* ci) 73{ 74 GLFWvidmode mode; 75 76 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) 77 { 78 mode.width = mi->height; 79 mode.height = mi->width; 80 } 81 else 82 { 83 mode.width = mi->width; 84 mode.height = mi->height; 85 } 86 87 mode.refreshRate = calculateRefreshRate(mi); 88 89 _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), 90 &mode.redBits, &mode.greenBits, &mode.blueBits); 91 92 return mode; 93} 94 95 96////////////////////////////////////////////////////////////////////////// 97////// GLFW internal API ////// 98////////////////////////////////////////////////////////////////////////// 99 100// Poll for changes in the set of connected monitors 101// 102void _glfwPollMonitorsX11(void) 103{ 104 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 105 { 106 int disconnectedCount, screenCount = 0; 107 _GLFWmonitor** disconnected = NULL; 108 XineramaScreenInfo* screens = NULL; 109 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, 110 _glfw.x11.root); 111 RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, 112 _glfw.x11.root); 113 114 if (_glfw.x11.xinerama.available) 115 screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); 116 117 disconnectedCount = _glfw.monitorCount; 118 if (disconnectedCount) 119 { 120 disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); 121 memcpy(disconnected, 122 _glfw.monitors, 123 _glfw.monitorCount * sizeof(_GLFWmonitor*)); 124 } 125 126 for (int i = 0; i < sr->noutput; i++) 127 { 128 int j, type, widthMM, heightMM; 129 130 XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); 131 if (oi->connection != RR_Connected || oi->crtc == None) 132 { 133 XRRFreeOutputInfo(oi); 134 continue; 135 } 136 137 for (j = 0; j < disconnectedCount; j++) 138 { 139 if (disconnected[j] && 140 disconnected[j]->x11.output == sr->outputs[i]) 141 { 142 disconnected[j] = NULL; 143 break; 144 } 145 } 146 147 if (j < disconnectedCount) 148 { 149 XRRFreeOutputInfo(oi); 150 continue; 151 } 152 153 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); 154 if (!ci) 155 { 156 XRRFreeOutputInfo(oi); 157 continue; 158 } 159 160 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) 161 { 162 widthMM = oi->mm_height; 163 heightMM = oi->mm_width; 164 } 165 else 166 { 167 widthMM = oi->mm_width; 168 heightMM = oi->mm_height; 169 } 170 171 if (widthMM <= 0 || heightMM <= 0) 172 { 173 // HACK: If RandR does not provide a physical size, assume the 174 // X11 default 96 DPI and calculate from the CRTC viewport 175 // NOTE: These members are affected by rotation, unlike the mode 176 // info and output info members 177 widthMM = (int) (ci->width * 25.4f / 96.f); 178 heightMM = (int) (ci->height * 25.4f / 96.f); 179 } 180 181 _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); 182 monitor->x11.output = sr->outputs[i]; 183 monitor->x11.crtc = oi->crtc; 184 185 for (j = 0; j < screenCount; j++) 186 { 187 if (screens[j].x_org == ci->x && 188 screens[j].y_org == ci->y && 189 screens[j].width == ci->width && 190 screens[j].height == ci->height) 191 { 192 monitor->x11.index = j; 193 break; 194 } 195 } 196 197 if (monitor->x11.output == primary) 198 type = _GLFW_INSERT_FIRST; 199 else 200 type = _GLFW_INSERT_LAST; 201 202 _glfwInputMonitor(monitor, GLFW_CONNECTED, type); 203 204 XRRFreeOutputInfo(oi); 205 XRRFreeCrtcInfo(ci); 206 } 207 208 XRRFreeScreenResources(sr); 209 210 if (screens) 211 XFree(screens); 212 213 for (int i = 0; i < disconnectedCount; i++) 214 { 215 if (disconnected[i]) 216 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); 217 } 218 219 _glfw_free(disconnected); 220 } 221 else 222 { 223 const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); 224 const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); 225 226 _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM), 227 GLFW_CONNECTED, 228 _GLFW_INSERT_FIRST); 229 } 230} 231 232// Set the current video mode for the specified monitor 233// 234void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) 235{ 236 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 237 { 238 GLFWvidmode current; 239 RRMode native = None; 240 241 const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); 242 _glfwGetVideoModeX11(monitor, ¤t); 243 if (_glfwCompareVideoModes(¤t, best) == 0) 244 return; 245 246 XRRScreenResources* sr = 247 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 248 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 249 XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); 250 251 for (int i = 0; i < oi->nmode; i++) 252 { 253 const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); 254 if (!modeIsGood(mi)) 255 continue; 256 257 const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); 258 if (_glfwCompareVideoModes(best, &mode) == 0) 259 { 260 native = mi->id; 261 break; 262 } 263 } 264 265 if (native) 266 { 267 if (monitor->x11.oldMode == None) 268 monitor->x11.oldMode = ci->mode; 269 270 XRRSetCrtcConfig(_glfw.x11.display, 271 sr, monitor->x11.crtc, 272 CurrentTime, 273 ci->x, ci->y, 274 native, 275 ci->rotation, 276 ci->outputs, 277 ci->noutput); 278 } 279 280 XRRFreeOutputInfo(oi); 281 XRRFreeCrtcInfo(ci); 282 XRRFreeScreenResources(sr); 283 } 284} 285 286// Restore the saved (original) video mode for the specified monitor 287// 288void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) 289{ 290 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 291 { 292 if (monitor->x11.oldMode == None) 293 return; 294 295 XRRScreenResources* sr = 296 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 297 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 298 299 XRRSetCrtcConfig(_glfw.x11.display, 300 sr, monitor->x11.crtc, 301 CurrentTime, 302 ci->x, ci->y, 303 monitor->x11.oldMode, 304 ci->rotation, 305 ci->outputs, 306 ci->noutput); 307 308 XRRFreeCrtcInfo(ci); 309 XRRFreeScreenResources(sr); 310 311 monitor->x11.oldMode = None; 312 } 313} 314 315 316////////////////////////////////////////////////////////////////////////// 317////// GLFW platform API ////// 318////////////////////////////////////////////////////////////////////////// 319 320void _glfwFreeMonitorX11(_GLFWmonitor* monitor) 321{ 322} 323 324void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos) 325{ 326 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 327 { 328 XRRScreenResources* sr = 329 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 330 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 331 332 if (ci) 333 { 334 if (xpos) 335 *xpos = ci->x; 336 if (ypos) 337 *ypos = ci->y; 338 339 XRRFreeCrtcInfo(ci); 340 } 341 342 XRRFreeScreenResources(sr); 343 } 344} 345 346void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, 347 float* xscale, float* yscale) 348{ 349 if (xscale) 350 *xscale = _glfw.x11.contentScaleX; 351 if (yscale) 352 *yscale = _glfw.x11.contentScaleY; 353} 354 355void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, 356 int* xpos, int* ypos, 357 int* width, int* height) 358{ 359 int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0; 360 361 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 362 { 363 XRRScreenResources* sr = 364 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 365 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 366 367 areaX = ci->x; 368 areaY = ci->y; 369 370 const XRRModeInfo* mi = getModeInfo(sr, ci->mode); 371 372 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) 373 { 374 areaWidth = mi->height; 375 areaHeight = mi->width; 376 } 377 else 378 { 379 areaWidth = mi->width; 380 areaHeight = mi->height; 381 } 382 383 XRRFreeCrtcInfo(ci); 384 XRRFreeScreenResources(sr); 385 } 386 else 387 { 388 areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); 389 areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); 390 } 391 392 if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP) 393 { 394 Atom* extents = NULL; 395 Atom* desktop = NULL; 396 const unsigned long extentCount = 397 _glfwGetWindowPropertyX11(_glfw.x11.root, 398 _glfw.x11.NET_WORKAREA, 399 XA_CARDINAL, 400 (unsigned char**) &extents); 401 402 if (_glfwGetWindowPropertyX11(_glfw.x11.root, 403 _glfw.x11.NET_CURRENT_DESKTOP, 404 XA_CARDINAL, 405 (unsigned char**) &desktop) > 0) 406 { 407 if (extentCount >= 4 && *desktop < extentCount / 4) 408 { 409 const int globalX = extents[*desktop * 4 + 0]; 410 const int globalY = extents[*desktop * 4 + 1]; 411 const int globalWidth = extents[*desktop * 4 + 2]; 412 const int globalHeight = extents[*desktop * 4 + 3]; 413 414 if (areaX < globalX) 415 { 416 areaWidth -= globalX - areaX; 417 areaX = globalX; 418 } 419 420 if (areaY < globalY) 421 { 422 areaHeight -= globalY - areaY; 423 areaY = globalY; 424 } 425 426 if (areaX + areaWidth > globalX + globalWidth) 427 areaWidth = globalX - areaX + globalWidth; 428 if (areaY + areaHeight > globalY + globalHeight) 429 areaHeight = globalY - areaY + globalHeight; 430 } 431 } 432 433 if (extents) 434 XFree(extents); 435 if (desktop) 436 XFree(desktop); 437 } 438 439 if (xpos) 440 *xpos = areaX; 441 if (ypos) 442 *ypos = areaY; 443 if (width) 444 *width = areaWidth; 445 if (height) 446 *height = areaHeight; 447} 448 449GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) 450{ 451 GLFWvidmode* result; 452 453 *count = 0; 454 455 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 456 { 457 XRRScreenResources* sr = 458 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 459 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 460 XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); 461 462 result = _glfw_calloc(oi->nmode, sizeof(GLFWvidmode)); 463 464 for (int i = 0; i < oi->nmode; i++) 465 { 466 const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); 467 if (!modeIsGood(mi)) 468 continue; 469 470 const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); 471 int j; 472 473 for (j = 0; j < *count; j++) 474 { 475 if (_glfwCompareVideoModes(result + j, &mode) == 0) 476 break; 477 } 478 479 // Skip duplicate modes 480 if (j < *count) 481 continue; 482 483 (*count)++; 484 result[*count - 1] = mode; 485 } 486 487 XRRFreeOutputInfo(oi); 488 XRRFreeCrtcInfo(ci); 489 XRRFreeScreenResources(sr); 490 } 491 else 492 { 493 *count = 1; 494 result = _glfw_calloc(1, sizeof(GLFWvidmode)); 495 _glfwGetVideoModeX11(monitor, result); 496 } 497 498 return result; 499} 500 501GLFWbool _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode) 502{ 503 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 504 { 505 XRRScreenResources* sr = 506 XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 507 const XRRModeInfo* mi = NULL; 508 509 XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 510 if (ci) 511 { 512 mi = getModeInfo(sr, ci->mode); 513 if (mi) 514 *mode = vidmodeFromModeInfo(mi, ci); 515 516 XRRFreeCrtcInfo(ci); 517 } 518 519 XRRFreeScreenResources(sr); 520 521 if (!mi) 522 { 523 _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to query video mode"); 524 return GLFW_FALSE; 525 } 526 } 527 else 528 { 529 mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); 530 mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); 531 mode->refreshRate = 0; 532 533 _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), 534 &mode->redBits, &mode->greenBits, &mode->blueBits); 535 } 536 537 return GLFW_TRUE; 538} 539 540GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp) 541{ 542 if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) 543 { 544 const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, 545 monitor->x11.crtc); 546 XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, 547 monitor->x11.crtc); 548 549 _glfwAllocGammaArrays(ramp, size); 550 551 memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); 552 memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); 553 memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); 554 555 XRRFreeGamma(gamma); 556 return GLFW_TRUE; 557 } 558 else if (_glfw.x11.vidmode.available) 559 { 560 int size; 561 XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); 562 563 _glfwAllocGammaArrays(ramp, size); 564 565 XF86VidModeGetGammaRamp(_glfw.x11.display, 566 _glfw.x11.screen, 567 ramp->size, ramp->red, ramp->green, ramp->blue); 568 return GLFW_TRUE; 569 } 570 else 571 { 572 _glfwInputError(GLFW_PLATFORM_ERROR, 573 "X11: Gamma ramp access not supported by server"); 574 return GLFW_FALSE; 575 } 576} 577 578void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) 579{ 580 if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) 581 { 582 if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) 583 { 584 _glfwInputError(GLFW_PLATFORM_ERROR, 585 "X11: Gamma ramp size must match current ramp size"); 586 return; 587 } 588 589 XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); 590 591 memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); 592 memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); 593 memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); 594 595 XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); 596 XRRFreeGamma(gamma); 597 } 598 else if (_glfw.x11.vidmode.available) 599 { 600 XF86VidModeSetGammaRamp(_glfw.x11.display, 601 _glfw.x11.screen, 602 ramp->size, 603 (unsigned short*) ramp->red, 604 (unsigned short*) ramp->green, 605 (unsigned short*) ramp->blue); 606 } 607 else 608 { 609 _glfwInputError(GLFW_PLATFORM_ERROR, 610 "X11: Gamma ramp access not supported by server"); 611 } 612} 613 614 615////////////////////////////////////////////////////////////////////////// 616////// GLFW native API ////// 617////////////////////////////////////////////////////////////////////////// 618 619GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) 620{ 621 _GLFW_REQUIRE_INIT_OR_RETURN(None); 622 623 if (_glfw.platform.platformID != GLFW_PLATFORM_X11) 624 { 625 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); 626 return None; 627 } 628 629 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 630 assert(monitor != NULL); 631 632 return monitor->x11.crtc; 633} 634 635GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) 636{ 637 _GLFW_REQUIRE_INIT_OR_RETURN(None); 638 639 if (_glfw.platform.platformID != GLFW_PLATFORM_X11) 640 { 641 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); 642 return None; 643 } 644 645 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 646 assert(monitor != NULL); 647 648 return monitor->x11.output; 649} 650 651#endif // _GLFW_X11 652 653[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.