view src/video/SDL_video.c @ 4157:baf615f9f2a0 SDL-1.2

Date: Thu, 16 Oct 2008 20:27:34 +0400 From: "Ilya Kasnacheev" <ilya.kasnacheev@gmail.com> To: sdl@lists.libsdl.org Subject: [SDL] SDL for Windows CE: a few GAPI patches Hi *! I've just ported a POWDER roguelike ( http://www.zincland.com/powder/ ) to Windows CE (PDAs, Windows Mobile/Pocket PC). To do that, I had to get libsdl working. Thanks for the awesome project files, it built without a hitch. Nevertheless, I've found quite a few bugs in Windows CE (GAPI) SDL implementation, which I've solved and now present as a serie of patches. I'll try carefully annotate them. Please annotate them so I can work toward accepting them into the main source tree since without them SDL isn't really working on Windows CE (I wonder why nobody fixed them before, btw: why isn't SDL popular as a way to develop Windows CE games? Where are no ports?) These changes can't be considered flawless, but they can be considered working because I've yet to hear complains about things I fixed and POWDER build for Windows CE is now considered stable. Note: my comments start with !!, delete them before applying. diff -bru SDL-1.2.13/src/video/gapi/SDL_gapivideo.c SDL-1.2.13-new/src/video/gapi/SDL_gapivideo.c --- SDL-1.2.13/src/video/gapi/SDL_gapivideo.c 2007-12-31 07:48:00.000000000 +0300 +++ SDL-1.2.13-new/src/video/gapi/SDL_gapivideo.c 2008-10-16 20:02:11.000000000 +0400 @@ -643,6 +643,7 @@ } gapi->userOrientation = SDL_ORIENTATION_UP; + gapi->systemOrientation = SDL_ORIENTATION_UP; video->flags = SDL_FULLSCREEN; /* Clear flags, GAPI supports fullscreen only */ /* GAPI or VGA? */ @@ -661,18 +662,21 @@ } /* detect user landscape mode */ - if( (width > height) && (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN))) + if( (width > height) && (gapi->gxProperties.cxWidth < gapi->gxProperties.cyHeight)) gapi->userOrientation = SDL_ORIENTATION_RIGHT; + if(GetSystemMetrics(SM_CYSCREEN) < GetSystemMetrics(SM_CXSCREEN)) + gapi->systemOrientation = SDL_ORIENTATION_RIGHT; + /* shall we apply hires fix? for example when we do not use hires resource */ gapi->hiresFix = 0; - if( gapi->userOrientation == SDL_ORIENTATION_RIGHT ) + if( gapi->systemOrientation == gapi->userOrientation ) { - if( (width > GetSystemMetrics(SM_CYSCREEN)) || (height > GetSystemMetrics(SM_CXSCREEN))) + if( (width > GetSystemMetrics(SM_CXSCREEN)) || (height > GetSystemMetrics(SM_CYSCREEN))) gapi->hiresFix = 1; } else - if( (width > GetSystemMetrics(SM_CXSCREEN)) || (height > GetSystemMetrics(SM_CYSCREEN))) - if( !((width == GetSystemMetrics(SM_CYSCREEN)) && (height == GetSystemMetrics(SM_CXSCREEN)))) // user portrait, device landscape + if( (width > GetSystemMetrics(SM_CYSCREEN)) || (height > GetSystemMetrics(SM_CXSCREEN))) +// if( !((width == gapi->gxProperties.cyHeight) && (height == gapi->gxProperties.cxWidth))) // user portrait, device landscape gapi->hiresFix = 1; switch( gapi->userOrientation ) !! It used to query system metrics which return dimensions according to screen !! orientation, which can really be portrait, left landscape or right landscape. !! This is presumably incorrect because we couldn't care less about user mode !! dimensions - all we want are the GAPI framebuffer dimensions, which only match !! user dimensions in one of possible orientations. !! There's a fair dose of cargo cult programming involved in this fix, but it !! used to work only in one orientation (portrait for PDAs, where frame-buffer !! have same orientation as user screen), and now it works on all orientations. @@ -742,21 +746,30 @@ WIN_FlushMessageQueue(); /* Open GAPI display */ - if( !gapi->useVga && this->hidden->useGXOpenDisplay ) + if( !gapi->useVga && this->hidden->useGXOpenDisplay && !this->hidden->alreadyGXOpened ) + { + this->hidden->alreadyGXOpened = 1; if( !gapi->gxFunc.GXOpenDisplay(SDL_Window, GX_FULLSCREEN) ) { SDL_SetError("Couldn't initialize GAPI"); return(NULL); } + } #if REPORT_VIDEO_INFO printf("Video properties:\n"); printf("display bpp: %d\n", gapi->gxProperties.cBPP); printf("display width: %d\n", gapi->gxProperties.cxWidth); printf("display height: %d\n", gapi->gxProperties.cyHeight); + printf("system display width: %d\n", GetSystemMetrics(SM_CXSCREEN)); + printf("system display height: %d\n", GetSystemMetrics(SM_CYSCREEN)); printf("x pitch: %d\n", gapi->gxProperties.cbxPitch); printf("y pitch: %d\n", gapi->gxProperties.cbyPitch); printf("gapi flags: 0x%x\n", gapi->gxProperties.ffFormat); + printf("user orientation: %d\n", gapi->userOrientation); + printf("system orientation: %d\n", gapi->userOrientation); + printf("gapi orientation: %d\n", gapi->gapiOrientation); + if( !gapi->useVga && this->hidden->useGXOpenDisplay && gapi->needUpdate) { !! Previous version used to call gapi->gxFunc.GXOpenDisplay each time the video !! mode would be changed. You shouldn't, because this call has a meaning "Lock the !! GAPI framebuffer, designate it as busy", so the second call will fail (it is !! already locked/busy). !! Testing might not find that because most programs set up the video mode only !! once, but POWDER does this once in a while, so it crashed when in 320x240 mode !! (640x480 mode doesn't use that code, it worked fine). diff -bru SDL-1.2.13/src/video/gapi/SDL_gapivideo.h SDL-1.2.13-new/src/video/gapi/SDL_gapivideo.h --- SDL-1.2.13/src/video/gapi/SDL_gapivideo.h 2007-12-31 07:48:00.000000000 +0300 +++ SDL-1.2.13-new/src/video/gapi/SDL_gapivideo.h 2008-10-16 20:02:11.000000000 +0400 @@ -132,12 +132,17 @@ #define NUM_MODELISTS 4 /* 8, 16, 24, and 32 bits-per-pixel */ int SDL_nummodes[NUM_MODELISTS]; SDL_Rect **SDL_modelist[NUM_MODELISTS]; + // The orientation of the video mode user wants to get + // Probably restricted to UP and RIGHT enum SDL_ScreenOrientation userOrientation; int invert; char hiresFix; // using hires mode without defining hires resource // -------------- int useGXOpenDisplay; /* use GXOpenDispplay */ + int alreadyGXOpened; int w, h; + // The orientation of GAPI framebuffer. + // Never changes on the same device. enum SDL_ScreenOrientation gapiOrientation; void *buffer; // may be 8, 16, 24, 32 bpp @@ -153,6 +158,10 @@ int startOffset; // in bytes int useVga; int suspended; // do not pu anything into video memory + // The orientation of the system, as defined by SM_CXSCREEN and SM_CYSCREEN + // User can change it by using 'screen layout' in system options + // Restricted to UP or RIGHT + enum SDL_ScreenOrientation systemOrientation; }; !! This is a flag variable, see the previous comment !! And yet another orientation: now we have to keep three of them in mind. diff -bru SDL-1.2.13/src/video/wincommon/SDL_sysevents.c SDL-1.2.13-new/src/video/wincommon/SDL_sysevents.c --- SDL-1.2.13/src/video/wincommon/SDL_sysevents.c 2007-12-31 07:48:02.000000000 +0300 +++ SDL-1.2.13-new/src/video/wincommon/SDL_sysevents.c 2008-10-16 20:02:12.000000000 +0400 @@ -160,10 +160,22 @@ #endif */ } break; + // FIXME: Older version used just SDL_VideoSurface->(w, h) + // w and h are "clipped" while x and y are "raw", which caused + // x in former and y in latter case to be clipped in a wrong direction, + // thus offsetting the coordinate on 2 x clip pixels + // (like, 128 for 640 -> 512 clipping). + // We will now try to extract and use raw values. + // The way to do that RIGHT is do (orientation-dependent) clipping before + // doing this transform, but it's hardly possible. + + // SEE SDL_mouse.c /ClipOffset to understand these calculations. case SDL_ORIENTATION_RIGHT: if (!SDL_VideoSurface) break; - rotatedX = SDL_VideoSurface->w - *y; + rotatedX = (2 * ((SDL_VideoSurface->offset%SDL_VideoSurface->pitch)/ + SDL_VideoSurface->format->BytesPerPixel)) + + SDL_VideoSurface->w - *y; rotatedY = *x; *x = rotatedX; *y = rotatedY; @@ -172,7 +184,8 @@ if (!SDL_VideoSurface) break; rotatedX = *y; - rotatedY = SDL_VideoSurface->h - *x; + rotatedY = (2 * (SDL_VideoSurface->offset/SDL_VideoSurface->pitch)) + + SDL_VideoSurface->h - *x; *x = rotatedX; *y = rotatedY; break; !! That's the trickest part, hence the long comment. !! GAPI would really support only 320x240 or 640x480 mode, if application !! requested the different screen size (as POWDER did, wishing 256x192), then SDL !! is going to grab the first mode that fits the requested, and pad the screen !! with black bars (as they do with wide-screen films). !! It would also get, say, 240x320 mode, and to turn it into 256x192 it would !! need to rotate mouse clicks. !! It worked, but one bug slipped through: it would receive mouse clicks !! unpadded, then rotate them, and then pad the black bars. The problem is: rotate !! is done by GAPI driver while padding is done by SDL core. SDL core doesn't know !! anything about rotating, so it would pad one of dimensions incorrectly. I understand that some of my claims (or code) might seem unbacked, but you can always grab the POWDER binary, compile your own libsdl with one or more of those fixes turned off, and see how weird it would misbehave. I can even supply you with those custom builds of libsdl if you don't want to set up the build environment for windows ce, you'll just need a PDA or a smartphone with it. I plan to take care of SDL on Windows CE as long as I maintain the POWDER port. POWDER is good for that because it: Employs both padded (with centered image, black bars) and unpadded (image occupies full screen) graphics; initializes video more than once; uses both 320x240 and 640x480 video; uses both stylus and buttons. There's still a list of unresolved issues which I'm planning to fix: 1) Arrow buttons on PDA return weird scancodes compared to PC, this caused the game to misbehave before I've fixed that. You can see it on those diagrams: http://wrar.name/upload/powder-htc.png http://wrar.name/upload/powder-pda.png 2) SDL (or underlying windows) doesn't care to rotate arrow presses when we're in a low-res GAPI mode, but it will rotate them in VGA mode (because of different screen orientations, the same arrow buttons can suddently mean different directions). Solution: we should stick to GAPI user orientation (the orientation the program supposedly wants) and rotate the keys on our own. _______________________________________________ SDL mailing list SDL@lists.libsdl.org http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
author Sam Lantinga <slouken@libsdl.org>
date Fri, 07 Nov 2008 04:15:36 +0000
parents 4433ef2a1802
children a1b03ba2fcd0
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2006 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

