/*
Copyright (C) 2003-2005 Andrey Nazarov

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

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

//
// qsdl_video.c
//

#include <SDL.h>
#include "qcommon.h"
#include "in_public.h"
#include "vid_public.h"
#include "key_public.h"

#ifdef _WIN32
#include <SDL_syswm.h>	/* this also includes windows.h */
#endif

/* local variables */
static SDL_Surface	*sdl_surface;
static SDL_Surface	*sdl_icon;
static Uint16		sdl_original_gamma[3][256];
static vidFlags_t	sdl_flags;

static qboolean		mouseactive;	// qfalse when not focus app
static qboolean		mouseinitialized;

/* get the list of acceptable video modes */
#include "vid_modes.h"

#include "q2icon.xbm"

#define q2icon_numbits	( q2icon_width * q2icon_height )

/*
===============================================================================

COMMON SDL VIDEO RELATED ROUTINES

===============================================================================
*/

static qboolean QSDL_PreInitVideo( void ) {
	char buffer[MAX_QPATH];
	int ret;

#if ( defined _WIN32 && !defined _WIN32_WCE )
	/* we need to pass main module handle to SDL
     * so DirectInput initializes properly */
	SDL_SetModuleHandle( ( HINSTANCE )Cvar_VariableInteger( "sys_hinstance" ) );
#endif

	Com_Printf( "Initializing SDL Video: " );

	if( SDL_WasInit( SDL_INIT_EVERYTHING ) == 0 ) {
		ret = SDL_Init( SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE );
	} else {
		ret = SDL_InitSubSystem( SDL_INIT_VIDEO );
	}

	if( ret == -1 ) {
		Com_Printf( "failed\n" );
		Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );
		return qfalse;
	}

	Com_Printf( "ok\n" );

	if( SDL_VideoDriverName( buffer, sizeof( buffer ) ) != NULL ) {
		Com_Printf( "Using SDL video driver: '%s'\n", buffer );
	}

	return qtrue;

}

static qboolean QSDL_PostInitVideo( void ) {
	Com_Printf( "Initializing gamma control: " );
	if( SDL_GetGammaRamp( sdl_original_gamma[0], sdl_original_gamma[1],
                sdl_original_gamma[2] ) == -1 )
    {
		Com_Printf( "failed\n" );
	} else {
		Com_Printf( "ok\n" );
		sdl_flags |= QVF_GAMMARAMP_ENABLED;
	}

	return qtrue;

}

/*
============
Video_Shutdown
============
*/
static void QSDL_ShutdownVideo( void ) {
	Com_Printf( "Shutting down SDL Video...\n" );

	if( sdl_flags & QVF_GAMMARAMP_ENABLED ) {
		Com_Printf( "...restoring gamma settings: " );
		if( SDL_SetGammaRamp( sdl_original_gamma[0], sdl_original_gamma[1],
                    sdl_original_gamma[2] ) == -1 )
        {
			Com_Printf( "failed\n" );
		} else {
			Com_Printf( "ok\n" );
		}
	}

	if( sdl_icon ) {
		SDL_FreeSurface( sdl_icon );
		sdl_icon = NULL;
	}

	if( SDL_WasInit( SDL_INIT_EVERYTHING ) == SDL_INIT_VIDEO ) {
		SDL_Quit();
	} else {
		SDL_QuitSubSystem( SDL_INIT_VIDEO );
	}

	sdl_surface = NULL;
	sdl_flags = 0;

#ifdef _WIN32
	Cvar_SetInteger( "win_hwnd", -1 );
#endif
}

/*
==============
Video_UpdateGamma
==============
*/
static void QSDL_UpdateGamma( const byte *table ) {
	Uint16 gammaRamp[256];
	int i;

	if( !( sdl_flags & QVF_GAMMARAMP_ENABLED ) ) {
		return;
	}
	
	for( i = 0; i < 256; i++ ) {
		gammaRamp[i] = table[i] << 8;
	}

	SDL_SetGammaRamp( gammaRamp, gammaRamp, gammaRamp );
	
}

