/*
Copyright (C) 1996-1997 Id Software, Inc.

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.

*/
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/vt.h>
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>

#include <dlfcn.h>

#include "quakedef.h"

#include <GL/glx.h>

#include <X11/Xatom.h> //Clipboard
#include <X11/keysym.h>
#include <X11/cursorfont.h>

#include <X11/extensions/xf86dga.h>
#include <X11/extensions/xf86vmode.h>

#define WARP_WIDTH              320
#define WARP_HEIGHT             200

static 	int (*qglXGetConfig) (Display *dpy, XVisualInfo *vis, int attrib, int *value);
static	Display		*dpy = NULL;
static	int		scrnum;
static	Window		win;
static	GLXContext	ctx = NULL;

#define KEY_MASK (KeyPressMask | KeyReleaseMask)
#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
		    PointerMotionMask | ButtonMotionMask )
#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
 
unsigned short	*currentgammaramp = NULL;
static unsigned	short systemgammaramp[3][256];

qboolean	vid_gammaworks = false;
qboolean	vid_hwgamma_enabled = false;
qboolean	customgamma = false;
qboolean 	fullsbardraw = false;
qboolean 	fullscreen = false;

static	qboolean mouse_avail;
static	qboolean mouse_active;
static	int	mx, my;
static	int	old_mouse_x, old_mouse_y;

cvar_t	vid_mode = {"vid_mode","0",false};
cvar_t	vid_hwgammacontrol = {"vid_hwgammacontrol", "1"};
static	cvar_t	in_mouse = {"in_mouse", "1", false};
static	cvar_t	in_dgamouse = {"in_dgamouse", "1", false};
static	cvar_t	m_filter = {"m_filter", "0"};
cvar_t	_vid_default_mode = {"_vid_default_mode","0", true};
// Note that 3 is MODE_FULLSCREEN_DEFAULT
cvar_t	_vid_default_mode_win = {"_vid_default_mode_win","3", true};
cvar_t	vid_wait = {"vid_wait","0"};
cvar_t	vid_nopageflip = {"vid_nopageflip","0", true};
cvar_t	_vid_wait_override = {"_vid_wait_override", "0", true};
cvar_t	vid_config_x = {"vid_config_x","800", true};
cvar_t	vid_config_y = {"vid_config_y","600", true};
cvar_t	vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
qboolean OnChange_windowed_mouse (cvar_t *var, char *value);
cvar_t	_windowed_mouse = {"_windowed_mouse", "1", false, false, OnChange_windowed_mouse};

qboolean dgamouse = false;
qboolean vidmode_ext = false;
qboolean stencildraw;

static	int	win_x, win_y;
static	int	scr_width, scr_height;

static	XF86VidModeModeInfo **vidmodes;
static	int		num_vidmodes;
static	qboolean	vidmode_active = false;
static 	Time 	 	myxtime; 	//Clipboard

//===========================================

void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
{
}

void D_EndDirectRect (int x, int y, int width, int height)
{
}

void VID_LockBuffer (void)
{
}

void VID_UnlockBuffer (void)
{
}

