view src/video/macrom/SDL_romvideo.c @ 1585:980d2a0dc2a3

Date: Tue, 4 Mar 2003 15:05:31 -0800 From: "Jim" Subject: [SDL] Frame Buffer patches... Okay I'm new at patch generation - so please tell me if there's a better way I could have done this. Attached are two patch files generated with 'cvs diff -u' SDL-fb-open-lock.patch applies to SDL_fbvideo.c Modifies the open loop to check /dev/fb/0 found on devfs... Modifies the lock code to return failure if the current virtual terminal is not the one opened for frame buffer writing... Lock would hang forever if switched away (ctrl-alt-F1) ... SDL-fb-mousedrv-screensave.patch applies to SDL_fbevents.c Switches default mouse mode based on SDL_MOUSEDRV - currently only accepts PS2 - otherwise default is MS Mouse. When the screen is switched - exisiting code (wrapped in ifdef SAVE_SCREEN_COTENTS) would save the wrong bit of the screen.... ( I run frame buffer 1600x1200, the size I requested was 800x600 - the save would save the top 800 lines (non biased) and restore them... Adding screen->offset fixed that ) However, if that option is not set, then a call to SDL_UpdateRect (full screen) is made. (which may have had it's contents changed since the screen is not entirely locked because of lock-failure patch) Jim [patches slightly tweaked for SDL 1.2.10]
author Sam Lantinga <slouken@libsdl.org>
date Wed, 22 Mar 2006 07:48:22 +0000
parents 8d9bb0cf2c2a
children f12379c41042
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"

#if defined(__APPLE__) && defined(__MACH__)
#include <Carbon/Carbon.h>
#if USE_QUICKTIME
#include <QuickTime/Movies.h>
#endif
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
#include <Carbon.h>
/* The fullscreen code requires the QuickTime framework, and the window
   is still at the back on MacOS X, which is where this code is needed.
 */
#if USE_QUICKTIME
#include <Movies.h>
#endif
#else
#include <LowMem.h>
#include <Gestalt.h>
#include <Devices.h>
#include <DiskInit.h>
#include <QDOffscreen.h>
#endif

#include "SDL_video.h"
#include "SDL_syswm.h"
#include "../SDL_sysvideo.h"
#include "SDL_romvideo.h"
#include "../maccommon/SDL_macgl_c.h"
#include "../maccommon/SDL_macwm_c.h"
#include "../maccommon/SDL_macmouse_c.h"
#include "../maccommon/SDL_macevents_c.h"

/* Initialization/Query functions */
static int ROM_VideoInit(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect **ROM_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface *ROM_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static int ROM_SetColors(_THIS, int firstcolor, int ncolors,
			 SDL_Color *colors);
static void ROM_VideoQuit(_THIS);

/* Hardware surface functions */
static int ROM_AllocHWSurface(_THIS, SDL_Surface *surface);
static int ROM_LockHWSurface(_THIS, SDL_Surface *surface);
static void ROM_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void ROM_FreeHWSurface(_THIS, SDL_Surface *surface);

#if !TARGET_API_MAC_CARBON /* This seems not to be available? -sts Aug 2000 */
/* Saved state for the menu bar */
static RgnHandle	gSaveGrayRgn = nil;
static short		gSaveMenuBar = 0;
static Boolean		gSaveCSVis = true;

#if powerc
/* Mixed mode glue to activate the 68K emulator and twiddle a register */
#define ONEWORDSTUB(p1) \
		{ 0x41FA, 0x0010, 0x209F, (p1), 0x41FA, \
		  0x0008, 0x2F10, 0x4E75, 0x0000, 0x0000, 0x0000 }

#define TWOWORDSTUB(p1,p2) \
		{ 0x41FA, 0x0012, 0x209F, (p1), (p2), 0x41FA, \
		  0x0008, 0x2F10, 0x4E75, 0x0000, 0x0000, 0x0000 }

#define THREEWORDSTUB(p1,p2,p3) \
		{ 0x41FA, 0x0014, 0x209F, (p1), (p2), (p3), 0x41FA, \
		  0x0008, 0x2F10, 0x4E75, 0x0000, 0x0000, 0x0000 }

/* ControlStrip inline glue for PowerPC */
static pascal Boolean SBIsControlStripVisible(void)
{
	static short procData[] = TWOWORDSTUB(0x7000, 0xAAF2);
	ProcInfoType procInfo = kD0DispatchedPascalStackBased
				| RESULT_SIZE(SIZE_CODE(sizeof(Boolean)))
            	| DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kFourByteCode);
            				
	return((Boolean) CallUniversalProc((UniversalProcPtr) procData, procInfo, 0x00));
}

static pascal void SBShowHideControlStrip(Boolean showIt)
{
	static short procData[] = THREEWORDSTUB(0x303C, 0x0101, 0xAAF2);
	ProcInfoType procInfo = kD0DispatchedPascalStackBased
				| DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kFourByteCode)
				| DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(Boolean)));

	CallUniversalProc((UniversalProcPtr) procData, procInfo, 0x01, showIt);
}
#endif /* powerc */
#endif /* !TARGET_API_MAC_CARBON */

