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