static int XLateKey(XKeyEvent *ev)
{
	int	key;
	char	buf[64];
	KeySym	keysym;

	key = 0;

	XLookupString (ev, buf, sizeof buf, &keysym, 0);

	switch (keysym)
	{
		case XK_KP_Page_Up:	 
		case XK_Page_Up:
			key = K_PGUP;
			break;

		case XK_KP_Page_Down: 
		case XK_Page_Down:
			key = K_PGDN;
			break;

		case XK_KP_Home: 
		case XK_Home:
			key = K_HOME;
			break;

		case XK_KP_End:  
		case XK_End:
			key = K_END;
			break;

		case XK_KP_Left: 
		case XK_Left:
			key = K_LEFTARROW;
			break;

		case XK_KP_Right: 
		case XK_Right:
			key = K_RIGHTARROW;
			break;

		case XK_KP_Down: 
		case XK_Down:
			key = K_DOWNARROW;
			break;

		case XK_KP_Up:   
		case XK_Up:
			key = K_UPARROW;
			break;

		case XK_Escape:
			key = K_ESCAPE;
			break;

		case XK_KP_Enter: 
		case XK_Return:
			key = K_ENTER;
			break;

		case XK_Tab:
			key = K_TAB;
			break;

		case XK_F1:
			key = K_F1;
			break;

		case XK_F2:
			key = K_F2;
			break;

		case XK_F3:
			key = K_F3;
			break;

		case XK_F4:
			key = K_F4;
			break;

		case XK_F5:
			key = K_F5;
			break;

		case XK_F6:
			key = K_F6;
			break;

		case XK_F7:
			key = K_F7;
			break;

		case XK_F8:
			key = K_F8;
			break;

		case XK_F9:
			key = K_F9;
			break;

		case XK_F10:
			key = K_F10;
			break;

		case XK_F11:
			key = K_F11;
			break;

		case XK_F12:
			key = K_F12;
			break;

		case XK_BackSpace:
			key = K_BACKSPACE;
			break;

		case XK_KP_Delete:
		case XK_Delete:
			key = K_DEL;
			break;

		case XK_Pause:
			key = K_PAUSE;
			break;

		case XK_Shift_L:
		case XK_Shift_R:
			key = K_SHIFT;
			break;

		case XK_Execute: 
		case XK_Control_L: 
		case XK_Control_R:
			key = K_CTRL;
			break;

		case XK_Alt_L:	
		case XK_Meta_L: 
		case XK_Alt_R:	
		case XK_Meta_R:
			key = K_ALT;
			break;

		case XK_KP_Begin:
			key = K_AUX30;
			break;

		case XK_Insert:
		case XK_KP_Insert:
			key = K_INS;
			break;

		case XK_KP_Multiply:
			key = '*';
			break;

		case XK_KP_Add:
			key = '+';
			break;

		case XK_KP_Subtract:
			key = '-';
			break;

		case XK_KP_Divide:
			key = '/';
			break;

#if 0
		case 0x021: key = '1';break;/* [!] */
		case 0x040: key = '2';break;/* [@] */
		case 0x023: key = '3';break;/* [#] */
		case 0x024: key = '4';break;/* [$] */
		case 0x025: key = '5';break;/* [%] */
		case 0x05e: key = '6';break;/* [^] */
		case 0x026: key = '7';break;/* [&] */
		case 0x02a: key = '8';break;/* [*] */
		case 0x028: key = '9';;break;/* [(] */
		case 0x029: key = '0';break;/* [)] */
		case 0x05f: key = '-';break;/* [_] */
		case 0x02b: key = '=';break;/* [+] */
		case 0x07c: key = '\'';break;/* [|] */
		case 0x07d: key = '[';break;/* [}] */
		case 0x07b: key = ']';break;/* [{] */
		case 0x022: key = '\'';break;/* ["] */
		case 0x03a: key = ';';break;/* [:] */
		case 0x03f: key = '/';break;/* [?] */
		case 0x03e: key = '.';break;/* [>] */
		case 0x03c: key = ',';break;/* [<] */
#endif

		default:
			key = *(unsigned char*)buf;
			if (key >= 'A' && key <= 'Z')
				key = key - 'A' + 'a';
			//Clipboard	
			if (key >= 1 && key <= 26)
				key = key + 'a' - 1;
			break;
	} 

	return key;
}

static Cursor CreateNullCursor (Display *display, Window root)
{
	Pixmap		cursormask; 
	XGCValues	xgc;
	GC		gc;
	XColor		dummycolour;
	Cursor		cursor;

	cursormask = XCreatePixmap (display, root, 1, 1, 1/*depth*/);
	xgc.function = GXclear;
	gc =  XCreateGC (display, cursormask, GCFunction, &xgc);
	XFillRectangle (display, cursormask, gc, 0, 0, 1, 1);
	dummycolour.pixel = 0;
	dummycolour.red = 0;
	dummycolour.flags = 04;
	cursor = XCreatePixmapCursor (display, cursormask, cursormask, &dummycolour, &dummycolour, 0, 0);
	XFreePixmap (display,cursormask);
	XFreeGC (display,gc);

	return cursor;
}