/*
==============
Video_GetFlags
==============
*/
static vidFlags_t QSDL_GetVideoFlags( void ) {
	return sdl_flags;
}

static void QSDL_KeyEvent( SDL_keysym *keysym, qboolean down ) {
	uint32 key;

#define MAPKEY( s, d )	case s: key = d; break;

	switch( keysym->sym ) {
	MAPKEY( SDLK_BACKSPACE,		K_BACKSPACE	)
	MAPKEY( SDLK_TAB,			K_TAB		)
	MAPKEY( SDLK_RETURN,		K_ENTER		)
	MAPKEY( SDLK_PAUSE,			K_PAUSE		)
	MAPKEY( SDLK_ESCAPE,		K_ESCAPE	)
	MAPKEY( SDLK_SPACE,			K_SPACE		)
	MAPKEY( SDLK_EXCLAIM,		'!'			)
	MAPKEY( SDLK_QUOTEDBL,		'\"'		)
	MAPKEY( SDLK_HASH,			'#'			)
	MAPKEY( SDLK_DOLLAR,		'$'			)
	MAPKEY( SDLK_AMPERSAND,		'&'			)
	MAPKEY( SDLK_QUOTE,			'\''		)
	MAPKEY( SDLK_LEFTPAREN,		'('			)
	MAPKEY( SDLK_RIGHTPAREN,	')'			)
	MAPKEY( SDLK_ASTERISK,		'*'			)
	MAPKEY( SDLK_PLUS,			'+'			)
	MAPKEY( SDLK_COMMA,			','			)
	MAPKEY( SDLK_MINUS,			'-'			)
	MAPKEY( SDLK_PERIOD,		'.'			)
	MAPKEY( SDLK_SLASH,			'/'			)
	MAPKEY( SDLK_0,				'0'			)
	MAPKEY( SDLK_1,				'1'			)
	MAPKEY( SDLK_2,				'2'			)
	MAPKEY( SDLK_3,				'3'			)
	MAPKEY( SDLK_4,				'4'			)
	MAPKEY( SDLK_5,				'5'			)
	MAPKEY( SDLK_6,				'6'			)
	MAPKEY( SDLK_7,				'7'			)
	MAPKEY( SDLK_8,				'8'			)
	MAPKEY( SDLK_9,				'9'			)
	MAPKEY( SDLK_COLON,			':'			)
	MAPKEY( SDLK_SEMICOLON,		';'			)
	MAPKEY( SDLK_LESS,			'<'			)
	MAPKEY( SDLK_EQUALS,		'='			)
	MAPKEY( SDLK_GREATER,		'>'			)
	MAPKEY( SDLK_QUESTION,		'?'			)
	MAPKEY( SDLK_AT,			'@'			)

	MAPKEY( SDLK_LEFTBRACKET,	'['		)
	MAPKEY( SDLK_BACKSLASH,		'\\'	)
	MAPKEY( SDLK_RIGHTBRACKET,	']'		)
	MAPKEY( SDLK_CARET,			'^'		)
	MAPKEY( SDLK_UNDERSCORE,	'_'		)
	MAPKEY( SDLK_BACKQUOTE,		'`'		)
	MAPKEY( SDLK_a,				'a'		)
	MAPKEY( SDLK_b,				'b'		)
	MAPKEY( SDLK_c,				'c'		)
	MAPKEY( SDLK_d,				'd'		)
	MAPKEY( SDLK_e,				'e'		)
	MAPKEY( SDLK_f,				'f'		)
	MAPKEY( SDLK_g,				'g'		)
	MAPKEY( SDLK_h,				'h'		)
	MAPKEY( SDLK_i,				'i'		)
	MAPKEY( SDLK_j,				'j'		)
	MAPKEY( SDLK_k,				'k'		)
	MAPKEY( SDLK_l,				'l'		)
	MAPKEY( SDLK_m,				'm'		)
	MAPKEY( SDLK_n,				'n'		)
	MAPKEY( SDLK_o,				'o'		)
	MAPKEY( SDLK_p,				'p'		)
	MAPKEY( SDLK_q,				'q'		)
	MAPKEY( SDLK_r,				'r'		)
	MAPKEY( SDLK_s,				's'		)
	MAPKEY( SDLK_t,				't'		)
	MAPKEY( SDLK_u,				'u'		)
	MAPKEY( SDLK_v,				'v'		)
	MAPKEY( SDLK_w,				'w'		)
	MAPKEY( SDLK_x,				'x'		)
	MAPKEY( SDLK_y,				'y'		)
	MAPKEY( SDLK_z,				'z'		)
	MAPKEY( SDLK_DELETE,		K_DEL	)

	MAPKEY( SDLK_KP0,			K_KP_INS		)
	MAPKEY( SDLK_KP1,			K_KP_END		)
	MAPKEY( SDLK_KP2,			K_KP_DOWNARROW	)
	MAPKEY( SDLK_KP3,			K_KP_PGDN		)
	MAPKEY( SDLK_KP4,			K_KP_LEFTARROW	)
	MAPKEY( SDLK_KP5,			K_KP_5			)
	MAPKEY( SDLK_KP6,			K_KP_RIGHTARROW	)
	MAPKEY( SDLK_KP7,			K_KP_HOME		)
	MAPKEY( SDLK_KP8,			K_KP_UPARROW	)
	MAPKEY( SDLK_KP9,			K_KP_PGUP		)
	MAPKEY( SDLK_KP_PERIOD,		K_KP_DEL		)
	MAPKEY( SDLK_KP_DIVIDE,		K_KP_SLASH		)
	MAPKEY( SDLK_KP_MULTIPLY,   K_KP_MULTIPLY   )
	MAPKEY( SDLK_KP_MINUS,		K_KP_MINUS		)
	MAPKEY( SDLK_KP_PLUS,		K_KP_PLUS		)
	MAPKEY( SDLK_KP_ENTER,		K_KP_ENTER		)

	MAPKEY( SDLK_UP,			K_UPARROW		)
	MAPKEY( SDLK_DOWN,			K_DOWNARROW		)
	MAPKEY( SDLK_RIGHT,			K_RIGHTARROW	)
	MAPKEY( SDLK_LEFT,			K_LEFTARROW		)
	MAPKEY( SDLK_INSERT,		K_INS			)
	MAPKEY( SDLK_HOME,			K_HOME			)
	MAPKEY( SDLK_END,			K_END			)
	MAPKEY( SDLK_PAGEUP,		K_PGUP			)
	MAPKEY( SDLK_PAGEDOWN,		K_PGDN			)

	MAPKEY( SDLK_F1,			K_F1			)
	MAPKEY( SDLK_F2,			K_F2			)
	MAPKEY( SDLK_F3,			K_F3			)
	MAPKEY( SDLK_F4,			K_F4			)
	MAPKEY( SDLK_F5,			K_F5			)
	MAPKEY( SDLK_F6,			K_F6			)
	MAPKEY( SDLK_F7,			K_F7			)
	MAPKEY( SDLK_F8,			K_F8			)
	MAPKEY( SDLK_F9,			K_F9			)
	MAPKEY( SDLK_F10,			K_F10			)
	MAPKEY( SDLK_F11,			K_F11			)
	MAPKEY( SDLK_F12,			K_F12			)

	MAPKEY( SDLK_NUMLOCK,		K_NUMLOCK		)
	MAPKEY( SDLK_CAPSLOCK,		K_CAPSLOCK		)
	MAPKEY( SDLK_SCROLLOCK,		K_SCROLLOCK		)
	MAPKEY( SDLK_LSUPER,		K_LWINKEY		)
	MAPKEY( SDLK_RSUPER,		K_RWINKEY		)
	MAPKEY( SDLK_MENU,		    K_MENU		    )

	MAPKEY( SDLK_RSHIFT,		K_SHIFT			)
	MAPKEY( SDLK_LSHIFT,		K_SHIFT			)
	MAPKEY( SDLK_RCTRL,			K_CTRL			)
	MAPKEY( SDLK_LCTRL,			K_CTRL			)
	MAPKEY( SDLK_RALT,			K_ALT			)
	MAPKEY( SDLK_LALT,			K_ALT			)

#undef MAPKEY

	default:
		Com_DPrintf( "QSDL_KeyEvent: unknown keysym %d\n", keysym->sym );
        return;
	}

	Key_Event( key, down, com_eventTime );
}

