src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Apr 2003 15:46:56 +0000
changeset 610 95433459fbd2
parent 580 be6495850a62
child 630 550bccdf04bd
permissions -rw-r--r--
Date: Mon, 14 Apr 2003 22:08:27 +0100
From: Patrice Mandin
Subject: [SDL][PATCH] 2 patches for sdl

Here are 2 patches for SDL:

- One is to put the dummy video drivers at the end of the
video drivers list. It gave me problems, when
SDL_VIDEODRIVER is not set, and the dummy driver is used
instead of the platform's driver, just because it is
always available. So the dummy driver must always be at
the end of the list. I suppose picogui and dc video
drivers also don't work.
     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 /* The high-level video driver subsystem */
    29 
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 
    34 #include "SDL.h"
    35 #include "SDL_error.h"
    36 #include "SDL_video.h"
    37 #include "SDL_events.h"
    38 #include "SDL_mutex.h"
    39 #include "SDL_sysvideo.h"
    40 #include "SDL_sysevents.h"
    41 #include "SDL_blit.h"
    42 #include "SDL_pixels_c.h"
    43 #include "SDL_events_c.h"
    44 #include "SDL_cursor_c.h"
    45 
    46 /* Available video drivers */
    47 static VideoBootStrap *bootstrap[] = {
    48 #ifdef ENABLE_X11
    49 	&X11_bootstrap,
    50 #endif
    51 #ifdef ENABLE_DGA
    52 	&DGA_bootstrap,
    53 #endif
    54 #ifdef ENABLE_NANOX
    55 	&NX_bootstrap,
    56 #endif
    57 #ifdef ENABLE_QTOPIA
    58 	&Qtopia_bootstrap,
    59 #endif
    60 #ifdef ENABLE_FBCON
    61 	&FBCON_bootstrap,
    62 #endif
    63 #ifdef ENABLE_DIRECTFB
    64 	&DirectFB_bootstrap,
    65 #endif
    66 #ifdef ENABLE_PS2GS
    67 	&PS2GS_bootstrap,
    68 #endif
    69 #ifdef ENABLE_GGI
    70 	&GGI_bootstrap,
    71 #endif
    72 #ifdef ENABLE_VGL
    73 	&VGL_bootstrap,
    74 #endif
    75 #ifdef ENABLE_SVGALIB
    76 	&SVGALIB_bootstrap,
    77 #endif
    78 #ifdef ENABLE_AALIB
    79 	&AALIB_bootstrap,
    80 #endif
    81 #ifdef ENABLE_DIRECTX
    82 	&DIRECTX_bootstrap,
    83 #endif
    84 #ifdef ENABLE_WINDIB
    85 	&WINDIB_bootstrap,
    86 #endif
    87 #ifdef ENABLE_BWINDOW
    88 	&BWINDOW_bootstrap,
    89 #endif
    90 #ifdef ENABLE_TOOLBOX
    91 	&TOOLBOX_bootstrap,
    92 #endif
    93 #ifdef ENABLE_DRAWSPROCKET
    94 	&DSp_bootstrap,
    95 #endif
    96 #ifdef ENABLE_QUARTZ
    97 	&QZ_bootstrap,
    98 #endif
    99 #ifdef ENABLE_CYBERGRAPHICS
   100 	&CGX_bootstrap,
   101 #endif
   102 #ifdef ENABLE_PHOTON
   103 	&ph_bootstrap,
   104 #endif
   105 #ifdef ENABLE_EPOC
   106 	&EPOC_bootstrap,
   107 #endif
   108 #ifdef ENABLE_XBIOS
   109 	&XBIOS_bootstrap,
   110 #endif
   111 #ifdef ENABLE_GEM
   112 	&GEM_bootstrap,
   113 #endif
   114 #ifdef ENABLE_PICOGUI
   115 	&PG_bootstrap,
   116 #endif
   117 #ifdef ENABLE_DC
   118 	&DC_bootstrap,
   119 #endif
   120 #ifdef ENABLE_DUMMYVIDEO
   121 	&DUMMY_bootstrap,
   122 #endif
   123 	NULL
   124 };
   125 
   126 SDL_VideoDevice *current_video = NULL;
   127 
   128 /* Various local functions */
   129 int SDL_VideoInit(const char *driver_name, Uint32 flags);
   130 void SDL_VideoQuit(void);
   131 void SDL_GL_UpdateRectsLock(SDL_VideoDevice* this, int numrects, SDL_Rect* rects);
   132 
   133 static SDL_GrabMode SDL_WM_GrabInputOff(void);
   134 #ifdef HAVE_OPENGL
   135 static int lock_count = 0;
   136 #endif
   137 
   138 
   139 /*
   140  * Initialize the video and event subsystems -- determine native pixel format
   141  */
   142 int SDL_VideoInit (const char *driver_name, Uint32 flags)
   143 {
   144 	SDL_VideoDevice *video;
   145 	int index;
   146 	int i;
   147 	SDL_PixelFormat vformat;
   148 	Uint32 video_flags;
   149 
   150 	/* Toggle the event thread flags, based on OS requirements */
   151 #if defined(MUST_THREAD_EVENTS)
   152 	flags |= SDL_INIT_EVENTTHREAD;
   153 #elif defined(CANT_THREAD_EVENTS)
   154 	if ( (flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
   155 		SDL_SetError("OS doesn't support threaded events");
   156 		return(-1);
   157 	}
   158 #endif
   159 
   160 	/* Check to make sure we don't overwrite 'current_video' */
   161 	if ( current_video != NULL ) {
   162 		SDL_VideoQuit();
   163 	}
   164 
   165 	/* Select the proper video driver */
   166 	index = 0;
   167 	video = NULL;
   168 	if ( driver_name != NULL ) {
   169 #if 0	/* This will be replaced with a better driver selection API */
   170 		if ( strrchr(driver_name, ':') != NULL ) {
   171 			index = atoi(strrchr(driver_name, ':')+1);
   172 		}
   173 #endif
   174 		for ( i=0; bootstrap[i]; ++i ) {
   175 			if ( strncmp(bootstrap[i]->name, driver_name,
   176 			             strlen(bootstrap[i]->name)) == 0 ) {
   177 				if ( bootstrap[i]->available() ) {
   178 					video = bootstrap[i]->create(index);
   179 					break;
   180 				}
   181 			}
   182 		}
   183 	} else {
   184 		for ( i=0; bootstrap[i]; ++i ) {
   185 			if ( bootstrap[i]->available() ) {
   186 				video = bootstrap[i]->create(index);
   187 				if ( video != NULL ) {
   188 					break;
   189 				}
   190 			}
   191 		}
   192 	}
   193 	if ( video == NULL ) {
   194 		SDL_SetError("No available video device");
   195 		return(-1);
   196 	}
   197 	current_video = video;
   198 	current_video->name = bootstrap[i]->name;
   199 
   200 	/* Do some basic variable initialization */
   201 	video->screen = NULL;
   202 	video->shadow = NULL;
   203 	video->visible = NULL;
   204 	video->physpal = NULL;
   205 	video->gammacols = NULL;
   206 	video->gamma = NULL;
   207 	video->wm_title = NULL;
   208 	video->wm_icon  = NULL;
   209 	video->offset_x = 0;
   210 	video->offset_y = 0;
   211 	memset(&video->info, 0, (sizeof video->info));
   212 
   213 	/* Set some very sane GL defaults */
   214 	video->gl_config.driver_loaded = 0;
   215 	video->gl_config.dll_handle = NULL;
   216 	video->gl_config.red_size = 5;
   217 #if 1 /* This seems to work on more video cards, as a default */
   218 	video->gl_config.green_size = 5;
   219 #else
   220 	video->gl_config.green_size = 6;
   221 #endif
   222 	video->gl_config.blue_size = 5;
   223 	video->gl_config.alpha_size = 0;
   224 	video->gl_config.buffer_size = 0;
   225 	video->gl_config.depth_size = 16;
   226 	video->gl_config.stencil_size = 0;
   227 	video->gl_config.double_buffer = 1;
   228 	video->gl_config.accum_red_size = 0;
   229 	video->gl_config.accum_green_size = 0;
   230 	video->gl_config.accum_blue_size = 0;
   231 	video->gl_config.accum_alpha_size = 0;
   232 	video->gl_config.stereo = 0;
   233 	
   234 	/* Initialize the video subsystem */
   235 	memset(&vformat, 0, sizeof(vformat));
   236 	if ( video->VideoInit(video, &vformat) < 0 ) {
   237 		SDL_VideoQuit();
   238 		return(-1);
   239 	}
   240 
   241 	/* Create a zero sized video surface of the appropriate format */
   242 	video_flags = SDL_SWSURFACE;
   243 	SDL_VideoSurface = SDL_CreateRGBSurface(video_flags, 0, 0,
   244 				vformat.BitsPerPixel,
   245 				vformat.Rmask, vformat.Gmask, vformat.Bmask, 0);
   246 	if ( SDL_VideoSurface == NULL ) {
   247 		SDL_VideoQuit();
   248 		return(-1);
   249 	}
   250 	SDL_PublicSurface = NULL;	/* Until SDL_SetVideoMode() */
   251 
   252 #if 0 /* Don't change the current palette - may be used by other programs.
   253        * The application can't do anything with the display surface until
   254        * a video mode has been set anyway. :)
   255        */
   256 	/* If we have a palettized surface, create a default palette */
   257 	if ( SDL_VideoSurface->format->palette ) {
   258 	        SDL_PixelFormat *vf = SDL_VideoSurface->format;
   259 		SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);
   260 		video->SetColors(video,
   261 				 0, vf->palette->ncolors, vf->palette->colors);
   262 	}
   263 #endif
   264 	video->info.vfmt = SDL_VideoSurface->format;
   265 
   266 	/* Start the event loop */
   267 	if ( SDL_StartEventLoop(flags) < 0 ) {
   268 		SDL_VideoQuit();
   269 		return(-1);
   270 	}
   271 	SDL_CursorInit(flags & SDL_INIT_EVENTTHREAD);
   272 
   273 	/* We're ready to go! */
   274 	return(0);
   275 }
   276 
   277 char *SDL_VideoDriverName(char *namebuf, int maxlen)
   278 {
   279 	if ( current_video != NULL ) {
   280 		strncpy(namebuf, current_video->name, maxlen-1);
   281 		namebuf[maxlen-1] = '\0';
   282 		return(namebuf);
   283 	}
   284 	return(NULL);
   285 }
   286 
   287 /*
   288  * Get the current display surface
   289  */
   290 SDL_Surface *SDL_GetVideoSurface(void)
   291 {
   292 	SDL_Surface *visible;
   293 
   294 	visible = NULL;
   295 	if ( current_video ) {
   296 		visible = current_video->visible;
   297 	}
   298 	return(visible);
   299 }
   300 
   301 /*
   302  * Get the current information about the video hardware
   303  */
   304 const SDL_VideoInfo *SDL_GetVideoInfo(void)
   305 {
   306 	const SDL_VideoInfo *info;
   307 
   308 	info = NULL;
   309 	if ( current_video ) {
   310 		info = &current_video->info;
   311 	}
   312 	return(info);
   313 }
   314 
   315 /*
   316  * Return a pointer to an array of available screen dimensions for the
   317  * given format, sorted largest to smallest.  Returns NULL if there are
   318  * no dimensions available for a particular format, or (SDL_Rect **)-1
   319  * if any dimension is okay for the given format.  If 'format' is NULL,
   320  * the mode list will be for the format given by SDL_GetVideoInfo()->vfmt
   321  */
   322 SDL_Rect ** SDL_ListModes (SDL_PixelFormat *format, Uint32 flags)
   323 {
   324 	SDL_VideoDevice *video = current_video;
   325 	SDL_VideoDevice *this  = current_video;
   326 	SDL_Rect **modes;
   327 
   328 	modes = NULL;
   329 	if ( SDL_VideoSurface ) {
   330 		if ( format == NULL ) {
   331 			format = SDL_VideoSurface->format;
   332 		}
   333 		modes = video->ListModes(this, format, flags);
   334 	}
   335 	return(modes);
   336 }
   337 
   338 /*
   339  * Check to see if a particular video mode is supported.
   340  * It returns 0 if the requested mode is not supported under any bit depth,
   341  * or returns the bits-per-pixel of the closest available mode with the
   342  * given width and height.  If this bits-per-pixel is different from the
   343  * one used when setting the video mode, SDL_SetVideoMode() will succeed,
   344  * but will emulate the requested bits-per-pixel with a shadow surface.
   345  */
   346 static Uint8 SDL_closest_depths[4][8] = {
   347 	/* 8 bit closest depth ordering */
   348 	{ 0, 8, 16, 15, 32, 24, 0, 0 },
   349 	/* 15,16 bit closest depth ordering */
   350 	{ 0, 16, 15, 32, 24, 8, 0, 0 },
   351 	/* 24 bit closest depth ordering */
   352 	{ 0, 24, 32, 16, 15, 8, 0, 0 },
   353 	/* 32 bit closest depth ordering */
   354 	{ 0, 32, 16, 15, 24, 8, 0, 0 }
   355 };
   356 
   357 int SDL_VideoModeOK (int width, int height, int bpp, Uint32 flags) 
   358 {
   359 	int table, b, i;
   360 	int supported;
   361 	SDL_PixelFormat format;
   362 	SDL_Rect **sizes;
   363 
   364 	/* Currently 1 and 4 bpp are not supported */
   365 	if ( bpp < 8 || bpp > 32 ) {
   366 		return(0);
   367 	}
   368 	if ( (width <= 0) || (height <= 0) ) {
   369 		return(0);
   370 	}
   371 
   372 	/* Search through the list valid of modes */
   373 	memset(&format, 0, sizeof(format));
   374 	supported = 0;
   375 	table = ((bpp+7)/8)-1;
   376 	SDL_closest_depths[table][0] = bpp;
   377 	SDL_closest_depths[table][7] = 0;
   378 	for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
   379 		format.BitsPerPixel = SDL_closest_depths[table][b];
   380 		sizes = SDL_ListModes(&format, flags);
   381 		if ( sizes == (SDL_Rect **)0 ) {
   382 			/* No sizes supported at this bit-depth */
   383 			continue;
   384 		} else 
   385 #ifdef macintosh /* MPW optimization bug? */
   386 		if ( (sizes == (SDL_Rect **)0xFFFFFFFF) ||
   387 #else
   388 		if ( (sizes == (SDL_Rect **)-1) ||
   389 #endif
   390 		     current_video->handles_any_size ) {
   391 			/* Any size supported at this bit-depth */
   392 			supported = 1;
   393 			continue;
   394 		} else
   395 		for ( i=0; sizes[i]; ++i ) {
   396 			if ((sizes[i]->w == width) && (sizes[i]->h == height)) {
   397 				supported = 1;
   398 				break;
   399 			}
   400 		}
   401 	}
   402 	if ( supported ) {
   403 		--b;
   404 		return(SDL_closest_depths[table][b]);
   405 	} else {
   406 		return(0);
   407 	}
   408 }
   409 
   410 /*
   411  * Get the closest non-emulated video mode to the one requested
   412  */
   413 static int SDL_GetVideoMode (int *w, int *h, int *BitsPerPixel, Uint32 flags)
   414 {
   415 	int table, b, i;
   416 	int supported;
   417 	int native_bpp;
   418 	SDL_PixelFormat format;
   419 	SDL_Rect **sizes;
   420 
   421 	/* Check parameters */
   422 	if ( *BitsPerPixel < 8 || *BitsPerPixel > 32 ) {
   423 		SDL_SetError("Invalid bits per pixel (range is {8...32})");
   424 		return(0);
   425 	}
   426 	if ((*w <= 0) || (*h <= 0)) {
   427 		SDL_SetError("Invalid width or height");
   428 		return(0);
   429 	}
   430 
   431 	/* Try the original video mode, get the closest depth */
   432 	native_bpp = SDL_VideoModeOK(*w, *h, *BitsPerPixel, flags);
   433 	if ( native_bpp == *BitsPerPixel ) {
   434 		return(1);
   435 	}
   436 	if ( native_bpp > 0 ) {
   437 		*BitsPerPixel = native_bpp;
   438 		return(1);
   439 	}
   440 
   441 	/* No exact size match at any depth, look for closest match */
   442 	memset(&format, 0, sizeof(format));
   443 	supported = 0;
   444 	table = ((*BitsPerPixel+7)/8)-1;
   445 	SDL_closest_depths[table][0] = *BitsPerPixel;
   446 	SDL_closest_depths[table][7] = SDL_VideoSurface->format->BitsPerPixel;
   447 	for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
   448 		format.BitsPerPixel = SDL_closest_depths[table][b];
   449 		sizes = SDL_ListModes(&format, flags);
   450 		if ( sizes == (SDL_Rect **)0 ) {
   451 			/* No sizes supported at this bit-depth */
   452 			continue;
   453 		}
   454 		for ( i=0; sizes[i]; ++i ) {
   455 			if ((sizes[i]->w < *w) || (sizes[i]->h < *h)) {
   456 				if ( i > 0 ) {
   457 					--i;
   458 					*w = sizes[i]->w;
   459 					*h = sizes[i]->h;
   460 					*BitsPerPixel = SDL_closest_depths[table][b];
   461 					supported = 1;
   462 				} else {
   463 					/* Largest mode too small... */;
   464 				}
   465 				break;
   466 			}
   467 		}
   468 		if ( (i > 0) && ! sizes[i] ) {
   469 			/* The smallest mode was larger than requested, OK */
   470 			--i;
   471 			*w = sizes[i]->w;
   472 			*h = sizes[i]->h;
   473 			*BitsPerPixel = SDL_closest_depths[table][b];
   474 			supported = 1;
   475 		}
   476 	}
   477 	if ( ! supported ) {
   478 		SDL_SetError("No video mode large enough for %dx%d", *w, *h);
   479 	}
   480 	return(supported);
   481 }
   482 
   483 /* This should probably go somewhere else -- like SDL_surface.c */
   484 static void SDL_ClearSurface(SDL_Surface *surface)
   485 {
   486 	Uint32 black;
   487 
   488 	black = SDL_MapRGB(surface->format, 0, 0, 0);
   489 	SDL_FillRect(surface, NULL, black);
   490 	if ((surface->flags&SDL_HWSURFACE) && (surface->flags&SDL_DOUBLEBUF)) {
   491 		SDL_Flip(surface);
   492 		SDL_FillRect(surface, NULL, black);
   493 	}
   494 	SDL_Flip(surface);
   495 }
   496 
   497 /*
   498  * Create a shadow surface suitable for fooling the app. :-)
   499  */
   500 static void SDL_CreateShadowSurface(int depth)
   501 {
   502 	Uint32 Rmask, Gmask, Bmask;
   503 
   504 	/* Allocate the shadow surface */
   505 	if ( depth == (SDL_VideoSurface->format)->BitsPerPixel ) {
   506 		Rmask = (SDL_VideoSurface->format)->Rmask;
   507 		Gmask = (SDL_VideoSurface->format)->Gmask;
   508 		Bmask = (SDL_VideoSurface->format)->Bmask;
   509 	} else {
   510 		Rmask = Gmask = Bmask = 0;
   511 	}
   512 	SDL_ShadowSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   513 				SDL_VideoSurface->w, SDL_VideoSurface->h,
   514 						depth, Rmask, Gmask, Bmask, 0);
   515 	if ( SDL_ShadowSurface == NULL ) {
   516 		return;
   517 	}
   518 
   519 	/* 8-bit shadow surfaces report that they have exclusive palette */
   520 	if ( SDL_ShadowSurface->format->palette ) {
   521 		SDL_ShadowSurface->flags |= SDL_HWPALETTE;
   522 		if ( depth == (SDL_VideoSurface->format)->BitsPerPixel ) {
   523 			memcpy(SDL_ShadowSurface->format->palette->colors,
   524 				SDL_VideoSurface->format->palette->colors,
   525 				SDL_VideoSurface->format->palette->ncolors*
   526 							sizeof(SDL_Color));
   527 		} else {
   528 			SDL_DitherColors(
   529 			SDL_ShadowSurface->format->palette->colors, depth);
   530 		}
   531 	}
   532 
   533 	/* If the video surface is resizable, the shadow should say so */
   534 	if ( (SDL_VideoSurface->flags & SDL_RESIZABLE) == SDL_RESIZABLE ) {
   535 		SDL_ShadowSurface->flags |= SDL_RESIZABLE;
   536 	}
   537 	/* If the video surface has no frame, the shadow should say so */
   538 	if ( (SDL_VideoSurface->flags & SDL_NOFRAME) == SDL_NOFRAME ) {
   539 		SDL_ShadowSurface->flags |= SDL_NOFRAME;
   540 	}
   541 	/* If the video surface is fullscreen, the shadow should say so */
   542 	if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
   543 		SDL_ShadowSurface->flags |= SDL_FULLSCREEN;
   544 	}
   545 	/* If the video surface is flippable, the shadow should say so */
   546 	if ( (SDL_VideoSurface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
   547 		SDL_ShadowSurface->flags |= SDL_DOUBLEBUF;
   548 	}
   549 	return;
   550 }
   551 
   552 /*
   553  * Set the requested video mode, allocating a shadow buffer if necessary.
   554  */
   555 SDL_Surface * SDL_SetVideoMode (int width, int height, int bpp, Uint32 flags)
   556 {
   557 	SDL_VideoDevice *video, *this;
   558 	SDL_Surface *prev_mode, *mode;
   559 	int video_w;
   560 	int video_h;
   561 	int video_bpp;
   562 	int is_opengl;
   563 	SDL_GrabMode saved_grab;
   564 
   565 	/* Start up the video driver, if necessary..
   566 	   WARNING: This is the only function protected this way!
   567 	 */
   568 	if ( ! current_video ) {
   569 		if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) {
   570 			return(NULL);
   571 		}
   572 	}
   573 	this = video = current_video;
   574 
   575 	/* Default to the current video bpp */
   576 	if ( bpp == 0 ) {
   577 		flags |= SDL_ANYFORMAT;
   578 		bpp = SDL_VideoSurface->format->BitsPerPixel;
   579 	}
   580 
   581 	/* Get a good video mode, the closest one possible */
   582 	video_w = width;
   583 	video_h = height;
   584 	video_bpp = bpp;
   585 	if ( ! SDL_GetVideoMode(&video_w, &video_h, &video_bpp, flags) ) {
   586 		return(NULL);
   587 	}
   588 
   589 	/* Check the requested flags */
   590 	/* There's no palette in > 8 bits-per-pixel mode */
   591 	if ( video_bpp > 8 ) {
   592 		flags &= ~SDL_HWPALETTE;
   593 	}
   594 #if 0
   595 	if ( (flags&SDL_FULLSCREEN) != SDL_FULLSCREEN ) {
   596 		/* There's no windowed double-buffering */
   597 		flags &= ~SDL_DOUBLEBUF;
   598 	}
   599 #endif
   600 	if ( (flags&SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
   601 		/* Use hardware surfaces when double-buffering */
   602 		flags |= SDL_HWSURFACE;
   603 	}
   604 
   605 	is_opengl = ( ( flags & SDL_OPENGL ) == SDL_OPENGL );
   606 	if ( is_opengl ) {
   607 		/* These flags are for 2D video modes only */
   608 		flags &= ~(SDL_HWSURFACE|SDL_DOUBLEBUF);
   609 	}
   610 
   611 	/* Reset the keyboard here so event callbacks can run */
   612 	SDL_ResetKeyboard();
   613 	SDL_ResetMouse();
   614 
   615 	/* Clean up any previous video mode */
   616 	if ( SDL_PublicSurface != NULL ) {
   617 		SDL_PublicSurface = NULL;
   618 	}
   619 	if ( SDL_ShadowSurface != NULL ) {
   620 		SDL_Surface *ready_to_go;
   621 		ready_to_go = SDL_ShadowSurface;
   622 		SDL_ShadowSurface = NULL;
   623 		SDL_FreeSurface(ready_to_go);
   624 	}
   625 	if ( video->physpal ) {
   626 		free(video->physpal->colors);
   627 		free(video->physpal);
   628 		video->physpal = NULL;
   629 	}
   630 	if( video->gammacols) {
   631 	        free(video->gammacols);
   632 		video->gammacols = NULL;
   633 	}
   634 
   635 	/* Save the previous grab state and turn off grab for mode switch */
   636 	saved_grab = SDL_WM_GrabInputOff();
   637 
   638 	/* Try to set the video mode, along with offset and clipping */
   639 	prev_mode = SDL_VideoSurface;
   640 	SDL_LockCursor();
   641 	SDL_VideoSurface = NULL;	/* In case it's freed by driver */
   642 	mode = video->SetVideoMode(this, prev_mode,video_w,video_h,video_bpp,flags);
   643 	if ( mode ) { /* Prevent resize events from mode change */
   644 	    SDL_PrivateResize(mode->w, mode->h);
   645 
   646 	    /* Sam - If we asked for OpenGL mode, and didn't get it, fail */
   647 	    if ( is_opengl && !(mode->flags & SDL_OPENGL) ) {
   648 		mode = NULL;
   649 	    }
   650         }
   651 	/*
   652 	 * rcg11292000
   653 	 * If you try to set an SDL_OPENGL surface, and fail to find a
   654 	 * matching  visual, then the next call to SDL_SetVideoMode()
   655 	 * will segfault, since  we no longer point to a dummy surface,
   656 	 * but rather NULL.
   657 	 * Sam 11/29/00
   658 	 * WARNING, we need to make sure that the previous mode hasn't
   659 	 * already been freed by the video driver.  What do we do in
   660 	 * that case?  Should we call SDL_VideoInit() again?
   661 	 */
   662 	SDL_VideoSurface = (mode != NULL) ? mode : prev_mode;
   663 
   664 	if ( (mode != NULL) && (!is_opengl) ) {
   665 		/* Sanity check */
   666 		if ( (mode->w < width) || (mode->h < height) ) {
   667 			SDL_SetError("Video mode smaller than requested");
   668 			return(NULL);
   669 		}
   670 
   671 		/* If we have a palettized surface, create a default palette */
   672 		if ( mode->format->palette ) {
   673 	        	SDL_PixelFormat *vf = mode->format;
   674 			SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);
   675 			video->SetColors(this, 0, vf->palette->ncolors,
   676 			                           vf->palette->colors);
   677 		}
   678 
   679 		/* Clear the surface to black */
   680 		video->offset_x = 0;
   681 		video->offset_y = 0;
   682 		mode->offset = 0;
   683 		SDL_SetClipRect(mode, NULL);
   684 		SDL_ClearSurface(mode);
   685 
   686 		/* Now adjust the offsets to match the desired mode */
   687 		video->offset_x = (mode->w-width)/2;
   688 		video->offset_y = (mode->h-height)/2;
   689 		mode->offset = video->offset_y*mode->pitch +
   690 				video->offset_x*mode->format->BytesPerPixel;
   691 #ifdef DEBUG_VIDEO
   692   fprintf(stderr,
   693 	"Requested mode: %dx%dx%d, obtained mode %dx%dx%d (offset %d)\n",
   694 		width, height, bpp,
   695 		mode->w, mode->h, mode->format->BitsPerPixel, mode->offset);
   696 #endif
   697 		mode->w = width;
   698 		mode->h = height;
   699 		SDL_SetClipRect(mode, NULL);
   700 	}
   701 	SDL_ResetCursor();
   702 	SDL_UnlockCursor();
   703 
   704 	/* If we failed setting a video mode, return NULL... (Uh Oh!) */
   705 	if ( mode == NULL ) {
   706 		return(NULL);
   707 	}
   708 
   709 	/* If there is no window manager, set the SDL_NOFRAME flag */
   710 	if ( ! video->info.wm_available ) {
   711 		mode->flags |= SDL_NOFRAME;
   712 	}
   713 
   714 	/* Reset the mouse cursor and grab for new video mode */
   715 	SDL_SetCursor(NULL);
   716 	if ( video->UpdateMouse ) {
   717 		video->UpdateMouse(this);
   718 	}
   719 	SDL_WM_GrabInput(saved_grab);
   720 	SDL_GetRelativeMouseState(NULL, NULL); /* Clear first large delta */
   721 
   722 	/* If we're running OpenGL, make the context current */
   723 	if ( (video->screen->flags & SDL_OPENGL) &&
   724 	      video->GL_MakeCurrent ) {
   725 		if ( video->GL_MakeCurrent(this) < 0 ) {
   726 			return(NULL);
   727 		}
   728 	}
   729 
   730 	/* Set up a fake SDL surface for OpenGL "blitting" */
   731 	if ( (flags & SDL_OPENGLBLIT) == SDL_OPENGLBLIT ) {
   732 		/* Load GL functions for performing the texture updates */
   733 #ifdef HAVE_OPENGL
   734 #define SDL_PROC(ret,func,params) \
   735 do { \
   736 	video->func = SDL_GL_GetProcAddress(#func); \
   737 	if ( ! video->func ) { \
   738 		SDL_SetError("Couldn't load GL function: %s\n", #func); \
   739 		return(NULL); \
   740 	} \
   741 } while ( 0 );
   742 #include "SDL_glfuncs.h"
   743 #undef SDL_PROC	
   744 
   745 		/* Create a software surface for blitting */
   746 #ifdef GL_VERSION_1_2
   747 		/* If the implementation either supports the packed pixels
   748 		   extension, or implements the core OpenGL 1.2 API, it will
   749 		   support the GL_UNSIGNED_SHORT_5_6_5 texture format.
   750 		 */
   751 		if ( (bpp == 16) &&
   752 		     (strstr((const char *)video->glGetString(GL_EXTENSIONS), "GL_EXT_packed_pixels") ||
   753 		     (atof((const char *)video->glGetString(GL_VERSION)) >= 1.2f))
   754 		   ) {
   755 			video->is_32bit = 0;
   756 			SDL_VideoSurface = SDL_CreateRGBSurface(
   757 				flags, 
   758 				width, 
   759 				height,  
   760 				16,
   761 				31 << 11,
   762 				63 << 5,
   763 				31,
   764 				0
   765 				);
   766 		}
   767 		else
   768 #endif /* OpenGL 1.2 */
   769 		{
   770 			video->is_32bit = 1;
   771 			SDL_VideoSurface = SDL_CreateRGBSurface(
   772 				flags, 
   773 				width, 
   774 				height, 
   775 				32, 
   776 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   777 				0x000000FF,
   778 				0x0000FF00,
   779 				0x00FF0000,
   780 				0xFF000000
   781 #else
   782 				0xFF000000,
   783 				0x00FF0000,
   784 				0x0000FF00,
   785 				0x000000FF
   786 #endif
   787 				);
   788 		}
   789 		if ( ! SDL_VideoSurface ) {
   790 			return(NULL);
   791 		}
   792 		SDL_VideoSurface->flags = mode->flags | SDL_OPENGLBLIT;
   793 
   794 		/* Free the original video mode surface (is this safe?) */
   795 		SDL_FreeSurface(mode);
   796 
   797                 /* Set the surface completely opaque & white by default */
   798 		memset( SDL_VideoSurface->pixels, 255, SDL_VideoSurface->h * SDL_VideoSurface->pitch );
   799 		video->glGenTextures( 1, &video->texture );
   800 		video->glBindTexture( GL_TEXTURE_2D, video->texture );
   801 		video->glTexImage2D(
   802 			GL_TEXTURE_2D,
   803 			0,
   804 			video->is_32bit ? GL_RGBA : GL_RGB,
   805 			256,
   806 			256,
   807 			0,
   808 			video->is_32bit ? GL_RGBA : GL_RGB,
   809 #ifdef GL_VERSION_1_2
   810 			video->is_32bit ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5,
   811 #else
   812 			GL_UNSIGNED_BYTE,
   813 #endif
   814 			NULL);
   815 
   816 		video->UpdateRects = SDL_GL_UpdateRectsLock;
   817 #else
   818 		SDL_SetError("Somebody forgot to #define HAVE_OPENGL");
   819 		return(NULL);
   820 #endif
   821 	}
   822 
   823 	/* Create a shadow surface if necessary */
   824 	/* There are three conditions under which we create a shadow surface:
   825 		1.  We need a particular bits-per-pixel that we didn't get.
   826 		2.  We need a hardware palette and didn't get one.
   827 		3.  We need a software surface and got a hardware surface.
   828 	*/
   829 	if ( !(SDL_VideoSurface->flags & SDL_OPENGL) &&
   830 	     (
   831 	     (  !(flags&SDL_ANYFORMAT) &&
   832 			(SDL_VideoSurface->format->BitsPerPixel != bpp)) ||
   833 	     (   (flags&SDL_HWPALETTE) && 
   834 				!(SDL_VideoSurface->flags&SDL_HWPALETTE)) ||
   835 		/* If the surface is in hardware, video writes are visible
   836 		   as soon as they are performed, so we need to buffer them
   837 		 */
   838 	     (   ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) &&
   839 				(SDL_VideoSurface->flags&SDL_HWSURFACE)) ||
   840 	     (   (flags&SDL_DOUBLEBUF) &&
   841 				(SDL_VideoSurface->flags&SDL_HWSURFACE) &&
   842 				!(SDL_VideoSurface->flags&SDL_DOUBLEBUF))
   843 	     ) ) {
   844 		SDL_CreateShadowSurface(bpp);
   845 		if ( SDL_ShadowSurface == NULL ) {
   846 			SDL_SetError("Couldn't create shadow surface");
   847 			return(NULL);
   848 		}
   849 		SDL_PublicSurface = SDL_ShadowSurface;
   850 	} else {
   851 		SDL_PublicSurface = SDL_VideoSurface;
   852 	}
   853 	video->info.vfmt = SDL_VideoSurface->format;
   854 
   855 	/* We're done! */
   856 	return(SDL_PublicSurface);
   857 }
   858 
   859 /* 
   860  * Convert a surface into the video pixel format.
   861  */
   862 SDL_Surface * SDL_DisplayFormat (SDL_Surface *surface)
   863 {
   864 	Uint32 flags;
   865 
   866 	if ( ! SDL_PublicSurface ) {
   867 		SDL_SetError("No video mode has been set");
   868 		return(NULL);
   869 	}
   870 	/* Set the flags appropriate for copying to display surface */
   871 	if (((SDL_PublicSurface->flags&SDL_HWSURFACE) == SDL_HWSURFACE) && current_video->info.blit_hw)
   872 		flags = SDL_HWSURFACE;
   873 	else 
   874 		flags = SDL_SWSURFACE;
   875 #ifdef AUTORLE_DISPLAYFORMAT
   876 	flags |= (surface->flags & (SDL_SRCCOLORKEY|SDL_SRCALPHA));
   877 	flags |= SDL_RLEACCELOK;
   878 #else
   879 	flags |= surface->flags & (SDL_SRCCOLORKEY|SDL_SRCALPHA|SDL_RLEACCELOK);
   880 #endif
   881 	return(SDL_ConvertSurface(surface, SDL_PublicSurface->format, flags));
   882 }
   883 
   884 /*
   885  * Convert a surface into a format that's suitable for blitting to
   886  * the screen, but including an alpha channel.
   887  */
   888 SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface)
   889 {
   890 	SDL_PixelFormat *vf;
   891 	SDL_PixelFormat *format;
   892 	SDL_Surface *converted;
   893 	Uint32 flags;
   894 	/* default to ARGB8888 */
   895 	Uint32 amask = 0xff000000;
   896 	Uint32 rmask = 0x00ff0000;
   897 	Uint32 gmask = 0x0000ff00;
   898 	Uint32 bmask = 0x000000ff;
   899 
   900 	if ( ! SDL_PublicSurface ) {
   901 		SDL_SetError("No video mode has been set");
   902 		return(NULL);
   903 	}
   904 	vf = SDL_PublicSurface->format;
   905 
   906 	switch(vf->BytesPerPixel) {
   907 	    case 2:
   908 		/* For XGY5[56]5, use, AXGY8888, where {X, Y} = {R, B}.
   909 		   For anything else (like ARGB4444) it doesn't matter
   910 		   since we have no special code for it anyway */
   911 		if ( (vf->Rmask == 0x1f) &&
   912 		     (vf->Bmask == 0xf800 || vf->Bmask == 0x7c00)) {
   913 			rmask = 0xff;
   914 			bmask = 0xff0000;
   915 		}
   916 		break;
   917 
   918 	    case 3:
   919 	    case 4:
   920 		/* Keep the video format, as long as the high 8 bits are
   921 		   unused or alpha */
   922 		if ( (vf->Rmask == 0xff) && (vf->Bmask == 0xff0000) ) {
   923 			rmask = 0xff;
   924 			bmask = 0xff0000;
   925 		}
   926 		break;
   927 
   928 	    default:
   929 		/* We have no other optimised formats right now. When/if a new
   930 		   optimised alpha format is written, add the converter here */
   931 		break;
   932 	}
   933 	format = SDL_AllocFormat(32, rmask, gmask, bmask, amask);
   934 	flags = SDL_PublicSurface->flags & SDL_HWSURFACE;
   935 	flags |= surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
   936 	converted = SDL_ConvertSurface(surface, format, flags);
   937 	SDL_FreeFormat(format);
   938 	return(converted);
   939 }
   940 
   941 /*
   942  * Update a specific portion of the physical screen
   943  */
   944 void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
   945 {
   946 	if ( screen ) {
   947 		SDL_Rect rect;
   948 
   949 		/* Perform some checking */
   950 		if ( w == 0 )
   951 			w = screen->w;
   952 		if ( h == 0 )
   953 			h = screen->h;
   954 		if ( (int)(x+w) > screen->w )
   955 			return;
   956 		if ( (int)(y+h) > screen->h )
   957 			return;
   958 
   959 		/* Fill the rectangle */
   960 		rect.x = x;
   961 		rect.y = y;
   962 		rect.w = w;
   963 		rect.h = h;
   964 		SDL_UpdateRects(screen, 1, &rect);
   965 	}
   966 }
   967 void SDL_UpdateRects (SDL_Surface *screen, int numrects, SDL_Rect *rects)
   968 {
   969 	int i;
   970 	SDL_VideoDevice *video = current_video;
   971 	SDL_VideoDevice *this = current_video;
   972 
   973 	if ( screen == SDL_ShadowSurface ) {
   974 		/* Blit the shadow surface using saved mapping */
   975 		SDL_Palette *pal = screen->format->palette;
   976 		SDL_Color *saved_colors = NULL;
   977 		if ( pal && !(SDL_VideoSurface->flags & SDL_HWPALETTE) ) {
   978 			/* simulated 8bpp, use correct physical palette */
   979 			saved_colors = pal->colors;
   980 			if ( video->gammacols ) {
   981 				/* gamma-corrected palette */
   982 				pal->colors = video->gammacols;
   983 			} else if ( video->physpal ) {
   984 				/* physical palette different from logical */
   985 				pal->colors = video->physpal->colors;
   986 			}
   987 		}
   988 		if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
   989 			SDL_LockCursor();
   990 			SDL_DrawCursor(SDL_ShadowSurface);
   991 			for ( i=0; i<numrects; ++i ) {
   992 				SDL_LowerBlit(SDL_ShadowSurface, &rects[i], 
   993 						SDL_VideoSurface, &rects[i]);
   994 			}
   995 			SDL_EraseCursor(SDL_ShadowSurface);
   996 			SDL_UnlockCursor();
   997 		} else {
   998 			for ( i=0; i<numrects; ++i ) {
   999 				SDL_LowerBlit(SDL_ShadowSurface, &rects[i], 
  1000 						SDL_VideoSurface, &rects[i]);
  1001 			}
  1002 		}
  1003 		if ( saved_colors ) {
  1004 			pal->colors = saved_colors;
  1005 		}
  1006 
  1007 		/* Fall through to video surface update */
  1008 		screen = SDL_VideoSurface;
  1009 	}
  1010 	if ( screen == SDL_VideoSurface ) {
  1011 		/* Update the video surface */
  1012 		if ( screen->offset ) {
  1013 			for ( i=0; i<numrects; ++i ) {
  1014 				rects[i].x += video->offset_x;
  1015 				rects[i].y += video->offset_y;
  1016 			}
  1017 			video->UpdateRects(this, numrects, rects);
  1018 			for ( i=0; i<numrects; ++i ) {
  1019 				rects[i].x -= video->offset_x;
  1020 				rects[i].y -= video->offset_y;
  1021 			}
  1022 		} else {
  1023 			video->UpdateRects(this, numrects, rects);
  1024 		}
  1025 	}
  1026 }
  1027 
  1028 /*
  1029  * Performs hardware double buffering, if possible, or a full update if not.
  1030  */
  1031 int SDL_Flip(SDL_Surface *screen)
  1032 {
  1033 	SDL_VideoDevice *video = current_video;
  1034 	/* Copy the shadow surface to the video surface */
  1035 	if ( screen == SDL_ShadowSurface ) {
  1036 		SDL_Rect rect;
  1037 		SDL_Palette *pal = screen->format->palette;
  1038 		SDL_Color *saved_colors = NULL;
  1039 		if ( pal && !(SDL_VideoSurface->flags & SDL_HWPALETTE) ) {
  1040 			/* simulated 8bpp, use correct physical palette */
  1041 			saved_colors = pal->colors;
  1042 			if ( video->gammacols ) {
  1043 				/* gamma-corrected palette */
  1044 				pal->colors = video->gammacols;
  1045 			} else if ( video->physpal ) {
  1046 				/* physical palette different from logical */
  1047 				pal->colors = video->physpal->colors;
  1048 			}
  1049 		}
  1050 
  1051 		rect.x = 0;
  1052 		rect.y = 0;
  1053 		rect.w = screen->w;
  1054 		rect.h = screen->h;
  1055 		if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
  1056 			SDL_LockCursor();
  1057 			SDL_DrawCursor(SDL_ShadowSurface);
  1058 			SDL_LowerBlit(SDL_ShadowSurface, &rect,
  1059 					SDL_VideoSurface, &rect);
  1060 			SDL_EraseCursor(SDL_ShadowSurface);
  1061 			SDL_UnlockCursor();
  1062 		} else {
  1063 			SDL_LowerBlit(SDL_ShadowSurface, &rect,
  1064 					SDL_VideoSurface, &rect);
  1065 		}
  1066 		if ( saved_colors ) {
  1067 			pal->colors = saved_colors;
  1068 		}
  1069 
  1070 		/* Fall through to video surface update */
  1071 		screen = SDL_VideoSurface;
  1072 	}
  1073 	if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
  1074 		SDL_VideoDevice *this  = current_video;
  1075 		return(video->FlipHWSurface(this, SDL_VideoSurface));
  1076 	} else {
  1077 		SDL_UpdateRect(screen, 0, 0, 0, 0);
  1078 	}
  1079 	return(0);
  1080 }
  1081 
  1082 static void SetPalette_logical(SDL_Surface *screen, SDL_Color *colors,
  1083 			       int firstcolor, int ncolors)
  1084 {
  1085         SDL_Palette *pal = screen->format->palette;
  1086 	SDL_Palette *vidpal;
  1087 
  1088 	if ( colors != (pal->colors + firstcolor) ) {
  1089 	        memcpy(pal->colors + firstcolor, colors,
  1090 		       ncolors * sizeof(*colors));
  1091 	}
  1092 
  1093 	vidpal = SDL_VideoSurface->format->palette;
  1094 	if ( (screen == SDL_ShadowSurface) && vidpal ) {
  1095 	        /*
  1096 		 * This is a shadow surface, and the physical
  1097 		 * framebuffer is also indexed. Propagate the
  1098 		 * changes to its logical palette so that
  1099 		 * updates are always identity blits
  1100 		 */
  1101 		memcpy(vidpal->colors + firstcolor, colors,
  1102 		       ncolors * sizeof(*colors));
  1103 	}
  1104 	SDL_FormatChanged(screen);
  1105 }
  1106 
  1107 static int SetPalette_physical(SDL_Surface *screen,
  1108                                SDL_Color *colors, int firstcolor, int ncolors)
  1109 {
  1110 	SDL_VideoDevice *video = current_video;
  1111 	int gotall = 1;
  1112 
  1113 	if ( video->physpal ) {
  1114 		/* We need to copy the new colors, since we haven't
  1115 		 * already done the copy in the logical set above.
  1116 		 */
  1117 		memcpy(video->physpal->colors + firstcolor,
  1118 		       colors, ncolors * sizeof(*colors));
  1119 	}
  1120 	if ( screen == SDL_ShadowSurface ) {
  1121 		if ( SDL_VideoSurface->flags & SDL_HWPALETTE ) {
  1122 			/*
  1123 			 * The real screen is also indexed - set its physical
  1124 			 * palette. The physical palette does not include the
  1125 			 * gamma modification, we apply it directly instead,
  1126 			 * but this only happens if we have hardware palette.
  1127 			 */
  1128 			screen = SDL_VideoSurface;
  1129 		} else {
  1130 			/*
  1131 			 * The video surface is not indexed - invalidate any
  1132 			 * active shadow-to-video blit mappings.
  1133 			 */
  1134 			if ( screen->map->dst == SDL_VideoSurface ) {
  1135 				SDL_InvalidateMap(screen->map);
  1136 			}
  1137 			if ( video->gamma ) {
  1138 				if( ! video->gammacols ) {
  1139 					SDL_Palette *pp = video->physpal;
  1140 					if(!pp)
  1141 						pp = screen->format->palette;
  1142 					video->gammacols = malloc(pp->ncolors
  1143 							  * sizeof(SDL_Color));
  1144 					SDL_ApplyGamma(video->gamma,
  1145 						       pp->colors,
  1146 						       video->gammacols,
  1147 						       pp->ncolors);
  1148 				} else {
  1149 					SDL_ApplyGamma(video->gamma, colors,
  1150 						       video->gammacols
  1151 						       + firstcolor,
  1152 						       ncolors);
  1153 				}
  1154 			}
  1155 			SDL_UpdateRect(screen, 0, 0, 0, 0);
  1156 		}
  1157 	}
  1158 
  1159 	if ( screen == SDL_VideoSurface ) {
  1160 		SDL_Color gcolors[256];
  1161 
  1162 	        if ( video->gamma ) {
  1163 		        SDL_ApplyGamma(video->gamma, colors, gcolors, ncolors);
  1164 			colors = gcolors;
  1165 		}
  1166 		gotall = video->SetColors(video, firstcolor, ncolors, colors);
  1167 		if ( ! gotall ) {
  1168 			/* The video flags shouldn't have SDL_HWPALETTE, and
  1169 			   the video driver is responsible for copying back the
  1170 			   correct colors into the video surface palette.
  1171 			*/
  1172 			;
  1173 		}
  1174 		SDL_CursorPaletteChanged();
  1175 	}
  1176 	return gotall;
  1177 }
  1178 
  1179 /*
  1180  * Set the physical and/or logical colormap of a surface:
  1181  * Only the screen has a physical colormap. It determines what is actually
  1182  * sent to the display.
  1183  * The logical colormap is used to map blits to/from the surface.
  1184  * 'which' is one or both of SDL_LOGPAL, SDL_PHYSPAL
  1185  *
  1186  * Return nonzero if all colours were set as requested, or 0 otherwise.
  1187  */
  1188 int SDL_SetPalette(SDL_Surface *screen, int which,
  1189 		   SDL_Color *colors, int firstcolor, int ncolors)
  1190 {
  1191         SDL_Palette *pal;
  1192 	int gotall;
  1193 	int palsize;
  1194 
  1195 	if ( ! current_video ) {
  1196 		return 0;
  1197 	}
  1198 	if ( screen != SDL_PublicSurface ) {
  1199 	        /* only screens have physical palettes */
  1200 	        which &= ~SDL_PHYSPAL;
  1201 	} else if( (screen->flags & SDL_HWPALETTE) != SDL_HWPALETTE ) {
  1202 	        /* hardware palettes required for split colormaps */
  1203 	        which |= SDL_PHYSPAL | SDL_LOGPAL;
  1204 	}
  1205 
  1206 	/* Verify the parameters */
  1207 	pal = screen->format->palette;
  1208 	if( !pal ) {
  1209 	        return 0;	/* not a palettized surface */
  1210 	}
  1211 	gotall = 1;
  1212 	palsize = 1 << screen->format->BitsPerPixel;
  1213 	if ( ncolors > (palsize - firstcolor) ) {
  1214 	        ncolors = (palsize - firstcolor);
  1215 		gotall = 0;
  1216 	}
  1217 
  1218 	if ( which & SDL_LOGPAL ) {
  1219 		/*
  1220 		 * Logical palette change: The actual screen isn't affected,
  1221 		 * but the internal colormap is altered so that the
  1222 		 * interpretation of the pixel values (for blits etc) is
  1223 		 * changed.
  1224 		 */
  1225 	        SetPalette_logical(screen, colors, firstcolor, ncolors);
  1226 	}
  1227 	if ( which & SDL_PHYSPAL ) {
  1228 		SDL_VideoDevice *video = current_video;
  1229 	        /*
  1230 		 * Physical palette change: This doesn't affect the
  1231 		 * program's idea of what the screen looks like, but changes
  1232 		 * its actual appearance.
  1233 		 */
  1234 	        if(!video)
  1235 		        return gotall;	/* video not yet initialized */
  1236 		if(!video->physpal && !(which & SDL_LOGPAL) ) {
  1237 			/* Lazy physical palette allocation */
  1238 		        int size;
  1239 			SDL_Palette *pp = malloc(sizeof(*pp));
  1240 			current_video->physpal = pp;
  1241 			pp->ncolors = pal->ncolors;
  1242 			size = pp->ncolors * sizeof(SDL_Color);
  1243 			pp->colors = malloc(size);
  1244 			memcpy(pp->colors, pal->colors, size);
  1245 		}
  1246 		if ( ! SetPalette_physical(screen,
  1247 		                           colors, firstcolor, ncolors) ) {
  1248 			gotall = 0;
  1249 		}
  1250 	}
  1251 	return gotall;
  1252 }
  1253 
  1254 int SDL_SetColors(SDL_Surface *screen, SDL_Color *colors, int firstcolor,
  1255 		  int ncolors)
  1256 {
  1257         return SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL,
  1258 			      colors, firstcolor, ncolors);
  1259 }
  1260 
  1261 /*
  1262  * Clean up the video subsystem
  1263  */
  1264 void SDL_VideoQuit (void)
  1265 {
  1266 	SDL_Surface *ready_to_go;
  1267 
  1268 	if ( current_video ) {
  1269 		SDL_VideoDevice *video = current_video;
  1270 		SDL_VideoDevice *this  = current_video;
  1271 
  1272 		/* Halt event processing before doing anything else */
  1273 		SDL_StopEventLoop();
  1274 
  1275 		/* Clean up allocated window manager items */
  1276 		if ( SDL_PublicSurface ) {
  1277 			SDL_PublicSurface = NULL;
  1278 		}
  1279 		SDL_CursorQuit();
  1280 
  1281 		/* Just in case... */
  1282 		SDL_WM_GrabInputOff();
  1283 
  1284 		/* Clean up the system video */
  1285 		video->VideoQuit(this);
  1286 
  1287 		/* Free any lingering surfaces */
  1288 		ready_to_go = SDL_ShadowSurface;
  1289 		SDL_ShadowSurface = NULL;
  1290 		SDL_FreeSurface(ready_to_go);
  1291 		if ( SDL_VideoSurface != NULL ) {
  1292 			ready_to_go = SDL_VideoSurface;
  1293 			SDL_VideoSurface = NULL;
  1294 			SDL_FreeSurface(ready_to_go);
  1295 		}
  1296 		SDL_PublicSurface = NULL;
  1297 
  1298 		/* Clean up miscellaneous memory */
  1299 		if ( video->physpal ) {
  1300 			free(video->physpal->colors);
  1301 			free(video->physpal);
  1302 			video->physpal = NULL;
  1303 		}
  1304 		if ( video->gammacols ) {
  1305 			free(video->gammacols);
  1306 			video->gammacols = NULL;
  1307 		}
  1308 		if ( video->gamma ) {
  1309 			free(video->gamma);
  1310 			video->gamma = NULL;
  1311 		}
  1312 		if ( video->wm_title != NULL ) {
  1313 			free(video->wm_title);
  1314 			video->wm_title = NULL;
  1315 		}
  1316 		if ( video->wm_icon != NULL ) {
  1317 			free(video->wm_icon);
  1318 			video->wm_icon = NULL;
  1319 		}
  1320 
  1321 		/* Finish cleaning up video subsystem */
  1322 		video->free(this);
  1323 		current_video = NULL;
  1324 	}
  1325 	return;
  1326 }
  1327 
  1328 /* Load the GL driver library */
  1329 int SDL_GL_LoadLibrary(const char *path)
  1330 {
  1331 	SDL_VideoDevice *video = current_video;
  1332 	SDL_VideoDevice *this = current_video;
  1333 	int retval;
  1334 
  1335 	retval = -1;
  1336 	if ( video == NULL ) {
  1337 		SDL_SetError("Video subsystem has not been initialized");
  1338 	} else {
  1339 		if ( video->GL_LoadLibrary ) {
  1340 			retval = video->GL_LoadLibrary(this, path);
  1341 		} else {
  1342 			SDL_SetError("No dynamic GL support in video driver");
  1343 		}
  1344 	}
  1345 	return(retval);
  1346 }
  1347 
  1348 void *SDL_GL_GetProcAddress(const char* proc)
  1349 {
  1350 	SDL_VideoDevice *video = current_video;
  1351 	SDL_VideoDevice *this = current_video;
  1352 	void *func;
  1353 
  1354 	func = NULL;
  1355 	if ( video->GL_GetProcAddress ) {
  1356 		if ( video->gl_config.driver_loaded ) {
  1357 			func = video->GL_GetProcAddress(this, proc);
  1358 		} else {
  1359 			SDL_SetError("No GL driver has been loaded");
  1360 		}
  1361 	} else {
  1362 		SDL_SetError("No dynamic GL support in video driver");
  1363 	}
  1364 	return func;
  1365 }
  1366 
  1367 /* Set the specified GL attribute for setting up a GL video mode */
  1368 int SDL_GL_SetAttribute( SDL_GLattr attr, int value )
  1369 {
  1370 	int retval;
  1371 	SDL_VideoDevice *video = current_video;
  1372 
  1373 	retval = 0;
  1374 	switch (attr) {
  1375 		case SDL_GL_RED_SIZE:
  1376 			video->gl_config.red_size = value;
  1377 			break;
  1378 		case SDL_GL_GREEN_SIZE:
  1379 			video->gl_config.green_size = value;
  1380 			break;
  1381 		case SDL_GL_BLUE_SIZE:
  1382 			video->gl_config.blue_size = value;
  1383 			break;
  1384 		case SDL_GL_ALPHA_SIZE:
  1385 			video->gl_config.alpha_size = value;
  1386 			break;
  1387 		case SDL_GL_DOUBLEBUFFER:
  1388 			video->gl_config.double_buffer = value;
  1389 			break;
  1390         	case SDL_GL_BUFFER_SIZE:
  1391 	        	video->gl_config.buffer_size = value;
  1392 			break;
  1393 		case SDL_GL_DEPTH_SIZE:
  1394 			video->gl_config.depth_size = value;
  1395 			break;
  1396 		case SDL_GL_STENCIL_SIZE:
  1397 			video->gl_config.stencil_size = value;
  1398 			break;
  1399 		case SDL_GL_ACCUM_RED_SIZE:
  1400 			video->gl_config.accum_red_size = value;
  1401 			break;
  1402 		case SDL_GL_ACCUM_GREEN_SIZE:
  1403 			video->gl_config.accum_green_size = value;
  1404 			break;
  1405 		case SDL_GL_ACCUM_BLUE_SIZE:
  1406 			video->gl_config.accum_blue_size = value;
  1407 			break;
  1408 		case SDL_GL_ACCUM_ALPHA_SIZE:
  1409 			video->gl_config.accum_alpha_size = value;
  1410 			break;
  1411 		case SDL_GL_STEREO:
  1412 			video->gl_config.stereo = value;
  1413 			break;
  1414 		default:
  1415 			SDL_SetError("Unknown OpenGL attribute");
  1416 			retval = -1;
  1417 			break;
  1418 	}
  1419 	return(retval);
  1420 }
  1421 
  1422 /* Retrieve an attribute value from the windowing system. */
  1423 int SDL_GL_GetAttribute(SDL_GLattr attr, int* value)
  1424 {
  1425 	int retval = -1;
  1426 	SDL_VideoDevice* video = current_video;
  1427 	SDL_VideoDevice* this = current_video;
  1428 
  1429 	if ( video->GL_GetAttribute ) {
  1430 		retval = this->GL_GetAttribute(this, attr, value);
  1431 	} else {
  1432 		*value = 0;
  1433 		SDL_SetError("GL_GetAttribute not supported");
  1434 	}
  1435 	return retval;
  1436 }
  1437 
  1438 /* Perform a GL buffer swap on the current GL context */
  1439 void SDL_GL_SwapBuffers(void)
  1440 {
  1441 	SDL_VideoDevice *video = current_video;
  1442 	SDL_VideoDevice *this = current_video;
  1443 
  1444 	if ( video->screen->flags & SDL_OPENGL ) {
  1445 		video->GL_SwapBuffers(this);
  1446 	} else {
  1447 		SDL_SetError("OpenGL video mode has not been set");
  1448 	}
  1449 }
  1450 
  1451 /* Update rects with locking */
  1452 void SDL_GL_UpdateRectsLock(SDL_VideoDevice* this, int numrects, SDL_Rect *rects)
  1453 {
  1454 	SDL_GL_Lock();
  1455  	SDL_GL_UpdateRects(numrects, rects);
  1456 	SDL_GL_Unlock();
  1457 }
  1458 
  1459 /* Update rects without state setting and changing (the caller is responsible for it) */
  1460 void SDL_GL_UpdateRects(int numrects, SDL_Rect *rects)
  1461 {
  1462 #ifdef HAVE_OPENGL
  1463 	SDL_VideoDevice *this = current_video;
  1464 	SDL_Rect update, tmp;
  1465 	int x, y, i;
  1466 
  1467 	for ( i = 0; i < numrects; i++ )
  1468 	{
  1469 		tmp.y = rects[i].y;
  1470 		tmp.h = rects[i].h;
  1471 		for ( y = 0; y <= rects[i].h / 256; y++ )
  1472 		{
  1473 			tmp.x = rects[i].x;
  1474 			tmp.w = rects[i].w;
  1475 			for ( x = 0; x <= rects[i].w / 256; x++ )
  1476 			{
  1477 				update.x = tmp.x;
  1478 				update.y = tmp.y;
  1479 				update.w = tmp.w;
  1480 				update.h = tmp.h;
  1481 
  1482 				if ( update.w > 256 )
  1483 					update.w = 256;
  1484 
  1485 				if ( update.h > 256 )
  1486 					update.h = 256;
  1487 			
  1488 				this->glFlush();
  1489 				this->glTexSubImage2D( 
  1490 					GL_TEXTURE_2D, 
  1491 					0, 
  1492 					0, 
  1493 					0, 
  1494 					update.w, 
  1495 					update.h, 
  1496 					this->is_32bit? GL_RGBA : GL_RGB,
  1497 #ifdef GL_VERSION_1_2
  1498 					this->is_32bit ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5,
  1499 #else
  1500 					GL_UNSIGNED_BYTE,
  1501 #endif
  1502 					(Uint8 *)this->screen->pixels + 
  1503 						this->screen->format->BytesPerPixel * update.x + 
  1504 						update.y * this->screen->pitch );
  1505 	
  1506 				this->glFlush();
  1507 				/*
  1508 				* Note the parens around the function name:
  1509 				* This is because some OpenGL implementations define glTexCoord etc 
  1510 				* as macros, and we don't want them expanded here.
  1511 				*/
  1512 				this->glBegin(GL_TRIANGLE_STRIP);
  1513 					(this->glTexCoord2f)( 0.0, 0.0 );	
  1514 					(this->glVertex2i)( update.x, update.y );
  1515 					(this->glTexCoord2f)( (float)(update.w / 256.0), 0.0 );	
  1516 					(this->glVertex2i)( update.x + update.w, update.y );
  1517 					(this->glTexCoord2f)( 0.0, (float)(update.h / 256.0) );
  1518 					(this->glVertex2i)( update.x, update.y + update.h );
  1519 					(this->glTexCoord2f)( (float)(update.w / 256.0), (float)(update.h / 256.0) );	
  1520 					(this->glVertex2i)( update.x + update.w	, update.y + update.h );
  1521 				this->glEnd();	
  1522 			
  1523 				tmp.x += 256;
  1524 				tmp.w -= 256;
  1525 			}
  1526 			tmp.y += 256;
  1527 			tmp.h -= 256;
  1528 		}
  1529 	}
  1530 #endif
  1531 }
  1532 
  1533 /* Lock == save current state */
  1534 void SDL_GL_Lock()
  1535 {
  1536 #ifdef HAVE_OPENGL
  1537 	lock_count--;
  1538 	if (lock_count==-1)
  1539 	{
  1540 		SDL_VideoDevice *this = current_video;
  1541 
  1542 		this->glPushAttrib( GL_ALL_ATTRIB_BITS );	/* TODO: narrow range of what is saved */
  1543 #ifdef GL_CLIENT_PIXEL_STORE_BIT
  1544 		this->glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT );
  1545 #endif
  1546 
  1547 		this->glEnable(GL_TEXTURE_2D);
  1548 		this->glEnable(GL_BLEND);
  1549 		this->glDisable(GL_FOG);
  1550 		this->glDisable(GL_ALPHA_TEST);
  1551 		this->glDisable(GL_DEPTH_TEST);
  1552 		this->glDisable(GL_SCISSOR_TEST);	
  1553 		this->glDisable(GL_STENCIL_TEST);
  1554 		this->glDisable(GL_CULL_FACE);
  1555 
  1556 		this->glBindTexture( GL_TEXTURE_2D, this->texture );
  1557 		this->glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  1558 		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  1559 		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  1560 		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  1561 		this->glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  1562 
  1563 		this->glPixelStorei( GL_UNPACK_ROW_LENGTH, this->screen->pitch / this->screen->format->BytesPerPixel );
  1564 		this->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1565 		(this->glColor4f)(1.0, 1.0, 1.0, 1.0);		/* Solaris workaround */
  1566 
  1567 		this->glViewport(0, 0, this->screen->w, this->screen->h);
  1568 		this->glMatrixMode(GL_PROJECTION);
  1569 		this->glPushMatrix();
  1570 		this->glLoadIdentity();
  1571 
  1572 		this->glOrtho(0.0, (GLdouble) this->screen->w, (GLdouble) this->screen->h, 0.0, 0.0, 1.0);
  1573 
  1574 		this->glMatrixMode(GL_MODELVIEW);
  1575 		this->glPushMatrix();
  1576 		this->glLoadIdentity();
  1577 	}
  1578 #endif
  1579 }
  1580 
  1581 /* Unlock == restore saved state */
  1582 void SDL_GL_Unlock()
  1583 {
  1584 #ifdef HAVE_OPENGL
  1585 	lock_count++;
  1586 	if (lock_count==0)
  1587 	{
  1588 		SDL_VideoDevice *this = current_video;
  1589 
  1590 		this->glPopMatrix();
  1591 		this->glMatrixMode(GL_PROJECTION);
  1592 		this->glPopMatrix();
  1593 
  1594 		this->glPopClientAttrib();
  1595 		this->glPopAttrib();
  1596 	}
  1597 #endif
  1598 }
  1599 
  1600 /*
  1601  * Sets/Gets the title and icon text of the display window, if any.
  1602  */
  1603 void SDL_WM_SetCaption (const char *title, const char *icon)
  1604 {
  1605 	SDL_VideoDevice *video = current_video;
  1606 	SDL_VideoDevice *this  = current_video;
  1607 
  1608 	if ( video ) {
  1609 		if ( title ) {
  1610 			if ( video->wm_title ) {
  1611 				free(video->wm_title);
  1612 			}
  1613 			video->wm_title = (char *)malloc(strlen(title)+1);
  1614 			if ( video->wm_title != NULL ) {
  1615 				strcpy(video->wm_title, title);
  1616 			}
  1617 		}
  1618 		if ( icon ) {
  1619 			if ( video->wm_icon ) {
  1620 				free(video->wm_icon);
  1621 			}
  1622 			video->wm_icon = (char *)malloc(strlen(icon)+1);
  1623 			if ( video->wm_icon != NULL ) {
  1624 				strcpy(video->wm_icon, icon);
  1625 			}
  1626 		}
  1627 		if ( (title || icon) && (video->SetCaption != NULL) ) {
  1628 			video->SetCaption(this, video->wm_title,video->wm_icon);
  1629 		}
  1630 	}
  1631 }
  1632 void SDL_WM_GetCaption (char **title, char **icon)
  1633 {
  1634 	SDL_VideoDevice *video = current_video;
  1635 
  1636 	if ( video ) {
  1637 		if ( title ) {
  1638 			*title = video->wm_title;
  1639 		}
  1640 		if ( icon ) {
  1641 			*icon = video->wm_icon;
  1642 		}
  1643 	}
  1644 }
  1645 
  1646 /* Utility function used by SDL_WM_SetIcon();
  1647  * flags & 1 for color key, flags & 2 for alpha channel. */
  1648 static void CreateMaskFromColorKeyOrAlpha(SDL_Surface *icon, Uint8 *mask, int flags)
  1649 {
  1650 	int x, y;
  1651 	Uint32 colorkey;
  1652 #define SET_MASKBIT(icon, x, y, mask) \
  1653 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  1654 
  1655 	colorkey = icon->format->colorkey;
  1656 	switch (icon->format->BytesPerPixel) {
  1657 		case 1: { Uint8 *pixels;
  1658 			for ( y=0; y<icon->h; ++y ) {
  1659 				pixels = (Uint8 *)icon->pixels + y*icon->pitch;
  1660 				for ( x=0; x<icon->w; ++x ) {
  1661 					if ( *pixels++ == colorkey ) {
  1662 						SET_MASKBIT(icon, x, y, mask);
  1663 					}
  1664 				}
  1665 			}
  1666 		}
  1667 		break;
  1668 
  1669 		case 2: { Uint16 *pixels;
  1670 			for ( y=0; y<icon->h; ++y ) {
  1671 				pixels = (Uint16 *)icon->pixels +
  1672 				                   y*icon->pitch/2;
  1673 				for ( x=0; x<icon->w; ++x ) {
  1674 					if ( (flags & 1) && *pixels == colorkey ) {
  1675 						SET_MASKBIT(icon, x, y, mask);
  1676 					} else if((flags & 2) && (*pixels & icon->format->Amask) == 0) {
  1677 						SET_MASKBIT(icon, x, y, mask);
  1678 					}
  1679 					pixels++;
  1680 				}
  1681 			}
  1682 		}
  1683 		break;
  1684 
  1685 		case 4: { Uint32 *pixels;
  1686 			for ( y=0; y<icon->h; ++y ) {
  1687 				pixels = (Uint32 *)icon->pixels +
  1688 				                   y*icon->pitch/4;
  1689 				for ( x=0; x<icon->w; ++x ) {
  1690 					if ( (flags & 1) && *pixels == colorkey ) {
  1691 						SET_MASKBIT(icon, x, y, mask);
  1692 					} else if((flags & 2) && (*pixels & icon->format->Amask) == 0) {
  1693 						SET_MASKBIT(icon, x, y, mask);
  1694 					}
  1695 					pixels++;
  1696 				}
  1697 			}
  1698 		}
  1699 		break;
  1700 	}
  1701 }
  1702 
  1703 /*
  1704  * Sets the window manager icon for the display window.
  1705  */
  1706 void SDL_WM_SetIcon (SDL_Surface *icon, Uint8 *mask)
  1707 {
  1708 	SDL_VideoDevice *video = current_video;
  1709 	SDL_VideoDevice *this  = current_video;
  1710 
  1711 	if ( icon && video->SetIcon ) {
  1712 		/* Generate a mask if necessary, and create the icon! */
  1713 		if ( mask == NULL ) {
  1714 			int mask_len = icon->h*(icon->w+7)/8;
  1715 			int flags = 0;
  1716 			mask = (Uint8 *)malloc(mask_len);
  1717 			if ( mask == NULL ) {
  1718 				return;
  1719 			}
  1720 			memset(mask, ~0, mask_len);
  1721 			if ( icon->flags & SDL_SRCCOLORKEY ) flags |= 1;
  1722 			if ( icon->flags & SDL_SRCALPHA ) flags |= 2;
  1723 			if( flags ) {
  1724 				CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  1725 			}
  1726 			video->SetIcon(video, icon, mask);
  1727 			free(mask);
  1728 		} else {
  1729 			video->SetIcon(this, icon, mask);
  1730 		}
  1731 	}
  1732 }
  1733 
  1734 /*
  1735  * Grab or ungrab the keyboard and mouse input.
  1736  * This function returns the final grab mode after calling the
  1737  * driver dependent function.
  1738  */
  1739 static SDL_GrabMode SDL_WM_GrabInputRaw(SDL_GrabMode mode)
  1740 {
  1741 	SDL_VideoDevice *video = current_video;
  1742 	SDL_VideoDevice *this  = current_video;
  1743 
  1744 	/* Only do something if we have support for grabs */
  1745 	if ( video->GrabInput == NULL ) {
  1746 		return(video->input_grab);
  1747 	}
  1748 
  1749 	/* If the final grab mode if off, only then do we actually grab */
  1750 #ifdef DEBUG_GRAB
  1751   printf("SDL_WM_GrabInputRaw(%d) ... ", mode);
  1752 #endif
  1753 	if ( mode == SDL_GRAB_OFF ) {
  1754 		if ( video->input_grab != SDL_GRAB_OFF ) {
  1755 			mode = video->GrabInput(this, mode);
  1756 		}
  1757 	} else {
  1758 		if ( video->input_grab == SDL_GRAB_OFF ) {
  1759 			mode = video->GrabInput(this, mode);
  1760 		}
  1761 	}
  1762 	if ( mode != video->input_grab ) {
  1763 		video->input_grab = mode;
  1764 		if ( video->CheckMouseMode ) {
  1765 			video->CheckMouseMode(this);
  1766 		}
  1767 	}
  1768 #ifdef DEBUG_GRAB
  1769   printf("Final mode %d\n", video->input_grab);
  1770 #endif
  1771 
  1772 	/* Return the final grab state */
  1773 	if ( mode >= SDL_GRAB_FULLSCREEN ) {
  1774 		mode -= SDL_GRAB_FULLSCREEN;
  1775 	}
  1776 	return(mode);
  1777 }
  1778 SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode)
  1779 {
  1780 	SDL_VideoDevice *video = current_video;
  1781 
  1782 	/* If the video isn't initialized yet, we can't do anything */
  1783 	if ( ! video ) {
  1784 		return SDL_GRAB_OFF;
  1785 	}
  1786 
  1787 	/* Return the current mode on query */
  1788 	if ( mode == SDL_GRAB_QUERY ) {
  1789 		mode = video->input_grab;
  1790 		if ( mode >= SDL_GRAB_FULLSCREEN ) {
  1791 			mode -= SDL_GRAB_FULLSCREEN;
  1792 		}
  1793 		return(mode);
  1794 	}
  1795 
  1796 #ifdef DEBUG_GRAB
  1797   printf("SDL_WM_GrabInput(%d) ... ", mode);
  1798 #endif
  1799 	/* If the video surface is fullscreen, we always grab */
  1800 	if ( mode >= SDL_GRAB_FULLSCREEN ) {
  1801 		mode -= SDL_GRAB_FULLSCREEN;
  1802 	}
  1803 	if ( SDL_VideoSurface && (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
  1804 		mode += SDL_GRAB_FULLSCREEN;
  1805 	}
  1806 	return(SDL_WM_GrabInputRaw(mode));
  1807 }
  1808 static SDL_GrabMode SDL_WM_GrabInputOff(void)
  1809 {
  1810 	SDL_GrabMode mode;
  1811 
  1812 	/* First query the current grab state */
  1813 	mode = SDL_WM_GrabInput(SDL_GRAB_QUERY);
  1814 
  1815 	/* Now explicitly turn off input grab */
  1816 	SDL_WM_GrabInputRaw(SDL_GRAB_OFF);
  1817 
  1818 	/* Return the old state */
  1819 	return(mode);
  1820 }
  1821 
  1822 /*
  1823  * Iconify the window in window managed environments.
  1824  * A successful iconification will result in an SDL_APPACTIVE loss event.
  1825  */
  1826 int SDL_WM_IconifyWindow(void)
  1827 {
  1828 	SDL_VideoDevice *video = current_video;
  1829 	SDL_VideoDevice *this  = current_video;
  1830 	int retval;
  1831 
  1832 	retval = 0;
  1833 	if ( video->IconifyWindow ) {
  1834 		retval = video->IconifyWindow(this);
  1835 	}
  1836 	return(retval);
  1837 }
  1838 
  1839 /*
  1840  * Toggle fullscreen mode
  1841  */
  1842 int SDL_WM_ToggleFullScreen(SDL_Surface *surface)
  1843 {
  1844 	SDL_VideoDevice *video = current_video;
  1845 	SDL_VideoDevice *this  = current_video;
  1846 	int toggled;
  1847 
  1848 	toggled = 0;
  1849 	if ( SDL_PublicSurface && (surface == SDL_PublicSurface) &&
  1850 	     video->ToggleFullScreen ) {
  1851 		if ( surface->flags & SDL_FULLSCREEN ) {
  1852 			toggled = video->ToggleFullScreen(this, 0);
  1853 			if ( toggled ) {
  1854 				SDL_VideoSurface->flags &= ~SDL_FULLSCREEN;
  1855 				SDL_PublicSurface->flags &= ~SDL_FULLSCREEN;
  1856 			}
  1857 		} else {
  1858 			toggled = video->ToggleFullScreen(this, 1);
  1859 			if ( toggled ) {
  1860 				SDL_VideoSurface->flags |= SDL_FULLSCREEN;
  1861 				SDL_PublicSurface->flags |= SDL_FULLSCREEN;
  1862 			}
  1863 		}
  1864 		/* Double-check the grab state inside SDL_WM_GrabInput() */
  1865 		if ( toggled ) {
  1866 			SDL_WM_GrabInput(video->input_grab);
  1867 		}
  1868 	}
  1869 	return(toggled);
  1870 }
  1871 
  1872 /*
  1873  * Get some platform dependent window manager information
  1874  */
  1875 int SDL_GetWMInfo (SDL_SysWMinfo *info)
  1876 {
  1877 	SDL_VideoDevice *video = current_video;
  1878 	SDL_VideoDevice *this  = current_video;
  1879 
  1880 	if ( video && video->GetWMInfo ) {
  1881 		return(video->GetWMInfo(this, info));
  1882 	} else {
  1883 		return(0);
  1884 	}
  1885 }