view src/video/macrom/SDL_romvideo.c @ 4167:a6f635e5eaa6 SDL-1.2

Fixed bug #611 From Tim Angus 2008-08-12 11:18:06 I'm one of the maintainers of ioquake3.org, an updated version of the Quake 3 engine. Relatively recently, we moved ioq3 to use SDL as a replacement for 95% of the platform specific code that was there. On the whole it's doing a great job but unfortunately since the move we've been getting complaints about the quality of the mouse input on the Windows platform to the point where for many the game is unplayable. Put in other terms, the current stable SDL 1.2 is basically not fit for purpose if you need high quality mouse input as you do in a first person shooter. Over the weekend I decided to pull my finger out and actually figure out what's going on. There are basically two major problems. Firstly, when using the "windib" driver, mouse input is gathered via the WM_MOUSEMOVE message. Googling for this indicates that often this is known to result in "spurious" and/or "missing" mouse movement events; this is the primary cause of the poor mouse input. The second problem is that the "directx" driver does not work at all in combination with OpenGL meaning that you can't use DirectInput if your application also uses OpenGL. In other words you're locked into using the "windib" driver and its poor mouse input. In order to address these problems I've done the following: * Remove WM_MOUSEMOVE based motion event generation and replace with calls to GetCursorPos which seems much more reliable. In order to achieve this I've moved mouse motion out into a separate function that is called once per DIB_PumpEvents. * Remove the restriction on the "directx" driver being inoperable in combination with OpenGL. There is a bug for this issues that I've hijacked to a certain extent (http://bugzilla.libsdl.org/show_bug.cgi?id=265). I'm the first to admit I don't really understand why this restriction is there in the first place. The commit message for the bug fix that introduced this restriction (r581) isn't very elaborate and I couldn't see any other bug tracking the issue. If anyone has more information on the bug that was avoided by r581 it would be helpful as I/someone could then look into addressing the problem without disabling the "directx" driver. * I've also removed the restriction on not being allowed to use DirectInput in windowed mode. I couldn't see any reason for this, at least not from our perspective. I have my suspicions that it'll be something like matching up the cursor with the mouse coordinates... * I bumped up the DirectInput API used to version 7 in order to get access to mouse buttons 4-7. I've had to inject a little bit of the DX7 headers into SDL there as the MinGW ones aren't up to date in this respect.
author Sam Lantinga <slouken@libsdl.org>
date Thu, 02 Apr 2009 04:43:36 +0000
parents a1b03ba2fcd0
children
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 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 Mac OS X, which is where this code is needed.
 */
#if USE_QUICKTIME
#include <Movies.h>
#endif
#else
#include <Quickdraw.h>
#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_MACCLASSIC_GAMMA_SUPPORT
	device->SetGammaRamp = Mac_SetGammaRamp;
	device->GetGammaRamp = Mac_GetGammaRamp;
#endif
#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 && ACCESSOR_CALLS_ARE_FUNCTIONS
	memBits = GetPortBitMapForCopyBits((CGrafPtr) memworld);
#else
	memBits = &((GrafPtr)memworld)->portBits;
#endif
#if TARGET_API_MAC_CARBON && ACCESSOR_CALLS_ARE_FUNCTIONS
	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 0
	if ( (this->screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN )
#endif
	{
		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());

#if SDL_MACCLASSIC_GAMMA_SUPPORT
	Mac_QuitGamma(this);
#endif

	/* 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;
	}
}