/* Macintosh toolbox driver bootstrap functions */

static int ROM_Available(void)
{
	return(1);
}

static void ROM_DeleteDevice(SDL_VideoDevice *device)
{
	SDL_free(device->hidden);
	SDL_free(device);
}

static SDL_VideoDevice *ROM_CreateDevice(int devindex)
{
	SDL_VideoDevice *device;

	/* Initialize all variables that we clean on shutdown */
	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
	if ( device ) {
		SDL_memset(device, 0, (sizeof *device));
		device->hidden = (struct SDL_PrivateVideoData *)
				SDL_malloc((sizeof *device->hidden));
	}
	if ( (device == NULL) || (device->hidden == NULL) ) {
		SDL_OutOfMemory();
		if ( device ) {
			SDL_free(device);
		}
		return(0);
	}
	SDL_memset(device->hidden, 0, (sizeof *device->hidden));

	/* Set the function pointers */
	device->VideoInit = ROM_VideoInit;
	device->ListModes = ROM_ListModes;
	device->SetVideoMode = ROM_SetVideoMode;
	device->SetColors = ROM_SetColors;
	device->UpdateRects = NULL;
	device->VideoQuit = ROM_VideoQuit;
	device->AllocHWSurface = ROM_AllocHWSurface;
	device->CheckHWBlit = NULL;
	device->FillHWRect = NULL;
	device->SetHWColorKey = NULL;
	device->SetHWAlpha = NULL;
	device->LockHWSurface = ROM_LockHWSurface;
	device->UnlockHWSurface = ROM_UnlockHWSurface;
	device->FlipHWSurface = NULL;
	device->FreeHWSurface = ROM_FreeHWSurface;
#if SDL_VIDEO_OPENGL
	device->GL_MakeCurrent = Mac_GL_MakeCurrent;
	device->GL_SwapBuffers = Mac_GL_SwapBuffers;
	device->GL_LoadLibrary = Mac_GL_LoadLibrary;
	device->GL_GetProcAddress = Mac_GL_GetProcAddress;
#endif	// Have OpenGL
	device->SetCaption = Mac_SetCaption;
	device->SetIcon = NULL;
	device->IconifyWindow = NULL;
	device->GrabInput = NULL;
	device->GetWMInfo = NULL;
	device->FreeWMCursor = Mac_FreeWMCursor;
	device->CreateWMCursor = Mac_CreateWMCursor;
	device->ShowWMCursor = Mac_ShowWMCursor;
	device->WarpWMCursor = Mac_WarpWMCursor;
	device->InitOSKeymap = Mac_InitOSKeymap;
	device->PumpEvents = Mac_PumpEvents;

	device->free = ROM_DeleteDevice;

	return device;
}

VideoBootStrap TOOLBOX_bootstrap = {
	"toolbox", "MacOS ROM Toolbox",
	ROM_Available, ROM_CreateDevice
};