/* The high-level video driver subsystem */

#include "SDL.h"
#include "SDL_sysvideo.h"
#include "SDL_blit.h"
#include "SDL_pixels_c.h"
#include "SDL_cursor_c.h"
#include "../events/SDL_sysevents.h"
#include "../events/SDL_events_c.h"

/* Available video drivers */
static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_QUARTZ
	&QZ_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_X11
	&X11_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DGA
	&DGA_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_NANOX
	&NX_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_IPOD
	&iPod_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_QTOPIA
	&Qtopia_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WSCONS
	&WSCONS_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_FBCON
	&FBCON_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DIRECTFB
	&DirectFB_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_PS2GS
	&PS2GS_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_GGI
	&GGI_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_VGL
	&VGL_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_SVGALIB
	&SVGALIB_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_GAPI
	&GAPI_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WINDIB
	&WINDIB_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DDRAW
	&DIRECTX_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_BWINDOW
	&BWINDOW_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_TOOLBOX
	&TOOLBOX_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DRAWSPROCKET
	&DSp_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_PHOTON
	&ph_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_EPOC
	&EPOC_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_XBIOS
	&XBIOS_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_GEM
	&GEM_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_PICOGUI
	&PG_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DC
	&DC_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_NDS
	&NDS_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_RISCOS
	&RISCOS_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_OS2FS
	&OS2FSLib_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_AALIB
	&AALIB_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DUMMY
	&DUMMY_bootstrap,
#endif
	NULL
};

SDL_VideoDevice *current_video = NULL;

/* Various local functions */
int SDL_VideoInit(const char *driver_name, Uint32 flags);
void SDL_VideoQuit(void);
void SDL_GL_UpdateRectsLock(SDL_VideoDevice* this, int numrects, SDL_Rect* rects);

static SDL_GrabMode SDL_WM_GrabInputOff(void);
#if SDL_VIDEO_OPENGL
static int lock_count = 0;
#endif


/*
 * Initialize the video and event subsystems -- determine native pixel format
 */
int SDL_VideoInit (const char *driver_name, Uint32 flags)
{
	SDL_VideoDevice *video;
	int index;
	int i;
	SDL_PixelFormat vformat;
	Uint32 video_flags;

	/* Toggle the event thread flags, based on OS requirements */
#if defined(MUST_THREAD_EVENTS)
	flags |= SDL_INIT_EVENTTHREAD;
#elif defined(CANT_THREAD_EVENTS)
	if ( (flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
		SDL_SetError("OS doesn't support threaded events");
		return(-1);
	}
#endif

	/* Check to make sure we don't overwrite 'current_video' */
	if ( current_video != NULL ) {
		SDL_VideoQuit();
	}

	/* Select the proper video driver */
	index = 0;
	video = NULL;
	if ( driver_name != NULL ) {
#if 0	/* This will be replaced with a better driver selection API */
		if ( SDL_strrchr(driver_name, ':') != NULL ) {
			index = atoi(SDL_strrchr(driver_name, ':')+1);
		}
#endif
		for ( i=0; bootstrap[i]; ++i ) {
			if ( SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
				if ( bootstrap[i]->available() ) {
					video = bootstrap[i]->create(index);
					break;
				}
			}
		}
	} else {
		for ( i=0; bootstrap[i]; ++i ) {
			if ( bootstrap[i]->available() ) {
				video = bootstrap[i]->create(index);
				if ( video != NULL ) {
					break;
				}
			}
		}
	}
	if ( video == NULL ) {
		SDL_SetError("No available video device");
		return(-1);
	}
	current_video = video;
	current_video->name = bootstrap[i]->name;

	/* Do some basic variable initialization */
	video->screen = NULL;
	video->shadow = NULL;
	video->visible = NULL;
	video->physpal = NULL;
	video->gammacols = NULL;
	video->gamma = NULL;
	video->wm_title = NULL;
	video->wm_icon  = NULL;
	video->offset_x = 0;
	video->offset_y = 0;
	SDL_memset(&video->info, 0, (sizeof video->info));
	
	video->displayformatalphapixel = NULL;

	/* Set some very sane GL defaults */
	video->gl_config.driver_loaded = 0;
	video->gl_config.dll_handle = NULL;
	video->gl_config.red_size = 3;
	video->gl_config.green_size = 3;
	video->gl_config.blue_size = 2;
	video->gl_config.alpha_size = 0;
	video->gl_config.buffer_size = 0;
	video->gl_config.depth_size = 16;
	video->gl_config.stencil_size = 0;
	video->gl_config.double_buffer = 1;
	video->gl_config.accum_red_size = 0;
	video->gl_config.accum_green_size = 0;
	video->gl_config.accum_blue_size = 0;
	video->gl_config.accum_alpha_size = 0;
	video->gl_config.stereo = 0;
	video->gl_config.multisamplebuffers = 0;
	video->gl_config.multisamplesamples = 0;
	video->gl_config.accelerated = -1; /* not known, don't set */
	video->gl_config.swap_control = -1; /* not known, don't set */
	
	/* Initialize the video subsystem */
	SDL_memset(&vformat, 0, sizeof(vformat));
	if ( video->VideoInit(video, &vformat) < 0 ) {
		SDL_VideoQuit();
		return(-1);
	}

	/* Create a zero sized video surface of the appropriate format */
	video_flags = SDL_SWSURFACE;
	SDL_VideoSurface = SDL_CreateRGBSurface(video_flags, 0, 0,
				vformat.BitsPerPixel,
				vformat.Rmask, vformat.Gmask, vformat.Bmask, 0);
	if ( SDL_VideoSurface == NULL ) {
		SDL_VideoQuit();
		return(-1);
	}
	SDL_PublicSurface = NULL;	/* Until SDL_SetVideoMode() */

#if 0 /* Don't change the current palette - may be used by other programs.
       * The application can't do anything with the display surface until
       * a video mode has been set anyway. :)
       */
	/* If we have a palettized surface, create a default palette */
	if ( SDL_VideoSurface->format->palette ) {
		SDL_PixelFormat *vf = SDL_VideoSurface->format;
		SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);
		video->SetColors(video,
				 0, vf->palette->ncolors, vf->palette->colors);
	}
#endif
	video->info.vfmt = SDL_VideoSurface->format;

	/* Start the event loop */
	if ( SDL_StartEventLoop(flags) < 0 ) {
		SDL_VideoQuit();
		return(-1);
	}
	SDL_CursorInit(flags & SDL_INIT_EVENTTHREAD);

	/* We're ready to go! */
	return(0);
}

