Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

glw_imp.c (21153B)


      1 /*
      2 ** GLW_IMP.C
      3 **
      4 ** This file contains ALL Linux specific stuff having to do with the
      5 ** OpenGL refresh.  When a port is being made the following functions
      6 ** must be implemented by the port:
      7 **
      8 ** GLimp_EndFrame
      9 ** GLimp_Init
     10 ** GLimp_Shutdown
     11 ** GLimp_SwitchFullscreen
     12 **
     13 */
     14 
     15 #include <signal.h>
     16 
     17 #include <X11/Xlib.h>
     18 #include <X11/Xutil.h>
     19 #include <X11/Xatom.h>
     20 #include <X11/keysym.h>
     21 #include <X11/extensions/XShm.h>
     22 #include <Xm/MwmUtil.h>
     23 
     24 #include <GL/glx.h>
     25 
     26 #include "../ref_gl/gl_local.h"
     27 #include "../client/keys.h"
     28 #include "../linux/rw_linux.h"
     29 
     30 GLXContext				gl_cx;
     31 
     32 static qboolean			doShm;
     33 static Display			*x_disp;
     34 static Colormap			x_cmap;
     35 static Window			x_win;
     36 static GC				x_gc;
     37 static Visual			*x_vis;
     38 static XVisualInfo		*x_visinfo;
     39 
     40 static int				StudlyRGBattributes[] =
     41 {
     42     GLX_DOUBLEBUFFER,
     43     GLX_RGBA,
     44     GLX_RED_SIZE, 4,
     45     GLX_GREEN_SIZE, 4,
     46     GLX_BLUE_SIZE, 4,
     47     GLX_DEPTH_SIZE, 1,
     48     GLX_SAMPLES_SGIS, 4, /* for better AA */
     49     None,
     50 };
     51 
     52 static int				RGBattributes[] =
     53 {
     54     GLX_DOUBLEBUFFER,
     55     GLX_RGBA,
     56     GLX_RED_SIZE, 4,
     57     GLX_GREEN_SIZE, 4,
     58     GLX_BLUE_SIZE, 4,
     59     GLX_DEPTH_SIZE, 1,
     60     None,
     61 };
     62 
     63 #define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
     64 	     | KeyReleaseMask | ExposureMask | PointerMotionMask | \
     65 	     ButtonPressMask | ButtonReleaseMask)
     66 
     67 int current_framebuffer;
     68 static int				x_shmeventtype;
     69 //static XShmSegmentInfo	x_shminfo;
     70 
     71 static qboolean			oktodraw = false;
     72 static qboolean			X11_active = false;
     73 
     74 struct
     75 {
     76 	int key;
     77 	int down;
     78 } keyq[64];
     79 int keyq_head=0;
     80 int keyq_tail=0;
     81 
     82 static int		mx, my;
     83 static int p_mouse_x, p_mouse_y;
     84 static cvar_t	*_windowed_mouse;
     85 
     86 static cvar_t *sensitivity;
     87 static cvar_t *lookstrafe;
     88 static cvar_t *m_side;
     89 static cvar_t *m_yaw;
     90 static cvar_t *m_pitch;
     91 static cvar_t *m_forward;
     92 static cvar_t *freelook;
     93 
     94 int config_notify=0;
     95 int config_notify_width;
     96 int config_notify_height;
     97 						      
     98 typedef unsigned short PIXEL;
     99 
    100 // Console variables that we need to access from this module
    101 
    102 /*****************************************************************************/
    103 /* MOUSE                                                                     */
    104 /*****************************************************************************/
    105 
    106 // this is inside the renderer shared lib, so these are called from vid_so
    107 
    108 static qboolean        mouse_avail;
    109 static int     mouse_buttonstate;
    110 static int     mouse_oldbuttonstate;
    111 static int   mouse_x, mouse_y;
    112 static int	old_mouse_x, old_mouse_y;
    113 static float old_windowed_mouse;
    114 static int p_mouse_x, p_mouse_y;
    115 
    116 static cvar_t	*_windowed_mouse;
    117 static cvar_t	*m_filter;
    118 static cvar_t	*in_mouse;
    119 
    120 static qboolean	mlooking;
    121 
    122 // state struct passed in Init
    123 static in_state_t	*in_state;
    124 
    125 int XShmQueryExtension(Display *);
    126 int XShmGetEventBase(Display *);
    127 
    128 static void signal_handler(int sig)
    129 {
    130 	fprintf(stderr, "Received signal %d, exiting...\n", sig);
    131 	GLimp_Shutdown();
    132 	_exit(0);
    133 }
    134 
    135 static void InitSig(void)
    136 {
    137         struct sigaction sa;
    138 	sigaction(SIGINT, 0, &sa);
    139 	sa.sa_handler = signal_handler;
    140 	sigaction(SIGINT, &sa, 0);
    141 	sigaction(SIGTERM, &sa, 0);
    142 }
    143 
    144 /*
    145 ** GLimp_SetMode
    146 */
    147 int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
    148 {
    149 	int width, height;
    150 	GLint attribs[32];
    151 
    152 	fprintf(stderr, "GLimp_SetMode\n");
    153 
    154 	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
    155 
    156 	ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
    157 
    158 	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
    159 	{
    160 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
    161 		return rserr_invalid_mode;
    162 	}
    163 
    164 	ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
    165 
    166 	// destroy the existing window
    167 	GLimp_Shutdown ();
    168 
    169 	*pwidth = width;
    170 	*pheight = height;
    171 
    172 	if ( !GLimp_InitGraphics( fullscreen ) ) {
    173 		// failed to set a valid mode in windowed mode
    174 		return rserr_invalid_mode;
    175 	}
    176 /* 	gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True ); */
    177 
    178 	// let the sound and input subsystems know about the new window
    179 	ri.Vid_NewWindow (width, height);
    180 
    181 	return rserr_ok;
    182 }
    183 
    184 /*
    185 ** GLimp_Shutdown
    186 **
    187 ** This routine does all OS specific shutdown procedures for the OpenGL
    188 ** subsystem.  Under OpenGL this means NULLing out the current DC and
    189 ** HGLRC, deleting the rendering context, and releasing the DC acquired
    190 ** for the window.  The state structure is also nulled out.
    191 **
    192 */
    193 void GLimp_Shutdown( void )
    194 {
    195 	fprintf(stderr, "GLimp_Shutdown\n");
    196 
    197 	if (!x_disp)
    198 	    return;
    199 
    200 	XSynchronize( x_disp, True );
    201 	XAutoRepeatOn(x_disp);
    202 	XCloseDisplay(x_disp);
    203 	x_disp = NULL;
    204 }
    205 
    206 /*
    207 ** GLimp_Init
    208 **
    209 ** This routine is responsible for initializing the OS specific portions
    210 ** of OpenGL.  
    211 */
    212 int GLimp_Init( void *hinstance, void *wndproc )
    213 {
    214 // catch signals so i can turn on auto-repeat and stuff
    215 	InitSig();
    216 
    217 	return true;
    218 }
    219 
    220 /*
    221 ** GLimp_BeginFrame
    222 */
    223 void GLimp_BeginFrame( float camera_seperation )
    224 {
    225 }
    226 
    227 /*
    228 ** GLimp_EndFrame
    229 ** 
    230 ** Responsible for doing a swapbuffers and possibly for other stuff
    231 ** as yet to be determined.  Probably better not to make this a GLimp
    232 ** function and instead do a call to GLimp_SwapBuffers.
    233 */
    234 void GLimp_EndFrame (void)
    235 {
    236 	glFlush();
    237 	glXSwapBuffers( x_disp, x_win );
    238 }
    239 
    240 /*
    241 ** GLimp_AppActivate
    242 */
    243 void GLimp_AppActivate( qboolean active )
    244 {
    245 }
    246 
    247 // ========================================================================
    248 // makes a null cursor
    249 // ========================================================================
    250 
    251 static Cursor CreateNullCursor(Display *display, Window root)
    252 {
    253     Pixmap cursormask; 
    254     XGCValues xgc;
    255     GC gc;
    256     XColor dummycolour;
    257     Cursor cursor;
    258 
    259     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
    260     xgc.function = GXclear;
    261     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
    262     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
    263     dummycolour.pixel = 0;
    264     dummycolour.red = 0;
    265     dummycolour.flags = 04;
    266     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
    267           &dummycolour,&dummycolour, 0,0);
    268     XFreePixmap(display,cursormask);
    269     XFreeGC(display,gc);
    270     return cursor;
    271 }
    272 
    273 /*
    274 ** GLimp_InitGraphics
    275 **
    276 ** This initializes the GL implementation specific
    277 ** graphics subsystem.
    278 **
    279 ** The necessary width and height parameters are grabbed from
    280 ** vid.width and vid.height.
    281 */
    282 qboolean GLimp_InitGraphics( qboolean fullscreen )
    283 {
    284 	int pnum, i;
    285 	XVisualInfo template;
    286 	int num_visuals;
    287 	int template_mask;
    288 
    289 	fprintf(stderr, "GLimp_InitGraphics\n");
    290 
    291 	srandom(getpid());
    292 
    293 	// let the sound and input subsystems know about the new window
    294 	ri.Vid_NewWindow (vid.width, vid.height);
    295 
    296 	// open the display
    297 	x_disp = XOpenDisplay(NULL);
    298 	if (!x_disp)
    299 	{
    300 		if (getenv("DISPLAY"))
    301 			Sys_Error("VID: Could not open display [%s]\n",
    302 				getenv("DISPLAY"));
    303 		else
    304 			Sys_Error("VID: Could not open local display\n");
    305 	}
    306 	else
    307 	    fprintf(stderr, "VID: Opened display %s\n", getenv("DISPLAY"));
    308 
    309 	XAutoRepeatOff(x_disp);
    310 
    311 // for debugging only
    312 	XSynchronize(x_disp, True);
    313 
    314 // check for command-line window size
    315 	template_mask = 0;
    316 
    317 #if 0
    318 // specify a visual id
    319 	if ((pnum=COM_CheckParm("-visualid")))
    320 	{
    321 		if (pnum >= com_argc-1)
    322 			Sys_Error("VID: -visualid <id#>\n");
    323 		template.visualid = Q_atoi(com_argv[pnum+1]);
    324 		template_mask = VisualIDMask;
    325 	}
    326 
    327 // If not specified, use default visual
    328 	else
    329 #endif
    330 	{
    331 		int screen;
    332 		screen = XDefaultScreen(x_disp);
    333 		template.visualid =
    334 			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
    335 		template_mask = VisualIDMask;
    336 	}
    337 
    338 // pick a visual- warn if more than one was available
    339 
    340 	x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
    341 				     StudlyRGBattributes );
    342 	if (!x_visinfo)
    343 	{
    344 	    fprintf(stderr, "Using non studly RGB attributes\n");
    345 		x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
    346 					     RGBattributes );
    347 		if (!x_visinfo) Sys_Error( "No matching visual available!\n" );
    348 	}
    349 
    350 	ri.Con_Printf(PRINT_ALL, "Using visualid 0x%x:\n",
    351 		   (int)(x_visinfo->visualid));
    352 #if 0
    353 	if (verbose)
    354 	{
    355 		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
    356 		printf("	screen %d\n", x_visinfo->screen);
    357 		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
    358 		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
    359 		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
    360 		printf("	colormap_size %d\n", x_visinfo->colormap_size);
    361 		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
    362 	}
    363 #endif
    364 
    365 	x_vis = x_visinfo->visual;
    366 
    367 // setup attributes for main window
    368 	{
    369 	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
    370 	   XSetWindowAttributes attribs;
    371 	   Colormap tmpcmap;
    372 	   
    373 	   Window root_win = XRootWindow(x_disp, x_visinfo->screen);
    374 
    375 	   tmpcmap = XCreateColormap(x_disp, root_win, x_vis, AllocNone);
    376 				     
    377 	   
    378 	   attribs.event_mask = STD_EVENT_MASK;
    379 	   attribs.border_pixel = 0;
    380 	   attribs.colormap = tmpcmap;
    381 
    382 // create the main window
    383 		x_win = XCreateWindow(	x_disp,
    384 			root_win,		
    385 			0, 0,	// x, y
    386 			vid.width, vid.height,
    387 			0, // borderwidth
    388 			x_visinfo->depth,
    389 			InputOutput,
    390 			x_vis,
    391 			attribmask,
    392 			&attribs );
    393 		XStoreName(x_disp, x_win, "Quake II");
    394 
    395 		if (x_visinfo->class != TrueColor)
    396 			XFreeColormap(x_disp, tmpcmap);
    397 	}
    398 
    399 	if (x_visinfo->depth == 8)
    400 	{
    401 	// create and upload the palette
    402 		if (x_visinfo->class == PseudoColor)
    403 		{
    404 			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
    405 			XSetWindowColormap(x_disp, x_win, x_cmap);
    406 		}
    407 
    408 	}
    409 
    410 // inviso cursor
    411 	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
    412 
    413 // create the GC
    414 	{
    415 		XGCValues xgcvalues;
    416 		int valuemask = GCGraphicsExposures;
    417 		xgcvalues.graphics_exposures = False;
    418 		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
    419 	}
    420 
    421 // set window properties for full screen
    422 	if (fullscreen) {
    423 	    MotifWmHints    wmhints;
    424 	    Atom aHints;
    425 	    XSizeHints              sizehints;
    426 	    XWindowChanges  changes;
    427 
    428 	    aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
    429 	    if (aHints == None)
    430 	    {
    431                 ri.Con_Printf( PRINT_ALL, "Could not intern X atom for _MOTIF_WM_HINTS." );
    432 /*                 return( false ); */
    433 	    }
    434 	    else {
    435 		wmhints.flags = MWM_HINTS_DECORATIONS;
    436 		wmhints.decorations = 0; // Absolutely no decorations.
    437 		XChangeProperty(x_disp, x_win, aHints, aHints, 32,
    438 				PropModeReplace, (unsigned char *)&wmhints,
    439 				4 );
    440 
    441 		sizehints.flags = USPosition | USSize;
    442 		sizehints.x = 0;
    443 		sizehints.y = 0;
    444 		sizehints.width = vid.width;
    445 		sizehints.height = vid.height;
    446 		XSetWMNormalHints( x_disp, x_win, &sizehints );
    447 
    448 		changes.x = 0;
    449 		changes.y = 0;
    450 		changes.width = vid.width;
    451 		changes.height = vid.height;
    452 		changes.stack_mode = TopIf;
    453 		XConfigureWindow(x_disp, x_win,
    454 				 CWX | CWY | CWWidth | CWHeight | CWStackMode,
    455 				 &changes);
    456 	    }
    457 	}
    458 
    459 // map the window
    460 	XMapWindow(x_disp, x_win);
    461 
    462 // wait for first exposure event
    463 	{
    464 		XEvent event;
    465 		do
    466 		{
    467 			XNextEvent(x_disp, &event);
    468 			if (event.type == Expose && !event.xexpose.count)
    469 				oktodraw = true;
    470 		} while (!oktodraw);
    471 	}
    472 // now safe to draw
    473 
    474     gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True );
    475     if (!glXMakeCurrent( x_disp, x_win, gl_cx ))
    476 		Sys_Error( "Can't make window current to context\n" );
    477 
    478 // even if MITSHM is available, make sure it's a local connection
    479 #if 0
    480 // This is messing up the DISPLAY environment variable so can't close and
    481 // reopen the window (it lops off the :0.0)...
    482 	if (XShmQueryExtension(x_disp))
    483 	{
    484 		char *displayname;
    485 		doShm = true;
    486 		displayname = (char *) getenv("DISPLAY");
    487 		if (displayname)
    488 		{
    489 			char *d = displayname;
    490 			while (*d && (*d != ':')) d++;
    491 			if (*d) *d = 0;
    492 			if (!(!strcasecmp(displayname, "unix") || !*displayname))
    493 				doShm = false;
    494 		}
    495 	}
    496 #endif
    497 
    498 #if 0
    499 	if (doShm)
    500 	{
    501 		x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
    502 		ResetSharedFrameBuffers();
    503 	}
    504 	else
    505 		ResetFrameBuffer();
    506 #endif
    507 
    508 	current_framebuffer = 0;
    509 /* 	vid.rowbytes = x_framebuffer[0]->bytes_per_line; */
    510 /* 	vid.buffer = x_framebuffer[0]->data; */
    511 
    512 //	XSynchronize(x_disp, False);
    513 
    514 	X11_active = true;
    515 
    516 	return true;
    517 }
    518 
    519 /*****************************************************************************/
    520 
    521 int XLateKey(XKeyEvent *ev)
    522 {
    523 
    524 	int key;
    525 	char buf[64];
    526 	KeySym keysym;
    527 
    528 	key = 0;
    529 
    530 	XLookupString(ev, buf, sizeof buf, &keysym, 0);
    531 
    532 	switch(keysym)
    533 	{
    534 		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
    535 		case XK_Page_Up:	 key = K_PGUP; break;
    536 
    537 		case XK_KP_Page_Down: key = K_KP_PGDN; break;
    538 		case XK_Page_Down:	 key = K_PGDN; break;
    539 
    540 		case XK_KP_Home: key = K_KP_HOME; break;
    541 		case XK_Home:	 key = K_HOME; break;
    542 
    543 		case XK_KP_End:  key = K_KP_END; break;
    544 		case XK_End:	 key = K_END; break;
    545 
    546 		case XK_KP_Left: key = K_KP_LEFTARROW; break;
    547 		case XK_Left:	 key = K_LEFTARROW; break;
    548 
    549 		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
    550 		case XK_Right:	key = K_RIGHTARROW;		break;
    551 
    552 		case XK_KP_Down: key = K_KP_DOWNARROW; break;
    553 		case XK_Down:	 key = K_DOWNARROW; break;
    554 
    555 		case XK_KP_Up:   key = K_KP_UPARROW; break;
    556 		case XK_Up:		 key = K_UPARROW;	 break;
    557 
    558 		case XK_Escape: key = K_ESCAPE;		break;
    559 
    560 		case XK_KP_Enter: key = K_KP_ENTER;	break;
    561 		case XK_Return: key = K_ENTER;		 break;
    562 
    563 		case XK_Tab:		key = K_TAB;			 break;
    564 
    565 		case XK_F1:		 key = K_F1;				break;
    566 
    567 		case XK_F2:		 key = K_F2;				break;
    568 
    569 		case XK_F3:		 key = K_F3;				break;
    570 
    571 		case XK_F4:		 key = K_F4;				break;
    572 
    573 		case XK_F5:		 key = K_F5;				break;
    574 
    575 		case XK_F6:		 key = K_F6;				break;
    576 
    577 		case XK_F7:		 key = K_F7;				break;
    578 
    579 		case XK_F8:		 key = K_F8;				break;
    580 
    581 		case XK_F9:		 key = K_F9;				break;
    582 
    583 		case XK_F10:		key = K_F10;			 break;
    584 
    585 		case XK_F11:		key = K_F11;			 break;
    586 
    587 		case XK_F12:		key = K_F12;			 break;
    588 
    589 		case XK_BackSpace: key = K_BACKSPACE; break;
    590 
    591 		case XK_KP_Delete: key = K_KP_DEL; break;
    592 		case XK_Delete: key = K_DEL; break;
    593 
    594 		case XK_Pause:	key = K_PAUSE;		 break;
    595 
    596 		case XK_Shift_L:
    597 		case XK_Shift_R:	key = K_SHIFT;		break;
    598 
    599 		case XK_Execute: 
    600 		case XK_Control_L: 
    601 		case XK_Control_R:	key = K_CTRL;		 break;
    602 
    603 		case XK_Alt_L:	
    604 		case XK_Meta_L: 
    605 		case XK_Alt_R:	
    606 		case XK_Meta_R: key = K_ALT;			break;
    607 
    608 		case XK_KP_Begin: key = K_KP_5;	break;
    609 
    610 		case XK_Insert:key = K_INS; break;
    611 		case XK_KP_Insert: key = K_KP_INS; break;
    612 
    613 		case XK_KP_Multiply: key = '*'; break;
    614 		case XK_KP_Add:  key = K_KP_PLUS; break;
    615 		case XK_KP_Subtract: key = K_KP_MINUS; break;
    616 		case XK_KP_Divide: key = K_KP_SLASH; break;
    617 
    618 #if 0
    619 		case 0x021: key = '1';break;/* [!] */
    620 		case 0x040: key = '2';break;/* [@] */
    621 		case 0x023: key = '3';break;/* [#] */
    622 		case 0x024: key = '4';break;/* [$] */
    623 		case 0x025: key = '5';break;/* [%] */
    624 		case 0x05e: key = '6';break;/* [^] */
    625 		case 0x026: key = '7';break;/* [&] */
    626 		case 0x02a: key = '8';break;/* [*] */
    627 		case 0x028: key = '9';;break;/* [(] */
    628 		case 0x029: key = '0';break;/* [)] */
    629 		case 0x05f: key = '-';break;/* [_] */
    630 		case 0x02b: key = '=';break;/* [+] */
    631 		case 0x07c: key = '\'';break;/* [|] */
    632 		case 0x07d: key = '[';break;/* [}] */
    633 		case 0x07b: key = ']';break;/* [{] */
    634 		case 0x022: key = '\'';break;/* ["] */
    635 		case 0x03a: key = ';';break;/* [:] */
    636 		case 0x03f: key = '/';break;/* [?] */
    637 		case 0x03e: key = '.';break;/* [>] */
    638 		case 0x03c: key = ',';break;/* [<] */
    639 #endif
    640 
    641 		default:
    642 			key = *(unsigned char*)buf;
    643 			if (key >= 'A' && key <= 'Z')
    644 				key = key - 'A' + 'a';
    645 			break;
    646 	} 
    647 
    648 	return key;
    649 }
    650 
    651 void GetEvent(void)
    652 {
    653 	XEvent x_event;
    654 	int b;
    655    
    656 	XNextEvent(x_disp, &x_event);
    657 	switch(x_event.type) {
    658 	case KeyPress:
    659 		keyq[keyq_head].key = XLateKey(&x_event.xkey);
    660 		keyq[keyq_head].down = true;
    661 		keyq_head = (keyq_head + 1) & 63;
    662 		break;
    663 	case KeyRelease:
    664 		keyq[keyq_head].key = XLateKey(&x_event.xkey);
    665 		keyq[keyq_head].down = false;
    666 		keyq_head = (keyq_head + 1) & 63;
    667 		break;
    668 
    669 	case MotionNotify:
    670 		if (_windowed_mouse->value) {
    671 			mx += ((int)x_event.xmotion.x - (int)(vid.width/2));
    672 			my += ((int)x_event.xmotion.y - (int)(vid.height/2));
    673 
    674 			/* move the mouse to the window center again */
    675 			XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
    676 			XWarpPointer(x_disp,None,x_win,0,0,0,0, 
    677 				(vid.width/2),(vid.height/2));
    678 			XSelectInput(x_disp,x_win, STD_EVENT_MASK);
    679 		} else {
    680 			mx = ((int)x_event.xmotion.x - (int)p_mouse_x);
    681 			my = ((int)x_event.xmotion.y - (int)p_mouse_y);
    682 			p_mouse_x=x_event.xmotion.x;
    683 			p_mouse_y=x_event.xmotion.y;
    684 		}
    685 		break;
    686 
    687 	case ButtonPress:
    688 		b=-1;
    689 		if (x_event.xbutton.button == 1)
    690 			b = 0;
    691 		else if (x_event.xbutton.button == 2)
    692 			b = 2;
    693 		else if (x_event.xbutton.button == 3)
    694 			b = 1;
    695 		if (b>=0)
    696 			mouse_buttonstate |= 1<<b;
    697 		break;
    698 
    699 	case ButtonRelease:
    700 		b=-1;
    701 		if (x_event.xbutton.button == 1)
    702 			b = 0;
    703 		else if (x_event.xbutton.button == 2)
    704 			b = 2;
    705 		else if (x_event.xbutton.button == 3)
    706 			b = 1;
    707 		if (b>=0)
    708 			mouse_buttonstate &= ~(1<<b);
    709 		break;
    710 	
    711 	case ConfigureNotify:
    712 		config_notify_width = x_event.xconfigure.width;
    713 		config_notify_height = x_event.xconfigure.height;
    714 		config_notify = 1;
    715 		break;
    716 
    717 	default:
    718 		if (doShm && x_event.type == x_shmeventtype)
    719 			oktodraw = true;
    720 	}
    721    
    722 	if (old_windowed_mouse != _windowed_mouse->value) {
    723 		old_windowed_mouse = _windowed_mouse->value;
    724 
    725 		if (!_windowed_mouse->value) {
    726 			/* ungrab the pointer */
    727 			XUngrabPointer(x_disp,CurrentTime);
    728 		} else {
    729 			/* grab the pointer */
    730 			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
    731 				GrabModeAsync,x_win,None,CurrentTime);
    732 		}
    733 	}
    734 }
    735 
    736 /*****************************************************************************/
    737 
    738 /*****************************************************************************/
    739 /* KEYBOARD                                                                  */
    740 /*****************************************************************************/
    741 
    742 Key_Event_fp_t Key_Event_fp;
    743 
    744 void KBD_Init(Key_Event_fp_t fp)
    745 {
    746 	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
    747 	Key_Event_fp = fp;
    748 }
    749 
    750 void KBD_Update(void)
    751 {
    752 // get events from x server
    753 	if (x_disp)
    754 	{
    755 		while (XPending(x_disp)) 
    756 			GetEvent();
    757 		while (keyq_head != keyq_tail)
    758 		{
    759 			Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
    760 			keyq_tail = (keyq_tail + 1) & 63;
    761 		}
    762 	}
    763 }
    764 
    765 void KBD_Close(void)
    766 {
    767 }
    768 
    769 
    770 static void Force_CenterView_f (void)
    771 {
    772 	in_state->viewangles[PITCH] = 0;
    773 }
    774 
    775 static void RW_IN_MLookDown (void) 
    776 { 
    777 	mlooking = true; 
    778 }
    779 
    780 static void RW_IN_MLookUp (void) 
    781 {
    782 	mlooking = false;
    783 	in_state->IN_CenterView_fp ();
    784 }
    785 
    786 void RW_IN_Init(in_state_t *in_state_p)
    787 {
    788 	int mtype;
    789 	int i;
    790 
    791 	fprintf(stderr, "GL RW_IN_Init\n");
    792 
    793 	in_state = in_state_p;
    794 
    795 	// mouse variables
    796 	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
    797 	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
    798     in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
    799 	freelook = ri.Cvar_Get( "freelook", "0", 0 );
    800 	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
    801 	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
    802 	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
    803 	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
    804 	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
    805 	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
    806 
    807 	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
    808 	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
    809 
    810 	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
    811 
    812 	mouse_x = mouse_y = 0.0;
    813 	mouse_avail = true;
    814 }
    815 
    816 void RW_IN_Shutdown(void)
    817 {
    818 	mouse_avail = false;
    819 
    820 	ri.Cmd_RemoveCommand ("force_centerview");
    821 	ri.Cmd_RemoveCommand ("+mlook");
    822 	ri.Cmd_RemoveCommand ("-mlook");
    823 }
    824 
    825 /*
    826 ===========
    827 IN_Commands
    828 ===========
    829 */
    830 void RW_IN_Commands (void)
    831 {
    832 	int i;
    833    
    834 	if (!mouse_avail) 
    835 		return;
    836    
    837 	for (i=0 ; i<3 ; i++) {
    838 		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
    839 			in_state->Key_Event_fp (K_MOUSE1 + i, true);
    840 
    841 		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
    842 			in_state->Key_Event_fp (K_MOUSE1 + i, false);
    843 	}
    844 	mouse_oldbuttonstate = mouse_buttonstate;
    845 }
    846 
    847 /*
    848 ===========
    849 IN_Move
    850 ===========
    851 */
    852 void RW_IN_Move (usercmd_t *cmd)
    853 {
    854 	if (!mouse_avail)
    855 		return;
    856    
    857 	if (m_filter->value)
    858 	{
    859 		mouse_x = (mx + old_mouse_x) * 0.5;
    860 		mouse_y = (my + old_mouse_y) * 0.5;
    861 	} else {
    862 		mouse_x = mx;
    863 		mouse_y = my;
    864 	}
    865 
    866 	old_mouse_x = mx;
    867 	old_mouse_y = my;
    868 
    869 	if (!mouse_x && !mouse_y)
    870 		return;
    871 
    872 	mouse_x *= sensitivity->value;
    873 	mouse_y *= sensitivity->value;
    874 
    875 // add mouse X/Y movement to cmd
    876 	if ( (*in_state->in_strafe_state & 1) || 
    877 		(lookstrafe->value && mlooking ))
    878 		cmd->sidemove += m_side->value * mouse_x;
    879 	else
    880 		in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
    881 
    882 	if ( (mlooking || freelook->value) && 
    883 		!(*in_state->in_strafe_state & 1))
    884 	{
    885 		in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
    886 	}
    887 	else
    888 	{
    889 		cmd->forwardmove -= m_forward->value * mouse_y;
    890 	}
    891 	mx = my = 0;
    892 }
    893 
    894 void RW_IN_Frame (void)
    895 {
    896 }
    897 
    898 void RW_IN_Activate(void)
    899 {
    900 }
    901 
    902 
    903 //===============================================================================
    904 
    905 /*
    906 ================
    907 Sys_MakeCodeWriteable
    908 ================
    909 */
    910 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
    911 {
    912 
    913 	int r;
    914 	unsigned long addr;
    915 	int psize = getpagesize();
    916 
    917 	addr = (startaddr & ~(psize-1)) - psize;
    918 
    919 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
    920 //			addr, startaddr+length, length);
    921 
    922 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
    923 
    924 	if (r < 0)
    925     		Sys_Error("Protection change failed\n");
    926 
    927 }