src/video/x11/SDL_x11modes.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 22 Mar 2006 05:00:59 +0000
changeset 1575 3ba88cb7eb1b
parent 1545 8d9bb0cf2c2a
child 1589 34cca785be57
permissions -rw-r--r--
Updated dynamic X11 code. See details in Bugzilla #170.
     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@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 #if SDL_VIDEO_DRIVER_X11_XINERAMA
    37 #include "../Xext/extensions/Xinerama.h"
    38 #endif 
    39 
    40 #define MAX(a, b)        (a > b ? a : b)
    41 
    42 #if SDL_VIDEO_DRIVER_X11_VIDMODE
    43 Bool SDL_NAME(XF86VidModeGetModeInfo)(Display *dpy, int scr, SDL_NAME(XF86VidModeModeInfo) *info)
    44 {
    45     SDL_NAME(XF86VidModeModeLine) *l = (SDL_NAME(XF86VidModeModeLine)*)((char*)info + sizeof info->dotclock);
    46     return SDL_NAME(XF86VidModeGetModeLine)(dpy, scr, (int*)&info->dotclock, l);
    47 }
    48 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
    49 
    50 #if SDL_VIDEO_DRIVER_X11_VIDMODE
    51 static void save_mode(_THIS)
    52 {
    53     SDL_memset(&saved_mode, 0, sizeof(saved_mode));
    54     SDL_NAME(XF86VidModeGetModeInfo)(SDL_Display,SDL_Screen,&saved_mode);
    55     SDL_NAME(XF86VidModeGetViewPort)(SDL_Display,SDL_Screen,&saved_view.x,&saved_view.y);
    56 }
    57 #endif
    58 
    59 #if SDL_VIDEO_DRIVER_X11_VIDMODE
    60 static void restore_mode(_THIS)
    61 {
    62     SDL_NAME(XF86VidModeModeLine) mode;
    63     int unused;
    64 
    65     if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
    66         if ( (saved_mode.hdisplay != mode.hdisplay) ||
    67              (saved_mode.vdisplay != mode.vdisplay) ) {
    68             SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, &saved_mode);
    69         }
    70     }
    71     if ( (saved_view.x != 0) || (saved_view.y != 0) ) {
    72         SDL_NAME(XF86VidModeSetViewPort)(SDL_Display, SDL_Screen, saved_view.x, saved_view.y);
    73     }
    74 }
    75 #endif
    76 
    77 #if SDL_VIDEO_DRIVER_X11_VIDMODE
    78 static int cmpmodes(const void *va, const void *vb)
    79 {
    80     const SDL_NAME(XF86VidModeModeInfo) *a = *(const SDL_NAME(XF86VidModeModeInfo)**)va;
    81     const SDL_NAME(XF86VidModeModeInfo) *b = *(const SDL_NAME(XF86VidModeModeInfo)**)vb;
    82     if ( a->hdisplay == b->hdisplay )
    83         return b->vdisplay - a->vdisplay;
    84     else
    85         return b->hdisplay - a->hdisplay;
    86 }
    87 #endif
    88 
    89 static void get_real_resolution(_THIS, int* w, int* h);
    90 
    91 static void set_best_resolution(_THIS, int width, int height)
    92 {
    93 #if SDL_VIDEO_DRIVER_X11_VIDMODE
    94     if ( use_vidmode ) {
    95         SDL_NAME(XF86VidModeModeLine) mode;
    96         SDL_NAME(XF86VidModeModeInfo) **modes;
    97         int i;
    98         int best_width = 0, best_height = 0;
    99         int nmodes;
   100 
   101         if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &i, &mode) &&
   102              SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display,SDL_Screen,&nmodes,&modes)){
   103 #ifdef XFREE86_DEBUG
   104             printf("Available modes (unsorted):\n");
   105             for ( i = 0; i < nmodes; ++i ) {
   106                 printf("Mode %d: %d x %d @ %d\n", i,
   107                         modes[i]->hdisplay, modes[i]->vdisplay,
   108                         1000 * modes[i]->dotclock / (modes[i]->htotal *
   109                         modes[i]->vtotal) );
   110             }
   111 #endif
   112             for ( i = 0; i < nmodes ; i++ ) {
   113                 if ( (modes[i]->hdisplay == width) &&
   114                      (modes[i]->vdisplay == height) )
   115                     goto match;
   116             }
   117             qsort(modes, nmodes, sizeof *modes, cmpmodes);
   118             for ( i = nmodes-1; i > 0 ; i-- ) {
   119 		if ( ! best_width ) {
   120                     if ( (modes[i]->hdisplay >= width) &&
   121                          (modes[i]->vdisplay >= height) ) {
   122                         best_width = modes[i]->hdisplay;
   123                         best_height = modes[i]->vdisplay;
   124                     }
   125                 } else {
   126                     if ( (modes[i]->hdisplay != best_width) ||
   127                          (modes[i]->vdisplay != best_height) ) {
   128                         i++;
   129                         break;
   130                     }
   131                 }
   132             }
   133        match:
   134             if ( (modes[i]->hdisplay != mode.hdisplay) ||
   135                  (modes[i]->vdisplay != mode.vdisplay) ) {
   136                 SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, modes[i]);
   137             }
   138             XFree(modes);
   139         }
   140     }
   141 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
   142 
   143                                 /* XiG */
   144 #if SDL_VIDEO_DRIVER_X11_XME
   145 #ifdef XIG_DEBUG
   146     fprintf(stderr, "XME: set_best_resolution(): w = %d, h = %d\n",
   147             width, height);
   148 #endif
   149     if ( SDL_modelist ) {
   150         int i;
   151 
   152         for ( i=0; SDL_modelist[i]; ++i ) {
   153             if ( (SDL_modelist[i]->w >= width) &&
   154                  (SDL_modelist[i]->h >= height) ) {
   155                 break;
   156             }
   157         }
   158         
   159         if ( SDL_modelist[i] ) { /* found one, lets try it */
   160             int w, h;        
   161 
   162             /* check current mode so we can avoid uneccessary mode changes */
   163             get_real_resolution(this, &w, &h);
   164 
   165             if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) {
   166 # ifdef XIG_DEBUG
   167                 fprintf(stderr, "XME: set_best_resolution: "
   168                         "XiGMiscChangeResolution: %d %d\n",
   169                         SDL_modelist[s]->w, SDL_modelist[s]->h);
   170 # endif
   171                 XiGMiscChangeResolution(SDL_Display, 
   172                                         SDL_Screen,
   173                                         0, /* view */
   174                                         SDL_modelist[i]->w, 
   175                                         SDL_modelist[i]->h, 
   176                                         0);
   177                 XSync(SDL_Display, False);
   178             }
   179         }
   180     }
   181 #endif /* SDL_VIDEO_DRIVER_X11_XME */
   182 
   183 }
   184 
   185 static void get_real_resolution(_THIS, int* w, int* h)
   186 {
   187 #if SDL_VIDEO_DRIVER_X11_VIDMODE
   188     if ( use_vidmode ) {
   189         SDL_NAME(XF86VidModeModeLine) mode;
   190         int unused;
   191 
   192         if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) {
   193             *w = mode.hdisplay;
   194             *h = mode.vdisplay;
   195             return;
   196         }
   197     }
   198 #endif
   199 
   200 #if SDL_VIDEO_DRIVER_X11_XME
   201     if ( use_xme ) {
   202         int ractive;
   203         XiGMiscResolutionInfo *modelist;
   204 
   205         XiGMiscQueryResolutions(SDL_Display, SDL_Screen,
   206                                 0, /* view */
   207                                 &ractive, &modelist);
   208         *w = modelist[ractive].width;
   209         *h = modelist[ractive].height;
   210 #ifdef XIG_DEBUG
   211         fprintf(stderr, "XME: get_real_resolution: w = %d h = %d\n", *w, *h);
   212 #endif
   213         XFree(modelist);
   214         return;
   215     }
   216 #endif /* XIG_XME */
   217 
   218     *w = DisplayWidth(SDL_Display, SDL_Screen);
   219     *h = DisplayHeight(SDL_Display, SDL_Screen);
   220 }
   221 
   222 /* Called after mapping a window - waits until the window is mapped */
   223 void X11_WaitMapped(_THIS, Window win)
   224 {
   225     XEvent event;
   226     do {
   227         XMaskEvent(SDL_Display, StructureNotifyMask, &event);
   228     } while ( (event.type != MapNotify) || (event.xmap.event != win) );
   229 }
   230 
   231 /* Called after unmapping a window - waits until the window is unmapped */
   232 void X11_WaitUnmapped(_THIS, Window win)
   233 {
   234     XEvent event;
   235     do {
   236         XMaskEvent(SDL_Display, StructureNotifyMask, &event);
   237     } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) );
   238 }
   239 
   240 static void move_cursor_to(_THIS, int x, int y)
   241 {
   242     XWarpPointer(SDL_Display, None, SDL_Root, 0, 0, 0, 0, x, y);
   243 }
   244 
   245 static int add_visual(_THIS, int depth, int class)
   246 {
   247     XVisualInfo vi;
   248     if(XMatchVisualInfo(SDL_Display, SDL_Screen, depth, class, &vi)) {
   249         int n = this->hidden->nvisuals;
   250         this->hidden->visuals[n].depth = vi.depth;
   251         this->hidden->visuals[n].visual = vi.visual;
   252         this->hidden->nvisuals++;
   253     }
   254     return(this->hidden->nvisuals);
   255 }
   256 static int add_visual_byid(_THIS, const char *visual_id)
   257 {
   258     XVisualInfo *vi, template;
   259     int nvis;
   260 
   261     if ( visual_id ) {
   262         SDL_memset(&template, 0, (sizeof template));
   263         template.visualid = SDL_strtol(visual_id, NULL, 0);
   264         vi = XGetVisualInfo(SDL_Display, VisualIDMask, &template, &nvis);
   265         if ( vi ) {
   266             int n = this->hidden->nvisuals;
   267             this->hidden->visuals[n].depth = vi->depth;
   268             this->hidden->visuals[n].visual = vi->visual;
   269             this->hidden->nvisuals++;
   270             XFree(vi);
   271         }
   272     }
   273     return(this->hidden->nvisuals);
   274 }
   275 
   276 /* Global for the error handler */
   277 int vm_event, vm_error = -1;
   278 
   279 int X11_GetVideoModes(_THIS)
   280 {
   281 #if SDL_VIDEO_DRIVER_X11_VIDMODE
   282     int buggy_X11;
   283     int vm_major, vm_minor;
   284     int nmodes;
   285     SDL_NAME(XF86VidModeModeInfo) **modes;
   286 #endif
   287 #if SDL_VIDEO_DRIVER_X11_XME
   288     int xme_major, xme_minor;
   289     int ractive, nummodes;
   290     XiGMiscResolutionInfo *modelist;
   291 #endif
   292     int i, n;
   293     int screen_w;
   294     int screen_h;
   295 
   296     vm_error = -1;
   297     use_vidmode = 0;
   298     screen_w = DisplayWidth(SDL_Display, SDL_Screen);
   299     screen_h = DisplayHeight(SDL_Display, SDL_Screen);
   300 
   301 #if SDL_VIDEO_DRIVER_X11_VIDMODE
   302     /* Metro-X 4.3.0 and earlier has a broken implementation of
   303        XF86VidModeGetAllModeLines() - it hangs the client.
   304      */
   305     buggy_X11 = 0;
   306     if ( SDL_strcmp(ServerVendor(SDL_Display), "Metro Link Incorporated") == 0 ) {
   307         FILE *metro_fp;
   308 
   309         metro_fp = fopen("/usr/X11R6/lib/X11/Metro/.version", "r");
   310         if ( metro_fp != NULL ) {
   311             int major, minor, patch, version;
   312             major = 0; minor = 0; patch = 0;
   313             fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch);
   314             version = major*100+minor*10+patch;
   315             if ( version < 431 ) {
   316                 buggy_X11 = 1;
   317             }
   318             fclose(metro_fp);
   319         }
   320     }
   321 #if 0 /* Let's try this again... hopefully X servers have improved... */
   322 #if defined(__alpha__) || defined(__sparc64__) || defined(__powerpc__)
   323     /* The alpha, sparc64 and PPC XFree86 servers are also buggy */
   324     buggy_X11 = 1;
   325 #endif
   326 #endif
   327     /* Enumerate the available fullscreen modes */
   328     if ( ! buggy_X11 ) {
   329         if ( SDL_NAME(XF86VidModeQueryExtension)(SDL_Display, &vm_event, &vm_error) &&
   330               SDL_NAME(XF86VidModeQueryVersion)(SDL_Display, &vm_major, &vm_minor) ) {
   331 #ifdef BROKEN_XFREE86_4001
   332 #ifdef X_XF86VidModeGetDotClocks  /* Compiled under XFree86 4.0 */
   333                 /* Earlier X servers hang when doing vidmode */
   334                 if ( vm_major < 2 ) {
   335 #ifdef XFREE86_DEBUG
   336                     printf("Compiled under XFree86 4.0, server is XFree86 3.X\n");
   337 #endif
   338                     buggy_X11 = 1;
   339                 }
   340 #else
   341                 /* XFree86 3.X code works with XFree86 4.0 servers */;
   342 #endif /* XFree86 4.0 */
   343 #endif /* XFree86 4.02 and newer are fixed wrt backwards compatibility */
   344         } else {
   345             buggy_X11 = 1;
   346         }
   347     }
   348     if ( ! buggy_X11 &&
   349          SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) {
   350 
   351 #ifdef XFREE86_DEBUG
   352         printf("Available modes: (sorted)\n");
   353         for ( i = 0; i < nmodes; ++i ) {
   354             printf("Mode %d: %d x %d @ %d\n", i,
   355                     modes[i]->hdisplay, modes[i]->vdisplay,
   356                     1000 * modes[i]->dotclock / (modes[i]->htotal *
   357                     modes[i]->vtotal) );
   358         }
   359 #endif
   360 
   361         SDL_qsort(modes, nmodes, sizeof *modes, cmpmodes);
   362         SDL_modelist = (SDL_Rect **)SDL_malloc((nmodes+2)*sizeof(SDL_Rect *));
   363         if ( SDL_modelist ) {
   364             n = 0;
   365             for ( i=0; i<nmodes; ++i ) {
   366                 int w, h;
   367 
   368 		/* Eliminate duplicate modes with different refresh rates */
   369 		if ( i > 0 &&
   370 		     modes[i]->hdisplay == modes[i-1]->hdisplay &&
   371 		     modes[i]->vdisplay == modes[i-1]->vdisplay ) {
   372 			continue;
   373 		}
   374 
   375                 /* Check to see if we should add the screen size (Xinerama) */
   376                 w = modes[i]->hdisplay;
   377                 h = modes[i]->vdisplay;
   378                 if ( (screen_w * screen_h) >= (w * h) ) {
   379                     if ( (screen_w != w) || (screen_h != h) ) {
   380                         SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
   381                         if ( SDL_modelist[n] ) {
   382                             SDL_modelist[n]->x = 0;
   383                             SDL_modelist[n]->y = 0;
   384                             SDL_modelist[n]->w = screen_w;
   385                             SDL_modelist[n]->h = screen_h;
   386                             ++n;
   387                         }
   388                     }
   389                     screen_w = 0;
   390                     screen_h = 0;
   391                 }
   392 
   393                 /* Add the size from the video mode list */
   394                 SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
   395                 if ( SDL_modelist[n] == NULL ) {
   396                     break;
   397                 }
   398                 SDL_modelist[n]->x = 0;
   399                 SDL_modelist[n]->y = 0;
   400                 SDL_modelist[n]->w = w;
   401                 SDL_modelist[n]->h = h;
   402                 ++n;
   403             }
   404             SDL_modelist[n] = NULL;
   405         }
   406         XFree(modes);
   407 
   408         use_vidmode = vm_major * 100 + vm_minor;
   409         save_mode(this);
   410     }
   411 #endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */
   412 
   413                                 /* XiG */
   414 #if SDL_VIDEO_DRIVER_X11_XME
   415     /* first lets make sure we have the extension, and it's at least v2.0 */
   416     if (XiGMiscQueryVersion(SDL_Display, &xme_major, &xme_minor)) {
   417 #ifdef XIG_DEBUG
   418         fprintf(stderr, "XME: XiGMiscQueryVersion: V%d.%d\n",
   419                 xme_major, xme_minor);
   420 #endif
   421         /* work around a XiGMisc bogosity in our version of libXext */
   422         if (xme_major == 0 && xme_major == 0) {
   423             /* Ideally libxme would spit this out, but the problem is that
   424                the right Query func will never be called if using the bogus
   425                libXext version.
   426              */
   427             fprintf(stderr, 
   428 "XME: If you are using Xi Graphics CDE and a Summit server, you need to\n"
   429 "XME: get the libXext update from our ftp site before fullscreen switching\n"
   430 "XME: will work.  Fullscreen switching is only supported on Summit Servers\n");
   431           }
   432     } else {
   433         /* not there. Bummer. */
   434         xme_major = xme_minor = 0;
   435     }
   436 
   437     modelist = NULL;
   438     if (xme_major >= 2 && (nummodes = XiGMiscQueryResolutions(SDL_Display, 
   439                                             SDL_Screen,
   440                                             0, /* view */
   441                                             &ractive, 
   442                                             &modelist)) > 1)
   443     {                                /* then we actually have some */
   444         int j;
   445 
   446 #ifdef XIG_DEBUG
   447         fprintf(stderr, "XME: nummodes = %d, active mode = %d\n",
   448                 nummodes, ractive);
   449 #endif
   450 
   451         SDL_modelist = (SDL_Rect **)SDL_malloc((nummodes+1)*sizeof(SDL_Rect *));
   452 
   453                                 /* we get the list already sorted in */
   454                                 /* descending order.  We'll copy it in */
   455                                 /* reverse order so SDL is happy */
   456         if (SDL_modelist) {
   457             for ( i=0, j=nummodes-1; j>=0; i++, j-- ) {
   458                 if ((SDL_modelist[i] = 
   459                      (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect))) == NULL)
   460                   break;
   461 #ifdef XIG_DEBUG
   462                 fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n",
   463                        i, modelist[i].width, modelist[i].height);
   464 #endif
   465                 
   466                 SDL_modelist[i]->x = 0;
   467                 SDL_modelist[i]->y = 0;
   468                 SDL_modelist[i]->w = modelist[j].width;
   469                 SDL_modelist[i]->h = modelist[j].height;
   470                 
   471             }
   472             SDL_modelist[i] = NULL; /* terminator */
   473         }
   474         use_xme = 1;
   475         saved_res = modelist[ractive]; /* save the current resolution */
   476     } else {
   477         use_xme = 0;
   478     }
   479     if ( modelist ) {
   480         XFree(modelist);
   481     }
   482 #endif /* SDL_VIDEO_DRIVER_X11_XME */
   483 
   484     {
   485         static int depth_list[] = { 32, 24, 16, 15, 8 };
   486         int j, np;
   487         int use_directcolor = 1;
   488         XPixmapFormatValues *pf;
   489 
   490         /* Search for the visuals in deepest-first order, so that the first
   491            will be the richest one */
   492         if ( SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) {
   493                 use_directcolor = 0;
   494         }
   495         this->hidden->nvisuals = 0;
   496         if ( ! add_visual_byid(this, SDL_getenv("SDL_VIDEO_X11_VISUALID")) ) {
   497                 for ( i=0; i<SDL_arraysize(depth_list); ++i ) {
   498                         if ( depth_list[i] > 8 ) {
   499                                 if ( use_directcolor ) {
   500                                         add_visual(this, depth_list[i], DirectColor);
   501                                 }
   502                                 add_visual(this, depth_list[i], TrueColor);
   503                         } else {
   504                                 add_visual(this, depth_list[i], PseudoColor);
   505                                 add_visual(this, depth_list[i], StaticColor);
   506                         }
   507                 }
   508         }
   509         if ( this->hidden->nvisuals == 0 ) {
   510             SDL_SetError("Found no sufficiently capable X11 visuals");
   511             return -1;
   512         }
   513             
   514         /* look up the pixel quantum for each depth */
   515         pf = XListPixmapFormats(SDL_Display, &np);
   516         for(i = 0; i < this->hidden->nvisuals; i++) {
   517             int d = this->hidden->visuals[i].depth;
   518             for(j = 0; j < np; j++)
   519                 if(pf[j].depth == d)
   520                     break;
   521             this->hidden->visuals[i].bpp = j < np ? pf[j].bits_per_pixel : d;
   522         }
   523 
   524         XFree(pf);
   525     }
   526 
   527     if ( SDL_modelist == NULL ) {
   528         SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *));
   529         if ( SDL_modelist ) {
   530             n = 0;
   531             SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
   532             if ( SDL_modelist[n] ) {
   533                 SDL_modelist[n]->x = 0;
   534                 SDL_modelist[n]->y = 0;
   535                 SDL_modelist[n]->w = screen_w;
   536                 SDL_modelist[n]->h = screen_h;
   537                 ++n;
   538             }
   539             SDL_modelist[n] = NULL;
   540         }
   541     }
   542 
   543 #if defined(XFREE86_DEBUG) || defined(XIG_DEBUG)
   544     if ( use_vidmode ) {
   545         printf("XFree86 VidMode is enabled\n");
   546     }
   547 
   548 #if SDL_VIDEO_DRIVER_X11_XME
   549     if ( use_xme )
   550       printf("Xi Graphics XME fullscreen is enabled\n");
   551     else
   552       printf("Xi Graphics XME fullscreen is not available\n");
   553 #endif 
   554 
   555     if ( SDL_modelist ) {
   556         printf("X11 video mode list:\n");
   557         for ( i=0; SDL_modelist[i]; ++i ) {
   558             printf("\t%dx%d\n", SDL_modelist[i]->w, SDL_modelist[i]->h);
   559         }
   560     }
   561 #endif /* XFREE86_DEBUG || XIG_DEBUG */
   562 
   563     /* The default X/Y fullscreen offset is 0/0 */
   564     xinerama_x = 0;
   565     xinerama_y = 0;
   566 
   567 #if SDL_VIDEO_DRIVER_X11_XINERAMA
   568     /* Query Xinerama extention */
   569     if ( SDL_NAME(XineramaQueryExtension)(SDL_Display, &i, &i) &&
   570          SDL_NAME(XineramaIsActive)(SDL_Display) ) {
   571         /* Find out which screen is the desired one */
   572         int desired = 0;
   573         int screens;
   574         SDL_NAME(XineramaScreenInfo) *xinerama;
   575 
   576 #ifdef XINERAMA_DEBUG
   577         printf("X11 detected Xinerama:\n");
   578 #endif
   579 #if 0 /* Apparently the vidmode extension doesn't work with Xinerama */
   580         const char *variable = SDL_getenv("SDL_VIDEO_X11_XINERAMA_SCREEN");
   581         if ( variable ) {
   582                 desired = atoi(variable);
   583         }
   584 #endif
   585         xinerama = SDL_NAME(XineramaQueryScreens)(SDL_Display, &screens);
   586         for ( i = 0; i < screens; i++ ) {
   587 #ifdef XINERAMA_DEBUG
   588             printf("xinerama %d: %dx%d+%d+%d\n",
   589                 xinerama[i].screen_number,
   590                 xinerama[i].width, xinerama[i].height,
   591                 xinerama[i].x_org, xinerama[i].y_org);
   592 #endif
   593             if ( xinerama[i].screen_number == desired ) {
   594                 xinerama_x = xinerama[i].x_org;
   595                 xinerama_y = xinerama[i].y_org;
   596             }
   597         }
   598         XFree(xinerama);
   599     }
   600 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
   601 
   602     return 0;
   603 }
   604 
   605 int X11_SupportedVisual(_THIS, SDL_PixelFormat *format)
   606 {
   607     int i;
   608     for(i = 0; i < this->hidden->nvisuals; i++)
   609         if(this->hidden->visuals[i].bpp == format->BitsPerPixel)
   610             return 1;
   611     return 0;
   612 }
   613 
   614 SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   615 {
   616     if ( X11_SupportedVisual(this, format) ) {
   617         if ( flags & SDL_FULLSCREEN ) {
   618             return(SDL_modelist);
   619         } else {
   620             return((SDL_Rect **)-1);
   621         }
   622     } else {
   623         return((SDL_Rect **)0);
   624     }
   625 }
   626 
   627 void X11_FreeVideoModes(_THIS)
   628 {
   629     int i;
   630 
   631     if ( SDL_modelist ) {
   632         for ( i=0; SDL_modelist[i]; ++i ) {
   633             SDL_free(SDL_modelist[i]);
   634         }
   635         SDL_free(SDL_modelist);
   636         SDL_modelist = NULL;
   637     }
   638 }
   639 
   640 int X11_ResizeFullScreen(_THIS)
   641 {
   642     int x, y;
   643     int real_w, real_h;
   644     int screen_w;
   645     int screen_h;
   646 
   647     screen_w = DisplayWidth(SDL_Display, SDL_Screen);
   648     screen_h = DisplayHeight(SDL_Display, SDL_Screen);
   649 
   650     x = xinerama_x;
   651     y = xinerama_y;
   652     if ( currently_fullscreen ) {
   653         /* Switch resolution and cover it with the FSwindow */
   654         move_cursor_to(this, x, y);
   655         set_best_resolution(this, window_w, window_h);
   656         move_cursor_to(this, x, y);
   657         get_real_resolution(this, &real_w, &real_h);
   658         if ( window_w > real_w ) {
   659             real_w = MAX(real_w, screen_w);
   660         }
   661         if ( window_h > real_h ) {
   662             real_h = MAX(real_h, screen_h);
   663         }
   664         XMoveResizeWindow(SDL_Display, FSwindow, x, y, real_w, real_h);
   665         move_cursor_to(this, real_w/2, real_h/2);
   666 
   667         /* Center and reparent the drawing window */
   668         x = (real_w - window_w)/2;
   669         y = (real_h - window_h)/2;
   670         XReparentWindow(SDL_Display, SDL_Window, FSwindow, x, y);
   671         /* FIXME: move the mouse to the old relative location */
   672         XSync(SDL_Display, True);   /* Flush spurious mode change events */
   673     }
   674     return(1);
   675 }
   676 
   677 void X11_QueueEnterFullScreen(_THIS)
   678 {
   679     switch_waiting = 0x01 | SDL_FULLSCREEN;
   680     switch_time = SDL_GetTicks() + 1500;
   681 #if 0 /* This causes a BadMatch error if the window is iconified (not needed) */
   682     XSetInputFocus(SDL_Display, WMwindow, RevertToNone, CurrentTime);
   683 #endif
   684 }
   685 
   686 int X11_EnterFullScreen(_THIS)
   687 {
   688     int okay;
   689 #if 0
   690     Window tmpwin, *windows;
   691     int i, nwindows;
   692 #endif
   693     int real_w, real_h;
   694     int screen_w;
   695     int screen_h;
   696 
   697     okay = 1;
   698     if ( currently_fullscreen ) {
   699         return(okay);
   700     }
   701 
   702     /* Ungrab the input so that we can move the mouse around */
   703     X11_GrabInputNoLock(this, SDL_GRAB_OFF);
   704 
   705     /* Map the fullscreen window to blank the screen */
   706     screen_w = DisplayWidth(SDL_Display, SDL_Screen);
   707     screen_h = DisplayHeight(SDL_Display, SDL_Screen);
   708     get_real_resolution(this, &real_w, &real_h);
   709     if ( window_w > real_w ) {
   710         real_w = MAX(real_w, screen_w);
   711     }
   712     if ( window_h > real_h ) {
   713         real_h = MAX(real_h, screen_h);
   714     }
   715     XMoveResizeWindow(SDL_Display, FSwindow,
   716                       xinerama_x, xinerama_y, real_w, real_h);
   717     XMapRaised(SDL_Display, FSwindow);
   718     X11_WaitMapped(this, FSwindow);
   719 
   720 #if 0 /* This seems to break WindowMaker in focus-follows-mouse mode */
   721     /* Make sure we got to the top of the window stack */
   722     if ( XQueryTree(SDL_Display, SDL_Root, &tmpwin, &tmpwin,
   723                             &windows, &nwindows) && windows ) {
   724         /* If not, try to put us there - if fail... oh well */
   725         if ( windows[nwindows-1] != FSwindow ) {
   726             tmpwin = windows[nwindows-1];
   727             for ( i=0; i<nwindows; ++i ) {
   728                 if ( windows[i] == FSwindow ) {
   729                     SDL_memcpy(&windows[i], &windows[i+1],
   730                            (nwindows-i-1)*sizeof(windows[i]));
   731                     break;
   732                 }
   733             }
   734             windows[nwindows-1] = FSwindow;
   735             XRestackWindows(SDL_Display, windows, nwindows);
   736             XSync(SDL_Display, False);
   737         }
   738         XFree(windows);
   739     }
   740 #else
   741     XRaiseWindow(SDL_Display, FSwindow);
   742 #endif
   743 
   744 #if SDL_VIDEO_DRIVER_X11_VIDMODE
   745     /* Save the current video mode */
   746     if ( use_vidmode ) {
   747         SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, True);
   748     }
   749 #endif
   750     currently_fullscreen = 1;
   751 
   752     /* Set the new resolution */
   753     okay = X11_ResizeFullScreen(this);
   754     if ( ! okay ) {
   755         X11_LeaveFullScreen(this);
   756     }
   757     /* Set the colormap */
   758     if ( SDL_XColorMap ) {
   759         XInstallColormap(SDL_Display, SDL_XColorMap);
   760     }
   761     if ( okay )
   762         X11_GrabInputNoLock(this, this->input_grab | SDL_GRAB_FULLSCREEN);
   763 
   764     /* We may need to refresh the screen at this point (no backing store)
   765        We also don't get an event, which is why we explicitly refresh. */
   766     if ( this->screen ) {
   767         if ( this->screen->flags & SDL_OPENGL ) {
   768             SDL_PrivateExpose();
   769         } else {
   770             X11_RefreshDisplay(this);
   771         }
   772     }
   773 
   774     return(okay);
   775 }
   776 
   777 int X11_LeaveFullScreen(_THIS)
   778 {
   779     if ( currently_fullscreen ) {
   780         XReparentWindow(SDL_Display, SDL_Window, WMwindow, 0, 0);
   781 #if SDL_VIDEO_DRIVER_X11_VIDMODE
   782         if ( use_vidmode ) {
   783             restore_mode(this);
   784             SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False);
   785         }
   786 #endif
   787 
   788 #if SDL_VIDEO_DRIVER_X11_XME
   789         if ( use_xme ) {
   790             int rw, rh;        
   791             
   792             /* check current mode so we can avoid uneccessary mode changes */
   793             get_real_resolution(this, &rw, &rh);
   794 
   795             if (rw != saved_res.width || rh != saved_res.height) {
   796                 XiGMiscChangeResolution(SDL_Display, 
   797                                         SDL_Screen,
   798                                         0, /* view */
   799                                         saved_res.width, 
   800                                         saved_res.height,
   801                                         0);
   802                 XSync(SDL_Display, False);
   803             }
   804         }
   805 #endif
   806 
   807         XUnmapWindow(SDL_Display, FSwindow);
   808         X11_WaitUnmapped(this, FSwindow);
   809         XSync(SDL_Display, True);   /* Flush spurious mode change events */
   810         currently_fullscreen = 0;
   811     }
   812     /* If we get popped out of fullscreen mode for some reason, input_grab
   813        will still have the SDL_GRAB_FULLSCREEN flag set, since this is only
   814        temporary.  In this case, release the grab unless the input has been
   815        explicitly grabbed.
   816      */
   817     X11_GrabInputNoLock(this, this->input_grab & ~SDL_GRAB_FULLSCREEN);
   818 
   819     /* We may need to refresh the screen at this point (no backing store)
   820        We also don't get an event, which is why we explicitly refresh. */
   821     if ( this->screen ) {
   822         if ( this->screen->flags & SDL_OPENGL ) {
   823             SDL_PrivateExpose();
   824         } else {
   825             X11_RefreshDisplay(this);
   826         }
   827     }
   828 
   829     return(0);
   830 }