char *SDL_VideoDriverName(char *namebuf, int maxlen)
{
	if ( current_video != NULL ) {
		SDL_strlcpy(namebuf, current_video->name, maxlen);
		return(namebuf);
	}
	return(NULL);
}

/*
 * Get the current display surface
 */
SDL_Surface *SDL_GetVideoSurface(void)
{
	SDL_Surface *visible;

	visible = NULL;
	if ( current_video ) {
		visible = current_video->visible;
	}
	return(visible);
}

/*
 * Get the current information about the video hardware
 */
const SDL_VideoInfo *SDL_GetVideoInfo(void)
{
	const SDL_VideoInfo *info;

	info = NULL;
	if ( current_video ) {
		info = &current_video->info;
	}
	return(info);
}

/*
 * Return a pointer to an array of available screen dimensions for the
 * given format, sorted largest to smallest.  Returns NULL if there are
 * no dimensions available for a particular format, or (SDL_Rect **)-1
 * if any dimension is okay for the given format.  If 'format' is NULL,
 * the mode list will be for the format given by SDL_GetVideoInfo()->vfmt
 */
SDL_Rect ** SDL_ListModes (SDL_PixelFormat *format, Uint32 flags)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;
	SDL_Rect **modes;

	modes = NULL;
	if ( SDL_VideoSurface ) {
		if ( format == NULL ) {
			format = SDL_VideoSurface->format;
		}
		modes = video->ListModes(this, format, flags);
	}
	return(modes);
}

/*
 * Check to see if a particular video mode is supported.
 * It returns 0 if the requested mode is not supported under any bit depth,
 * or returns the bits-per-pixel of the closest available mode with the
 * given width and height.  If this bits-per-pixel is different from the
 * one used when setting the video mode, SDL_SetVideoMode() will succeed,
 * but will emulate the requested bits-per-pixel with a shadow surface.
 */
static Uint8 SDL_closest_depths[4][8] = {
	/* 8 bit closest depth ordering */
	{ 0, 8, 16, 15, 32, 24, 0, 0 },
	/* 15,16 bit closest depth ordering */
	{ 0, 16, 15, 32, 24, 8, 0, 0 },
	/* 24 bit closest depth ordering */
	{ 0, 24, 32, 16, 15, 8, 0, 0 },
	/* 32 bit closest depth ordering */
	{ 0, 32, 16, 15, 24, 8, 0, 0 }
};


#ifdef __MACOS__ /* MPW optimization bug? */
#define NEGATIVE_ONE 0xFFFFFFFF
#else
#define NEGATIVE_ONE -1
#endif

int SDL_VideoModeOK (int width, int height, int bpp, Uint32 flags)
{
	int table, b, i;
	int supported;
	SDL_PixelFormat format;
	SDL_Rect **sizes;

	/* Currently 1 and 4 bpp are not supported */
	if ( bpp < 8 || bpp > 32 ) {
		return(0);
	}
	if ( (width <= 0) || (height <= 0) ) {
		return(0);
	}

	/* Search through the list valid of modes */
	SDL_memset(&format, 0, sizeof(format));
	supported = 0;
	table = ((bpp+7)/8)-1;
	SDL_closest_depths[table][0] = bpp;
	SDL_closest_depths[table][7] = 0;
	for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
		format.BitsPerPixel = SDL_closest_depths[table][b];
		sizes = SDL_ListModes(&format, flags);
		if ( sizes == (SDL_Rect **)0 ) {
			/* No sizes supported at this bit-depth */
			continue;
		} else 
		if (sizes == (SDL_Rect **)NEGATIVE_ONE) {
			/* Any size supported at this bit-depth */
			supported = 1;
			continue;
		} else if (current_video->handles_any_size) {
			/* Driver can center a smaller surface to simulate fullscreen */
			for ( i=0; sizes[i]; ++i ) {
				if ((sizes[i]->w >= width) && (sizes[i]->h >= height)) {
					supported = 1; /* this mode can fit the centered window. */
					break;
				}
			}
		} else
		for ( i=0; sizes[i]; ++i ) {
			if ((sizes[i]->w == width) && (sizes[i]->h == height)) {
				supported = 1;
				break;
			}
		}
	}
	if ( supported ) {
		--b;
		return(SDL_closest_depths[table][b]);
	} else {
		return(0);
	}
}

/*
 * Get the closest non-emulated video mode to the one requested
 */
static int SDL_GetVideoMode (int *w, int *h, int *BitsPerPixel, Uint32 flags)
{
	int table, b, i;
	int supported;
	int native_bpp;
	SDL_PixelFormat format;
	SDL_Rect **sizes;

	/* Check parameters */
	if ( *BitsPerPixel < 8 || *BitsPerPixel > 32 ) {
		SDL_SetError("Invalid bits per pixel (range is {8...32})");
		return(0);
	}
	if ((*w <= 0) || (*h <= 0)) {
		SDL_SetError("Invalid width or height");
		return(0);
	}

	/* Try the original video mode, get the closest depth */
	native_bpp = SDL_VideoModeOK(*w, *h, *BitsPerPixel, flags);
	if ( native_bpp == *BitsPerPixel ) {
		return(1);
	}
	if ( native_bpp > 0 ) {
		*BitsPerPixel = native_bpp;
		return(1);
	}

	/* No exact size match at any depth, look for closest match */
	SDL_memset(&format, 0, sizeof(format));
	supported = 0;
	table = ((*BitsPerPixel+7)/8)-1;
	SDL_closest_depths[table][0] = *BitsPerPixel;
	SDL_closest_depths[table][7] = SDL_VideoSurface->format->BitsPerPixel;
	for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
		int best;

		format.BitsPerPixel = SDL_closest_depths[table][b];
		sizes = SDL_ListModes(&format, flags);
		if ( sizes == (SDL_Rect **)0 ) {
			/* No sizes supported at this bit-depth */
			continue;
		}
		best=0;
		for ( i=0; sizes[i]; ++i ) {
			/* Mode with both dimensions bigger or equal than asked ? */
			if ((sizes[i]->w >= *w) && (sizes[i]->h >= *h)) {
				/* Mode with any dimension smaller or equal than current best ? */
				if ((sizes[i]->w <= sizes[best]->w) || (sizes[i]->h <= sizes[best]->h)) {
					/* Now choose the mode that has less pixels */
					if ((sizes[i]->w * sizes[i]->h) <= (sizes[best]->w * sizes[best]->h)) {
						best=i;
						supported = 1;
					}
				}
			}
		}
		if (supported) {
			*w=sizes[best]->w;
			*h=sizes[best]->h;
			*BitsPerPixel = SDL_closest_depths[table][b];
		}
	}
	if ( ! supported ) {
		SDL_SetError("No video mode large enough for %dx%d", *w, *h);
	}
	return(supported);
}

/* This should probably go somewhere else -- like SDL_surface.c */
static void SDL_ClearSurface(SDL_Surface *surface)
{
	Uint32 black;

	black = SDL_MapRGB(surface->format, 0, 0, 0);
	SDL_FillRect(surface, NULL, black);
	if ((surface->flags&SDL_HWSURFACE) && (surface->flags&SDL_DOUBLEBUF)) {
		SDL_Flip(surface);
		SDL_FillRect(surface, NULL, black);
	}
	if (surface->flags&SDL_FULLSCREEN) {
		SDL_Flip(surface);
	}
}

/*
 * Create a shadow surface suitable for fooling the app. :-)
 */
static void SDL_CreateShadowSurface(int depth)
{
	Uint32 Rmask, Gmask, Bmask;

	/* Allocate the shadow surface */
	if ( depth == (SDL_VideoSurface->format)->BitsPerPixel ) {
		Rmask = (SDL_VideoSurface->format)->Rmask;
		Gmask = (SDL_VideoSurface->format)->Gmask;
		Bmask = (SDL_VideoSurface->format)->Bmask;
	} else {
		Rmask = Gmask = Bmask = 0;
	}
	SDL_ShadowSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
				SDL_VideoSurface->w, SDL_VideoSurface->h,
						depth, Rmask, Gmask, Bmask, 0);
	if ( SDL_ShadowSurface == NULL ) {
		return;
	}

	/* 8-bit shadow surfaces report that they have exclusive palette */
	if ( SDL_ShadowSurface->format->palette ) {
		SDL_ShadowSurface->flags |= SDL_HWPALETTE;
		if ( depth == (SDL_VideoSurface->format)->BitsPerPixel ) {
			SDL_memcpy(SDL_ShadowSurface->format->palette->colors,
				SDL_VideoSurface->format->palette->colors,
				SDL_VideoSurface->format->palette->ncolors*
							sizeof(SDL_Color));
		} else {
			SDL_DitherColors(
			SDL_ShadowSurface->format->palette->colors, depth);
		}
	}

	/* If the video surface is resizable, the shadow should say so */
	if ( (SDL_VideoSurface->flags & SDL_RESIZABLE) == SDL_RESIZABLE ) {
		SDL_ShadowSurface->flags |= SDL_RESIZABLE;
	}
	/* If the video surface has no frame, the shadow should say so */
	if ( (SDL_VideoSurface->flags & SDL_NOFRAME) == SDL_NOFRAME ) {
		SDL_ShadowSurface->flags |= SDL_NOFRAME;
	}
	/* If the video surface is fullscreen, the shadow should say so */
	if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
		SDL_ShadowSurface->flags |= SDL_FULLSCREEN;
	}
	/* If the video surface is flippable, the shadow should say so */
	if ( (SDL_VideoSurface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
		SDL_ShadowSurface->flags |= SDL_DOUBLEBUF;
	}
	return;
}

