Atlas - SDL_x11modes.c

Home / ext / SDL2 / src / video / x11 Lines: 20 | Size: 37649 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_X11 24 25#include "SDL_hints.h" 26#include "SDL_x11video.h" 27#include "SDL_timer.h" 28#include "edid.h" 29 30/* #define X11MODES_DEBUG */ 31 32/* I'm becoming more and more convinced that the application should never 33 * use XRandR, and it's the window manager's responsibility to track and 34 * manage display modes for fullscreen windows. Right now XRandR is completely 35 * broken with respect to window manager behavior on every window manager that 36 * I can find. For example, on Unity 3D if you show a fullscreen window while 37 * the resolution is changing (within ~250 ms) your window will retain the 38 * fullscreen state hint but be decorated and windowed. 39 * 40 * However, many people swear by it, so let them swear at it. :) 41*/ 42/* #define XRANDR_DISABLED_BY_DEFAULT */ 43 44 45static int 46get_visualinfo(Display * display, int screen, XVisualInfo * vinfo) 47{ 48 const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID"); 49 int depth; 50 51 /* Look for an exact visual, if requested */ 52 if (visual_id) { 53 XVisualInfo *vi, template; 54 int nvis; 55 56 SDL_zero(template); 57 template.visualid = SDL_strtol(visual_id, NULL, 0); 58 vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis); 59 if (vi) { 60 *vinfo = *vi; 61 X11_XFree(vi); 62 return 0; 63 } 64 } 65 66 depth = DefaultDepth(display, screen); 67 if ((X11_UseDirectColorVisuals() && 68 X11_XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) || 69 X11_XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) || 70 X11_XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) || 71 X11_XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) { 72 return 0; 73 } 74 return -1; 75} 76 77int 78X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo) 79{ 80 XVisualInfo *vi; 81 int nvis; 82 83 vinfo->visualid = X11_XVisualIDFromVisual(visual); 84 vi = X11_XGetVisualInfo(display, VisualIDMask, vinfo, &nvis); 85 if (vi) { 86 *vinfo = *vi; 87 X11_XFree(vi); 88 return 0; 89 } 90 return -1; 91} 92 93Uint32 94X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo) 95{ 96 if (vinfo->class == DirectColor || vinfo->class == TrueColor) { 97 int bpp; 98 Uint32 Rmask, Gmask, Bmask, Amask; 99 100 Rmask = vinfo->visual->red_mask; 101 Gmask = vinfo->visual->green_mask; 102 Bmask = vinfo->visual->blue_mask; 103 if (vinfo->depth == 32) { 104 Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask)); 105 } else { 106 Amask = 0; 107 } 108 109 bpp = vinfo->depth; 110 if (bpp == 24) { 111 int i, n; 112 XPixmapFormatValues *p = X11_XListPixmapFormats(display, &n); 113 if (p) { 114 for (i = 0; i < n; ++i) { 115 if (p[i].depth == 24) { 116 bpp = p[i].bits_per_pixel; 117 break; 118 } 119 } 120 X11_XFree(p); 121 } 122 } 123 124 return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); 125 } 126 127 if (vinfo->class == PseudoColor || vinfo->class == StaticColor) { 128 switch (vinfo->depth) { 129 case 8: 130 return SDL_PIXELTYPE_INDEX8; 131 case 4: 132 if (BitmapBitOrder(display) == LSBFirst) { 133 return SDL_PIXELFORMAT_INDEX4LSB; 134 } else { 135 return SDL_PIXELFORMAT_INDEX4MSB; 136 } 137 /* break; -Wunreachable-code-break */ 138 case 1: 139 if (BitmapBitOrder(display) == LSBFirst) { 140 return SDL_PIXELFORMAT_INDEX1LSB; 141 } else { 142 return SDL_PIXELFORMAT_INDEX1MSB; 143 } 144 /* break; -Wunreachable-code-break */ 145 } 146 } 147 148 return SDL_PIXELFORMAT_UNKNOWN; 149} 150 151#if SDL_VIDEO_DRIVER_X11_XINERAMA 152static SDL_bool 153CheckXinerama(Display * display, int *major, int *minor) 154{ 155 int event_base = 0; 156 int error_base = 0; 157 158 /* Default the extension not available */ 159 *major = *minor = 0; 160 161 /* Allow environment override */ 162 if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XINERAMA, SDL_TRUE)) { 163#ifdef X11MODES_DEBUG 164 printf("Xinerama disabled due to hint\n"); 165#endif 166 return SDL_FALSE; 167 } 168 169 if (!SDL_X11_HAVE_XINERAMA) { 170#ifdef X11MODES_DEBUG 171 printf("Xinerama support not available\n"); 172#endif 173 return SDL_FALSE; 174 } 175 176 /* Query the extension version */ 177 if (!X11_XineramaQueryExtension(display, &event_base, &error_base) || 178 !X11_XineramaQueryVersion(display, major, minor) || 179 !X11_XineramaIsActive(display)) { 180#ifdef X11MODES_DEBUG 181 printf("Xinerama not active on the display\n"); 182#endif 183 return SDL_FALSE; 184 } 185#ifdef X11MODES_DEBUG 186 printf("Xinerama available at version %d.%d!\n", *major, *minor); 187#endif 188 return SDL_TRUE; 189} 190 191/* !!! FIXME: remove this later. */ 192/* we have a weird bug where XineramaQueryScreens() throws an X error, so this 193 is here to help track it down (and not crash, too!). */ 194static SDL_bool xinerama_triggered_error = SDL_FALSE; 195static int 196X11_XineramaFailed(Display * d, XErrorEvent * e) 197{ 198 xinerama_triggered_error = SDL_TRUE; 199 fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n", 200 e->type, e->serial, (unsigned int) e->error_code, 201 (unsigned int) e->request_code, (unsigned int) e->minor_code); 202 fflush(stderr); 203 return 0; 204} 205#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 206 207#if SDL_VIDEO_DRIVER_X11_XRANDR 208static SDL_bool 209CheckXRandR(Display * display, int *major, int *minor) 210{ 211 /* Default the extension not available */ 212 *major = *minor = 0; 213 214 /* Allow environment override */ 215#ifdef XRANDR_DISABLED_BY_DEFAULT 216 if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_FALSE)) { 217#ifdef X11MODES_DEBUG 218 printf("XRandR disabled by default due to window manager issues\n"); 219#endif 220 return SDL_FALSE; 221 } 222#else 223 if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_TRUE)) { 224#ifdef X11MODES_DEBUG 225 printf("XRandR disabled due to hint\n"); 226#endif 227 return SDL_FALSE; 228 } 229#endif /* XRANDR_ENABLED_BY_DEFAULT */ 230 231 if (!SDL_X11_HAVE_XRANDR) { 232#ifdef X11MODES_DEBUG 233 printf("XRandR support not available\n"); 234#endif 235 return SDL_FALSE; 236 } 237 238 /* Query the extension version */ 239 *major = 1; *minor = 3; /* we want 1.3 */ 240 if (!X11_XRRQueryVersion(display, major, minor)) { 241#ifdef X11MODES_DEBUG 242 printf("XRandR not active on the display\n"); 243#endif 244 *major = *minor = 0; 245 return SDL_FALSE; 246 } 247#ifdef X11MODES_DEBUG 248 printf("XRandR available at version %d.%d!\n", *major, *minor); 249#endif 250 return SDL_TRUE; 251} 252 253#define XRANDR_ROTATION_LEFT (1 << 1) 254#define XRANDR_ROTATION_RIGHT (1 << 3) 255 256static int 257CalculateXRandRRefreshRate(const XRRModeInfo *info) 258{ 259 return (info->hTotal && info->vTotal) ? 260 round(((double)info->dotClock / (double)(info->hTotal * info->vTotal))) : 0; 261} 262 263static SDL_bool 264SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc, 265 RRMode modeID, SDL_DisplayMode *mode) 266{ 267 int i; 268 for (i = 0; i < res->nmode; ++i) { 269 const XRRModeInfo *info = &res->modes[i]; 270 if (info->id == modeID) { 271 XRRCrtcInfo *crtcinfo; 272 Rotation rotation = 0; 273 274 crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc); 275 if (crtcinfo) { 276 rotation = crtcinfo->rotation; 277 X11_XRRFreeCrtcInfo(crtcinfo); 278 } 279 280 if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { 281 mode->w = info->height; 282 mode->h = info->width; 283 } else { 284 mode->w = info->width; 285 mode->h = info->height; 286 } 287 mode->refresh_rate = CalculateXRandRRefreshRate(info); 288 ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID; 289#ifdef X11MODES_DEBUG 290 printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate); 291#endif 292 return SDL_TRUE; 293 } 294 } 295 return SDL_FALSE; 296} 297 298static void 299SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm) 300{ 301 /* See if we can get the EDID data for the real monitor name */ 302 int inches; 303 int nprop; 304 Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop); 305 int i; 306 307 for (i = 0; i < nprop; ++i) { 308 unsigned char *prop; 309 int actual_format; 310 unsigned long nitems, bytes_after; 311 Atom actual_type; 312 313 if (props[i] == EDID) { 314 if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False, 315 False, AnyPropertyType, &actual_type, 316 &actual_format, &nitems, &bytes_after, 317 &prop) == Success) { 318 MonitorInfo *info = decode_edid(prop); 319 if (info) { 320#ifdef X11MODES_DEBUG 321 printf("Found EDID data for %s\n", name); 322 dump_monitor_info(info); 323#endif 324 SDL_strlcpy(name, info->dsc_product_name, namelen); 325 free(info); 326 } 327 X11_XFree(prop); 328 } 329 break; 330 } 331 } 332 333 if (props) { 334 X11_XFree(props); 335 } 336 337 inches = (int)((SDL_sqrtf(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f); 338 if (*name && inches) { 339 const size_t len = SDL_strlen(name); 340 SDL_snprintf(&name[len], namelen-len, " %d\"", inches); 341 } 342 343#ifdef X11MODES_DEBUG 344 printf("Display name: %s\n", name); 345#endif 346} 347 348 349static int 350X11_InitModes_XRandR(_THIS) 351{ 352 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 353 Display *dpy = data->display; 354 const int screencount = ScreenCount(dpy); 355 const int default_screen = DefaultScreen(dpy); 356 RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen)); 357 Atom EDID = X11_XInternAtom(dpy, "EDID", False); 358 XRRScreenResources *res = NULL; 359 Uint32 pixelformat; 360 XVisualInfo vinfo; 361 XPixmapFormatValues *pixmapformats; 362 int looking_for_primary; 363 int scanline_pad; 364 int output; 365 int screen, i, n; 366 367 for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) { 368 for (screen = 0; screen < screencount; screen++) { 369 370 /* we want the primary output first, and then skipped later. */ 371 if (looking_for_primary && (screen != default_screen)) { 372 continue; 373 } 374 375 if (get_visualinfo(dpy, screen, &vinfo) < 0) { 376 continue; /* uh, skip this screen? */ 377 } 378 379 pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); 380 if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { 381 continue; /* Palettized video modes are no longer supported */ 382 } 383 384 scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; 385 pixmapformats = X11_XListPixmapFormats(dpy, &n); 386 if (pixmapformats) { 387 for (i = 0; i < n; ++i) { 388 if (pixmapformats[i].depth == vinfo.depth) { 389 scanline_pad = pixmapformats[i].scanline_pad; 390 break; 391 } 392 } 393 X11_XFree(pixmapformats); 394 } 395 396 res = X11_XRRGetScreenResourcesCurrent(dpy, RootWindow(dpy, screen)); 397 if (!res || res->noutput == 0) { 398 if (res) { 399 X11_XRRFreeScreenResources(res); 400 } 401 402 res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen)); 403 if (!res) { 404 continue; 405 } 406 } 407 408 for (output = 0; output < res->noutput; output++) { 409 XRROutputInfo *output_info; 410 int display_x, display_y; 411 unsigned long display_mm_width, display_mm_height; 412 SDL_DisplayData *displaydata; 413 char display_name[128]; 414 SDL_DisplayMode mode; 415 SDL_DisplayModeData *modedata; 416 SDL_VideoDisplay display; 417 RRMode modeID; 418 RRCrtc output_crtc; 419 XRRCrtcInfo *crtc; 420 421 /* The primary output _should_ always be sorted first, but just in case... */ 422 if ((looking_for_primary && (res->outputs[output] != primary)) || 423 (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) { 424 continue; 425 } 426 427 output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]); 428 if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) { 429 X11_XRRFreeOutputInfo(output_info); 430 continue; 431 } 432 433 SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); 434 display_mm_width = output_info->mm_width; 435 display_mm_height = output_info->mm_height; 436 output_crtc = output_info->crtc; 437 X11_XRRFreeOutputInfo(output_info); 438 439 crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc); 440 if (!crtc) { 441 continue; 442 } 443 444 SDL_zero(mode); 445 modeID = crtc->mode; 446 mode.w = crtc->width; 447 mode.h = crtc->height; 448 mode.format = pixelformat; 449 450 display_x = crtc->x; 451 display_y = crtc->y; 452 453 X11_XRRFreeCrtcInfo(crtc); 454 455 displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); 456 if (!displaydata) { 457 return SDL_OutOfMemory(); 458 } 459 460 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 461 if (!modedata) { 462 SDL_free(displaydata); 463 return SDL_OutOfMemory(); 464 } 465 modedata->xrandr_mode = modeID; 466 mode.driverdata = modedata; 467 468 displaydata->screen = screen; 469 displaydata->visual = vinfo.visual; 470 displaydata->depth = vinfo.depth; 471 displaydata->hdpi = display_mm_width ? (((float) mode.w) * 25.4f / display_mm_width) : 0.0f; 472 displaydata->vdpi = display_mm_height ? (((float) mode.h) * 25.4f / display_mm_height) : 0.0f; 473 displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f); 474 displaydata->scanline_pad = scanline_pad; 475 displaydata->x = display_x; 476 displaydata->y = display_y; 477 displaydata->use_xrandr = 1; 478 displaydata->xrandr_output = res->outputs[output]; 479 480 SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode); 481 SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height); 482 483 SDL_zero(display); 484 if (*display_name) { 485 display.name = display_name; 486 } 487 display.desktop_mode = mode; 488 display.current_mode = mode; 489 display.driverdata = displaydata; 490 SDL_AddVideoDisplay(&display); 491 } 492 493 X11_XRRFreeScreenResources(res); 494 } 495 } 496 497 if (_this->num_displays == 0) { 498 return SDL_SetError("No available displays"); 499 } 500 501 return 0; 502} 503#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 504 505#if SDL_VIDEO_DRIVER_X11_XVIDMODE 506static SDL_bool 507CheckVidMode(Display * display, int *major, int *minor) 508{ 509 int vm_event, vm_error = -1; 510 /* Default the extension not available */ 511 *major = *minor = 0; 512 513 /* Allow environment override */ 514 if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XVIDMODE, SDL_TRUE)) { 515#ifdef X11MODES_DEBUG 516 printf("XVidMode disabled due to hint\n"); 517#endif 518 return SDL_FALSE; 519 } 520 521 if (!SDL_X11_HAVE_XVIDMODE) { 522#ifdef X11MODES_DEBUG 523 printf("XVidMode support not available\n"); 524#endif 525 return SDL_FALSE; 526 } 527 528 /* Query the extension version */ 529 if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error) 530 || !X11_XF86VidModeQueryVersion(display, major, minor)) { 531#ifdef X11MODES_DEBUG 532 printf("XVidMode not active on the display\n"); 533#endif 534 return SDL_FALSE; 535 } 536#ifdef X11MODES_DEBUG 537 printf("XVidMode available at version %d.%d!\n", *major, *minor); 538#endif 539 return SDL_TRUE; 540} 541 542static 543Bool XF86VidModeGetModeInfo(Display * dpy, int scr, 544 XF86VidModeModeInfo* info) 545{ 546 Bool retval; 547 int dotclock; 548 XF86VidModeModeLine l; 549 SDL_zerop(info); 550 SDL_zero(l); 551 retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l); 552 info->dotclock = dotclock; 553 info->hdisplay = l.hdisplay; 554 info->hsyncstart = l.hsyncstart; 555 info->hsyncend = l.hsyncend; 556 info->htotal = l.htotal; 557 info->hskew = l.hskew; 558 info->vdisplay = l.vdisplay; 559 info->vsyncstart = l.vsyncstart; 560 info->vsyncend = l.vsyncend; 561 info->vtotal = l.vtotal; 562 info->flags = l.flags; 563 info->privsize = l.privsize; 564 info->private = l.private; 565 return retval; 566} 567 568static int 569CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info) 570{ 571 return (info->htotal 572 && info->vtotal) ? (1000 * info->dotclock / (info->htotal * 573 info->vtotal)) : 0; 574} 575 576static SDL_bool 577SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode) 578{ 579 mode->w = info->hdisplay; 580 mode->h = info->vdisplay; 581 mode->refresh_rate = CalculateXVidModeRefreshRate(info); 582 ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info; 583 return SDL_TRUE; 584} 585#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 586 587int 588X11_InitModes(_THIS) 589{ 590 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 591 int snum, screen, screencount = 0; 592#if SDL_VIDEO_DRIVER_X11_XINERAMA 593 int xinerama_major, xinerama_minor; 594 int use_xinerama = 0; 595 XineramaScreenInfo *xinerama = NULL; 596#endif 597#if SDL_VIDEO_DRIVER_X11_XRANDR 598 int xrandr_major, xrandr_minor; 599#endif 600#if SDL_VIDEO_DRIVER_X11_XVIDMODE 601 int vm_major, vm_minor; 602 int use_vidmode = 0; 603#endif 604 605/* XRandR is the One True Modern Way to do this on X11. If it's enabled and 606 available, don't even look at other ways of doing things. */ 607#if SDL_VIDEO_DRIVER_X11_XRANDR 608 /* require at least XRandR v1.3 */ 609 if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) && 610 (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) { 611 if (X11_InitModes_XRandR(_this) == 0) 612 return 0; 613 } 614#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 615 616/* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */ 617 618 /* This is a workaround for some apps (UnrealEngine4, for example) until 619 we sort out the ramifications of removing XVidMode support outright. 620 This block should be removed with the XVidMode support. */ 621 { 622 if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) { 623 #if SDL_VIDEO_DRIVER_X11_XRANDR 624 return SDL_SetError("XRandR support is required but not available"); 625 #else 626 return SDL_SetError("XRandR support is required but not built into SDL!"); 627 #endif 628 } 629 } 630 631#if SDL_VIDEO_DRIVER_X11_XINERAMA 632 /* Query Xinerama extention 633 * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012) 634 * or newer of the Nvidia binary drivers 635 */ 636 if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) { 637 int (*handler) (Display *, XErrorEvent *); 638 X11_XSync(data->display, False); 639 handler = X11_XSetErrorHandler(X11_XineramaFailed); 640 xinerama = X11_XineramaQueryScreens(data->display, &screencount); 641 X11_XSync(data->display, False); 642 X11_XSetErrorHandler(handler); 643 if (xinerama_triggered_error) { 644 xinerama = 0; 645 } 646 if (xinerama) { 647 use_xinerama = xinerama_major * 100 + xinerama_minor; 648 } 649 } 650 if (!xinerama) { 651 screencount = ScreenCount(data->display); 652 } 653#else 654 screencount = ScreenCount(data->display); 655#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 656 657#if SDL_VIDEO_DRIVER_X11_XVIDMODE 658 if (CheckVidMode(data->display, &vm_major, &vm_minor)) { 659 use_vidmode = vm_major * 100 + vm_minor; 660 } 661#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 662 663 for (snum = 0; snum < screencount; ++snum) { 664 XVisualInfo vinfo; 665 SDL_VideoDisplay display; 666 SDL_DisplayData *displaydata; 667 SDL_DisplayMode mode; 668 SDL_DisplayModeData *modedata; 669 XPixmapFormatValues *pixmapFormats; 670 char display_name[128]; 671 int i, n; 672 673 /* Re-order screens to always put default screen first */ 674 if (snum == 0) { 675 screen = DefaultScreen(data->display); 676 } else if (snum == DefaultScreen(data->display)) { 677 screen = 0; 678 } else { 679 screen = snum; 680 } 681 682#if SDL_VIDEO_DRIVER_X11_XINERAMA 683 if (xinerama) { 684 if (get_visualinfo(data->display, 0, &vinfo) < 0) { 685 continue; 686 } 687 } else { 688 if (get_visualinfo(data->display, screen, &vinfo) < 0) { 689 continue; 690 } 691 } 692#else 693 if (get_visualinfo(data->display, screen, &vinfo) < 0) { 694 continue; 695 } 696#endif 697 698 displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); 699 if (!displaydata) { 700 continue; 701 } 702 display_name[0] = '\0'; 703 704 mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo); 705 if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { 706 /* We don't support palettized modes now */ 707 SDL_free(displaydata); 708 continue; 709 } 710#if SDL_VIDEO_DRIVER_X11_XINERAMA 711 if (xinerama) { 712 mode.w = xinerama[screen].width; 713 mode.h = xinerama[screen].height; 714 } else { 715 mode.w = DisplayWidth(data->display, screen); 716 mode.h = DisplayHeight(data->display, screen); 717 } 718#else 719 mode.w = DisplayWidth(data->display, screen); 720 mode.h = DisplayHeight(data->display, screen); 721#endif 722 mode.refresh_rate = 0; 723 724 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 725 if (!modedata) { 726 SDL_free(displaydata); 727 continue; 728 } 729 mode.driverdata = modedata; 730 731#if SDL_VIDEO_DRIVER_X11_XINERAMA 732 /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active, 733 * there's only one screen available. So we force the screen number to zero and 734 * let Xinerama specific code handle specific functionality using displaydata->xinerama_info 735 */ 736 if (use_xinerama) { 737 displaydata->screen = 0; 738 displaydata->use_xinerama = use_xinerama; 739 displaydata->xinerama_info = xinerama[screen]; 740 displaydata->xinerama_screen = screen; 741 } 742 else displaydata->screen = screen; 743#else 744 displaydata->screen = screen; 745#endif 746 displaydata->visual = vinfo.visual; 747 displaydata->depth = vinfo.depth; 748 749 /* We use the displaydata screen index here so that this works 750 for both the Xinerama case, where we get the overall DPI, 751 and the regular X11 screen info case. */ 752 displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f / 753 DisplayWidthMM(data->display, displaydata->screen); 754 displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f / 755 DisplayHeightMM(data->display, displaydata->screen); 756 displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen), 757 DisplayHeight(data->display, displaydata->screen), 758 (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f, 759 (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f); 760 761 displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8; 762 pixmapFormats = X11_XListPixmapFormats(data->display, &n); 763 if (pixmapFormats) { 764 for (i = 0; i < n; ++i) { 765 if (pixmapFormats[i].depth == displaydata->depth) { 766 displaydata->scanline_pad = pixmapFormats[i].scanline_pad; 767 break; 768 } 769 } 770 X11_XFree(pixmapFormats); 771 } 772 773#if SDL_VIDEO_DRIVER_X11_XINERAMA 774 if (use_xinerama) { 775 displaydata->x = xinerama[screen].x_org; 776 displaydata->y = xinerama[screen].y_org; 777 } 778 else 779#endif 780 { 781 displaydata->x = 0; 782 displaydata->y = 0; 783 } 784 785#if SDL_VIDEO_DRIVER_X11_XVIDMODE 786 if (!displaydata->use_xrandr && 787#if SDL_VIDEO_DRIVER_X11_XINERAMA 788 /* XVidMode only works on the screen at the origin */ 789 (!displaydata->use_xinerama || 790 (displaydata->x == 0 && displaydata->y == 0)) && 791#endif 792 use_vidmode) { 793 displaydata->use_vidmode = use_vidmode; 794 if (displaydata->use_xinerama) { 795 displaydata->vidmode_screen = 0; 796 } else { 797 displaydata->vidmode_screen = screen; 798 } 799 XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode); 800 } 801#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 802 803 SDL_zero(display); 804 if (*display_name) { 805 display.name = display_name; 806 } 807 display.desktop_mode = mode; 808 display.current_mode = mode; 809 display.driverdata = displaydata; 810 SDL_AddVideoDisplay(&display); 811 } 812 813#if SDL_VIDEO_DRIVER_X11_XINERAMA 814 if (xinerama) X11_XFree(xinerama); 815#endif 816 817 if (_this->num_displays == 0) { 818 return SDL_SetError("No available displays"); 819 } 820 return 0; 821} 822 823void 824X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) 825{ 826 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 827 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 828#if SDL_VIDEO_DRIVER_X11_XVIDMODE 829 int nmodes; 830 XF86VidModeModeInfo ** modes; 831#endif 832 SDL_DisplayMode mode; 833 834 /* Unfortunately X11 requires the window to be created with the correct 835 * visual and depth ahead of time, but the SDL API allows you to create 836 * a window before setting the fullscreen display mode. This means that 837 * we have to use the same format for all windows and all display modes. 838 * (or support recreating the window with a new visual behind the scenes) 839 */ 840 mode.format = sdl_display->current_mode.format; 841 mode.driverdata = NULL; 842 843#if SDL_VIDEO_DRIVER_X11_XINERAMA 844 if (data->use_xinerama) { 845 int screen_w; 846 int screen_h; 847 848 screen_w = DisplayWidth(display, data->screen); 849 screen_h = DisplayHeight(display, data->screen); 850 851 if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org && 852 (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) { 853 SDL_DisplayModeData *modedata; 854 /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 855 * if we're using vidmode. 856 */ 857 mode.w = screen_w; 858 mode.h = screen_h; 859 mode.refresh_rate = 0; 860 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 861 if (modedata) { 862 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 863 } 864 mode.driverdata = modedata; 865 if (!SDL_AddDisplayMode(sdl_display, &mode)) { 866 SDL_free(modedata); 867 } 868 } 869 else if (!data->use_xrandr) 870 { 871 SDL_DisplayModeData *modedata; 872 /* Add the current mode of each monitor otherwise if we can't get them from xrandr */ 873 mode.w = data->xinerama_info.width; 874 mode.h = data->xinerama_info.height; 875 mode.refresh_rate = 0; 876 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 877 if (modedata) { 878 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 879 } 880 mode.driverdata = modedata; 881 if (!SDL_AddDisplayMode(sdl_display, &mode)) { 882 SDL_free(modedata); 883 } 884 } 885 886 } 887#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 888 889#if SDL_VIDEO_DRIVER_X11_XRANDR 890 if (data->use_xrandr) { 891 XRRScreenResources *res; 892 893 res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen)); 894 if (res) { 895 SDL_DisplayModeData *modedata; 896 XRROutputInfo *output_info; 897 int i; 898 899 output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output); 900 if (output_info && output_info->connection != RR_Disconnected) { 901 for (i = 0; i < output_info->nmode; ++i) { 902 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 903 if (!modedata) { 904 continue; 905 } 906 mode.driverdata = modedata; 907 908 if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) || 909 !SDL_AddDisplayMode(sdl_display, &mode)) { 910 SDL_free(modedata); 911 } 912 } 913 } 914 X11_XRRFreeOutputInfo(output_info); 915 X11_XRRFreeScreenResources(res); 916 } 917 return; 918 } 919#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 920 921#if SDL_VIDEO_DRIVER_X11_XVIDMODE 922 if (data->use_vidmode && 923 X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) { 924 int i; 925 SDL_DisplayModeData *modedata; 926 927#ifdef X11MODES_DEBUG 928 printf("VidMode modes: (unsorted)\n"); 929 for (i = 0; i < nmodes; ++i) { 930 printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i, 931 modes[i]->hdisplay, modes[i]->vdisplay, 932 CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags); 933 } 934#endif 935 for (i = 0; i < nmodes; ++i) { 936 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 937 if (!modedata) { 938 continue; 939 } 940 mode.driverdata = modedata; 941 942 if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) { 943 SDL_free(modedata); 944 } 945 } 946 X11_XFree(modes); 947 return; 948 } 949#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 950 951 if (!data->use_xrandr && !data->use_vidmode) { 952 SDL_DisplayModeData *modedata; 953 /* Add the desktop mode */ 954 mode = sdl_display->desktop_mode; 955 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 956 if (modedata) { 957 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 958 } 959 mode.driverdata = modedata; 960 if (!SDL_AddDisplayMode(sdl_display, &mode)) { 961 SDL_free(modedata); 962 } 963 } 964} 965 966int 967X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode) 968{ 969 SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; 970 Display *display = viddata->display; 971 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 972 SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; 973 974 viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2); 975 976#if SDL_VIDEO_DRIVER_X11_XRANDR 977 if (data->use_xrandr) { 978 XRRScreenResources *res; 979 XRROutputInfo *output_info; 980 XRRCrtcInfo *crtc; 981 Status status; 982 983 res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen)); 984 if (!res) { 985 return SDL_SetError("Couldn't get XRandR screen resources"); 986 } 987 988 output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output); 989 if (!output_info || output_info->connection == RR_Disconnected) { 990 X11_XRRFreeScreenResources(res); 991 return SDL_SetError("Couldn't get XRandR output info"); 992 } 993 994 crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc); 995 if (!crtc) { 996 X11_XRRFreeOutputInfo(output_info); 997 X11_XRRFreeScreenResources(res); 998 return SDL_SetError("Couldn't get XRandR crtc info"); 999 } 1000 1001 status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime, 1002 crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation, 1003 &data->xrandr_output, 1); 1004 1005 X11_XRRFreeCrtcInfo(crtc); 1006 X11_XRRFreeOutputInfo(output_info); 1007 X11_XRRFreeScreenResources(res); 1008 1009 if (status != Success) { 1010 return SDL_SetError("X11_XRRSetCrtcConfig failed"); 1011 } 1012 } 1013#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 1014 1015#if SDL_VIDEO_DRIVER_X11_XVIDMODE 1016 if (data->use_vidmode) { 1017 X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode); 1018 } 1019#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 1020 1021 return 0; 1022} 1023 1024void 1025X11_QuitModes(_THIS) 1026{ 1027} 1028 1029int 1030X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) 1031{ 1032 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 1033 1034 rect->x = data->x; 1035 rect->y = data->y; 1036 rect->w = sdl_display->current_mode.w; 1037 rect->h = sdl_display->current_mode.h; 1038 1039#if SDL_VIDEO_DRIVER_X11_XINERAMA 1040 /* Get the real current bounds of the display */ 1041 if (data->use_xinerama) { 1042 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 1043 int screencount; 1044 XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount); 1045 if (xinerama) { 1046 rect->x = xinerama[data->xinerama_screen].x_org; 1047 rect->y = xinerama[data->xinerama_screen].y_org; 1048 X11_XFree(xinerama); 1049 } 1050 } 1051#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 1052 return 0; 1053} 1054 1055int 1056X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi) 1057{ 1058 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 1059 1060 if (ddpi) { 1061 *ddpi = data->ddpi; 1062 } 1063 if (hdpi) { 1064 *hdpi = data->hdpi; 1065 } 1066 if (vdpi) { 1067 *vdpi = data->vdpi; 1068 } 1069 1070 return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI"); 1071} 1072 1073int 1074X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) 1075{ 1076 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 1077 Display *display = data->display; 1078 Atom _NET_WORKAREA; 1079 int status, real_format; 1080 int retval = -1; 1081 Atom real_type; 1082 unsigned long items_read = 0, items_left = 0; 1083 unsigned char *propdata = NULL; 1084 1085 if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) { 1086 return -1; 1087 } 1088 1089 _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False); 1090 status = X11_XGetWindowProperty(display, DefaultRootWindow(display), 1091 _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL, 1092 &real_type, &real_format, &items_read, 1093 &items_left, &propdata); 1094 if ((status == Success) && (items_read >= 4)) { 1095 const long *p = (long*) propdata; 1096 const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] }; 1097 retval = 0; 1098 if (!SDL_IntersectRect(rect, &usable, rect)) { 1099 SDL_zerop(rect); 1100 } 1101 } 1102 1103 if (propdata) { 1104 X11_XFree(propdata); 1105 } 1106 1107 return retval; 1108} 1109 1110#endif /* SDL_VIDEO_DRIVER_X11 */ 1111 1112/* vi: set ts=4 sw=4 expandtab: */ 1113
[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.