static int ROM_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
	long info;
	
	/* Check out some things about the system */
	Gestalt(gestaltQuickdrawVersion, &info);
	if ( info == gestaltOriginalQD ) {
		SDL_SetError("Color Quickdraw not available");
		return(-1);
	}

	/* Start ROMintosh events */
	Mac_InitEvents(this);

	/* Get a handle to the main monitor */
	SDL_Display = GetMainDevice();

	/* Determine the current screen size */
	this->info.current_w = (**SDL_Display).gdRect.right;
	this->info.current_h = (**SDL_Display).gdRect.bottom;

	/* Determine pixel format */
	vformat->BitsPerPixel = (**(**SDL_Display).gdPMap).pixelSize;
	switch (vformat->BitsPerPixel) {
		case 16:	/* 5-5-5 RGB */
			vformat->Rmask = 0x00007c00;
			vformat->Gmask = 0x000003e0;
			vformat->Bmask = 0x0000001f;
			break;
		default:
			break;
	}

	/* Create our palette */
	SDL_CTab = (CTabHandle)NewHandle(sizeof(ColorSpec)*256 + 8);
	if ( SDL_CTab == nil ) {
		SDL_OutOfMemory();
		return(-1);
	}
	(**SDL_CTab).ctSeed = GetCTSeed();
	(**SDL_CTab).ctFlags = 0;
	(**SDL_CTab).ctSize = 255;
	CTabChanged(SDL_CTab);
	SDL_CPal = NewPalette(256, SDL_CTab, pmExplicit+pmTolerant, 0);

	/* Get a list of available fullscreen modes */
	SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *));
	if ( SDL_modelist ) {
		SDL_modelist[0] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
		if ( SDL_modelist[0] ) {
			SDL_modelist[0]->x = 0;
			SDL_modelist[0]->y = 0;
			SDL_modelist[0]->w = (**SDL_Display).gdRect.right;
			SDL_modelist[0]->h = (**SDL_Display).gdRect.bottom;
		}
		SDL_modelist[1] = NULL;
	}

	/* Fill in some window manager capabilities */
	this->info.wm_available = 1;

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

static SDL_Rect **ROM_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
	if ( this->screen->format->BitsPerPixel == format->BitsPerPixel ) {
		if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
			return(SDL_modelist);
		} else {
			return((SDL_Rect **)-1);
		}
	} else {
		return((SDL_Rect **)0);
	}
}

static void ROM_HideMenuBar(_THIS)
{
#if !TARGET_API_MAC_CARBON /* This seems not to be available? -sts Aug 2000 */
	RgnHandle		drawRgn = nil;
	RgnHandle		tempRgn = nil;
	RgnHandle		grayRgn = nil;
	WindowPtr		window = nil;
	GDHandle		gd = nil;
	GrafPtr			savePort;
	long			response;
	short			height;
	EventRecord		theEvent;

	height = GetMBarHeight();
	
	if ( height > 0 ) {
		tempRgn = NewRgn();
		drawRgn = NewRgn();
		gSaveGrayRgn = NewRgn();
		if ( ! tempRgn || ! drawRgn || ! gSaveGrayRgn ) {
			goto CLEANUP;
		}
		grayRgn = GetGrayRgn(); /* No need to check for this */
	
		GetPort(&savePort);

		/* Hide the control strip if it's present, and record its 
		   previous position into the dirty region for redrawing. 
		   This isn't necessary, but may help catch stray bits. */
		CopyRgn(grayRgn, tempRgn);
		if (!Gestalt(gestaltControlStripAttr, &response) && 
			(response & (1L << gestaltControlStripExists))) {
			gSaveCSVis = SBIsControlStripVisible();
			if (gSaveCSVis)
				SBShowHideControlStrip(false);
		}
		DiffRgn(grayRgn, tempRgn, drawRgn);

		/* Save the gray region once the control strip is hidden*/
		CopyRgn(grayRgn, gSaveGrayRgn);

		/* Change the menu height in lowmem */
		gSaveMenuBar = height;
		LMSetMBarHeight(0);
		
		/* Walk the monitor rectangles, and combine any pieces that
		   aren't in GrayRgn: menubar, round corners, fake floaters. */
		for(gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) 
			{
			if (!TestDeviceAttribute(gd, screenDevice)) continue;
			if (!TestDeviceAttribute(gd, screenActive)) continue;

			RectRgn(tempRgn, &(*gd)->gdRect);	/* Get the whole screen */
			DiffRgn(tempRgn, grayRgn, tempRgn); /* Subtract out GrayRgn */
			UnionRgn(tempRgn, drawRgn, drawRgn);/* Combine all the bits */
			}
			
		/* Add the bits into the GrayRgn */
		UnionRgn(drawRgn, grayRgn, grayRgn);

		/* Modify the vis regions of exposed windows */
		window = (FrontWindow()) ? FrontWindow() : (WindowPtr) -1L;
		PaintBehind(window, drawRgn);
		CalcVisBehind(window, drawRgn);

		SetPort(savePort);
		
		/* Yield time so that floaters can catch up */
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		}

CLEANUP:

	if (tempRgn) DisposeRgn(tempRgn);
	if (drawRgn) DisposeRgn(drawRgn);
#endif /* !TARGET_API_MAC_CARBON */
}
	