#ifdef __QNXNTO__
    #include <sys/neutrino.h>
#endif /* __QNXNTO__ */

/*
 * Set the requested video mode, allocating a shadow buffer if necessary.
 */
SDL_Surface * SDL_SetVideoMode (int width, int height, int bpp, Uint32 flags)
{
	SDL_VideoDevice *video, *this;
	SDL_Surface *prev_mode, *mode;
	int video_w;
	int video_h;
	int video_bpp;
	int is_opengl;
	SDL_GrabMode saved_grab;

	/* Start up the video driver, if necessary..
	   WARNING: This is the only function protected this way!
	 */
	if ( ! current_video ) {
		if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) {
			return(NULL);
		}
	}
	this = video = current_video;

	/* Default to the current width and height */
	if ( width == 0 ) {
		width = video->info.current_w;
	}
	if ( height == 0 ) {
		height = video->info.current_h;
	}
	/* Default to the current video bpp */
	if ( bpp == 0 ) {
		flags |= SDL_ANYFORMAT;
		bpp = SDL_VideoSurface->format->BitsPerPixel;
	}

	/* Get a good video mode, the closest one possible */
	video_w = width;
	video_h = height;
	video_bpp = bpp;
	if ( ! SDL_GetVideoMode(&video_w, &video_h, &video_bpp, flags) ) {
		return(NULL);
	}

	/* Check the requested flags */
	/* There's no palette in > 8 bits-per-pixel mode */
	if ( video_bpp > 8 ) {
		flags &= ~SDL_HWPALETTE;
	}
#if 0
	if ( (flags&SDL_FULLSCREEN) != SDL_FULLSCREEN ) {
		/* There's no windowed double-buffering */
		flags &= ~SDL_DOUBLEBUF;
	}
#endif
	if ( (flags&SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
		/* Use hardware surfaces when double-buffering */
		flags |= SDL_HWSURFACE;
	}

	is_opengl = ( ( flags & SDL_OPENGL ) == SDL_OPENGL );
	if ( is_opengl ) {
		/* These flags are for 2D video modes only */
		flags &= ~(SDL_HWSURFACE|SDL_DOUBLEBUF);
	}

	/* Reset the keyboard here so event callbacks can run */
	SDL_ResetKeyboard();
	SDL_ResetMouse();
	SDL_cursorstate &= ~CURSOR_USINGSW;

	/* Clean up any previous video mode */
	if ( SDL_PublicSurface != NULL ) {
		SDL_PublicSurface = NULL;
	}
	if ( SDL_ShadowSurface != NULL ) {
		SDL_Surface *ready_to_go;
		ready_to_go = SDL_ShadowSurface;
		SDL_ShadowSurface = NULL;
		SDL_FreeSurface(ready_to_go);
	}
	if ( video->physpal ) {
		SDL_free(video->physpal->colors);
		SDL_free(video->physpal);
		video->physpal = NULL;
	}
	if( video->gammacols) {
		SDL_free(video->gammacols);
		video->gammacols = NULL;
	}

	/* Save the previous grab state and turn off grab for mode switch */
	saved_grab = SDL_WM_GrabInputOff();

	/* Try to set the video mode, along with offset and clipping */
	prev_mode = SDL_VideoSurface;
	SDL_LockCursor();
	SDL_VideoSurface = NULL;	/* In case it's freed by driver */
	mode = video->SetVideoMode(this, prev_mode,video_w,video_h,video_bpp,flags);
	if ( mode ) { /* Prevent resize events from mode change */
          /* But not on OS/2 */
#ifndef __OS2__
	    SDL_PrivateResize(mode->w, mode->h);
#endif

	    /* Sam - If we asked for OpenGL mode, and didn't get it, fail */
	    if ( is_opengl && !(mode->flags & SDL_OPENGL) ) {
		mode = NULL;
		SDL_SetError("OpenGL not available");
	    }
	}
	/*
	 * rcg11292000
	 * If you try to set an SDL_OPENGL surface, and fail to find a
	 * matching  visual, then the next call to SDL_SetVideoMode()
	 * will segfault, since  we no longer point to a dummy surface,
	 * but rather NULL.
	 * Sam 11/29/00
	 * WARNING, we need to make sure that the previous mode hasn't
	 * already been freed by the video driver.  What do we do in
	 * that case?  Should we call SDL_VideoInit() again?
	 */
	SDL_VideoSurface = (mode != NULL) ? mode : prev_mode;

	if ( (mode != NULL) && (!is_opengl) ) {
		/* Sanity check */
		if ( (mode->w < width) || (mode->h < height) ) {
			SDL_SetError("Video mode smaller than requested");
			return(NULL);
		}

		/* If we have a palettized surface, create a default palette */
		if ( mode->format->palette ) {
			SDL_PixelFormat *vf = mode->format;
			SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);
			video->SetColors(this, 0, vf->palette->ncolors,
			                           vf->palette->colors);
		}

		/* Clear the surface to black */
		video->offset_x = 0;
		video->offset_y = 0;
		mode->offset = 0;
		SDL_SetClipRect(mode, NULL);
		SDL_ClearSurface(mode);

		/* Now adjust the offsets to match the desired mode */
		video->offset_x = (mode->w-width)/2;
		video->offset_y = (mode->h-height)/2;
		mode->offset = video->offset_y*mode->pitch +
				video->offset_x*mode->format->BytesPerPixel;
#ifdef DEBUG_VIDEO
  fprintf(stderr,
	"Requested mode: %dx%dx%d, obtained mode %dx%dx%d (offset %d)\n",
		width, height, bpp,
		mode->w, mode->h, mode->format->BitsPerPixel, mode->offset);
#endif
		mode->w = width;
		mode->h = height;
		SDL_SetClipRect(mode, NULL);
	}
	SDL_ResetCursor();
	SDL_UnlockCursor();

	/* If we failed setting a video mode, return NULL... (Uh Oh!) */
	if ( mode == NULL ) {
		return(NULL);
	}

	/* If there is no window manager, set the SDL_NOFRAME flag */
	if ( ! video->info.wm_available ) {
		mode->flags |= SDL_NOFRAME;
	}

	/* Reset the mouse cursor and grab for new video mode */
	SDL_SetCursor(NULL);
	if ( video->UpdateMouse ) {
		video->UpdateMouse(this);
	}
	SDL_WM_GrabInput(saved_grab);
	SDL_GetRelativeMouseState(NULL, NULL); /* Clear first large delta */