static void QSDL_MouseButtonEvent( int button, qboolean down ) {
    uint32 key;

    if( !mouseinitialized ) {
        return;
    }
    switch( button ) {
    case SDL_BUTTON_LEFT:
        key = K_MOUSE1;
        break;
    case SDL_BUTTON_RIGHT:
        key = K_MOUSE2;
        break;
    case SDL_BUTTON_MIDDLE:
        key = K_MOUSE3;
        break;
    case SDL_BUTTON_WHEELUP:
        key = K_MWHEELUP;
        break;
    case SDL_BUTTON_WHEELDOWN:
        key = K_MWHEELDOWN;
        break;
    default:
		Com_DPrintf( "QSDL_MouseButtonEvent: unknown button %d\n", button );
        return;
    }

    Key_Event( key, down, com_eventTime );
}

/*
============
Video_PumpEvents
============
*/
void Video_PumpEvents( void ) {
	SDL_Event	event;

	while( SDL_PollEvent( &event ) ) {
		switch( event.type ) {
		case SDL_ACTIVEEVENT:
			/* state is actually a bitmask! */
			if( event.active.state & SDL_APPACTIVE ) {
				if( event.active.gain ) {
					CL_AppActivate( qtrue );
				} else {
					CL_AppActivate( qfalse );
				}
			}
			break;

		case SDL_QUIT:
			Com_Quit();
			break;

		case SDL_KEYDOWN:
			QSDL_KeyEvent( &event.key.keysym, qtrue );
			break;

		case SDL_KEYUP:
			QSDL_KeyEvent( &event.key.keysym, qfalse );
			break;

		case SDL_MOUSEBUTTONDOWN:
            QSDL_MouseButtonEvent( event.button.button, qtrue );
            break;

		case SDL_MOUSEBUTTONUP:
            QSDL_MouseButtonEvent( event.button.button, qfalse );
            break;
		}
	}
}


