SDL_x11modes.c (29904B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 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 "edid.h" 28 29/* #define X11MODES_DEBUG */ 30 31/* I'm becoming more and more convinced that the application should never 32 * use XRandR, and it's the window manager's responsibility to track and 33 * manage display modes for fullscreen windows. Right now XRandR is completely 34 * broken with respect to window manager behavior on every window manager that 35 * I can find. For example, on Unity 3D if you show a fullscreen window while 36 * the resolution is changing (within ~250 ms) your window will retain the 37 * fullscreen state hint but be decorated and windowed. 38 * 39 * However, many people swear by it, so let them swear at it. :) 40*/ 41/* #define XRANDR_DISABLED_BY_DEFAULT */ 42 43 44static int 45get_visualinfo(Display * display, int screen, XVisualInfo * vinfo) 46{ 47 const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID"); 48 int depth; 49 50 /* Look for an exact visual, if requested */ 51 if (visual_id) { 52 XVisualInfo *vi, template; 53 int nvis; 54 55 SDL_zero(template); 56 template.visualid = SDL_strtol(visual_id, NULL, 0); 57 vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis); 58 if (vi) { 59 *vinfo = *vi; 60 X11_XFree(vi); 61 return 0; 62 } 63 } 64 65 depth = DefaultDepth(display, screen); 66 if ((X11_UseDirectColorVisuals() && 67 X11_XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) || 68 X11_XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) || 69 X11_XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) || 70 X11_XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) { 71 return 0; 72 } 73 return -1; 74} 75 76int 77X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo) 78{ 79 XVisualInfo *vi; 80 int nvis; 81 82 vinfo->visualid = X11_XVisualIDFromVisual(visual); 83 vi = X11_XGetVisualInfo(display, VisualIDMask, vinfo, &nvis); 84 if (vi) { 85 *vinfo = *vi; 86 X11_XFree(vi); 87 return 0; 88 } 89 return -1; 90} 91 92Uint32 93X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo) 94{ 95 if (vinfo->class == DirectColor || vinfo->class == TrueColor) { 96 int bpp; 97 Uint32 Rmask, Gmask, Bmask, Amask; 98 99 Rmask = vinfo->visual->red_mask; 100 Gmask = vinfo->visual->green_mask; 101 Bmask = vinfo->visual->blue_mask; 102 if (vinfo->depth == 32) { 103 Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask)); 104 } else { 105 Amask = 0; 106 } 107 108 bpp = vinfo->depth; 109 if (bpp == 24) { 110 int i, n; 111 XPixmapFormatValues *p = X11_XListPixmapFormats(display, &n); 112 if (p) { 113 for (i = 0; i < n; ++i) { 114 if (p[i].depth == 24) { 115 bpp = p[i].bits_per_pixel; 116 break; 117 } 118 } 119 X11_XFree(p); 120 } 121 } 122 123 return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask); 124 } 125 126 if (vinfo->class == PseudoColor || vinfo->class == StaticColor) { 127 switch (vinfo->depth) { 128 case 8: 129 return SDL_PIXELTYPE_INDEX8; 130 case 4: 131 if (BitmapBitOrder(display) == LSBFirst) { 132 return SDL_PIXELFORMAT_INDEX4LSB; 133 } else { 134 return SDL_PIXELFORMAT_INDEX4MSB; 135 } 136 break; 137 case 1: 138 if (BitmapBitOrder(display) == LSBFirst) { 139 return SDL_PIXELFORMAT_INDEX1LSB; 140 } else { 141 return SDL_PIXELFORMAT_INDEX1MSB; 142 } 143 break; 144 } 145 } 146 147 return SDL_PIXELFORMAT_UNKNOWN; 148} 149 150/* Global for the error handler */ 151int vm_event, vm_error = -1; 152 153#if SDL_VIDEO_DRIVER_X11_XINERAMA 154static SDL_bool 155CheckXinerama(Display * display, int *major, int *minor) 156{ 157 int event_base = 0; 158 int error_base = 0; 159 const char *env; 160 161 /* Default the extension not available */ 162 *major = *minor = 0; 163 164 /* Allow environment override */ 165 env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA); 166 if (env && !SDL_atoi(env)) { 167#ifdef X11MODES_DEBUG 168 printf("Xinerama disabled due to hint\n"); 169#endif 170 return SDL_FALSE; 171 } 172 173 if (!SDL_X11_HAVE_XINERAMA) { 174#ifdef X11MODES_DEBUG 175 printf("Xinerama support not available\n"); 176#endif 177 return SDL_FALSE; 178 } 179 180 /* Query the extension version */ 181 if (!X11_XineramaQueryExtension(display, &event_base, &error_base) || 182 !X11_XineramaQueryVersion(display, major, minor) || 183 !X11_XineramaIsActive(display)) { 184#ifdef X11MODES_DEBUG 185 printf("Xinerama not active on the display\n"); 186#endif 187 return SDL_FALSE; 188 } 189#ifdef X11MODES_DEBUG 190 printf("Xinerama available at version %d.%d!\n", *major, *minor); 191#endif 192 return SDL_TRUE; 193} 194#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 195 196#if SDL_VIDEO_DRIVER_X11_XRANDR 197static SDL_bool 198CheckXRandR(Display * display, int *major, int *minor) 199{ 200 const char *env; 201 202 /* Default the extension not available */ 203 *major = *minor = 0; 204 205 /* Allow environment override */ 206 env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR); 207#ifdef XRANDR_DISABLED_BY_DEFAULT 208 if (!env || !SDL_atoi(env)) { 209#ifdef X11MODES_DEBUG 210 printf("XRandR disabled by default due to window manager issues\n"); 211#endif 212 return SDL_FALSE; 213 } 214#else 215 if (env && !SDL_atoi(env)) { 216#ifdef X11MODES_DEBUG 217 printf("XRandR disabled due to hint\n"); 218#endif 219 return SDL_FALSE; 220 } 221#endif /* XRANDR_ENABLED_BY_DEFAULT */ 222 223 if (!SDL_X11_HAVE_XRANDR) { 224#ifdef X11MODES_DEBUG 225 printf("XRandR support not available\n"); 226#endif 227 return SDL_FALSE; 228 } 229 230 /* Query the extension version */ 231 if (!X11_XRRQueryVersion(display, major, minor)) { 232#ifdef X11MODES_DEBUG 233 printf("XRandR not active on the display\n"); 234#endif 235 return SDL_FALSE; 236 } 237#ifdef X11MODES_DEBUG 238 printf("XRandR available at version %d.%d!\n", *major, *minor); 239#endif 240 return SDL_TRUE; 241} 242 243#define XRANDR_ROTATION_LEFT (1 << 1) 244#define XRANDR_ROTATION_RIGHT (1 << 3) 245 246static int 247CalculateXRandRRefreshRate(const XRRModeInfo *info) 248{ 249 return (info->hTotal 250 && info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0; 251} 252 253static SDL_bool 254SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info, 255 RRMode modeID, SDL_DisplayMode *mode) 256{ 257 int i; 258 for (i = 0; i < res->nmode; ++i) { 259 if (res->modes[i].id == modeID) { 260 XRRCrtcInfo *crtc; 261 Rotation rotation = 0; 262 const XRRModeInfo *info = &res->modes[i]; 263 264 crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc); 265 if (crtc) { 266 rotation = crtc->rotation; 267 X11_XRRFreeCrtcInfo(crtc); 268 } 269 270 if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { 271 mode->w = info->height; 272 mode->h = info->width; 273 } else { 274 mode->w = info->width; 275 mode->h = info->height; 276 } 277 mode->refresh_rate = CalculateXRandRRefreshRate(info); 278 ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID; 279#ifdef X11MODES_DEBUG 280 printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate); 281#endif 282 return SDL_TRUE; 283 } 284 } 285 return SDL_FALSE; 286} 287#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 288 289#if SDL_VIDEO_DRIVER_X11_XVIDMODE 290static SDL_bool 291CheckVidMode(Display * display, int *major, int *minor) 292{ 293 const char *env; 294 295 /* Default the extension not available */ 296 *major = *minor = 0; 297 298 /* Allow environment override */ 299 env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE); 300 if (env && !SDL_atoi(env)) { 301#ifdef X11MODES_DEBUG 302 printf("XVidMode disabled due to hint\n"); 303#endif 304 return SDL_FALSE; 305 } 306 307 if (!SDL_X11_HAVE_XVIDMODE) { 308#ifdef X11MODES_DEBUG 309 printf("XVidMode support not available\n"); 310#endif 311 return SDL_FALSE; 312 } 313 314 /* Query the extension version */ 315 vm_error = -1; 316 if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error) 317 || !X11_XF86VidModeQueryVersion(display, major, minor)) { 318#ifdef X11MODES_DEBUG 319 printf("XVidMode not active on the display\n"); 320#endif 321 return SDL_FALSE; 322 } 323#ifdef X11MODES_DEBUG 324 printf("XVidMode available at version %d.%d!\n", *major, *minor); 325#endif 326 return SDL_TRUE; 327} 328 329static 330Bool XF86VidModeGetModeInfo(Display * dpy, int scr, 331 XF86VidModeModeInfo* info) 332{ 333 Bool retval; 334 int dotclock; 335 XF86VidModeModeLine l; 336 SDL_zerop(info); 337 SDL_zero(l); 338 retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l); 339 info->dotclock = dotclock; 340 info->hdisplay = l.hdisplay; 341 info->hsyncstart = l.hsyncstart; 342 info->hsyncend = l.hsyncend; 343 info->htotal = l.htotal; 344 info->hskew = l.hskew; 345 info->vdisplay = l.vdisplay; 346 info->vsyncstart = l.vsyncstart; 347 info->vsyncend = l.vsyncend; 348 info->vtotal = l.vtotal; 349 info->flags = l.flags; 350 info->privsize = l.privsize; 351 info->private = l.private; 352 return retval; 353} 354 355static int 356CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info) 357{ 358 return (info->htotal 359 && info->vtotal) ? (1000 * info->dotclock / (info->htotal * 360 info->vtotal)) : 0; 361} 362 363SDL_bool 364SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode) 365{ 366 mode->w = info->hdisplay; 367 mode->h = info->vdisplay; 368 mode->refresh_rate = CalculateXVidModeRefreshRate(info); 369 ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info; 370 return SDL_TRUE; 371} 372#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 373 374int 375X11_InitModes(_THIS) 376{ 377 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 378 int snum, screen, screencount; 379#if SDL_VIDEO_DRIVER_X11_XINERAMA 380 int xinerama_major, xinerama_minor; 381 int use_xinerama = 0; 382 XineramaScreenInfo *xinerama = NULL; 383#endif 384#if SDL_VIDEO_DRIVER_X11_XRANDR 385 int xrandr_major, xrandr_minor; 386 int use_xrandr = 0; 387 XRRScreenResources *res = NULL; 388#endif 389#if SDL_VIDEO_DRIVER_X11_XVIDMODE 390 int vm_major, vm_minor; 391 int use_vidmode = 0; 392#endif 393 394#if SDL_VIDEO_DRIVER_X11_XINERAMA 395 /* Query Xinerama extention 396 * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012) 397 * or newer of the Nvidia binary drivers 398 */ 399 if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) { 400 xinerama = X11_XineramaQueryScreens(data->display, &screencount); 401 if (xinerama) { 402 use_xinerama = xinerama_major * 100 + xinerama_minor; 403 } 404 } 405 if (!xinerama) { 406 screencount = ScreenCount(data->display); 407 } 408#else 409 screencount = ScreenCount(data->display); 410#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 411 412#if SDL_VIDEO_DRIVER_X11_XRANDR 413 /* require at least XRandR v1.2 */ 414 if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) && 415 (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) { 416 use_xrandr = xrandr_major * 100 + xrandr_minor; 417 } 418#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 419 420#if SDL_VIDEO_DRIVER_X11_XVIDMODE 421 if (CheckVidMode(data->display, &vm_major, &vm_minor)) { 422 use_vidmode = vm_major * 100 + vm_minor; 423 } 424#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 425 426 for (snum = 0; snum < screencount; ++snum) { 427 XVisualInfo vinfo; 428 SDL_VideoDisplay display; 429 SDL_DisplayData *displaydata; 430 SDL_DisplayMode mode; 431 SDL_DisplayModeData *modedata; 432 XPixmapFormatValues *pixmapFormats; 433 char display_name[128]; 434 int i, n; 435 436 /* Re-order screens to always put default screen first */ 437 if (snum == 0) { 438 screen = DefaultScreen(data->display); 439 } else if (snum == DefaultScreen(data->display)) { 440 screen = 0; 441 } else { 442 screen = snum; 443 } 444 445#if SDL_VIDEO_DRIVER_X11_XINERAMA 446 if (xinerama) { 447 if (get_visualinfo(data->display, 0, &vinfo) < 0) { 448 continue; 449 } 450 } else { 451 if (get_visualinfo(data->display, screen, &vinfo) < 0) { 452 continue; 453 } 454 } 455#else 456 if (get_visualinfo(data->display, screen, &vinfo) < 0) { 457 continue; 458 } 459#endif 460 461 displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); 462 if (!displaydata) { 463 continue; 464 } 465 display_name[0] = '\0'; 466 467 mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo); 468 if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { 469 /* We don't support palettized modes now */ 470 SDL_free(displaydata); 471 continue; 472 } 473#if SDL_VIDEO_DRIVER_X11_XINERAMA 474 if (xinerama) { 475 mode.w = xinerama[screen].width; 476 mode.h = xinerama[screen].height; 477 } else { 478 mode.w = DisplayWidth(data->display, screen); 479 mode.h = DisplayHeight(data->display, screen); 480 } 481#else 482 mode.w = DisplayWidth(data->display, screen); 483 mode.h = DisplayHeight(data->display, screen); 484#endif 485 mode.refresh_rate = 0; 486 487 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 488 if (!modedata) { 489 SDL_free(displaydata); 490 continue; 491 } 492 mode.driverdata = modedata; 493 494#if SDL_VIDEO_DRIVER_X11_XINERAMA 495 /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active, 496 * there's only one screen available. So we force the screen number to zero and 497 * let Xinerama specific code handle specific functionality using displaydata->xinerama_info 498 */ 499 if (use_xinerama) { 500 displaydata->screen = 0; 501 displaydata->use_xinerama = use_xinerama; 502 displaydata->xinerama_info = xinerama[screen]; 503 displaydata->xinerama_screen = screen; 504 } 505 else displaydata->screen = screen; 506#else 507 displaydata->screen = screen; 508#endif 509 displaydata->visual = vinfo.visual; 510 displaydata->depth = vinfo.depth; 511 512 displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8; 513 pixmapFormats = X11_XListPixmapFormats(data->display, &n); 514 if (pixmapFormats) { 515 for (i = 0; i < n; ++i) { 516 if (pixmapFormats[i].depth == displaydata->depth) { 517 displaydata->scanline_pad = pixmapFormats[i].scanline_pad; 518 break; 519 } 520 } 521 X11_XFree(pixmapFormats); 522 } 523 524#if SDL_VIDEO_DRIVER_X11_XINERAMA 525 if (use_xinerama) { 526 displaydata->x = xinerama[screen].x_org; 527 displaydata->y = xinerama[screen].y_org; 528 } 529 else 530#endif 531 { 532 displaydata->x = 0; 533 displaydata->y = 0; 534 } 535 536#if SDL_VIDEO_DRIVER_X11_XRANDR 537 if (use_xrandr) { 538 res = X11_XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen)); 539 } 540 if (res) { 541 XRROutputInfo *output_info; 542 XRRCrtcInfo *crtc; 543 int output; 544 Atom EDID = X11_XInternAtom(data->display, "EDID", False); 545 Atom *props; 546 int nprop; 547 unsigned long width_mm; 548 unsigned long height_mm; 549 int inches = 0; 550 551 for (output = 0; output < res->noutput; output++) { 552 output_info = X11_XRRGetOutputInfo(data->display, res, res->outputs[output]); 553 if (!output_info || !output_info->crtc || 554 output_info->connection == RR_Disconnected) { 555 X11_XRRFreeOutputInfo(output_info); 556 continue; 557 } 558 559 /* Is this the output that corresponds to the current screen? 560 We're checking the crtc position, but that may not be a valid test 561 in all cases. Anybody want to give this some love? 562 */ 563 crtc = X11_XRRGetCrtcInfo(data->display, res, output_info->crtc); 564 if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y || 565 crtc->width != mode.w || crtc->height != mode.h) { 566 X11_XRRFreeOutputInfo(output_info); 567 X11_XRRFreeCrtcInfo(crtc); 568 continue; 569 } 570 571 displaydata->use_xrandr = use_xrandr; 572 displaydata->xrandr_output = res->outputs[output]; 573 SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode); 574 575 /* Get the name of this display */ 576 width_mm = output_info->mm_width; 577 height_mm = output_info->mm_height; 578 inches = (int)((sqrt(width_mm * width_mm + 579 height_mm * height_mm) / 25.4f) + 0.5f); 580 SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); 581 582 /* See if we can get the EDID data for the real monitor name */ 583 props = X11_XRRListOutputProperties(data->display, res->outputs[output], &nprop); 584 for (i = 0; i < nprop; ++i) { 585 unsigned char *prop; 586 int actual_format; 587 unsigned long nitems, bytes_after; 588 Atom actual_type; 589 590 if (props[i] == EDID) { 591 if (X11_XRRGetOutputProperty(data->display, 592 res->outputs[output], props[i], 593 0, 100, False, False, 594 AnyPropertyType, 595 &actual_type, &actual_format, 596 &nitems, &bytes_after, &prop) == Success ) { 597 MonitorInfo *info = decode_edid(prop); 598 if (info) { 599 #ifdef X11MODES_DEBUG 600 printf("Found EDID data for %s\n", output_info->name); 601 dump_monitor_info(info); 602 #endif 603 SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name)); 604 free(info); 605 } 606 X11_XFree(prop); 607 } 608 break; 609 } 610 } 611 if (props) { 612 X11_XFree(props); 613 } 614 615 if (*display_name && inches) { 616 size_t len = SDL_strlen(display_name); 617 SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches); 618 } 619#ifdef X11MODES_DEBUG 620 printf("Display name: %s\n", display_name); 621#endif 622 623 X11_XRRFreeOutputInfo(output_info); 624 X11_XRRFreeCrtcInfo(crtc); 625 break; 626 } 627#ifdef X11MODES_DEBUG 628 if (output == res->noutput) { 629 printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y); 630 } 631#endif 632 X11_XRRFreeScreenResources(res); 633 } 634#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 635 636#if SDL_VIDEO_DRIVER_X11_XVIDMODE 637 if (!displaydata->use_xrandr && 638#if SDL_VIDEO_DRIVER_X11_XINERAMA 639 /* XVidMode only works on the screen at the origin */ 640 (!displaydata->use_xinerama || 641 (displaydata->x == 0 && displaydata->y == 0)) && 642#endif 643 use_vidmode) { 644 displaydata->use_vidmode = use_vidmode; 645 if (displaydata->use_xinerama) { 646 displaydata->vidmode_screen = 0; 647 } else { 648 displaydata->vidmode_screen = screen; 649 } 650 XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode); 651 } 652#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 653 654 SDL_zero(display); 655 if (*display_name) { 656 display.name = display_name; 657 } 658 display.desktop_mode = mode; 659 display.current_mode = mode; 660 display.driverdata = displaydata; 661 SDL_AddVideoDisplay(&display); 662 } 663 664#if SDL_VIDEO_DRIVER_X11_XINERAMA 665 if (xinerama) X11_XFree(xinerama); 666#endif 667 668 if (_this->num_displays == 0) { 669 return SDL_SetError("No available displays"); 670 } 671 return 0; 672} 673 674void 675X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) 676{ 677 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 678 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 679#if SDL_VIDEO_DRIVER_X11_XVIDMODE 680 int nmodes; 681 XF86VidModeModeInfo ** modes; 682#endif 683 int screen_w; 684 int screen_h; 685 SDL_DisplayMode mode; 686 687 /* Unfortunately X11 requires the window to be created with the correct 688 * visual and depth ahead of time, but the SDL API allows you to create 689 * a window before setting the fullscreen display mode. This means that 690 * we have to use the same format for all windows and all display modes. 691 * (or support recreating the window with a new visual behind the scenes) 692 */ 693 mode.format = sdl_display->current_mode.format; 694 mode.driverdata = NULL; 695 696 screen_w = DisplayWidth(display, data->screen); 697 screen_h = DisplayHeight(display, data->screen); 698 699#if SDL_VIDEO_DRIVER_X11_XINERAMA 700 if (data->use_xinerama) { 701 if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org && 702 (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) { 703 SDL_DisplayModeData *modedata; 704 /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 705 * if we're using vidmode. 706 */ 707 mode.w = screen_w; 708 mode.h = screen_h; 709 mode.refresh_rate = 0; 710 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 711 if (modedata) { 712 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 713 } 714 mode.driverdata = modedata; 715 SDL_AddDisplayMode(sdl_display, &mode); 716 } 717 else if (!data->use_xrandr) 718 { 719 SDL_DisplayModeData *modedata; 720 /* Add the current mode of each monitor otherwise if we can't get them from xrandr */ 721 mode.w = data->xinerama_info.width; 722 mode.h = data->xinerama_info.height; 723 mode.refresh_rate = 0; 724 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 725 if (modedata) { 726 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 727 } 728 mode.driverdata = modedata; 729 SDL_AddDisplayMode(sdl_display, &mode); 730 } 731 732 } 733#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 734 735#if SDL_VIDEO_DRIVER_X11_XRANDR 736 if (data->use_xrandr) { 737 XRRScreenResources *res; 738 739 res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen)); 740 if (res) { 741 SDL_DisplayModeData *modedata; 742 XRROutputInfo *output_info; 743 int i; 744 745 output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output); 746 if (output_info && output_info->connection != RR_Disconnected) { 747 for (i = 0; i < output_info->nmode; ++i) { 748 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 749 if (!modedata) { 750 continue; 751 } 752 mode.driverdata = modedata; 753 754 if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) { 755 SDL_AddDisplayMode(sdl_display, &mode); 756 } else { 757 SDL_free(modedata); 758 } 759 } 760 } 761 X11_XRRFreeOutputInfo(output_info); 762 X11_XRRFreeScreenResources(res); 763 } 764 return; 765 } 766#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 767 768#if SDL_VIDEO_DRIVER_X11_XVIDMODE 769 if (data->use_vidmode && 770 X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) { 771 int i; 772 SDL_DisplayModeData *modedata; 773 774#ifdef X11MODES_DEBUG 775 printf("VidMode modes: (unsorted)\n"); 776 for (i = 0; i < nmodes; ++i) { 777 printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i, 778 modes[i]->hdisplay, modes[i]->vdisplay, 779 CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags); 780 } 781#endif 782 for (i = 0; i < nmodes; ++i) { 783 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 784 if (!modedata) { 785 continue; 786 } 787 mode.driverdata = modedata; 788 789 if (SetXVidModeModeInfo(modes[i], &mode)) { 790 SDL_AddDisplayMode(sdl_display, &mode); 791 } else { 792 SDL_free(modedata); 793 } 794 } 795 X11_XFree(modes); 796 return; 797 } 798#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 799 800 if (!data->use_xrandr && !data->use_vidmode) { 801 SDL_DisplayModeData *modedata; 802 /* Add the desktop mode */ 803 mode = sdl_display->desktop_mode; 804 modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); 805 if (modedata) { 806 *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; 807 } 808 mode.driverdata = modedata; 809 SDL_AddDisplayMode(sdl_display, &mode); 810 } 811} 812 813int 814X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode) 815{ 816 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 817 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 818 SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; 819 820#if SDL_VIDEO_DRIVER_X11_XRANDR 821 if (data->use_xrandr) { 822 XRRScreenResources *res; 823 XRROutputInfo *output_info; 824 XRRCrtcInfo *crtc; 825 Status status; 826 827 res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen)); 828 if (!res) { 829 return SDL_SetError("Couldn't get XRandR screen resources"); 830 } 831 832 output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output); 833 if (!output_info || output_info->connection == RR_Disconnected) { 834 X11_XRRFreeScreenResources(res); 835 return SDL_SetError("Couldn't get XRandR output info"); 836 } 837 838 crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc); 839 if (!crtc) { 840 X11_XRRFreeOutputInfo(output_info); 841 X11_XRRFreeScreenResources(res); 842 return SDL_SetError("Couldn't get XRandR crtc info"); 843 } 844 845 status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime, 846 crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation, 847 &data->xrandr_output, 1); 848 849 X11_XRRFreeCrtcInfo(crtc); 850 X11_XRRFreeOutputInfo(output_info); 851 X11_XRRFreeScreenResources(res); 852 853 if (status != Success) { 854 return SDL_SetError("X11_XRRSetCrtcConfig failed"); 855 } 856 } 857#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 858 859#if SDL_VIDEO_DRIVER_X11_XVIDMODE 860 if (data->use_vidmode) { 861 X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode); 862 } 863#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */ 864 865 return 0; 866} 867 868void 869X11_QuitModes(_THIS) 870{ 871} 872 873int 874X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) 875{ 876 SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; 877 878 rect->x = data->x; 879 rect->y = data->y; 880 rect->w = sdl_display->current_mode.w; 881 rect->h = sdl_display->current_mode.h; 882 883#if SDL_VIDEO_DRIVER_X11_XINERAMA 884 /* Get the real current bounds of the display */ 885 if (data->use_xinerama) { 886 Display *display = ((SDL_VideoData *) _this->driverdata)->display; 887 int screencount; 888 XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount); 889 if (xinerama) { 890 rect->x = xinerama[data->xinerama_screen].x_org; 891 rect->y = xinerama[data->xinerama_screen].y_org; 892 X11_XFree(xinerama); 893 } 894 } 895#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 896 return 0; 897} 898 899#endif /* SDL_VIDEO_DRIVER_X11 */ 900 901/* vi: set ts=4 sw=4 expandtab: */