static void install_grabs (void)
{
// inviso cursor
	XDefineCursor (dpy, win, CreateNullCursor(dpy, win));

	XGrabPointer (dpy, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);

	if (in_dgamouse.value)
	{
		int	MajorVersion, MinorVersion;

		if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion))
		{
			// unable to query, probalby not supported
			Con_Printf ("Failed to detect XF86DGA Mouse\n");
			in_dgamouse.value = 0;
		}
		else
		{
			dgamouse = true;
			XF86DGADirectVideo (dpy, DefaultScreen(dpy), XF86DGADirectMouse);
			XWarpPointer (dpy, None, win, 0, 0, 0, 0, 0, 0);
		}
	}
	else
	{
		XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
	}

	XGrabKeyboard (dpy, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);

	mouse_active = true;

//	XSync(dpy, True);
}

static void uninstall_grabs (void)
{
	if (!dpy || !win)
		return;

	if (dgamouse)
	{
		dgamouse = false;
		XF86DGADirectVideo (dpy, DefaultScreen(dpy), 0);
	}

	XUngrabPointer (dpy, CurrentTime);
	XUngrabKeyboard (dpy, CurrentTime);

// inviso cursor
	XUndefineCursor (dpy, win);

	mouse_active = false;
}

qboolean OnChange_windowed_mouse (cvar_t *var, char *value)
{
	if (vidmode_active && !Q_atof(value))
	{
		Con_Printf ("Cannot turn %s off when using -fullscreen mode\n", var->name);
		return true;
	}

	return false;
}