static void ROM_ShowMenuBar(_THIS)
{
#if !TARGET_API_MAC_CARBON /* This seems not to be available? -sts Aug 2000 */
	RgnHandle		drawRgn = nil;
	RgnHandle		menuRgn = nil;
	RgnHandle		tempRgn = nil;
	RgnHandle		grayRgn = nil;
	WindowPtr		window = nil;
	GrafPtr			wMgrPort;
	GrafPtr			savePort;
	Rect			menuRect;
	long			response;
	short			height;
	EventRecord		theEvent;
	RGBColor		saveRGB;
	RGBColor		blackRGB = { 0, 0, 0 };

	height = GetMBarHeight();
	
	if ((height <= 0) && (gSaveMenuBar > 0)) {
		drawRgn = NewRgn();
		menuRgn = NewRgn();
		tempRgn = NewRgn();
		if ( ! tempRgn || ! drawRgn || ! gSaveGrayRgn ) {
			goto CLEANUP;
		}
		grayRgn = GetGrayRgn(); /* No need to check for this */
	
		GetPort(&savePort);
		GetWMgrPort(&wMgrPort);

		/* Set the height properly */
		LMSetMBarHeight(gSaveMenuBar);

		/* Restore the old GrayRgn: rounded corners, etc, but not
		   the menubar -- subtract that out first! */
		if (gSaveGrayRgn)
			{
			menuRect = (*GetMainDevice())->gdRect;
			menuRect.bottom = menuRect.top + gSaveMenuBar;
			RectRgn(menuRgn, &menuRect);

			DiffRgn(grayRgn, gSaveGrayRgn, drawRgn); 	/* What do we inval? */
			DiffRgn(drawRgn, menuRgn, drawRgn);			/* Clip out the menu */
			
			/* Now redraw the corners and other bits black */
			SetPort(wMgrPort);
			GetClip(tempRgn);
			SetClip(drawRgn);
			GetForeColor(&saveRGB);
			RGBForeColor(&blackRGB);
			PaintRgn(drawRgn);
			RGBForeColor(&saveRGB);
			SetClip(tempRgn);
			SetPort(savePort);
			
			UnionRgn(drawRgn, menuRgn, drawRgn);		/* Put back the menu */

			/* Now actually restore the GrayRgn */
			CopyRgn(gSaveGrayRgn, grayRgn);
			DisposeRgn(gSaveGrayRgn);
			gSaveGrayRgn = nil;
			}

		/* Modify the vis regions of exposed windows and draw menubar */
		window = (FrontWindow()) ? FrontWindow() : (WindowPtr) -1L;
		PaintBehind(window, drawRgn);
		CalcVisBehind(window, drawRgn);
		DrawMenuBar();

		SetPort(savePort);
		gSaveMenuBar = 0;

		/* Now show the control strip if it's present */
		if (!Gestalt(gestaltControlStripAttr, &response) && 
				(response & (1L << gestaltControlStripExists)))
			{
			if (gSaveCSVis && !SBIsControlStripVisible())
				SBShowHideControlStrip(true);
			gSaveCSVis = true;
			}

		/* Yield time so that floaters can catch up */
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		EventAvail(0, &theEvent);
		}

CLEANUP:

	if (drawRgn) DisposeRgn(drawRgn);
	if (menuRgn) DisposeRgn(menuRgn);
	if (tempRgn) DisposeRgn(tempRgn);
#endif /* !TARGET_API_MAC_CARBON */
}

/* Various screen update functions available */
static void ROM_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
static void ROM_WindowUpdate(_THIS, int numrects, SDL_Rect *rects);