#if SDL_VIDEO_OPENGL
	/* Load GL symbols (before MakeCurrent, where we need glGetString). */
	if ( flags & (SDL_OPENGL | SDL_OPENGLBLIT) ) {

#if defined(__QNXNTO__) && (_NTO_VERSION < 630)
#define __SDL_NOGETPROCADDR__
#elif defined(__MINT__)
#define __SDL_NOGETPROCADDR__
#endif
#ifdef __SDL_NOGETPROCADDR__
    #define SDL_PROC(ret,func,params) video->func=func;
#else
    #define SDL_PROC(ret,func,params) \
    do { \
        video->func = SDL_GL_GetProcAddress(#func); \
        if ( ! video->func ) { \
            SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
        return(NULL); \
        } \
    } while ( 0 );

#endif /* __SDL_NOGETPROCADDR__ */

#include "SDL_glfuncs.h"
#undef SDL_PROC	
	}
#endif /* SDL_VIDEO_OPENGL */

	/* If we're running OpenGL, make the context current */
	if ( (video->screen->flags & SDL_OPENGL) &&
	      video->GL_MakeCurrent ) {
		if ( video->GL_MakeCurrent(this) < 0 ) {
			return(NULL);
		}
	}

	/* Set up a fake SDL surface for OpenGL "blitting" */
	if ( (flags & SDL_OPENGLBLIT) == SDL_OPENGLBLIT ) {
		/* Load GL functions for performing the texture updates */
#if SDL_VIDEO_OPENGL

		/* Create a software surface for blitting */
#ifdef GL_VERSION_1_2
		/* If the implementation either supports the packed pixels
		   extension, or implements the core OpenGL 1.2 API, it will
		   support the GL_UNSIGNED_SHORT_5_6_5 texture format.
		 */
		if ( (bpp == 16) &&
		     (SDL_strstr((const char *)video->glGetString(GL_EXTENSIONS), "GL_EXT_packed_pixels") ||
		     (SDL_atof((const char *)video->glGetString(GL_VERSION)) >= 1.2f))
		   ) {
			video->is_32bit = 0;
			SDL_VideoSurface = SDL_CreateRGBSurface(
				flags, 
				width, 
				height,  
				16,
				31 << 11,
				63 << 5,
				31,
				0
				);
		}
		else
#endif /* OpenGL 1.2 */
		{
			video->is_32bit = 1;
			SDL_VideoSurface = SDL_CreateRGBSurface(
				flags, 
				width, 
				height, 
				32, 
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
				0x000000FF,
				0x0000FF00,
				0x00FF0000,
				0xFF000000
#else
				0xFF000000,
				0x00FF0000,
				0x0000FF00,
				0x000000FF
#endif
				);
		}
		if ( ! SDL_VideoSurface ) {
			return(NULL);
		}
		SDL_VideoSurface->flags = mode->flags | SDL_OPENGLBLIT;

		/* Free the original video mode surface (is this safe?) */
		SDL_FreeSurface(mode);

		/* Set the surface completely opaque & white by default */
		SDL_memset( SDL_VideoSurface->pixels, 255, SDL_VideoSurface->h * SDL_VideoSurface->pitch );
		video->glGenTextures( 1, &video->texture );
		video->glBindTexture( GL_TEXTURE_2D, video->texture );
		video->glTexImage2D(
			GL_TEXTURE_2D,
			0,
			video->is_32bit ? GL_RGBA : GL_RGB,
			256,
			256,
			0,
			video->is_32bit ? GL_RGBA : GL_RGB,
#ifdef GL_VERSION_1_2
			video->is_32bit ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5,
#else
			GL_UNSIGNED_BYTE,
#endif
			NULL);

		video->UpdateRects = SDL_GL_UpdateRectsLock;
#else
		SDL_SetError("Somebody forgot to #define SDL_VIDEO_OPENGL");
		return(NULL);
#endif
	}

	/* Create a shadow surface if necessary */
	/* There are three conditions under which we create a shadow surface:
		1.  We need a particular bits-per-pixel that we didn't get.
		2.  We need a hardware palette and didn't get one.
		3.  We need a software surface and got a hardware surface.
	*/
	if ( !(SDL_VideoSurface->flags & SDL_OPENGL) &&
	     (
	     (  !(flags&SDL_ANYFORMAT) &&
			(SDL_VideoSurface->format->BitsPerPixel != bpp)) ||
	     (   (flags&SDL_HWPALETTE) && 
				!(SDL_VideoSurface->flags&SDL_HWPALETTE)) ||
		/* If the surface is in hardware, video writes are visible
		   as soon as they are performed, so we need to buffer them
		 */
	     (   ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) &&
				(SDL_VideoSurface->flags&SDL_HWSURFACE)) ||
	     (   (flags&SDL_DOUBLEBUF) &&
				(SDL_VideoSurface->flags&SDL_HWSURFACE) &&
				!(SDL_VideoSurface->flags&SDL_DOUBLEBUF))
	     ) ) {
		SDL_CreateShadowSurface(bpp);
		if ( SDL_ShadowSurface == NULL ) {
			SDL_SetError("Couldn't create shadow surface");
			return(NULL);
		}
		SDL_PublicSurface = SDL_ShadowSurface;
	} else {
		SDL_PublicSurface = SDL_VideoSurface;
	}
	video->info.vfmt = SDL_VideoSurface->format;
	video->info.current_w = SDL_VideoSurface->w;
	video->info.current_h = SDL_VideoSurface->h;

	/* We're done! */
	return(SDL_PublicSurface);
}

/* 
 * Convert a surface into the video pixel format.
 */
SDL_Surface * SDL_DisplayFormat (SDL_Surface *surface)
{
	Uint32 flags;

	if ( ! SDL_PublicSurface ) {
		SDL_SetError("No video mode has been set");
		return(NULL);
	}
	/* Set the flags appropriate for copying to display surface */
	if (((SDL_PublicSurface->flags&SDL_HWSURFACE) == SDL_HWSURFACE) && current_video->info.blit_hw)
		flags = SDL_HWSURFACE;
	else 
		flags = SDL_SWSURFACE;
#ifdef AUTORLE_DISPLAYFORMAT
	flags |= (surface->flags & (SDL_SRCCOLORKEY|SDL_SRCALPHA));
	flags |= SDL_RLEACCELOK;
#else
	flags |= surface->flags & (SDL_SRCCOLORKEY|SDL_SRCALPHA|SDL_RLEACCELOK);
#endif
	return(SDL_ConvertSurface(surface, SDL_PublicSurface->format, flags));
}

/*
 * Convert a surface into a format that's suitable for blitting to
 * the screen, but including an alpha channel.
 */
SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface)
{
	SDL_PixelFormat *vf;
	SDL_PixelFormat *format;
	SDL_Surface *converted;
	Uint32 flags;
	/* default to ARGB8888 */
	Uint32 amask = 0xff000000;
	Uint32 rmask = 0x00ff0000;
	Uint32 gmask = 0x0000ff00;
	Uint32 bmask = 0x000000ff;

	if ( ! SDL_PublicSurface ) {
		SDL_SetError("No video mode has been set");
		return(NULL);
	}
	vf = SDL_PublicSurface->format;

	switch(vf->BytesPerPixel) {
	    case 2:
		/* For XGY5[56]5, use, AXGY8888, where {X, Y} = {R, B}.
		   For anything else (like ARGB4444) it doesn't matter
		   since we have no special code for it anyway */
		if ( (vf->Rmask == 0x1f) &&
		     (vf->Bmask == 0xf800 || vf->Bmask == 0x7c00)) {
			rmask = 0xff;
			bmask = 0xff0000;
		}
		break;

	    case 3:
	    case 4:
		/* Keep the video format, as long as the high 8 bits are
		   unused or alpha */
		if ( (vf->Rmask == 0xff) && (vf->Bmask == 0xff0000) ) {
			rmask = 0xff;
			bmask = 0xff0000;
		}
		break;

	    default:
		/* We have no other optimised formats right now. When/if a new
		   optimised alpha format is written, add the converter here */
		break;
	}
	format = SDL_AllocFormat(32, rmask, gmask, bmask, amask);
	flags = SDL_PublicSurface->flags & SDL_HWSURFACE;
	flags |= surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
	converted = SDL_ConvertSurface(surface, format, flags);
	SDL_FreeFormat(format);
	return(converted);
}

/*
 * Update a specific portion of the physical screen
 */
void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
{
	if ( screen ) {
		SDL_Rect rect;

		/* Perform some checking */
		if ( w == 0 )
			w = screen->w;
		if ( h == 0 )
			h = screen->h;
		if ( (int)(x+w) > screen->w )
			return;
		if ( (int)(y+h) > screen->h )
			return;

		/* Fill the rectangle */
		rect.x = (Sint16)x;
		rect.y = (Sint16)y;
		rect.w = (Uint16)w;
		rect.h = (Uint16)h;
		SDL_UpdateRects(screen, 1, &rect);
	}
}
void SDL_UpdateRects (SDL_Surface *screen, int numrects, SDL_Rect *rects)
{
	int i;
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this = current_video;

	if ( (screen->flags & (SDL_OPENGL | SDL_OPENGLBLIT)) == SDL_OPENGL ) {
		SDL_SetError("OpenGL active, use SDL_GL_SwapBuffers()");
		return;
	}
	if ( screen == SDL_ShadowSurface ) {
		/* Blit the shadow surface using saved mapping */
		SDL_Palette *pal = screen->format->palette;
		SDL_Color *saved_colors = NULL;
		if ( pal && !(SDL_VideoSurface->flags & SDL_HWPALETTE) ) {
			/* simulated 8bpp, use correct physical palette */
			saved_colors = pal->colors;
			if ( video->gammacols ) {
				/* gamma-corrected palette */
				pal->colors = video->gammacols;
			} else if ( video->physpal ) {
				/* physical palette different from logical */
				pal->colors = video->physpal->colors;
			}
		}
		if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
			SDL_LockCursor();
			SDL_DrawCursor(SDL_ShadowSurface);
			for ( i=0; i<numrects; ++i ) {
				SDL_LowerBlit(SDL_ShadowSurface, &rects[i], 
						SDL_VideoSurface, &rects[i]);
			}
			SDL_EraseCursor(SDL_ShadowSurface);
			SDL_UnlockCursor();
		} else {
			for ( i=0; i<numrects; ++i ) {
				SDL_LowerBlit(SDL_ShadowSurface, &rects[i], 
						SDL_VideoSurface, &rects[i]);
			}
		}
		if ( saved_colors ) {
			pal->colors = saved_colors;
		}

		/* Fall through to video surface update */
		screen = SDL_VideoSurface;
	}
	if ( screen == SDL_VideoSurface ) {
		/* Update the video surface */
		if ( screen->offset ) {
			for ( i=0; i<numrects; ++i ) {
				rects[i].x += video->offset_x;
				rects[i].y += video->offset_y;
			}
			video->UpdateRects(this, numrects, rects);
			for ( i=0; i<numrects; ++i ) {
				rects[i].x -= video->offset_x;
				rects[i].y -= video->offset_y;
			}
		} else {
			video->UpdateRects(this, numrects, rects);
		}
	}
}