static void QSDL_PreCreateWindow( void ) {
	SDL_Color	color;
	byte *dst;
	int i;

	if( ( sdl_icon = SDL_CreateRGBSurface( SDL_SWSURFACE, q2icon_width,
                    q2icon_height, 8, 0, 0, 0, 0 ) ) != NULL )
    {
		SDL_SetColorKey( sdl_icon, SDL_SRCCOLORKEY, 0 );

		/* setup transparent pixel */
		color.r = 255;
		color.g = 255;
		color.b = 255;
		SDL_SetColors( sdl_icon, &color, 0, 1 );

		/* setup colored pixel */
		color.r = 0;
		color.g = 128;
		color.b = 128;
		SDL_SetColors( sdl_icon, &color, 1, 1 );

		/* expand the bitmap */
		dst = sdl_icon->pixels;
		for( i = 0; i < q2icon_numbits; i++ ) {
			*dst++ = Q_IsBitSet( q2icon_bits, i );
		}

		SDL_WM_SetIcon( sdl_icon, NULL );
	}

	SDL_WM_SetCaption( APPLICATION, APPLICATION );

	SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY,
            SDL_DEFAULT_REPEAT_INTERVAL );
}

static void QSDL_PostCreateWindow( void ) {
#ifdef _WIN32
	SDL_SysWMinfo	info;

	SDL_VERSION( &info.version );
	SDL_GetWMInfo( &info );

	Cvar_SetInteger( "win_hwnd", ( int )info.window );
#endif
	CL_AppActivate( qtrue );

}