static void ROM_UnsetVideoMode(_THIS, SDL_Surface *current)
{
	/* Free the current window, if any */
	if ( SDL_Window != nil ) {
		GWorldPtr memworld;
		
		/* Handle OpenGL support */
		Mac_GL_Quit(this);

		memworld = (GWorldPtr)GetWRefCon(SDL_Window);
		if ( memworld != nil ) {
			UnlockPixels(GetGWorldPixMap(memworld));
			DisposeGWorld(memworld);
		}
		if ( (current->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
#if USE_QUICKTIME
			EndFullScreen(fullscreen_ctx, nil);
			SDL_Window = nil;
#else
			ROM_ShowMenuBar(this);
#endif
		}
	}
	current->pixels = NULL;
	current->flags &= ~(SDL_HWSURFACE|SDL_FULLSCREEN);
}

static SDL_Surface *ROM_SetVideoMode(_THIS, SDL_Surface *current,
				int width, int height, int bpp, Uint32 flags)
{
	Rect wrect, orect;
#if TARGET_API_MAC_CARBON
	Rect tmprect;
#endif

	/* Free any previous video mode */
	ROM_UnsetVideoMode(this, current);

	/* Create the ROM window and SDL video surface */
	current->flags = 0;		/* Clear flags */
	current->w = width;
	current->h = height;
	SetRect(&wrect, 0, 0, width, height);
	if ( SDL_Window ) {
		/* If we recreate the window, don't move it around */
#if TARGET_API_MAC_CARBON
		orect = *GetWindowPortBounds(SDL_Window, &tmprect);
#else
		orect = SDL_Window->portRect;
#endif
		OffsetRect(&wrect, orect.left, orect.top);
	} else {
		/* Center the window the first time we show it */
		OffsetRect(&wrect,
		(SDL_modelist[0]->w-width)/2, (SDL_modelist[0]->h-height)/2);
	}

#if defined(__MACOSX__) && !USE_QUICKTIME
	/* Hum.. fullscreen mode is broken */
	flags &= ~SDL_FULLSCREEN;
#endif
	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
		/* Create the fullscreen window and use screen bits */
		current->flags |= SDL_HWSURFACE|SDL_FULLSCREEN;
		if ( SDL_Window ) {
			DisposeWindow(SDL_Window);
		}
#if USE_QUICKTIME
		BeginFullScreen(&fullscreen_ctx, nil, 0,0, &SDL_Window, nil, 0);
#else
		SDL_Window = NewCWindow(nil, &wrect, "\p", true, plainDBox,
						(WindowPtr)-1, false, 0);
		ROM_HideMenuBar(this);
#endif
		current->pitch = (**(**SDL_Display).gdPMap).rowBytes & 0x3FFF;
		current->pixels = (**(**SDL_Display).gdPMap).baseAddr;
		this->UpdateRects = ROM_DirectUpdate;
	} else {
		GWorldPtr memworld;
		PixMapHandle pixmap;
		int style;

		style = noGrowDocProc;
		if ( flags & SDL_NOFRAME ) {
			style = plainDBox;
			current->flags |= SDL_NOFRAME;
		} else
		if ( flags & SDL_RESIZABLE ) {
			style = zoomDocProc;
			current->flags |= SDL_RESIZABLE;
		}
		if ( SDL_Window && (style == current_style) ) {
			/* Resize existing window, if necessary */
			if ( ((orect.right-orect.left) != width) ||
			     ((orect.bottom-orect.top) != height) ) {
				SizeWindow(SDL_Window, width, height, false);
			}
		} else {
			/* Recreate the window in the new style */
			if ( SDL_Window ) {
				DisposeWindow(SDL_Window);
			}
			SDL_Window = NewCWindow(nil, &wrect, "\p", true,
			                        style, (WindowPtr)-1, true, 0);

			/* Set the window title, if any */
			{ char *title;
				SDL_WM_GetCaption(&title, NULL);
				if ( title ) {
					Mac_SetCaption(this, title, NULL);
				}
			}
		}
		current_style = style;
		SetPalette(SDL_Window, SDL_CPal, false);
		ActivatePalette(SDL_Window);
		if ( NewGWorld(&memworld, 0,
#if TARGET_API_MAC_CARBON
			       GetWindowPortBounds(SDL_Window, &tmprect),
#else
			       &SDL_Window->portRect,
#endif
			       SDL_CTab, nil, 0) != noErr ) {
			SDL_SetError("NewGWorld() failed");
			return(NULL);
		}
		SetWRefCon(SDL_Window, (long)memworld);
		pixmap = GetGWorldPixMap(memworld);
		LockPixels(pixmap);
		current->pitch = (**pixmap).rowBytes & 0x3FFF;
		current->pixels = GetPixBaseAddr(pixmap);
		this->UpdateRects = ROM_WindowUpdate;
	}
	SetPortWindowPort(SDL_Window);
	SelectWindow(SDL_Window);

	/* Handle OpenGL support */
	if ( flags & SDL_OPENGL ) {
		if ( Mac_GL_Init(this) == 0 ) {
			current->flags |= SDL_OPENGL;
		} else {
			current = NULL;
		}
	}
	
	if ( (flags & SDL_HWPALETTE) && (flags & SDL_FULLSCREEN) )
	   current->flags |= SDL_HWPALETTE;
	   
	/* We're live! */
	return(current);
}