/*
 * Performs hardware double buffering, if possible, or a full update if not.
 */
int SDL_Flip(SDL_Surface *screen)
{
	SDL_VideoDevice *video = current_video;
	/* Copy the shadow surface to the video surface */
	if ( screen == SDL_ShadowSurface ) {
		SDL_Rect rect;
		SDL_Palette *pal = screen->format->palette;
		SDL_Color *saved_colors = NULL;
		if ( pal && !(SDL_VideoSurface->flags & SDL_HWPALETTE) ) {
			/* simulated 8bpp, use correct physical palette */
			saved_colors = pal->colors;
			if ( video->gammacols ) {
				/* gamma-corrected palette */
				pal->colors = video->gammacols;
			} else if ( video->physpal ) {
				/* physical palette different from logical */
				pal->colors = video->physpal->colors;
			}
		}

		rect.x = 0;
		rect.y = 0;
		rect.w = screen->w;
		rect.h = screen->h;
		if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
			SDL_LockCursor();
			SDL_DrawCursor(SDL_ShadowSurface);
			SDL_LowerBlit(SDL_ShadowSurface, &rect,
					SDL_VideoSurface, &rect);
			SDL_EraseCursor(SDL_ShadowSurface);
			SDL_UnlockCursor();
		} else {
			SDL_LowerBlit(SDL_ShadowSurface, &rect,
					SDL_VideoSurface, &rect);
		}
		if ( saved_colors ) {
			pal->colors = saved_colors;
		}

		/* Fall through to video surface update */
		screen = SDL_VideoSurface;
	}
	if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
		SDL_VideoDevice *this  = current_video;
		return(video->FlipHWSurface(this, SDL_VideoSurface));
	} else {
		SDL_UpdateRect(screen, 0, 0, 0, 0);
	}
	return(0);
}

static void SetPalette_logical(SDL_Surface *screen, SDL_Color *colors,
			       int firstcolor, int ncolors)
{
	SDL_Palette *pal = screen->format->palette;
	SDL_Palette *vidpal;

	if ( colors != (pal->colors + firstcolor) ) {
		SDL_memcpy(pal->colors + firstcolor, colors,
		       ncolors * sizeof(*colors));
	}

	if ( current_video && SDL_VideoSurface ) {
		vidpal = SDL_VideoSurface->format->palette;
		if ( (screen == SDL_ShadowSurface) && vidpal ) {
			/*
			 * This is a shadow surface, and the physical
			 * framebuffer is also indexed. Propagate the
			 * changes to its logical palette so that
			 * updates are always identity blits
			 */
			SDL_memcpy(vidpal->colors + firstcolor, colors,
			       ncolors * sizeof(*colors));
		}
	}
	SDL_FormatChanged(screen);
}

static int SetPalette_physical(SDL_Surface *screen,
                               SDL_Color *colors, int firstcolor, int ncolors)
{
	SDL_VideoDevice *video = current_video;
	int gotall = 1;

	if ( video->physpal ) {
		/* We need to copy the new colors, since we haven't
		 * already done the copy in the logical set above.
		 */
		SDL_memcpy(video->physpal->colors + firstcolor,
		       colors, ncolors * sizeof(*colors));
	}
	if ( screen == SDL_ShadowSurface ) {
		if ( SDL_VideoSurface->flags & SDL_HWPALETTE ) {
			/*
			 * The real screen is also indexed - set its physical
			 * palette. The physical palette does not include the
			 * gamma modification, we apply it directly instead,
			 * but this only happens if we have hardware palette.
			 */
			screen = SDL_VideoSurface;
		} else {
			/*
			 * The video surface is not indexed - invalidate any
			 * active shadow-to-video blit mappings.
			 */
			if ( screen->map->dst == SDL_VideoSurface ) {
				SDL_InvalidateMap(screen->map);
			}
			if ( video->gamma ) {
				if( ! video->gammacols ) {
					SDL_Palette *pp = video->physpal;
					if(!pp)
						pp = screen->format->palette;
					video->gammacols = SDL_malloc(pp->ncolors
							  * sizeof(SDL_Color));
					SDL_ApplyGamma(video->gamma,
						       pp->colors,
						       video->gammacols,
						       pp->ncolors);
				} else {
					SDL_ApplyGamma(video->gamma, colors,
						       video->gammacols
						       + firstcolor,
						       ncolors);
				}
			}
			SDL_UpdateRect(screen, 0, 0, 0, 0);
		}
	}

	if ( screen == SDL_VideoSurface ) {
		SDL_Color gcolors[256];

		if ( video->gamma ) {
			SDL_ApplyGamma(video->gamma, colors, gcolors, ncolors);
			colors = gcolors;
		}
		gotall = video->SetColors(video, firstcolor, ncolors, colors);
		if ( ! gotall ) {
			/* The video flags shouldn't have SDL_HWPALETTE, and
			   the video driver is responsible for copying back the
			   correct colors into the video surface palette.
			*/
			;
		}
		SDL_CursorPaletteChanged();
	}
	return gotall;
}

/*
 * Set the physical and/or logical colormap of a surface:
 * Only the screen has a physical colormap. It determines what is actually
 * sent to the display.
 * The logical colormap is used to map blits to/from the surface.
 * 'which' is one or both of SDL_LOGPAL, SDL_PHYSPAL
 *
 * Return nonzero if all colours were set as requested, or 0 otherwise.
 */
int SDL_SetPalette(SDL_Surface *screen, int which,
		   SDL_Color *colors, int firstcolor, int ncolors)
{
	SDL_Palette *pal;
	int gotall;
	int palsize;

	if ( !screen ) {
		return 0;
	}
	if ( !current_video || screen != SDL_PublicSurface ) {
		/* only screens have physical palettes */
		which &= ~SDL_PHYSPAL;
	} else if ( (screen->flags & SDL_HWPALETTE) != SDL_HWPALETTE ) {
		/* hardware palettes required for split colormaps */
		which |= SDL_PHYSPAL | SDL_LOGPAL;
	}

	/* Verify the parameters */
	pal = screen->format->palette;
	if( !pal ) {
		return 0;	/* not a palettized surface */
	}
	gotall = 1;
	palsize = 1 << screen->format->BitsPerPixel;
	if ( ncolors > (palsize - firstcolor) ) {
		ncolors = (palsize - firstcolor);
		gotall = 0;
	}

	if ( which & SDL_LOGPAL ) {
		/*
		 * Logical palette change: The actual screen isn't affected,
		 * but the internal colormap is altered so that the
		 * interpretation of the pixel values (for blits etc) is
		 * changed.
		 */
		SetPalette_logical(screen, colors, firstcolor, ncolors);
	}
	if ( which & SDL_PHYSPAL ) {
		SDL_VideoDevice *video = current_video;
		/*
		 * Physical palette change: This doesn't affect the
		 * program's idea of what the screen looks like, but changes
		 * its actual appearance.
		 */
		if ( !video->physpal && !(which & SDL_LOGPAL) ) {
			/* Lazy physical palette allocation */
			int size;
			SDL_Palette *pp = SDL_malloc(sizeof(*pp));
			if ( !pp ) {
				return 0;
			}
			video->physpal = pp;
			pp->ncolors = pal->ncolors;
			size = pp->ncolors * sizeof(SDL_Color);
			pp->colors = SDL_malloc(size);
			if ( !pp->colors ) {
				return 0;
			}
			SDL_memcpy(pp->colors, pal->colors, size);
		}
		if ( ! SetPalette_physical(screen,
		                           colors, firstcolor, ncolors) ) {
			gotall = 0;
		}
	}
	return gotall;
}

int SDL_SetColors(SDL_Surface *screen, SDL_Color *colors, int firstcolor,
		  int ncolors)
{
	return SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL,
			      colors, firstcolor, ncolors);
}

/*
 * Clean up the video subsystem
 */