/*
===============================================================================

OPENGL SPECIFIC

===============================================================================
*/

/*
============
Video_InitGL
============
*/
static qboolean QSDL_InitGL( void ) {
	cvar_t *gl_driver;

	if( !QSDL_PreInitVideo() ) {
		return qfalse;
	}

	gl_driver = Cvar_Get( "gl_driver", DEFAULT_OPENGL_DRIVER, 0 );

	Com_Printf( "Loading '%s': ", gl_driver->string );
	if( SDL_GL_LoadLibrary( gl_driver->string ) == -1 ) {
		Com_Printf( "failed\n" );
		Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );

		if( SDL_WasInit( SDL_INIT_EVERYTHING ) == SDL_INIT_VIDEO ) {
			SDL_Quit();
		} else {
			SDL_QuitSubSystem( SDL_INIT_VIDEO );
		}

		return qfalse;
	}
	Com_Printf( "ok\n" );

	sdl_flags |= QVF_ACCELERATED;

	if( !QSDL_PostInitVideo() ) {
		return qfalse;
	}

	return qtrue;


}


/*
============
Video_SetMode
============
*/
static vidSetModeResult_t QSDL_SetModeGL( int *pwidth, int *pheight, int mode,
        qboolean fullscreen )
{
	int width, height;
	const char *win_fs[] = { "W", "FS" };
	int bitdepth;
	int flags;
	vidSetModeResult_t result = SETMODE_ERROR;

	Com_Printf( "Initializing OpenGL display\n" );

	if( mode == -1 ) {
		Com_Printf( "...setting custom mode: " );
		width = *pwidth;
		height = *pheight;
	} else {
	    Com_Printf( "...setting mode %d: ", mode );
        if( !VID_GetModeInfo( &width, &height, mode ) ) {
            Com_Printf( "invalid mode\n" );
            return SETMODE_ERROR;
        }
    }

	Com_Printf( "%d %d %s\n", width, height, win_fs[fullscreen] );

	*pwidth = width;
	*pheight = height;

	SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
	SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
	SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
	SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

	flags = SDL_OPENGL;

	QSDL_PreCreateWindow();

	if( !fullscreen ) {
		Com_Printf( "...setting windowed mode: " );
        sdl_surface = SDL_SetVideoMode( width, height, 0, flags );
		if( sdl_surface == NULL ) {
			Com_Printf( "failed\n" );
			Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );
			return SETMODE_ERROR;
		}
		Com_Printf( "ok\n" );

		result = SETMODE_WINDOWED;
	} else {
		bitdepth = Cvar_VariableInteger( "gl_bitdepth" );

		Com_Printf( "...attempting fullscreen: " );
        sdl_surface = SDL_SetVideoMode( width, height, bitdepth,
                flags | SDL_FULLSCREEN );
		if( sdl_surface == NULL ) {
			Com_Printf( "failed\n" );

			Com_Printf( "...falling back to windowed mode: " );
            sdl_surface = SDL_SetVideoMode( width, height, 0, flags );
			if( sdl_surface == NULL )  {
				Com_Printf( "failed\n" );
				Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );
				return SETMODE_ERROR;
			}
			Com_Printf( "ok\n" );

			result = SETMODE_WINDOWED;
		} else {
			Com_Printf( "ok\n" );

			sdl_flags |= QVF_FULLSCREEN_ENABLED;
			result = SETMODE_FULLSCREEN;
		}
	}

	QSDL_PostCreateWindow();

	return result;

}

static void QSDL_BeginFrameGL( float stereo_separation ) {
}

static void QSDL_EndFrameGL( void ) {
	SDL_GL_SwapBuffers();
}

/*
===============================================================================

SOFTWARE SPECIFIC

===============================================================================
*/