/* We don't actually allow hardware surfaces other than the main one */
static int ROM_AllocHWSurface(_THIS, SDL_Surface *surface)
{
	return(-1);
}
static void ROM_FreeHWSurface(_THIS, SDL_Surface *surface)
{
	return;
}
static int ROM_LockHWSurface(_THIS, SDL_Surface *surface)
{
	return(0);
}
static void ROM_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
	return;
}

static void ROM_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
{
	/* The application is already updating the visible video memory */
	return;
}

static void ROM_WindowUpdate(_THIS, int numrects, SDL_Rect *rects)
{
	GWorldPtr memworld;
	GrafPtr saveport;
	CGrafPtr thePort;
	const BitMap *memBits;
	const BitMap *winBits;
	int i;
	Rect update;
	
	/* Copy from the offscreen GWorld to the window port */
	GetPort(&saveport);
	SetPortWindowPort(SDL_Window);
	thePort = GetWindowPort(SDL_Window);
	memworld = (GWorldPtr)GetWRefCon(SDL_Window);
#if TARGET_API_MAC_CARBON
	memBits = GetPortBitMapForCopyBits((CGrafPtr) memworld);
#else
	memBits = &((GrafPtr)memworld)->portBits;
#endif
#if TARGET_API_MAC_CARBON
	winBits = GetPortBitMapForCopyBits(thePort);
#else
	winBits = &SDL_Window->portBits;
#endif
	for ( i=0; i<numrects; ++i ) {
		update.left = rects[i].x;
		update.right = rects[i].x+rects[i].w;
		update.top = rects[i].y;
		update.bottom = rects[i].y+rects[i].h;
		CopyBits(memBits, winBits,
			 &update, &update, srcCopy, nil);
	}
#if TARGET_API_MAC_CARBON
	if ( QDIsPortBuffered(thePort) ) {
		QDFlushPortBuffer(thePort, NULL);
	}
#endif
	SetPort(saveport);
}

static int ROM_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
	CTabHandle cTab;
	int i;

	/* Get the colortable from the either the display or window */
	if ( (this->screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
		cTab = (**(**SDL_Display).gdPMap).pmTable;
	} else {
		cTab = SDL_CTab;
	}

	/* Verify the range of colors */
	if ( (firstcolor+ncolors) > ((**cTab).ctSize+1) ) {
		return(0);
	}
	
	/* Set the screen palette and update the display */
	for ( i=0; i< ncolors; ++i ) {
	        int j = firstcolor + i;
		(**cTab).ctTable[j].value = j;
		(**cTab).ctTable[j].rgb.red = colors[i].r << 8 | colors[i].r;
		(**cTab).ctTable[j].rgb.green = colors[i].g << 8 | colors[i].g;
		(**cTab).ctTable[j].rgb.blue = colors[i].b << 8 | colors[i].b;
	}
//	if ( (this->screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) 
{
		GDevice **odisplay;
		odisplay = GetGDevice();
		SetGDevice(SDL_Display);
		SetEntries(0, (**cTab).ctSize, (ColorSpec *)&(**cTab).ctTable);
		SetGDevice(odisplay);
	}
	return(1);
}

void ROM_VideoQuit(_THIS)
{
	int i;

	/* Free current video mode */
	ROM_UnsetVideoMode(this, this->screen);
	if ( SDL_Window ) {
		DisposeWindow(SDL_Window);
		SDL_Window = nil;
	}

	/* Free palette and restore original one */
	if ( SDL_CTab != nil ) {
		DisposeHandle((Handle)SDL_CTab);
		SDL_CTab = nil;
	}
	if ( SDL_CPal != nil ) {
		DisposePalette(SDL_CPal);
		SDL_CPal = nil;
	}
	RestoreDeviceClut(GetMainDevice());

	/* Free list of video modes */
	if ( SDL_modelist != NULL ) {
		for ( i=0; SDL_modelist[i]; ++i ) {
			SDL_free(SDL_modelist[i]);
		}
		SDL_free(SDL_modelist);
		SDL_modelist = NULL;
	}
}