void SDL_VideoQuit (void)
{
	SDL_Surface *ready_to_go;

	if ( current_video ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;

		/* Halt event processing before doing anything else */
		SDL_StopEventLoop();

		/* Clean up allocated window manager items */
		if ( SDL_PublicSurface ) {
			SDL_PublicSurface = NULL;
		}
		SDL_CursorQuit();

		/* Just in case... */
		SDL_WM_GrabInputOff();

		/* Clean up the system video */
		video->VideoQuit(this);

		/* Free any lingering surfaces */
		ready_to_go = SDL_ShadowSurface;
		SDL_ShadowSurface = NULL;
		SDL_FreeSurface(ready_to_go);
		if ( SDL_VideoSurface != NULL ) {
			ready_to_go = SDL_VideoSurface;
			SDL_VideoSurface = NULL;
			SDL_FreeSurface(ready_to_go);
		}
		SDL_PublicSurface = NULL;

		/* Clean up miscellaneous memory */
		if ( video->physpal ) {
			SDL_free(video->physpal->colors);
			SDL_free(video->physpal);
			video->physpal = NULL;
		}
		if ( video->gammacols ) {
			SDL_free(video->gammacols);
			video->gammacols = NULL;
		}
		if ( video->gamma ) {
			SDL_free(video->gamma);
			video->gamma = NULL;
		}
		if ( video->wm_title != NULL ) {
			SDL_free(video->wm_title);
			video->wm_title = NULL;
		}
		if ( video->wm_icon != NULL ) {
			SDL_free(video->wm_icon);
			video->wm_icon = NULL;
		}

		/* Finish cleaning up video subsystem */
		video->free(this);
		current_video = NULL;
	}
	return;
}

/* Load the GL driver library */
int SDL_GL_LoadLibrary(const char *path)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this = current_video;
	int retval;

	retval = -1;
	if ( video == NULL ) {
		SDL_SetError("Video subsystem has not been initialized");
	} else {
		if ( video->GL_LoadLibrary ) {
			retval = video->GL_LoadLibrary(this, path);
		} else {
			SDL_SetError("No dynamic GL support in video driver");
		}
	}
	return(retval);
}

void *SDL_GL_GetProcAddress(const char* proc)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this = current_video;
	void *func;

	func = NULL;
	if ( video->GL_GetProcAddress ) {
		if ( video->gl_config.driver_loaded ) {
			func = video->GL_GetProcAddress(this, proc);
		} else {
			SDL_SetError("No GL driver has been loaded");
		}
	} else {
		SDL_SetError("No dynamic GL support in video driver");
	}
	return func;
}

/* Set the specified GL attribute for setting up a GL video mode */
int SDL_GL_SetAttribute( SDL_GLattr attr, int value )
{
	int retval;
	SDL_VideoDevice *video = current_video;

	retval = 0;
	switch (attr) {
		case SDL_GL_RED_SIZE:
			video->gl_config.red_size = value;
			break;
		case SDL_GL_GREEN_SIZE:
			video->gl_config.green_size = value;
			break;
		case SDL_GL_BLUE_SIZE:
			video->gl_config.blue_size = value;
			break;
		case SDL_GL_ALPHA_SIZE:
			video->gl_config.alpha_size = value;
			break;
		case SDL_GL_DOUBLEBUFFER:
			video->gl_config.double_buffer = value;
			break;
		case SDL_GL_BUFFER_SIZE:
			video->gl_config.buffer_size = value;
			break;
		case SDL_GL_DEPTH_SIZE:
			video->gl_config.depth_size = value;
			break;
		case SDL_GL_STENCIL_SIZE:
			video->gl_config.stencil_size = value;
			break;
		case SDL_GL_ACCUM_RED_SIZE:
			video->gl_config.accum_red_size = value;
			break;
		case SDL_GL_ACCUM_GREEN_SIZE:
			video->gl_config.accum_green_size = value;
			break;
		case SDL_GL_ACCUM_BLUE_SIZE:
			video->gl_config.accum_blue_size = value;
			break;
		case SDL_GL_ACCUM_ALPHA_SIZE:
			video->gl_config.accum_alpha_size = value;
			break;
		case SDL_GL_STEREO:
			video->gl_config.stereo = value;
			break;
		case SDL_GL_MULTISAMPLEBUFFERS:
			video->gl_config.multisamplebuffers = value;
			break;
		case SDL_GL_MULTISAMPLESAMPLES:
			video->gl_config.multisamplesamples = value;
			break;
		case SDL_GL_ACCELERATED_VISUAL:
			video->gl_config.accelerated = value;
			break;
		case SDL_GL_SWAP_CONTROL:
			video->gl_config.swap_control = value;
			break;
		default:
			SDL_SetError("Unknown OpenGL attribute");
			retval = -1;
			break;
	}
	return(retval);
}

/* Retrieve an attribute value from the windowing system. */
int SDL_GL_GetAttribute(SDL_GLattr attr, int* value)
{
	int retval = -1;
	SDL_VideoDevice* video = current_video;
	SDL_VideoDevice* this = current_video;

	if ( video->GL_GetAttribute ) {
		retval = this->GL_GetAttribute(this, attr, value);
	} else {
		*value = 0;
		SDL_SetError("GL_GetAttribute not supported");
	}
	return retval;
}

/* Perform a GL buffer swap on the current GL context */
void SDL_GL_SwapBuffers(void)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this = current_video;

	if ( video->screen->flags & SDL_OPENGL ) {
		video->GL_SwapBuffers(this);
	} else {
		SDL_SetError("OpenGL video mode has not been set");
	}
}

/* Update rects with locking */
void SDL_GL_UpdateRectsLock(SDL_VideoDevice* this, int numrects, SDL_Rect *rects)
{
	SDL_GL_Lock();
 	SDL_GL_UpdateRects(numrects, rects);
	SDL_GL_Unlock();
}

/* Update rects without state setting and changing (the caller is responsible for it) */
void SDL_GL_UpdateRects(int numrects, SDL_Rect *rects)
{
#if SDL_VIDEO_OPENGL
	SDL_VideoDevice *this = current_video;
	SDL_Rect update, tmp;
	int x, y, i;

	for ( i = 0; i < numrects; i++ )
	{
		tmp.y = rects[i].y;
		tmp.h = rects[i].h;
		for ( y = 0; y <= rects[i].h / 256; y++ )
		{
			tmp.x = rects[i].x;
			tmp.w = rects[i].w;
			for ( x = 0; x <= rects[i].w / 256; x++ )
			{
				update.x = tmp.x;
				update.y = tmp.y;
				update.w = tmp.w;
				update.h = tmp.h;

				if ( update.w > 256 )
					update.w = 256;

				if ( update.h > 256 )
					update.h = 256;
			
				this->glFlush();
				this->glTexSubImage2D( 
					GL_TEXTURE_2D, 
					0, 
					0, 
					0, 
					update.w, 
					update.h, 
					this->is_32bit? GL_RGBA : GL_RGB,
#ifdef GL_VERSION_1_2
					this->is_32bit ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5,
#else
					GL_UNSIGNED_BYTE,
#endif
					(Uint8 *)this->screen->pixels + 
						this->screen->format->BytesPerPixel * update.x + 
						update.y * this->screen->pitch );
	
				this->glFlush();
				/*
				* Note the parens around the function name:
				* This is because some OpenGL implementations define glTexCoord etc 
				* as macros, and we don't want them expanded here.
				*/
				this->glBegin(GL_TRIANGLE_STRIP);
					(this->glTexCoord2f)( 0.0, 0.0 );	
					(this->glVertex2i)( update.x, update.y );
					(this->glTexCoord2f)( (float)(update.w / 256.0), 0.0 );	
					(this->glVertex2i)( update.x + update.w, update.y );
					(this->glTexCoord2f)( 0.0, (float)(update.h / 256.0) );
					(this->glVertex2i)( update.x, update.y + update.h );
					(this->glTexCoord2f)( (float)(update.w / 256.0), (float)(update.h / 256.0) );	
					(this->glVertex2i)( update.x + update.w	, update.y + update.h );
				this->glEnd();	
			
				tmp.x += 256;
				tmp.w -= 256;
			}
			tmp.y += 256;
			tmp.h -= 256;
		}
	}
#endif
}

/* Lock == save current state */
void SDL_GL_Lock()
{
#if SDL_VIDEO_OPENGL
	lock_count--;
	if (lock_count==-1)
	{
		SDL_VideoDevice *this = current_video;

		this->glPushAttrib( GL_ALL_ATTRIB_BITS );	/* TODO: narrow range of what is saved */
#ifdef GL_CLIENT_PIXEL_STORE_BIT
		this->glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT );
#endif

		this->glEnable(GL_TEXTURE_2D);
		this->glEnable(GL_BLEND);
		this->glDisable(GL_FOG);
		this->glDisable(GL_ALPHA_TEST);
		this->glDisable(GL_DEPTH_TEST);
		this->glDisable(GL_SCISSOR_TEST);	
		this->glDisable(GL_STENCIL_TEST);
		this->glDisable(GL_CULL_FACE);

		this->glBindTexture( GL_TEXTURE_2D, this->texture );
		this->glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

		this->glPixelStorei( GL_UNPACK_ROW_LENGTH, this->screen->pitch / this->screen->format->BytesPerPixel );
		this->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		(this->glColor4f)(1.0, 1.0, 1.0, 1.0);		/* Solaris workaround */

		this->glViewport(0, 0, this->screen->w, this->screen->h);
		this->glMatrixMode(GL_PROJECTION);
		this->glPushMatrix();
		this->glLoadIdentity();

		this->glOrtho(0.0, (GLdouble) this->screen->w, (GLdouble) this->screen->h, 0.0, 0.0, 1.0);

		this->glMatrixMode(GL_MODELVIEW);
		this->glPushMatrix();
		this->glLoadIdentity();
	}