static void HandleEvents(void)
{
	XEvent		event;
	int		b;
	qboolean	dowarp = false;
	int	mwx = vid.width/2;
	int	mwy = vid.height/2;

	if (!dpy)
		return;

	while (XPending(dpy))
	{
		XNextEvent (dpy, &event);

		switch (event.type)
		{
		case KeyPress:
		case KeyRelease:
			Key_Event (XLateKey(&event.xkey), event.type == KeyPress);
			break;

		case MotionNotify:
			if (mouse_active)
			{
				if (dgamouse)
				{
					mx += (event.xmotion.x + win_x) * 2;
					my += (event.xmotion.y + win_y) * 2;
				} 
				else 
				{
					mx += ((int)event.xmotion.x - mwx) * 2;
					my += ((int)event.xmotion.y - mwy) * 2;
					mwx = event.xmotion.x;
					mwy = event.xmotion.y;

					if (mx || my)
						dowarp = true;
				}
			}
			break;

		case ButtonPress:
		case ButtonRelease:
		switch (event.xbutton.button)
		{
		case 1:
			Key_Event (K_MOUSE1, event.type == ButtonPress);
			break;

		case 2:
			Key_Event (K_MOUSE3, event.type == ButtonPress);
			break;

		case 3:
			Key_Event (K_MOUSE2, event.type == ButtonPress);
			break;

		case 4:
			Key_Event (K_MWHEELUP, event.type == ButtonPress);
			break;

		case 5:
			Key_Event (K_MWHEELDOWN, event.type == ButtonPress);
			break;
		}
		break;
		case CreateNotify :
			win_x = event.xcreatewindow.x;
			win_y = event.xcreatewindow.y;
			break;

		case ConfigureNotify :
			win_x = event.xconfigure.x;
			win_y = event.xconfigure.y;
			break;
		}
	}

	if (dowarp)
	{
		/* move the mouse to the window center again */
		XWarpPointer (dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
	}

}

static void IN_DeactivateMouse (void)
{
	if (!mouse_avail || !dpy || !win)
		return;

	if (mouse_active)
	{
		uninstall_grabs ();
		mouse_active = false;
	}
}

static void IN_ActivateMouse (void)
{
	if (!mouse_avail || !dpy || !win)
		return;

	if (!mouse_active)
	{
		mx = my = 0;		// don't spazz
		install_grabs ();
		mouse_active = true;
	}
}


void RestoreHWGamma (void)
{
	if (vid_gammaworks && customgamma)
	{
		customgamma = false;
		XF86VidModeSetGammaRamp (dpy, scrnum, 256, systemgammaramp[0], systemgammaramp[1], systemgammaramp[2]);
	}
}

void VID_Shutdown (void)
{
	if (!ctx || !dpy)
		return;

	IN_DeactivateMouse ();

	RestoreHWGamma ();
	
	if (dpy)
	{
		if (ctx)
			glXDestroyContext (dpy, ctx);
		if (win)
			XDestroyWindow (dpy, win);
		if (vidmode_active)
			XF86VidModeSwitchToMode (dpy, scrnum, vidmodes[0]);
		XCloseDisplay (dpy);
	}
	vidmode_active = false;
	dpy = NULL;
	win = 0;
	ctx = NULL;
}

void signal_handler (int sig)
{
	printf ("Received signal %d, exiting...\n", sig);
	Sys_Quit ();
	exit (0);
}

void InitSig (void)
{
	signal (SIGHUP, signal_handler);
	signal (SIGINT, signal_handler);
	signal (SIGQUIT, signal_handler);
	signal (SIGILL, signal_handler);
	signal (SIGTRAP, signal_handler);
	signal (SIGIOT, signal_handler);
	signal (SIGBUS, signal_handler);
	signal (SIGFPE, signal_handler);
	signal (SIGSEGV, signal_handler);
	signal (SIGTERM, signal_handler);
}

void VID_ShiftPalette (unsigned char *p)
{
//	VID_SetPalette(p);
}

void InitHWGamma (void)
{
	int	xf86vm_gammaramp_size;

	if (COM_CheckParm("-nohwgamma"))
		return;

	XF86VidModeGetGammaRampSize (dpy, scrnum, &xf86vm_gammaramp_size);
	
	vid_gammaworks = (xf86vm_gammaramp_size == 256);

	if (vid_gammaworks)
	{
		XF86VidModeGetGammaRamp (dpy,scrnum,xf86vm_gammaramp_size,
			systemgammaramp[0], systemgammaramp[1], systemgammaramp[2]);
	}

	vid_hwgamma_enabled = vid_hwgammacontrol.value && vid_gammaworks;
}

void VID_SetDeviceGammaRamp (unsigned short *ramps)
{
	if (vid_gammaworks)
	{
		currentgammaramp = ramps;
		if (vid_hwgamma_enabled)
		{
			XF86VidModeSetGammaRamp (dpy, scrnum, 256, ramps, ramps + 256, ramps + 512);
			customgamma = true;
		}
	}
}

/*
=================
GL_BeginRendering
=================
*/
void GL_BeginRendering (int *x, int *y, int *width, int *height)
{
	*x = *y = 0;
	*width = scr_width;
	*height = scr_height;
}

/*
=================
GL_EndRendering
=================
*/
void GL_EndRendering (void)
{
	static	qboolean old_hwgamma_enabled;

	vid_hwgamma_enabled = vid_hwgammacontrol.value && vid_gammaworks;
	if (vid_hwgamma_enabled != old_hwgamma_enabled)
	{
		old_hwgamma_enabled = vid_hwgamma_enabled;
		if (vid_hwgamma_enabled && currentgammaramp)
			VID_SetDeviceGammaRamp (currentgammaramp);
		/*else
			RestoreHWGamma ();*/
	}

	glFlush ();
	glXSwapBuffers (dpy, win);
	
	if (fullsbardraw)
		Sbar_Changed ();
}

void VID_Init (unsigned char *palette)
{
	int	i;
	int	attrib[] = {
		GLX_RGBA,
		GLX_RED_SIZE, 1,
		GLX_GREEN_SIZE, 1,
		GLX_BLUE_SIZE, 1,
		GLX_DOUBLEBUFFER,
		GLX_DEPTH_SIZE, 1,
		GLX_STENCIL_SIZE, 1,
		None
	};
	int	width = 800, height = 600;
	XSetWindowAttributes	attr;
	unsigned long		mask;
	Window		root;
	XVisualInfo	*visinfo;
	qboolean	fullscreen = true;
	int		MajorVersion, MinorVersion;
	int		actualWidth, actualHeight;

	Cvar_RegisterVariable (&vid_mode);
	Cvar_RegisterVariable (&vid_hwgammacontrol);
	Cvar_RegisterVariable (&in_mouse);
	Cvar_RegisterVariable (&in_dgamouse);
	Cvar_RegisterVariable (&m_filter);
	Cvar_RegisterVariable (&vid_wait);
	Cvar_RegisterVariable (&vid_nopageflip);
	Cvar_RegisterVariable (&_vid_wait_override);
	Cvar_RegisterVariable (&_vid_default_mode);
	Cvar_RegisterVariable (&_vid_default_mode_win);
	Cvar_RegisterVariable (&vid_config_x);
	Cvar_RegisterVariable (&vid_config_y);
	Cvar_RegisterVariable (&vid_stretch_by_2);
	
	vid.maxwarpwidth = WARP_WIDTH;
	vid.maxwarpheight = WARP_HEIGHT;
	vid.colormap = host_colormap;
	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));

