1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Utilities for getting and setting the X display mode */ 25 26 #include <stdio.h> 27 28 #include "SDL_timer.h" 29 #include "SDL_events.h" 30 #include "../../events/SDL_events_c.h" 31 #include "SDL_x11video.h" 32 #include "SDL_x11wm_c.h" 33 #include "SDL_x11modes_c.h" 34 #include "SDL_x11image_c.h" 35 36 /*#define X11MODES_DEBUG*/ 37 38 #define MAX(a, b) (a > b ? a : b) 39 40 #if SDL_VIDEO_DRIVER_X11_XRANDR 41 static int cmpmodelist(const void *va, const void *vb) 42 { 43 const SDL_Rect *a = *(const SDL_Rect **)va; 44 const SDL_Rect *b = *(const SDL_Rect **)vb; 45 if ( a->w == b->w ) 46 return b->h - a->h; 47 else 48 return b->w - a->w; 49 } 50 #endif 51 52 #if SDL_VIDEO_DRIVER_X11_VIDMODE 53 Bool SDL_NAME(XF86VidModeGetModeInfo)(Display *dpy, int scr, SDL_NAME(XF86VidModeModeInfo) *info) 54 { 55 SDL_NAME(XF86VidModeModeLine) *l = (SDL_NAME(XF86VidModeModeLine)*)((char*)info + sizeof info->dotclock); 56 return SDL_NAME(XF86VidModeGetModeLine)(dpy, scr, (int*)&info->dotclock, l); 57 } 58 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ 59 60 #if SDL_VIDEO_DRIVER_X11_VIDMODE 61 static void save_mode(_THIS) 62 { 63 SDL_memset(&saved_mode, 0, sizeof(saved_mode)); 64 SDL_NAME(XF86VidModeGetModeInfo)(SDL_Display,SDL_Screen,&saved_mode); 65 SDL_NAME(XF86VidModeGetViewPort)(SDL_Display,SDL_Screen,&saved_view.x,&saved_view.y); 66 } 67 #endif 68 69 #if SDL_VIDEO_DRIVER_X11_VIDMODE 70 static void restore_mode(_THIS) 71 { 72 SDL_NAME(XF86VidModeModeLine) mode; 73 int unused; 74 75 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) { 76 if ( (saved_mode.hdisplay != mode.hdisplay) || 77 (saved_mode.vdisplay != mode.vdisplay) ) { 78 SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, &saved_mode); 79 } 80 } 81 if ( (saved_view.x != 0) || (saved_view.y != 0) ) { 82 SDL_NAME(XF86VidModeSetViewPort)(SDL_Display, SDL_Screen, saved_view.x, saved_view.y); 83 } 84 } 85 #endif 86 87 #if SDL_VIDEO_DRIVER_X11_VIDMODE 88 static int cmpmodes(const void *va, const void *vb) 89 { 90 const SDL_NAME(XF86VidModeModeInfo) *a = *(const SDL_NAME(XF86VidModeModeInfo)**)va; 91 const SDL_NAME(XF86VidModeModeInfo) *b = *(const SDL_NAME(XF86VidModeModeInfo)**)vb; 92 if ( a->hdisplay == b->hdisplay ) 93 return b->vdisplay - a->vdisplay; 94 else 95 return b->hdisplay - a->hdisplay; 96 } 97 #endif 98 99 static void get_real_resolution(_THIS, int* w, int* h); 100 101 static void set_best_resolution(_THIS, int width, int height) 102 { 103 #if SDL_VIDEO_DRIVER_X11_VIDMODE 104 if ( use_vidmode ) { 105 SDL_NAME(XF86VidModeModeLine) mode; 106 SDL_NAME(XF86VidModeModeInfo) **modes; 107 int i; 108 int nmodes; 109 int best = -1; 110 111 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &i, &mode) && 112 SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display,SDL_Screen,&nmodes,&modes) ) { 113 for ( i = 0; i < nmodes ; i++ ) { 114 if ( (modes[i]->hdisplay == width) && 115 (modes[i]->vdisplay == height) ) { 116 best = i; 117 break; 118 } 119 if ( modes[i]->hdisplay >= width && 120 modes[i]->vdisplay >= height ) { 121 if ( best < 0 || 122 (modes[i]->hdisplay < modes[best]->hdisplay && 123 modes[i]->vdisplay <= modes[best]->vdisplay) || 124 (modes[i]->vdisplay < modes[best]->vdisplay && 125 modes[i]->hdisplay <= modes[best]->hdisplay) ) { 126 best = i; 127 } 128 } 129 } 130 if ( best >= 0 && 131 ((modes[best]->hdisplay != mode.hdisplay) || 132 (modes[best]->vdisplay != mode.vdisplay)) ) { 133 #ifdef X11MODES_DEBUG 134 printf("Best Mode %d: %d x %d @ %d\n", best, 135 modes[best]->hdisplay, modes[best]->vdisplay, 136 (modes[best]->htotal && modes[best]->vtotal) ? (1000 * modes[best]->dotclock / (modes[best]->htotal * modes[best]->vtotal)) : 0 ); 137 #endif 138 SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, modes[best]); 139 } 140 XFree(modes); 141 } 142 } 143 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ 144 145 /* XiG */ 146 #if SDL_VIDEO_DRIVER_X11_XME 147 if ( use_xme && SDL_modelist ) { 148 int i; 149 150 #ifdef X11MODES_DEBUG 151 fprintf(stderr, "XME: set_best_resolution(): w = %d, h = %d\n", 152 width, height); 153 #endif 154 for ( i=0; SDL_modelist[i]; ++i ) { 155 if ( (SDL_modelist[i]->w >= width) && 156 (SDL_modelist[i]->h >= height) ) { 157 break; 158 } 159 } 160 161 if ( SDL_modelist[i] ) { /* found one, lets try it */ 162 int w, h; 163 164 /* check current mode so we can avoid uneccessary mode changes */ 165 get_real_resolution(this, &w, &h); 166 167 if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) { 168 #ifdef X11MODES_DEBUG 169 fprintf(stderr, "XME: set_best_resolution: " 170 "XiGMiscChangeResolution: %d %d\n", 171 SDL_modelist[i]->w, SDL_modelist[i]->h); 172 #endif 173 XiGMiscChangeResolution(SDL_Display, 174 SDL_Screen, 175 0, /* view */ 176 SDL_modelist[i]->w, 177 SDL_modelist[i]->h, 178 0); 179 XSync(SDL_Display, False); 180 } 181 } 182 } 183 #endif /* SDL_VIDEO_DRIVER_X11_XME */ 184 185 #if SDL_VIDEO_DRIVER_X11_XRANDR 186 if ( use_xrandr && SDL_modelist ) { 187 #ifdef X11MODES_DEBUG 188 fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n", 189 width, height); 190 #endif 191 int i, nsizes; 192 XRRScreenSize *sizes; 193 194 /* find the smallest resolution that is at least as big as the user requested */ 195 sizes = XRRConfigSizes(screen_config, &nsizes); 196 for ( i = (nsizes-1); i >= 0; i-- ) { 197 if ( (SDL_modelist[i]->w >= width) && 198 (SDL_modelist[i]->h >= height) ) { 199 break; 200 } 201 } 202 203 if ( i >= 0 && SDL_modelist[i] ) { /* found one, lets try it */ 204 int w, h; 205 206 /* check current mode so we can avoid uneccessary mode changes */ 207 get_real_resolution(this, &w, &h); 208 209 if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) { 210 int size_id; 211 212 #ifdef X11MODES_DEBUG 213 fprintf(stderr, "XRANDR: set_best_resolution: " 214 "XXRSetScreenConfig: %d %d\n", 215 SDL_modelist[i]->w, SDL_modelist[i]->h); 216 #endif 217 218 /* find the matching size entry index */ 219 for ( size_id = 0; size_id < nsizes; ++size_id ) { 220 if ( (sizes[size_id].width == SDL_modelist[i]->w) && 221 (sizes[size_id].height == SDL_modelist[i]->h) ) 222 break; 223 } 224 225 XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, 226 size_id, saved_rotation, CurrentTime); 227 } 228 } 229 } 230 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 231 } 232 233 static void get_real_resolution(_THIS, int* w, int* h) 234 { 235 #if SDL_VIDEO_DRIVER_X11_XME 236 if ( use_xme ) { 237 int ractive; 238 XiGMiscResolutionInfo *modelist; 239 240 XiGMiscQueryResolutions(SDL_Display, SDL_Screen, 241 0, /* view */ 242 &ractive, &modelist); 243 *w = modelist[ractive].width; 244 *h = modelist[ractive].height; 245 #ifdef X11MODES_DEBUG 246 fprintf(stderr, "XME: get_real_resolution: w = %d h = %d\n", *w, *h); 247 #endif 248 XFree(modelist); 249 return; 250 } 251 #endif /* SDL_VIDEO_DRIVER_X11_XME */ 252 253 #if SDL_VIDEO_DRIVER_X11_VIDMODE 254 if ( use_vidmode ) { 255 SDL_NAME(XF86VidModeModeLine) mode; 256 int unused; 257 258 if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) { 259 *w = mode.hdisplay; 260 *h = mode.vdisplay; 261 return; 262 } 263 } 264 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ 265 266 #if SDL_VIDEO_DRIVER_X11_XRANDR 267 if ( use_xrandr ) { 268 int nsizes; 269 XRRScreenSize* sizes; 270 271 sizes = XRRConfigSizes(screen_config, &nsizes); 272 if ( nsizes > 0 ) { 273 int cur_size; 274 Rotation cur_rotation; 275 276 cur_size = XRRConfigCurrentConfiguration(screen_config, &cur_rotation); 277 if ( cur_size >= 0 && cur_size < nsizes ) { 278 *w = sizes[cur_size].width; 279 *h = sizes[cur_size].height; 280 } 281 #ifdef X11MODES_DEBUG 282 fprintf(stderr, "XRANDR: get_real_resolution: w = %d h = %d\n", *w, *h); 283 #endif 284 return; 285 } 286 } 287 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 288 289 #if SDL_VIDEO_DRIVER_X11_XINERAMA 290 if ( use_xinerama ) { 291 *w = xinerama_info.width; 292 *h = xinerama_info.height; 293 return; 294 } 295 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 296 297 *w = DisplayWidth(SDL_Display, SDL_Screen); 298 *h = DisplayHeight(SDL_Display, SDL_Screen); 299 } 300 301 /* Called after mapping a window - waits until the window is mapped */ 302 void X11_WaitMapped(_THIS, Window win) 303 { 304 XEvent event; 305 do { 306 XMaskEvent(SDL_Display, StructureNotifyMask, &event); 307 } while ( (event.type != MapNotify) || (event.xmap.event != win) ); 308 } 309 310 /* Called after unmapping a window - waits until the window is unmapped */ 311 void X11_WaitUnmapped(_THIS, Window win) 312 { 313 XEvent event; 314 do { 315 XMaskEvent(SDL_Display, StructureNotifyMask, &event); 316 } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) ); 317 } 318 319 static void move_cursor_to(_THIS, int x, int y) 320 { 321 XWarpPointer(SDL_Display, None, SDL_Root, 0, 0, 0, 0, x, y); 322 } 323 324 static int add_visual(_THIS, int depth, int class) 325 { 326 XVisualInfo vi; 327 if(XMatchVisualInfo(SDL_Display, SDL_Screen, depth, class, &vi)) { 328 int n = this->hidden->nvisuals; 329 this->hidden->visuals[n].depth = vi.depth; 330 this->hidden->visuals[n].visual = vi.visual; 331 this->hidden->nvisuals++; 332 } 333 return(this->hidden->nvisuals); 334 } 335 static int add_visual_byid(_THIS, const char *visual_id) 336 { 337 XVisualInfo *vi, template; 338 int nvis; 339 340 if ( visual_id ) { 341 SDL_memset(&template, 0, (sizeof template)); 342 template.visualid = SDL_strtol(visual_id, NULL, 0); 343 vi = XGetVisualInfo(SDL_Display, VisualIDMask, &template, &nvis); 344 if ( vi ) { 345 int n = this->hidden->nvisuals; 346 this->hidden->visuals[n].depth = vi->depth; 347 this->hidden->visuals[n].visual = vi->visual; 348 this->hidden->nvisuals++; 349 XFree(vi); 350 } 351 } 352 return(this->hidden->nvisuals); 353 } 354 355 /* Global for the error handler */ 356 int vm_event, vm_error = -1; 357 358 #if SDL_VIDEO_DRIVER_X11_XINERAMA 359 static int CheckXinerama(_THIS, int *major, int *minor) 360 { 361 const char *env; 362 363 /* Default the extension not available */ 364 *major = *minor = 0; 365 366 /* Allow environment override */ 367 env = getenv("SDL_VIDEO_X11_XINERAMA"); 368 if ( env && !SDL_atoi(env) ) { 369 return 0; 370 } 371 372 /* Query the extension version */ 373 if ( !SDL_NAME(XineramaQueryExtension)(SDL_Display, major, minor) || 374 !SDL_NAME(XineramaIsActive)(SDL_Display) ) { 375 return 0; 376 } 377 return 1; 378 } 379 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 380 381 #if SDL_VIDEO_DRIVER_X11_XRANDR 382 static int CheckXRandR(_THIS, int *major, int *minor) 383 { 384 const char *env; 385 386 /* Default the extension not available */ 387 *major = *minor = 0; 388 389 /* Allow environment override */ 390 env = getenv("SDL_VIDEO_X11_XRANDR"); 391 if ( env && !SDL_atoi(env) ) { 392 return 0; 393 } 394 395 /* This defaults off now, due to KDE window maximize problems */ 396 if ( !env ) { 397 return 0; 398 } 399 400 if ( !SDL_X11_HAVE_XRANDR ) { 401 return 0; 402 } 403 404 /* Query the extension version */ 405 if ( !XRRQueryVersion(SDL_Display, major, minor) ) { 406 return 0; 407 } 408 return 1; 409 } 410 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 411 412 #if SDL_VIDEO_DRIVER_X11_VIDMODE 413 static int CheckVidMode(_THIS, int *major, int *minor) 414 { 415 const char *env; 416 417 /* Default the extension not available */ 418 *major = *minor = 0; 419 420 /* Allow environment override */ 421 env = getenv("SDL_VIDEO_X11_VIDMODE"); 422 if ( env && !SDL_atoi(env) ) { 423 return 0; 424 } 425 426 /* Metro-X 4.3.0 and earlier has a broken implementation of 427 XF86VidModeGetAllModeLines() - it hangs the client. 428 */ 429 if ( SDL_strcmp(ServerVendor(SDL_Display), "Metro Link Incorporated") == 0 ) { 430 FILE *metro_fp; 431 432 metro_fp = fopen("/usr/X11R6/lib/X11/Metro/.version", "r"); 433 if ( metro_fp != NULL ) { 434 int major, minor, patch, version; 435 major = 0; minor = 0; patch = 0; 436 fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch); 437 fclose(metro_fp); 438 version = major*100+minor*10+patch; 439 if ( version < 431 ) { 440 return 0; 441 } 442 } 443 } 444 445 /* Query the extension version */ 446 vm_error = -1; 447 if ( !SDL_NAME(XF86VidModeQueryExtension)(SDL_Display, &vm_event, &vm_error) || 448 !SDL_NAME(XF86VidModeQueryVersion)(SDL_Display, major, minor) ) { 449 return 0; 450 } 451 return 1; 452 } 453 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ 454 455 #if SDL_VIDEO_DRIVER_X11_XME 456 static int CheckXME(_THIS, int *major, int *minor) 457 { 458 const char *env; 459 460 /* Default the extension not available */ 461 *major = *minor = 0; 462 463 /* Allow environment override */ 464 env = getenv("SDL_VIDEO_X11_VIDMODE"); 465 if ( env && !SDL_atoi(env) ) { 466 return 0; 467 } 468 469 /* Query the extension version */ 470 if ( !XiGMiscQueryVersion(SDL_Display, major, minor) ) { 471 return 0; 472 } 473 return 1; 474 } 475 #endif /* SDL_VIDEO_DRIVER_X11_XME */ 476 477 int X11_GetVideoModes(_THIS) 478 { 479 #if SDL_VIDEO_DRIVER_X11_XINERAMA 480 int xinerama_major, xinerama_minor; 481 #endif 482 #if SDL_VIDEO_DRIVER_X11_XRANDR 483 int xrandr_major, xrandr_minor; 484 int nsizes; 485 XRRScreenSize *sizes; 486 #endif 487 #if SDL_VIDEO_DRIVER_X11_VIDMODE 488 int vm_major, vm_minor; 489 int nmodes; 490 SDL_NAME(XF86VidModeModeInfo) **modes; 491 #endif 492 #if SDL_VIDEO_DRIVER_X11_XME 493 int xme_major, xme_minor; 494 int ractive, nummodes; 495 XiGMiscResolutionInfo *modelist; 496 #endif 497 int i, n; 498 int screen_w; 499 int screen_h; 500 501 use_xinerama = 0; 502 use_xrandr = 0; 503 use_vidmode = 0; 504 use_xme = 0; 505 screen_w = DisplayWidth(SDL_Display, SDL_Screen); 506 screen_h = DisplayHeight(SDL_Display, SDL_Screen); 507 508 #if SDL_VIDEO_DRIVER_X11_XINERAMA 509 /* Query Xinerama extention */ 510 if ( CheckXinerama(this, &xinerama_major, &xinerama_minor) ) { 511 /* Find out which screen is the desired one */ 512 int desired = 0; 513 int screens; 514 int w, h; 515 SDL_NAME(XineramaScreenInfo) *xinerama; 516 517 const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD"); 518 if ( variable ) { 519 desired = SDL_atoi(variable); 520 } 521 #ifdef X11MODES_DEBUG 522 printf("X11 detected Xinerama:\n"); 523 #endif 524 xinerama = SDL_NAME(XineramaQueryScreens)(SDL_Display, &screens); 525 for ( i = 0; i < screens; i++ ) { 526 #ifdef X11MODES_DEBUG 527 printf("xinerama %d: %dx%d+%d+%d\n", 528 xinerama[i].screen_number, 529 xinerama[i].width, xinerama[i].height, 530 xinerama[i].x_org, xinerama[i].y_org); 531 #endif 532 if ( xinerama[i].screen_number == desired ) { 533 use_xinerama = 1; 534 xinerama_info = xinerama[i]; 535 } 536 } 537 XFree(xinerama); 538 539 if ( use_xinerama ) { 540 SDL_modelist = (SDL_Rect **)SDL_malloc(3*sizeof(SDL_Rect *)); 541 if ( !SDL_modelist ) { 542 SDL_OutOfMemory(); 543 return -1; 544 } 545 546 /* Add the full xinerama mode */ 547 n = 0; 548 w = xinerama_info.width; 549 h = xinerama_info.height; 550 if ( screen_w > w || screen_h > h) { 551 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); 552 if ( SDL_modelist[n] ) { 553 SDL_modelist[n]->x = 0; 554 SDL_modelist[n]->y = 0; 555 SDL_modelist[n]->w = screen_w; 556 SDL_modelist[n]->h = screen_h; 557 ++n; 558 } 559 } 560 561 /* Add the head xinerama mode */ 562 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); 563 if ( SDL_modelist[n] ) { 564 SDL_modelist[n]->x = 0; 565 SDL_modelist[n]->y = 0; 566 SDL_modelist[n]->w = w; 567 SDL_modelist[n]->h = h; 568 ++n; 569 } 570 SDL_modelist[n] = NULL; 571 } 572 } 573 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 574 575 #if SDL_VIDEO_DRIVER_X11_XRANDR 576 /* XRandR */ 577 /* require at least XRandR v1.0 (arbitrary) */ 578 if ( CheckXRandR(this, &xrandr_major, &xrandr_minor) && (xrandr_major >= 1) ) 579 { 580 #ifdef X11MODES_DEBUG 581 fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n", 582 xrandr_major, xrandr_minor); 583 #endif 584 585 /* save the screen configuration since we must reference it 586 each time we toggle modes. 587 */ 588 screen_config = XRRGetScreenInfo(SDL_Display, SDL_Root); 589 590 /* retrieve the list of resolution */ 591 sizes = XRRConfigSizes(screen_config, &nsizes); 592 if (nsizes > 0) { 593 if ( SDL_modelist ) { 594 for ( i = 0; SDL_modelist[i]; ++i ) { 595 SDL_free(SDL_modelist[i]); 596 } 597 SDL_free(SDL_modelist); 598 } 599 SDL_modelist = (SDL_Rect **)malloc((nsizes+1)*sizeof(SDL_Rect *)); 600 if ( !SDL_modelist ) { 601 SDL_OutOfMemory(); 602 return -1; 603 } 604 for ( i=0; i < nsizes; i++ ) { 605 if ((SDL_modelist[i] = 606 (SDL_Rect *)malloc(sizeof(SDL_Rect))) == NULL) 607 break; 608 #ifdef X11MODES_DEBUG 609 fprintf(stderr, "XRANDR: mode = %4d, w = %4d, h = %4d\n", 610 i, sizes[i].width, sizes[i].height); 611 #endif 612 613 SDL_modelist[i]->x = 0; 614 SDL_modelist[i]->y = 0; 615 SDL_modelist[i]->w = sizes[i].width; 616 SDL_modelist[i]->h = sizes[i].height; 617 618 } 619 /* sort the mode list descending as SDL expects */ 620 SDL_qsort(SDL_modelist, nsizes, sizeof *SDL_modelist, cmpmodelist); 621 SDL_modelist[i] = NULL; /* terminator */ 622 623 use_xrandr = xrandr_major * 100 + xrandr_minor; 624 saved_size_id = XRRConfigCurrentConfiguration(screen_config, &saved_rotation); 625 } 626 } 627 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 628 629 #if SDL_VIDEO_DRIVER_X11_VIDMODE 630 /* XVidMode */ 631 if ( !use_xrandr && 632 #if SDL_VIDEO_DRIVER_X11_XINERAMA 633 (!use_xinerama || xinerama_info.screen_number == 0) && 634 #endif 635 CheckVidMode(this, &vm_major, &vm_minor) && 636 SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) 637 { 638 #ifdef X11MODES_DEBUG 639 printf("VidMode modes: (unsorted)\n"); 640 for ( i = 0; i < nmodes; ++i ) { 641 printf("Mode %d: %d x %d @ %d\n", i, 642 modes[i]->hdisplay, modes[i]->vdisplay, 643 (modes[i]->htotal && modes[i]->vtotal) ? (1000 * modes[i]->dotclock / (modes[i]->htotal * modes[i]->vtotal)) : 0 ); 644 } 645 #endif 646 if ( SDL_modelist ) { 647 for ( i = 0; SDL_modelist[i]; ++i ) { 648 SDL_free(SDL_modelist[i]); 649 } 650 SDL_free(SDL_modelist); 651 } 652 SDL_modelist = (SDL_Rect **)SDL_malloc((nmodes+2)*sizeof(SDL_Rect *)); 653 if ( !SDL_modelist ) { 654 SDL_OutOfMemory(); 655 return -1; 656 } 657 SDL_qsort(modes, nmodes, sizeof *modes, cmpmodes); 658 n = 0; 659 for ( i=0; i<nmodes; ++i ) { 660 int w, h; 661 662 /* Eliminate duplicate modes with different refresh rates */ 663 if ( i > 0 && 664 modes[i]->hdisplay == modes[i-1]->hdisplay && 665 modes[i]->vdisplay == modes[i-1]->vdisplay ) { 666 continue; 667 } 668 669 /* Check to see if we should add the screen size (Xinerama) */ 670 w = modes[i]->hdisplay; 671 h = modes[i]->vdisplay; 672 if ( (screen_w * screen_h) >= (w * h) ) { 673 if ( (screen_w != w) || (screen_h != h) ) { 674 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); 675 if ( SDL_modelist[n] ) { 676 SDL_modelist[n]->x = 0; 677 SDL_modelist[n]->y = 0; 678 SDL_modelist[n]->w = screen_w; 679 SDL_modelist[n]->h = screen_h; 680 ++n; 681 } 682 } 683 screen_w = 0; 684 screen_h = 0; 685 } 686 687 /* Add the size from the video mode list */ 688 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); 689 if ( SDL_modelist[n] == NULL ) { 690 break; 691 } 692 SDL_modelist[n]->x = 0; 693 SDL_modelist[n]->y = 0; 694 SDL_modelist[n]->w = w; 695 SDL_modelist[n]->h = h; 696 ++n; 697 } 698 SDL_modelist[n] = NULL; 699 XFree(modes); 700 701 use_vidmode = vm_major * 100 + vm_minor; 702 save_mode(this); 703 } 704 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ 705 706 #if SDL_VIDEO_DRIVER_X11_XME 707 /* XiG */ 708 modelist = NULL; 709 /* first lets make sure we have the extension, and it's at least v2.0 */ 710 if ( CheckXME(this, &xme_major, &xme_minor) && xme_major >= 2 && 711 (nummodes = XiGMiscQueryResolutions(SDL_Display, SDL_Screen, 712 0, /* view */ 713 &ractive, &modelist)) > 1 ) 714 { /* then we actually have some */ 715 int j; 716 717 /* We get the list already sorted in descending order. 718 We'll copy it in reverse order so SDL is happy */ 719 #ifdef X11MODES_DEBUG 720 fprintf(stderr, "XME: nummodes = %d, active mode = %d\n", 721 nummodes, ractive); 722 #endif 723 if ( SDL_modelist ) { 724 for ( i = 0; SDL_modelist[i]; ++i ) { 725 SDL_free(SDL_modelist[i]); 726 } 727 SDL_free(SDL_modelist); 728 } 729 SDL_modelist = (SDL_Rect **)SDL_malloc((nummodes+1)*sizeof(SDL_Rect *)); 730 if ( !SDL_modelist ) { 731 SDL_OutOfMemory(); 732 return -1; 733 } 734 for ( i=0, j=nummodes-1; j>=0; i++, j-- ) { 735 if ((SDL_modelist[i] = 736 (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect))) == NULL) 737 break; 738 #ifdef X11MODES_DEBUG 739 fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n", 740 i, modelist[i].width, modelist[i].height); 741 #endif 742 743 SDL_modelist[i]->x = 0; 744 SDL_modelist[i]->y = 0; 745 SDL_modelist[i]->w = modelist[j].width; 746 SDL_modelist[i]->h = modelist[j].height; 747 748 } 749 SDL_modelist[i] = NULL; /* terminator */ 750 751 use_xme = xme_major * 100 + xme_minor; 752 saved_res = modelist[ractive]; /* save the current resolution */ 753 } 754 if ( modelist ) { 755 XFree(modelist); 756 } 757 #endif /* SDL_VIDEO_DRIVER_X11_XME */ 758 759 { 760 /* It's interesting to note that if we allow 32 bit depths, 761 we get a visual with an alpha mask on composite servers. 762 static int depth_list[] = { 32, 24, 16, 15, 8 }; 763 */ 764 static int depth_list[] = { 24, 16, 15, 8 }; 765 int j, np; 766 int use_directcolor = 1; 767 XPixmapFormatValues *pf; 768 769 /* Search for the visuals in deepest-first order, so that the first 770 will be the richest one */ 771 if ( SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { 772 use_directcolor = 0; 773 } 774 this->hidden->nvisuals = 0; 775 if ( ! add_visual_byid(this, SDL_getenv("SDL_VIDEO_X11_VISUALID")) ) { 776 for ( i=0; i<SDL_arraysize(depth_list); ++i ) { 777 if ( depth_list[i] > 8 ) { 778 if ( use_directcolor ) { 779 add_visual(this, depth_list[i], DirectColor); 780 } 781 add_visual(this, depth_list[i], TrueColor); 782 } else { 783 add_visual(this, depth_list[i], PseudoColor); 784 add_visual(this, depth_list[i], StaticColor); 785 } 786 } 787 } 788 if ( this->hidden->nvisuals == 0 ) { 789 SDL_SetError("Found no sufficiently capable X11 visuals"); 790 return -1; 791 } 792 793 /* look up the pixel quantum for each depth */ 794 pf = XListPixmapFormats(SDL_Display, &np); 795 for(i = 0; i < this->hidden->nvisuals; i++) { 796 int d = this->hidden->visuals[i].depth; 797 for(j = 0; j < np; j++) 798 if(pf[j].depth == d) 799 break; 800 this->hidden->visuals[i].bpp = j < np ? pf[j].bits_per_pixel : d; 801 } 802 803 XFree(pf); 804 } 805 806 if ( SDL_modelist == NULL ) { 807 SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *)); 808 if ( !SDL_modelist ) { 809 SDL_OutOfMemory(); 810 return -1; 811 } 812 n = 0; 813 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); 814 if ( SDL_modelist[n] ) { 815 SDL_modelist[n]->x = 0; 816 SDL_modelist[n]->y = 0; 817 SDL_modelist[n]->w = screen_w; 818 SDL_modelist[n]->h = screen_h; 819 ++n; 820 } 821 SDL_modelist[n] = NULL; 822 } 823 824 #ifdef X11MODES_DEBUG 825 if ( use_xinerama ) { 826 printf("Xinerama is enabled\n"); 827 } 828 829 if ( use_xrandr ) { 830 printf("XRandR is enabled\n"); 831 } 832 833 if ( use_vidmode ) { 834 printf("VidMode is enabled\n"); 835 } 836 837 if ( use_xme ) { 838 printf("Xi Graphics XME fullscreen is enabled\n"); 839 } 840 841 if ( SDL_modelist ) { 842 printf("X11 video mode list:\n"); 843 for ( i=0; SDL_modelist[i]; ++i ) { 844 printf("\t%dx%d\n", SDL_modelist[i]->w, SDL_modelist[i]->h); 845 } 846 } 847 #endif /* X11MODES_DEBUG */ 848 849 return 0; 850 } 851 852 int X11_SupportedVisual(_THIS, SDL_PixelFormat *format) 853 { 854 int i; 855 for(i = 0; i < this->hidden->nvisuals; i++) 856 if(this->hidden->visuals[i].bpp == format->BitsPerPixel) 857 return 1; 858 return 0; 859 } 860 861 SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 862 { 863 if ( X11_SupportedVisual(this, format) ) { 864 if ( flags & SDL_FULLSCREEN ) { 865 return(SDL_modelist); 866 } else { 867 return((SDL_Rect **)-1); 868 } 869 } else { 870 return((SDL_Rect **)0); 871 } 872 } 873 874 void X11_FreeVideoModes(_THIS) 875 { 876 int i; 877 878 if ( SDL_modelist ) { 879 for ( i=0; SDL_modelist[i]; ++i ) { 880 SDL_free(SDL_modelist[i]); 881 } 882 SDL_free(SDL_modelist); 883 SDL_modelist = NULL; 884 } 885 886 #if SDL_VIDEO_DRIVER_X11_XRANDR 887 /* Free the Xrandr screen configuration */ 888 if ( screen_config ) { 889 XRRFreeScreenConfigInfo(screen_config); 890 screen_config = NULL; 891 } 892 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ 893 } 894 895 int X11_ResizeFullScreen(_THIS) 896 { 897 int x = 0, y = 0; 898 int real_w, real_h; 899 int screen_w; 900 int screen_h; 901 902 screen_w = DisplayWidth(SDL_Display, SDL_Screen); 903 screen_h = DisplayHeight(SDL_Display, SDL_Screen); 904 905 #if SDL_VIDEO_DRIVER_X11_XINERAMA 906 if ( use_xinerama && 907 window_w <= xinerama_info.width && 908 window_h <= xinerama_info.height ) { 909 x = xinerama_info.x_org; 910 y = xinerama_info.y_org; 911 } 912 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 913 914 if ( currently_fullscreen ) { 915 /* Switch resolution and cover it with the FSwindow */ 916 move_cursor_to(this, x, y); 917 set_best_resolution(this, window_w, window_h); 918 move_cursor_to(this, x, y); 919 get_real_resolution(this, &real_w, &real_h); 920 if ( window_w > real_w ) { 921 real_w = MAX(real_w, screen_w); 922 } 923 if ( window_h > real_h ) { 924 real_h = MAX(real_h, screen_h); 925 } 926 XMoveResizeWindow(SDL_Display, FSwindow, x, y, real_w, real_h); 927 move_cursor_to(this, real_w/2, real_h/2); 928 929 /* Center and reparent the drawing window */ 930 x = (real_w - window_w)/2; 931 y = (real_h - window_h)/2; 932 XReparentWindow(SDL_Display, SDL_Window, FSwindow, x, y); 933 /* FIXME: move the mouse to the old relative location */ 934 XSync(SDL_Display, True); /* Flush spurious mode change events */ 935 } 936 return(1); 937 } 938 939 void X11_QueueEnterFullScreen(_THIS) 940 { 941 switch_waiting = 0x01 | SDL_FULLSCREEN; 942 switch_time = SDL_GetTicks() + 1500; 943 #if 0 /* This causes a BadMatch error if the window is iconified (not needed) */ 944 XSetInputFocus(SDL_Display, WMwindow, RevertToNone, CurrentTime); 945 #endif 946 } 947 948 int X11_EnterFullScreen(_THIS) 949 { 950 int okay; 951 #if 0 952 Window tmpwin, *windows; 953 int i, nwindows; 954 #endif 955 int x = 0, y = 0; 956 int real_w, real_h; 957 int screen_w; 958 int screen_h; 959 960 okay = 1; 961 if ( currently_fullscreen ) { 962 return(okay); 963 } 964 965 /* Ungrab the input so that we can move the mouse around */ 966 X11_GrabInputNoLock(this, SDL_GRAB_OFF); 967 968 #if SDL_VIDEO_DRIVER_X11_XINERAMA 969 if ( use_xinerama && 970 window_w <= xinerama_info.width && 971 window_h <= xinerama_info.height ) { 972 x = xinerama_info.x_org; 973 y = xinerama_info.y_org; 974 } 975 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ 976 977 /* Map the fullscreen window to blank the screen */ 978 screen_w = DisplayWidth(SDL_Display, SDL_Screen); 979 screen_h = DisplayHeight(SDL_Display, SDL_Screen); 980 get_real_resolution(this, &real_w, &real_h); 981 if ( window_w > real_w ) { 982 real_w = MAX(real_w, screen_w); 983 } 984 if ( window_h > real_h ) { 985 real_h = MAX(real_h, screen_h); 986 } 987 XMoveResizeWindow(SDL_Display, FSwindow, 988 x, y, real_w, real_h); 989 XMapRaised(SDL_Display, FSwindow); 990 X11_WaitMapped(this, FSwindow); 991 992 #if 0 /* This seems to break WindowMaker in focus-follows-mouse mode */ 993 /* Make sure we got to the top of the window stack */ 994 if ( XQueryTree(SDL_Display, SDL_Root, &tmpwin, &tmpwin, 995 &windows, &nwindows) && windows ) { 996 /* If not, try to put us there - if fail... oh well */ 997 if ( windows[nwindows-1] != FSwindow ) { 998 tmpwin = windows[nwindows-1]; 999 for ( i=0; i<nwindows; ++i ) { 1000 if ( windows[i] == FSwindow ) { 1001 SDL_memcpy(&windows[i], &windows[i+1], 1002 (nwindows-i-1)*sizeof(windows[i])); 1003 break; 1004 } 1005 } 1006 windows[nwindows-1] = FSwindow; 1007 XRestackWindows(SDL_Display, windows, nwindows); 1008 XSync(SDL_Display, False); 1009 } 1010 XFree(windows); 1011 } 1012 #else 1013 XRaiseWindow(SDL_Display, FSwindow); 1014 #endif 1015 1016 #if SDL_VIDEO_DRIVER_X11_VIDMODE 1017 /* Save the current video mode */ 1018 if ( use_vidmode ) { 1019 SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, True); 1020 } 1021 #endif 1022 currently_fullscreen = 1; 1023 1024 /* Set the new resolution */ 1025 okay = X11_ResizeFullScreen(this); 1026 if ( ! okay ) { 1027 X11_LeaveFullScreen(this); 1028 } 1029 /* Set the colormap */ 1030 if ( SDL_XColorMap ) { 1031 XInstallColormap(SDL_Display, SDL_XColorMap); 1032 } 1033 if ( okay ) { 1034 X11_GrabInputNoLock(this, this->input_grab | SDL_GRAB_FULLSCREEN); 1035 } 1036 1037 /* We may need to refresh the screen at this point (no backing store) 1038 We also don't get an event, which is why we explicitly refresh. */ 1039 if ( this->screen ) { 1040 if ( this->screen->flags & SDL_OPENGL ) { 1041 SDL_PrivateExpose(); 1042 } else { 1043 X11_RefreshDisplay(this); 1044 } 1045 } 1046 1047 return(okay); 1048 } 1049 1050 int X11_LeaveFullScreen(_THIS) 1051 { 1052 if ( currently_fullscreen ) { 1053 XReparentWindow(SDL_Display, SDL_Window, WMwindow, 0, 0); 1054 #if SDL_VIDEO_DRIVER_X11_VIDMODE 1055 if ( use_vidmode ) { 1056 restore_mode(this); 1057 SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False); 1058 } 1059 #endif 1060 1061 #if SDL_VIDEO_DRIVER_X11_XME 1062 if ( use_xme ) { 1063 int rw, rh; 1064 1065 /* check current mode so we can avoid uneccessary mode changes */ 1066 get_real_resolution(this, &rw, &rh); 1067 1068 if (rw != saved_res.width || rh != saved_res.height) { 1069 XiGMiscChangeResolution(SDL_Display, 1070 SDL_Screen, 1071 0, /* view */ 1072 saved_res.width, 1073 saved_res.height, 1074 0); 1075 XSync(SDL_Display, False); 1076 } 1077 } 1078 #endif 1079 1080 #if SDL_VIDEO_DRIVER_X11_XRANDR 1081 if ( use_xrandr ) { 1082 XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, 1083 saved_size_id, saved_rotation, CurrentTime); 1084 } 1085 #endif 1086 1087 XUnmapWindow(SDL_Display, FSwindow); 1088 X11_WaitUnmapped(this, FSwindow); 1089 XSync(SDL_Display, True); /* Flush spurious mode change events */ 1090 currently_fullscreen = 0; 1091 } 1092 /* If we get popped out of fullscreen mode for some reason, input_grab 1093 will still have the SDL_GRAB_FULLSCREEN flag set, since this is only 1094 temporary. In this case, release the grab unless the input has been 1095 explicitly grabbed. 1096 */ 1097 X11_GrabInputNoLock(this, this->input_grab & ~SDL_GRAB_FULLSCREEN); 1098 1099 /* We may need to refresh the screen at this point (no backing store) 1100 We also don't get an event, which is why we explicitly refresh. */ 1101 if ( this->screen ) { 1102 if ( this->screen->flags & SDL_OPENGL ) { 1103 SDL_PrivateExpose(); 1104 } else { 1105 X11_RefreshDisplay(this); 1106 } 1107 } 1108 1109 return(0); 1110 } 1111