/*
============
Video_InitSoft
============
*/
static qboolean QSDL_InitSoft( void ) {
	if( !QSDL_PreInitVideo() ) {
		return qfalse;
	}

	/* no additional work here */

	if( !QSDL_PostInitVideo() ) {
		return qfalse;
	}

	return qtrue;


}

/*
============
Video_SetModeSoft
============
*/
static vidSetModeResult_t
QSDL_SetModeSoft( int *pwidth, int *pheight, byte **buffer, int *rowbytes,
        const byte *palette, int mode, qboolean fullscreen )
{
	int width, height;
	const char *win_fs[] = { "W", "FS" };
	int flags;
	int bpp = *rowbytes ? 32 : 8;
	vidSetModeResult_t result = SETMODE_ERROR;

	Com_Printf( "Initializing display surface\n" );

	Com_Printf( "...setting mode %d: ", mode );

	if( !VID_GetModeInfo( &width, &height, mode ) ) {
		Com_Printf( "invalid mode\n" );
		return SETMODE_ERROR;
	}

	Com_Printf( "%d %d %s %i bpp\n", width, height, win_fs[fullscreen], bpp );

	*pwidth = width;
	*pheight = height;

    flags = SDL_SWSURFACE | SDL_HWPALETTE;

	QSDL_PreCreateWindow();

	if( !fullscreen ) {
		Com_Printf( "...setting windowed mode: " );
        sdl_surface = SDL_SetVideoMode( width, height, bpp, flags );
		if( sdl_surface == NULL ) {
			Com_Printf( "failed\n" );
			Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );
			return SETMODE_ERROR;
		}
		Com_Printf( "ok\n" );

		result = SETMODE_WINDOWED;
	} else {
		Com_Printf( "...attempting fullscreen: " );
        sdl_surface = SDL_SetVideoMode( width, height, bpp,
                flags | SDL_FULLSCREEN );
		if( sdl_surface == NULL ) {
			Com_Printf( "failed\n" );

			Com_Printf( "...falling back to windowed mode: " );
            sdl_surface = SDL_SetVideoMode( width, height, bpp, flags );
			if( sdl_surface  == NULL ) {
				Com_Printf( "failed\n" );
				Com_Printf( "SDL_GetError: %s\n", SDL_GetError() );
				return SETMODE_ERROR;
			}
			Com_Printf( "ok\n" );

			result = SETMODE_WINDOWED;
		} else {
			Com_Printf( "ok\n" );

			sdl_flags |= QVF_FULLSCREEN_ENABLED;
			result = SETMODE_FULLSCREEN;
		}
	}

	*rowbytes = sdl_surface->pitch;
	*buffer = ( byte * )sdl_surface->pixels;

	QSDL_PostCreateWindow();

	return result;

}

/*
============
Video_UpdatePalette
============
*/
static void QSDL_UpdatePalette( const byte *palette ) {
	SDL_Color	colors[256];
	SDL_Color	*dest;
	int		i;

	dest = colors;
	for( i = 0; i < 256; i++ ) {
		dest->r = palette[0];
		dest->g = palette[1];
		dest->b = palette[2];
		palette += 4; dest++;
	}

	SDL_SetPalette( sdl_surface, SDL_LOGPAL, colors, 0, 256 );
}

/*
============
Video_BeginFrameSoft
============
*/
static void QSDL_BeginFrameSoft( float stereo_separation ) {
	 SDL_LockSurface( sdl_surface );
}

/*
============
Video_EndFrameSoft
============
*/
static void QSDL_EndFrameSoft( byte **buffer, int *rowbytes ) {
	SDL_UnlockSurface( sdl_surface );
	SDL_Flip( sdl_surface );
//	SDL_UpdateRect( sdl_surface, 0, 0, 0, 0 );
}


/*
===============================================================================

SDL MOUSE DRIVER

===============================================================================
*/

#define SDL_FULLFOCUS  (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS)