// interpret command-line params

// set vid parameters
	if ((i = COM_CheckParm("-window")) != 0)
		fullscreen = false;

	if ((i = COM_CheckParm("-width")) != 0)
		width = atoi(com_argv[i+1]);

	if ((i = COM_CheckParm("-height")) != 0)
		height = atoi(com_argv[i+1]);

	if ((i = COM_CheckParm("-conwidth")) != 0)
		vid.conwidth = Q_atoi(com_argv[i+1]);
	else
		vid.conwidth = 640;

	vid.conwidth &= 0xfff8; // make it a multiple of eight

	if (vid.conwidth < 320)
		vid.conwidth = 320;

	// pick a conheight that matches with correct aspect
	vid.conheight = vid.conwidth*3 / 4;

	if ((i = COM_CheckParm("-conheight")) != 0)
		vid.conheight = Q_atoi(com_argv[i+1]);
	if (vid.conheight < 200)
		vid.conheight = 200;

	if (!(dpy = XOpenDisplay(NULL)))
	{
		fprintf (stderr, "Error couldn't open the X display\n");
		exit (1);
	}

	scrnum = DefaultScreen(dpy);
	root = RootWindow(dpy, scrnum);

	// Get video mode list
	MajorVersion = MinorVersion = 0;
	if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion))
		vidmode_ext = false;
	else
	{
		Con_Printf ("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
		vidmode_ext = true;
	}

	if (!(visinfo = glXChooseVisual(dpy, scrnum, attrib)))
	{
		fprintf (stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
		exit (1);
	}

	if (vidmode_ext)
	{
		int	best_fit, best_dist, dist, x, y;
		
		XF86VidModeGetAllModeLines (dpy, scrnum, &num_vidmodes, &vidmodes);

		// Are we going fullscreen?  If so, let's change video mode
		if (fullscreen)
		{
			best_dist = 9999999;
			best_fit = -1;

			for (i=0 ; i<num_vidmodes ; i++)
			{
				if (width > vidmodes[i]->hdisplay || height > vidmodes[i]->vdisplay)
					continue;

				x = width - vidmodes[i]->hdisplay;
				y = height - vidmodes[i]->vdisplay;
				dist = (x * x) + (y * y);
				if (dist < best_dist)
				{
					best_dist = dist;
					best_fit = i;
				}
			}

			if (best_fit != -1)
			{
				actualWidth = vidmodes[best_fit]->hdisplay;
				actualHeight = vidmodes[best_fit]->vdisplay;

				// change to the mode
				XF86VidModeSwitchToMode (dpy, scrnum, vidmodes[best_fit]);
				vidmode_active = true;

				// Move the viewport to top left
				XF86VidModeSetViewPort (dpy, scrnum, 0, 0);
			}
			else
				fullscreen = 0;
		}
	}


	/* stencilbuffer shadows */
	if ( qglXGetConfig )
	{
		int stencil_bits;

		if (!qglXGetConfig(dpy, visinfo, GLX_STENCIL_SIZE, &stencil_bits)) {
		Con_Printf("Stencil Buffer Created with %d Bits \n", stencil_bits );
			if (stencil_bits >= 1) {
				stencildraw = true;
			}
		}
	} else {
		stencildraw = false;
	}
	
	/* window attributes */
	attr.background_pixel = 0;
	attr.border_pixel = 0;
	attr.colormap = XCreateColormap (dpy, root, visinfo->visual, AllocNone);
	attr.event_mask = X_MASK;
	if (vidmode_active)
	{
		mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | 
			CWEventMask | CWOverrideRedirect;
		attr.override_redirect = True;
		attr.backing_store = NotUseful;
		attr.save_under = False;
	}
	else
		mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;

	win = XCreateWindow (dpy, root, 0, 0, width, height, 0, visinfo->depth,
					InputOutput, visinfo->visual, mask, &attr);
	XStoreName(dpy, win, "DemonQuake 0.16");
	XMapWindow (dpy, win);

	if (vidmode_active)
	{
		XMoveWindow (dpy, win, 0, 0);
		XRaiseWindow (dpy, win);
		XWarpPointer (dpy, None, win, 0, 0, 0, 0, 0, 0);
		XFlush (dpy);
		// Move the viewport to top left
		XF86VidModeSetViewPort (dpy, scrnum, 0, 0);
	}

	XFlush (dpy);

	ctx = glXCreateContext (dpy, visinfo, NULL, True);

	glXMakeCurrent (dpy, win, ctx);

	scr_width = width;
	scr_height = height;

	if (vid.conheight > height)
		vid.conheight = height;
	if (vid.conwidth > width)
		vid.conwidth = width;
	vid.width = vid.conwidth;
	vid.height = vid.conheight;

	vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
	vid.numpages = 2;

	InitSig (); // trap evil signals

	VID_InitGL ();

	VID_CheckGamma (palette);
	VID_SetPalette (palette);

	InitHWGamma ();
	
	Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);

	vid.recalc_refdef = 1;				// force a surface cache flush
	
	if (COM_CheckParm("-fullsbar"))
		fullsbardraw = true;
		
	mouse_avail= true;
}