#endif
}

/* Unlock == restore saved state */
void SDL_GL_Unlock()
{
#if SDL_VIDEO_OPENGL
	lock_count++;
	if (lock_count==0)
	{
		SDL_VideoDevice *this = current_video;

		this->glPopMatrix();
		this->glMatrixMode(GL_PROJECTION);
		this->glPopMatrix();

		this->glPopClientAttrib();
		this->glPopAttrib();
	}
#endif
}

/*
 * Sets/Gets the title and icon text of the display window, if any.
 */
void SDL_WM_SetCaption (const char *title, const char *icon)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;

	if ( video ) {
		if ( title ) {
			if ( video->wm_title ) {
				SDL_free(video->wm_title);
			}
			video->wm_title = SDL_strdup(title);
		}
		if ( icon ) {
			if ( video->wm_icon ) {
				SDL_free(video->wm_icon);
			}
			video->wm_icon = SDL_strdup(icon);
		}
		if ( (title || icon) && (video->SetCaption != NULL) ) {
			video->SetCaption(this, video->wm_title,video->wm_icon);
		}
	}
}
void SDL_WM_GetCaption (char **title, char **icon)
{
	SDL_VideoDevice *video = current_video;

	if ( video ) {
		if ( title ) {
			*title = video->wm_title;
		}
		if ( icon ) {
			*icon = video->wm_icon;
		}
	}
}

/* Utility function used by SDL_WM_SetIcon();
 * flags & 1 for color key, flags & 2 for alpha channel. */
static void CreateMaskFromColorKeyOrAlpha(SDL_Surface *icon, Uint8 *mask, int flags)
{
	int x, y;
	Uint32 colorkey;
#define SET_MASKBIT(icon, x, y, mask) \
	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))

	colorkey = icon->format->colorkey;
	switch (icon->format->BytesPerPixel) {
		case 1: { Uint8 *pixels;
			for ( y=0; y<icon->h; ++y ) {
				pixels = (Uint8 *)icon->pixels + y*icon->pitch;
				for ( x=0; x<icon->w; ++x ) {
					if ( *pixels++ == colorkey ) {
						SET_MASKBIT(icon, x, y, mask);
					}
				}
			}
		}
		break;

		case 2: { Uint16 *pixels;
			for ( y=0; y<icon->h; ++y ) {
				pixels = (Uint16 *)icon->pixels +
				                   y*icon->pitch/2;
				for ( x=0; x<icon->w; ++x ) {
					if ( (flags & 1) && *pixels == colorkey ) {
						SET_MASKBIT(icon, x, y, mask);
					} else if((flags & 2) && (*pixels & icon->format->Amask) == 0) {
						SET_MASKBIT(icon, x, y, mask);
					}
					pixels++;
				}
			}
		}
		break;

		case 4: { Uint32 *pixels;
			for ( y=0; y<icon->h; ++y ) {
				pixels = (Uint32 *)icon->pixels +
				                   y*icon->pitch/4;
				for ( x=0; x<icon->w; ++x ) {
					if ( (flags & 1) && *pixels == colorkey ) {
						SET_MASKBIT(icon, x, y, mask);
					} else if((flags & 2) && (*pixels & icon->format->Amask) == 0) {
						SET_MASKBIT(icon, x, y, mask);
					}
					pixels++;
				}
			}
		}
		break;
	}
}

/*
 * Sets the window manager icon for the display window.
 */
void SDL_WM_SetIcon (SDL_Surface *icon, Uint8 *mask)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;

	if ( icon && video->SetIcon ) {
		/* Generate a mask if necessary, and create the icon! */
		if ( mask == NULL ) {
			int mask_len = icon->h*(icon->w+7)/8;
			int flags = 0;
			mask = (Uint8 *)SDL_malloc(mask_len);
			if ( mask == NULL ) {
				return;
			}
			SDL_memset(mask, ~0, mask_len);
			if ( icon->flags & SDL_SRCCOLORKEY ) flags |= 1;
			if ( icon->flags & SDL_SRCALPHA ) flags |= 2;
			if( flags ) {
				CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
			}
			video->SetIcon(video, icon, mask);
			SDL_free(mask);
		} else {
			video->SetIcon(this, icon, mask);
		}
	}
}

/*
 * Grab or ungrab the keyboard and mouse input.
 * This function returns the final grab mode after calling the
 * driver dependent function.
 */
static SDL_GrabMode SDL_WM_GrabInputRaw(SDL_GrabMode mode)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;

	/* Only do something if we have support for grabs */
	if ( video->GrabInput == NULL ) {
		return(video->input_grab);
	}

	/* If the final grab mode if off, only then do we actually grab */
#ifdef DEBUG_GRAB
  printf("SDL_WM_GrabInputRaw(%d) ... ", mode);
#endif
	if ( mode == SDL_GRAB_OFF ) {
		if ( video->input_grab != SDL_GRAB_OFF ) {
			mode = video->GrabInput(this, mode);
		}
	} else {
		if ( video->input_grab == SDL_GRAB_OFF ) {
			mode = video->GrabInput(this, mode);
		}
	}
	if ( mode != video->input_grab ) {
		video->input_grab = mode;
		if ( video->CheckMouseMode ) {
			video->CheckMouseMode(this);
		}
	}
#ifdef DEBUG_GRAB
  printf("Final mode %d\n", video->input_grab);
#endif

	/* Return the final grab state */
	if ( mode >= SDL_GRAB_FULLSCREEN ) {
		mode -= SDL_GRAB_FULLSCREEN;
	}
	return(mode);
}
SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode)
{
	SDL_VideoDevice *video = current_video;

	/* If the video isn't initialized yet, we can't do anything */
	if ( ! video ) {
		return SDL_GRAB_OFF;
	}

	/* Return the current mode on query */
	if ( mode == SDL_GRAB_QUERY ) {
		mode = video->input_grab;
		if ( mode >= SDL_GRAB_FULLSCREEN ) {
			mode -= SDL_GRAB_FULLSCREEN;
		}
		return(mode);
	}

#ifdef DEBUG_GRAB
  printf("SDL_WM_GrabInput(%d) ... ", mode);
#endif
	/* If the video surface is fullscreen, we always grab */
	if ( mode >= SDL_GRAB_FULLSCREEN ) {
		mode -= SDL_GRAB_FULLSCREEN;
	}
	if ( SDL_VideoSurface && (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
		mode += SDL_GRAB_FULLSCREEN;
	}
	return(SDL_WM_GrabInputRaw(mode));
}
static SDL_GrabMode SDL_WM_GrabInputOff(void)
{
	SDL_GrabMode mode;

	/* First query the current grab state */
	mode = SDL_WM_GrabInput(SDL_GRAB_QUERY);

	/* Now explicitly turn off input grab */
	SDL_WM_GrabInputRaw(SDL_GRAB_OFF);

	/* Return the old state */
	return(mode);
}

/*
 * Iconify the window in window managed environments.
 * A successful iconification will result in an SDL_APPACTIVE loss event.
 */
int SDL_WM_IconifyWindow(void)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;
	int retval;

	retval = 0;
	if ( video->IconifyWindow ) {
		retval = video->IconifyWindow(this);
	}
	return(retval);
}

/*
 * Toggle fullscreen mode
 */
int SDL_WM_ToggleFullScreen(SDL_Surface *surface)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;
	int toggled;

	toggled = 0;
	if ( SDL_PublicSurface && (surface == SDL_PublicSurface) &&
	     video->ToggleFullScreen ) {
		if ( surface->flags & SDL_FULLSCREEN ) {
			toggled = video->ToggleFullScreen(this, 0);
			if ( toggled ) {
				SDL_VideoSurface->flags &= ~SDL_FULLSCREEN;
				SDL_PublicSurface->flags &= ~SDL_FULLSCREEN;
			}
		} else {
			toggled = video->ToggleFullScreen(this, 1);
			if ( toggled ) {
				SDL_VideoSurface->flags |= SDL_FULLSCREEN;
				SDL_PublicSurface->flags |= SDL_FULLSCREEN;
			}
		}
		/* Double-check the grab state inside SDL_WM_GrabInput() */
		if ( toggled ) {
			SDL_WM_GrabInput(video->input_grab);
		}
	}
	return(toggled);
}

/*
 * Get some platform dependent window manager information
 */
int SDL_GetWMInfo (SDL_SysWMinfo *info)
{
	SDL_VideoDevice *video = current_video;
	SDL_VideoDevice *this  = current_video;

	if ( video && video->GetWMInfo ) {
		return(video->GetWMInfo(this, info));
	} else {
		return(0);
	}
}