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