void Sys_SendKeyEvents (void)
{
	HandleEvents ();
}

void Force_CenterView_f (void)
{
	cl.viewangles[PITCH] = 0;
}

void IN_Init (void)
{
}

void IN_Shutdown (void)
{
}

/*
===========
IN_Commands
===========
*/
void IN_Commands (void)
{
	if (!dpy || !win)
		return;

	if (vidmode_active || key_dest == key_game)
		IN_ActivateMouse();
	else
		IN_DeactivateMouse ();
}

/*
===========
IN_Move
===========
*/
void IN_MouseMove (usercmd_t *cmd)
{
	if (!mouse_avail)
		return;
   
	if (m_filter.value)
	{
		mx = (mx + old_mouse_x) * 0.5;
		my = (my + old_mouse_y) * 0.5;
	}
	old_mouse_x = mx;
	old_mouse_y = my;

	mx *= sensitivity.value;
	my *= sensitivity.value;

// add mouse X/Y movement to cmd
	if ((in_strafe.state & 1) || (lookstrafe.value && (mouselook.value)))
		cmd->sidemove += m_side.value * mx;
	else
		cl.viewangles[YAW] -= m_yaw.value * mx;
	
	if (mouselook.value)
		V_StopPitchDrift ();
		
	if ((mouselook.value) && !(in_strafe.state & 1))
	{
		cl.viewangles[PITCH] += m_pitch.value * my;
		cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80);
	}
	else
	{
		if ((in_strafe.state & 1) && noclip_anglehack)
			cmd->upmove -= m_forward.value * my;
		else
			cmd->forwardmove -= m_forward.value * my;
	}
	mx = my = 0;
}

void IN_Move (usercmd_t *cmd)
{
	IN_MouseMove (cmd);
}

//Clipboard function, thx quake2 icculus
char *Sys_GetClipboardData()
{
	Window sowner;
	Atom type, property;
	unsigned long len, bytes_left, tmp;
	unsigned char *data;
	int format, result;
	char *ret = NULL;
			
	sowner = XGetSelectionOwner(dpy, XA_PRIMARY);
			
	if (sowner != None) {
		property = XInternAtom(dpy,
				       "GETCLIPBOARDDATA_PROP",
				       False);
				
		XConvertSelection(dpy,
				  XA_PRIMARY, XA_STRING,
				  property, win, myxtime);
		XFlush(dpy);

		XGetWindowProperty(dpy,
				   win, property,
				   0, 0, False, AnyPropertyType,
				   &type, &format, &len,
				   &bytes_left, &data);
		if (bytes_left > 0) {
			result =
			XGetWindowProperty(dpy,
					   win, property,
					   0, bytes_left, True, AnyPropertyType,
					   &type, &format, &len,
					   &tmp, &data);
			if (result == Success) {
				ret = strdup(data);
			}
			XFree(data);
		}
	}
	return ret;
}


