x11_monitor.cc (15609B)
1 //======================================================================== 2 // GLFW 3.3 X11 - 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 <limits.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 35 // Check whether the display mode should be included in enumeration 36 // 37 static GLFWbool modeIsGood(const XRRModeInfo* mi) 38 { 39 return (mi->modeFlags & RR_Interlace) == 0; 40 } 41 42 // Calculates the refresh rate, in Hz, from the specified RandR mode info 43 // 44 static int calculateRefreshRate(const XRRModeInfo* mi) 45 { 46 if (mi->hTotal && mi->vTotal) 47 return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); 48 else 49 return 0; 50 } 51 52 // Returns the mode info for a RandR mode XID 53 // 54 static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) 55 { 56 int i; 57 58 for (i = 0; i < sr->nmode; i++) 59 { 60 if (sr->modes[i].id == id) 61 return sr->modes + i; 62 } 63 64 return NULL; 65 } 66 67 // Convert RandR mode info to GLFW video mode 68 // 69 static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, 70 const XRRCrtcInfo* ci) 71 { 72 GLFWvidmode mode; 73 74 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) 75 { 76 mode.width = mi->height; 77 mode.height = mi->width; 78 } 79 else 80 { 81 mode.width = mi->width; 82 mode.height = mi->height; 83 } 84 85 mode.refreshRate = calculateRefreshRate(mi); 86 87 _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), 88 &mode.redBits, &mode.greenBits, &mode.blueBits); 89 90 return mode; 91 } 92 93 94 ////////////////////////////////////////////////////////////////////////// 95 ////// GLFW internal API ////// 96 ////////////////////////////////////////////////////////////////////////// 97 98 // Poll for changes in the set of connected monitors 99 // 100 void _glfwPollMonitorsX11(void) 101 { 102 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 103 { 104 int i, j, disconnectedCount, screenCount = 0; 105 _GLFWmonitor** disconnected = NULL; 106 XineramaScreenInfo* screens = NULL; 107 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, 108 _glfw.x11.root); 109 RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, 110 _glfw.x11.root); 111 112 if (_glfw.x11.xinerama.available) 113 screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); 114 115 disconnectedCount = _glfw.monitorCount; 116 if (disconnectedCount) 117 { 118 disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); 119 memcpy(disconnected, 120 _glfw.monitors, 121 _glfw.monitorCount * sizeof(_GLFWmonitor*)); 122 } 123 124 for (i = 0; i < sr->noutput; i++) 125 { 126 int type, widthMM, heightMM; 127 XRROutputInfo* oi; 128 XRRCrtcInfo* ci; 129 _GLFWmonitor* monitor; 130 131 oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); 132 if (oi->connection != RR_Connected || oi->crtc == None) 133 { 134 XRRFreeOutputInfo(oi); 135 continue; 136 } 137 138 for (j = 0; j < disconnectedCount; j++) 139 { 140 if (disconnected[j] && 141 disconnected[j]->x11.output == sr->outputs[i]) 142 { 143 disconnected[j] = NULL; 144 break; 145 } 146 } 147 148 if (j < disconnectedCount) 149 { 150 XRRFreeOutputInfo(oi); 151 continue; 152 } 153 154 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); 155 if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) 156 { 157 widthMM = oi->mm_height; 158 heightMM = oi->mm_width; 159 } 160 else 161 { 162 widthMM = oi->mm_width; 163 heightMM = oi->mm_height; 164 } 165 166 monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); 167 monitor->x11.output = sr->outputs[i]; 168 monitor->x11.crtc = oi->crtc; 169 170 for (j = 0; j < screenCount; j++) 171 { 172 if (screens[j].x_org == ci->x && 173 screens[j].y_org == ci->y && 174 screens[j].width == ci->width && 175 screens[j].height == ci->height) 176 { 177 monitor->x11.index = j; 178 break; 179 } 180 } 181 182 if (monitor->x11.output == primary) 183 type = _GLFW_INSERT_FIRST; 184 else 185 type = _GLFW_INSERT_LAST; 186 187 _glfwInputMonitor(monitor, GLFW_CONNECTED, type); 188 189 XRRFreeOutputInfo(oi); 190 XRRFreeCrtcInfo(ci); 191 } 192 193 XRRFreeScreenResources(sr); 194 195 if (screens) 196 XFree(screens); 197 198 for (i = 0; i < disconnectedCount; i++) 199 { 200 if (disconnected[i]) 201 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); 202 } 203 204 free(disconnected); 205 } 206 207 if (!_glfw.monitorCount) 208 { 209 const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); 210 const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); 211 212 _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM), 213 GLFW_CONNECTED, 214 _GLFW_INSERT_FIRST); 215 } 216 } 217 218 // Set the current video mode for the specified monitor 219 // 220 GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) 221 { 222 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 223 { 224 XRRScreenResources* sr; 225 XRRCrtcInfo* ci; 226 XRROutputInfo* oi; 227 GLFWvidmode current; 228 const GLFWvidmode* best; 229 RRMode native = None; 230 int i; 231 232 best = _glfwChooseVideoMode(monitor, desired); 233 _glfwPlatformGetVideoMode(monitor, ¤t); 234 if (_glfwCompareVideoModes(¤t, best) == 0) 235 return GLFW_TRUE; 236 237 sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 238 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 239 oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); 240 241 for (i = 0; i < oi->nmode; i++) 242 { 243 const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); 244 if (!modeIsGood(mi)) 245 continue; 246 247 const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); 248 if (_glfwCompareVideoModes(best, &mode) == 0) 249 { 250 native = mi->id; 251 break; 252 } 253 } 254 255 if (native) 256 { 257 if (monitor->x11.oldMode == None) 258 monitor->x11.oldMode = ci->mode; 259 260 XRRSetCrtcConfig(_glfw.x11.display, 261 sr, monitor->x11.crtc, 262 CurrentTime, 263 ci->x, ci->y, 264 native, 265 ci->rotation, 266 ci->outputs, 267 ci->noutput); 268 } 269 270 XRRFreeOutputInfo(oi); 271 XRRFreeCrtcInfo(ci); 272 XRRFreeScreenResources(sr); 273 274 if (!native) 275 { 276 _glfwInputError(GLFW_PLATFORM_ERROR, 277 "X11: Monitor mode list changed"); 278 return GLFW_FALSE; 279 } 280 } 281 282 return GLFW_TRUE; 283 } 284 285 // Restore the saved (original) video mode for the specified monitor 286 // 287 void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) 288 { 289 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 290 { 291 XRRScreenResources* sr; 292 XRRCrtcInfo* ci; 293 294 if (monitor->x11.oldMode == None) 295 return; 296 297 sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 298 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 299 300 XRRSetCrtcConfig(_glfw.x11.display, 301 sr, monitor->x11.crtc, 302 CurrentTime, 303 ci->x, ci->y, 304 monitor->x11.oldMode, 305 ci->rotation, 306 ci->outputs, 307 ci->noutput); 308 309 XRRFreeCrtcInfo(ci); 310 XRRFreeScreenResources(sr); 311 312 monitor->x11.oldMode = None; 313 } 314 } 315 316 317 ////////////////////////////////////////////////////////////////////////// 318 ////// GLFW platform API ////// 319 ////////////////////////////////////////////////////////////////////////// 320 321 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) 322 { 323 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 324 { 325 XRRScreenResources* sr; 326 XRRCrtcInfo* ci; 327 328 sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 329 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 330 331 if (xpos) 332 *xpos = ci->x; 333 if (ypos) 334 *ypos = ci->y; 335 336 XRRFreeCrtcInfo(ci); 337 XRRFreeScreenResources(sr); 338 } 339 } 340 341 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) 342 { 343 GLFWvidmode* result; 344 345 *count = 0; 346 347 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 348 { 349 int i, j; 350 XRRScreenResources* sr; 351 XRRCrtcInfo* ci; 352 XRROutputInfo* oi; 353 354 sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 355 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 356 oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); 357 358 result = calloc(oi->nmode, sizeof(GLFWvidmode)); 359 360 for (i = 0; i < oi->nmode; i++) 361 { 362 const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); 363 if (!modeIsGood(mi)) 364 continue; 365 366 const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); 367 368 for (j = 0; j < *count; j++) 369 { 370 if (_glfwCompareVideoModes(result + j, &mode) == 0) 371 break; 372 } 373 374 // Skip duplicate modes 375 if (j < *count) 376 continue; 377 378 (*count)++; 379 result[*count - 1] = mode; 380 } 381 382 XRRFreeOutputInfo(oi); 383 XRRFreeCrtcInfo(ci); 384 XRRFreeScreenResources(sr); 385 } 386 else 387 { 388 *count = 1; 389 result = calloc(1, sizeof(GLFWvidmode)); 390 _glfwPlatformGetVideoMode(monitor, result); 391 } 392 393 return result; 394 } 395 396 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) 397 { 398 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 399 { 400 XRRScreenResources* sr; 401 XRRCrtcInfo* ci; 402 403 sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); 404 ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); 405 406 *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); 407 408 XRRFreeCrtcInfo(ci); 409 XRRFreeScreenResources(sr); 410 } 411 else 412 { 413 mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); 414 mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); 415 mode->refreshRate = 0; 416 417 _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), 418 &mode->redBits, &mode->greenBits, &mode->blueBits); 419 } 420 } 421 422 void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) 423 { 424 if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) 425 { 426 const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, 427 monitor->x11.crtc); 428 XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, 429 monitor->x11.crtc); 430 431 _glfwAllocGammaArrays(ramp, size); 432 433 memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); 434 memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); 435 memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); 436 437 XRRFreeGamma(gamma); 438 } 439 else if (_glfw.x11.vidmode.available) 440 { 441 int size; 442 XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); 443 444 _glfwAllocGammaArrays(ramp, size); 445 446 XF86VidModeGetGammaRamp(_glfw.x11.display, 447 _glfw.x11.screen, 448 ramp->size, ramp->red, ramp->green, ramp->blue); 449 } 450 } 451 452 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) 453 { 454 if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) 455 { 456 if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size) 457 { 458 _glfwInputError(GLFW_PLATFORM_ERROR, 459 "X11: Gamma ramp size must match current ramp size"); 460 return; 461 } 462 463 XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); 464 465 memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); 466 memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); 467 memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); 468 469 XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); 470 XRRFreeGamma(gamma); 471 } 472 else if (_glfw.x11.vidmode.available) 473 { 474 XF86VidModeSetGammaRamp(_glfw.x11.display, 475 _glfw.x11.screen, 476 ramp->size, 477 (unsigned short*) ramp->red, 478 (unsigned short*) ramp->green, 479 (unsigned short*) ramp->blue); 480 } 481 } 482 483 484 ////////////////////////////////////////////////////////////////////////// 485 ////// GLFW native API ////// 486 ////////////////////////////////////////////////////////////////////////// 487 488 GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) 489 { 490 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 491 _GLFW_REQUIRE_INIT_OR_RETURN(None); 492 return monitor->x11.crtc; 493 } 494 495 GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) 496 { 497 _GLFWmonitor* monitor = (_GLFWmonitor*) handle; 498 _GLFW_REQUIRE_INIT_OR_RETURN(None); 499 return monitor->x11.output; 500 } 501