static void QSDL_AcquireMouse( void ) {
	SDL_Surface *surface;
    uint32 state;

	/* move physical cursor at center of the
     * main window just before we grab the mouse */
	if( ( surface = SDL_GetVideoSurface() ) != NULL ) {
		SDL_WarpMouse( surface->w / 2, surface->h / 2 );
	}

	/* pump mouse motion events generated by SDL_WarpMouse,
     * this way SDL_APPMOUSEFOCUS gets set properly */
	SDL_PollEvent( NULL );

	/* grab the mouse, so SDL enters relative mouse mode */
	SDL_WM_GrabInput( SDL_GRAB_ON );
    state = SDL_GetAppState();
    if( ( state & SDL_FULLFOCUS ) != SDL_FULLFOCUS ) {
        Com_DPrintf( "QSDL_AcquireMouse: don't have full focus\n" );
    }
	SDL_ShowCursor( SDL_DISABLE );
	
	/* pump mouse motion events still pending */
	SDL_PollEvent( NULL );

	/* clear large deltas generated */
	SDL_GetRelativeMouseState( NULL, NULL );
}


static void QSDL_DeAcquireMouse( void ) {
	/* release the mouse */
	SDL_ShowCursor( SDL_ENABLE );
	SDL_WM_GrabInput( SDL_GRAB_OFF );
}

static void QSDL_SendMouseMoveEvents( void ) {
	int		dx, dy;

	if( !mouseinitialized ) {
		return;
	}

	if( !mouseactive ) {
		return;
	}

	SDL_GetRelativeMouseState( &dx, &dy );

	if( dx || dy ) {
	    CL_MouseEvent( dx, dy );
    }
}

static void QSDL_ShutdownMouse( void ) {
	QSDL_DeAcquireMouse();
	mouseactive = qfalse;
	mouseinitialized = qfalse;
}

static qboolean QSDL_InitMouse( void ) {
	if( SDL_WasInit( SDL_INIT_VIDEO ) != SDL_INIT_VIDEO ) {
		return qfalse;
	}

	mouseinitialized = qtrue;

	return qtrue;
}

static void QSDL_ActivateMouse( qboolean active ) {
	if( !mouseinitialized ) {
		return;
	}

	if( mouseactive == active ) {
		return;
	}

	if( active ) {
		QSDL_AcquireMouse();
	} else {
		QSDL_DeAcquireMouse();
	}

	mouseactive = active;

}

static void QSDL_ClearMouseStates( void ) {
	/* no work here */
}

void Video_FillGLAPI( vidGLAPI_t *api ) {
	api->Init = QSDL_InitGL;
	api->Shutdown = QSDL_ShutdownVideo;
	api->UpdateGamma = QSDL_UpdateGamma;
	api->GetFlags = QSDL_GetVideoFlags;
	api->SetMode = QSDL_SetModeGL;
	api->GetProcAddr = SDL_GL_GetProcAddress;
	api->BeginFrame = QSDL_BeginFrameGL;
	api->EndFrame = QSDL_EndFrameGL;
}

void Video_FillSWAPI( vidSWAPI_t *api ) {
	api->Init = QSDL_InitSoft;
	api->Shutdown = QSDL_ShutdownVideo;
	api->UpdateGamma = QSDL_UpdateGamma;
	api->GetFlags = QSDL_GetVideoFlags;
	api->SetMode = QSDL_SetModeSoft;
	api->UpdatePalette = QSDL_UpdatePalette;
	api->BeginFrame = QSDL_BeginFrameSoft;
	api->EndFrame = QSDL_EndFrameSoft;
}

/*
===================
Video_FillInputAPI
===================
*/
void Video_FillInputAPI( inputAPI_t *api ) {
	api->Init = QSDL_InitMouse;
	api->Shutdown = QSDL_ShutdownMouse;
	api->Activate = QSDL_ActivateMouse;
	api->Frame = QSDL_SendMouseMoveEvents;
	api->ClearStates = QSDL_ClearMouseStates;
}

