Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

rw_x11.c (25093B)


      1 /*
      2 ** RW_X11.C
      3 **
      4 ** This file contains ALL Linux specific stuff having to do with the
      5 ** software refresh.  When a port is being made the following functions
      6 ** must be implemented by the port:
      7 **
      8 ** SWimp_EndFrame
      9 ** SWimp_Init
     10 ** SWimp_InitGraphics
     11 ** SWimp_SetPalette
     12 ** SWimp_Shutdown
     13 ** SWimp_SwitchFullscreen
     14 */
     15 
     16 #include <ctype.h>
     17 #include <sys/time.h>
     18 #include <sys/types.h>
     19 #include <unistd.h>
     20 #include <signal.h>
     21 #include <stdlib.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <sys/ipc.h>
     25 #include <sys/shm.h>
     26 
     27 #include <X11/Xlib.h>
     28 #include <X11/Xutil.h>
     29 #include <X11/Xatom.h>
     30 #include <X11/keysym.h>
     31 #include <X11/extensions/XShm.h>
     32 
     33 #include "../ref_soft/r_local.h"
     34 #include "../client/keys.h"
     35 #include "../linux/rw_linux.h"
     36 
     37 /*****************************************************************************/
     38 
     39 static qboolean			doShm;
     40 static Display			*x_disp;
     41 static Colormap			x_cmap;
     42 static Window			x_win;
     43 static GC				x_gc;
     44 static Visual			*x_vis;
     45 static XVisualInfo		*x_visinfo;
     46 //static XImage			*x_image;
     47 
     48 #define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
     49 	     | KeyReleaseMask | ExposureMask | PointerMotionMask | \
     50 	     ButtonPressMask | ButtonReleaseMask)
     51 
     52 static int				x_shmeventtype;
     53 //static XShmSegmentInfo	x_shminfo;
     54 
     55 static qboolean			oktodraw = false;
     56 static qboolean			X11_active = false;
     57 
     58 int XShmQueryExtension(Display *);
     59 int XShmGetEventBase(Display *);
     60 
     61 int current_framebuffer;
     62 static XImage			*x_framebuffer[2] = { 0, 0 };
     63 static XShmSegmentInfo	x_shminfo[2];
     64 
     65 struct
     66 {
     67 	int key;
     68 	int down;
     69 } keyq[64];
     70 int keyq_head=0;
     71 int keyq_tail=0;
     72 
     73 int config_notify=0;
     74 int config_notify_width;
     75 int config_notify_height;
     76 						      
     77 typedef unsigned short PIXEL;
     78 
     79 // Console variables that we need to access from this module
     80 
     81 /*****************************************************************************/
     82 /* MOUSE                                                                     */
     83 /*****************************************************************************/
     84 
     85 // this is inside the renderer shared lib, so these are called from vid_so
     86 
     87 static qboolean        mouse_avail;
     88 static int     mouse_buttonstate;
     89 static int     mouse_oldbuttonstate;
     90 static int   mouse_x, mouse_y;
     91 static int	old_mouse_x, old_mouse_y;
     92 static int		mx, my;
     93 static float old_windowed_mouse;
     94 static int p_mouse_x, p_mouse_y;
     95 
     96 static cvar_t	*_windowed_mouse;
     97 static cvar_t	*m_filter;
     98 static cvar_t	*in_mouse;
     99 
    100 static qboolean	mlooking;
    101 
    102 // state struct passed in Init
    103 static in_state_t	*in_state;
    104 
    105 static cvar_t *sensitivity;
    106 static cvar_t *lookstrafe;
    107 static cvar_t *m_side;
    108 static cvar_t *m_yaw;
    109 static cvar_t *m_pitch;
    110 static cvar_t *m_forward;
    111 static cvar_t *freelook;
    112 
    113 static void Force_CenterView_f (void)
    114 {
    115 	in_state->viewangles[PITCH] = 0;
    116 }
    117 
    118 static void RW_IN_MLookDown (void) 
    119 { 
    120 	mlooking = true; 
    121 }
    122 
    123 static void RW_IN_MLookUp (void) 
    124 {
    125 	mlooking = false;
    126 	in_state->IN_CenterView_fp ();
    127 }
    128 
    129 void RW_IN_Init(in_state_t *in_state_p)
    130 {
    131 	int mtype;
    132 	int i;
    133 
    134 	in_state = in_state_p;
    135 
    136 	// mouse variables
    137 	_windowed_mouse = ri.Cvar_Get ("_windowed_mouse", "0", CVAR_ARCHIVE);
    138 	m_filter = ri.Cvar_Get ("m_filter", "0", 0);
    139     in_mouse = ri.Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
    140 	freelook = ri.Cvar_Get( "freelook", "0", 0 );
    141 	lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
    142 	sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
    143 	m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
    144 	m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
    145 	m_forward = ri.Cvar_Get ("m_forward", "1", 0);
    146 	m_side = ri.Cvar_Get ("m_side", "0.8", 0);
    147 
    148 	ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
    149 	ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
    150 
    151 	ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
    152 
    153 	mouse_x = mouse_y = 0.0;
    154 	mouse_avail = true;
    155 }
    156 
    157 void RW_IN_Shutdown(void)
    158 {
    159 	mouse_avail = false;
    160 }
    161 
    162 /*
    163 ===========
    164 IN_Commands
    165 ===========
    166 */
    167 void RW_IN_Commands (void)
    168 {
    169 	int i;
    170    
    171 	if (!mouse_avail) 
    172 		return;
    173    
    174 	for (i=0 ; i<3 ; i++) {
    175 		if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
    176 			in_state->Key_Event_fp (K_MOUSE1 + i, true);
    177 
    178 		if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
    179 			in_state->Key_Event_fp (K_MOUSE1 + i, false);
    180 	}
    181 	mouse_oldbuttonstate = mouse_buttonstate;
    182 }
    183 
    184 /*
    185 ===========
    186 IN_Move
    187 ===========
    188 */
    189 void RW_IN_Move (usercmd_t *cmd)
    190 {
    191 	if (!mouse_avail)
    192 		return;
    193    
    194 	if (m_filter->value)
    195 	{
    196 		mouse_x = (mx + old_mouse_x) * 0.5;
    197 		mouse_y = (my + old_mouse_y) * 0.5;
    198 	} else {
    199 		mouse_x = mx;
    200 		mouse_y = my;
    201 	}
    202 
    203 	old_mouse_x = mx;
    204 	old_mouse_y = my;
    205 
    206 	if (!mouse_x && !mouse_y)
    207 		return;
    208 
    209 	mouse_x *= sensitivity->value;
    210 	mouse_y *= sensitivity->value;
    211 
    212 // add mouse X/Y movement to cmd
    213 	if ( (*in_state->in_strafe_state & 1) || 
    214 		(lookstrafe->value && mlooking ))
    215 		cmd->sidemove += m_side->value * mouse_x;
    216 	else
    217 		in_state->viewangles[YAW] -= m_yaw->value * mouse_x;
    218 
    219 	if ( (mlooking || freelook->value) && 
    220 		!(*in_state->in_strafe_state & 1))
    221 	{
    222 		in_state->viewangles[PITCH] += m_pitch->value * mouse_y;
    223 	}
    224 	else
    225 	{
    226 		cmd->forwardmove -= m_forward->value * mouse_y;
    227 	}
    228 	mx = my = 0;
    229 }
    230 
    231 void RW_IN_Frame (void)
    232 {
    233 }
    234 
    235 void RW_IN_Activate(void)
    236 {
    237 }
    238 
    239 /*****************************************************************************/
    240 
    241 static PIXEL st2d_8to16table[256];
    242 static int shiftmask_fl=0;
    243 static long r_shift,g_shift,b_shift;
    244 static unsigned long r_mask,g_mask,b_mask;
    245 
    246 void shiftmask_init()
    247 {
    248     unsigned int x;
    249     r_mask=x_vis->red_mask;
    250     g_mask=x_vis->green_mask;
    251     b_mask=x_vis->blue_mask;
    252     for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
    253     for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
    254     for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
    255     shiftmask_fl=1;
    256 }
    257 
    258 PIXEL xlib_rgb(int r,int g,int b)
    259 {
    260     PIXEL p;
    261     if(shiftmask_fl==0) shiftmask_init();
    262     p=0;
    263 
    264     if(r_shift>0) {
    265         p=(r<<(r_shift))&r_mask;
    266     } else if(r_shift<0) {
    267         p=(r>>(-r_shift))&r_mask;
    268     } else p|=(r&r_mask);
    269 
    270     if(g_shift>0) {
    271         p|=(g<<(g_shift))&g_mask;
    272     } else if(g_shift<0) {
    273         p|=(g>>(-g_shift))&g_mask;
    274     } else p|=(g&g_mask);
    275 
    276     if(b_shift>0) {
    277         p|=(b<<(b_shift))&b_mask;
    278     } else if(b_shift<0) {
    279         p|=(b>>(-b_shift))&b_mask;
    280     } else p|=(b&b_mask);
    281 
    282     return p;
    283 }
    284 
    285 void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
    286 {
    287 	int xi,yi;
    288 	unsigned char *src;
    289 	PIXEL *dest;
    290 
    291 	if( (x<0)||(y<0) )return;
    292 
    293 	for (yi = y; yi < (y+height); yi++) {
    294 		src = &framebuf->data [yi * framebuf->bytes_per_line];
    295 		dest = (PIXEL*)src;
    296 		for(xi = (x+width-1); xi >= x; xi -= 8) {
    297 			dest[xi  ] = st2d_8to16table[src[xi  ]];
    298 			dest[xi-1] = st2d_8to16table[src[xi-1]];
    299 			dest[xi-2] = st2d_8to16table[src[xi-2]];
    300 			dest[xi-3] = st2d_8to16table[src[xi-3]];
    301 			dest[xi-4] = st2d_8to16table[src[xi-4]];
    302 			dest[xi-5] = st2d_8to16table[src[xi-5]];
    303 			dest[xi-6] = st2d_8to16table[src[xi-6]];
    304 			dest[xi-7] = st2d_8to16table[src[xi-7]];
    305 		}
    306 	}
    307 }
    308 
    309 // ========================================================================
    310 // makes a null cursor
    311 // ========================================================================
    312 
    313 static Cursor CreateNullCursor(Display *display, Window root)
    314 {
    315     Pixmap cursormask; 
    316     XGCValues xgc;
    317     GC gc;
    318     XColor dummycolour;
    319     Cursor cursor;
    320 
    321     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
    322     xgc.function = GXclear;
    323     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
    324     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
    325     dummycolour.pixel = 0;
    326     dummycolour.red = 0;
    327     dummycolour.flags = 04;
    328     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
    329           &dummycolour,&dummycolour, 0,0);
    330     XFreePixmap(display,cursormask);
    331     XFreeGC(display,gc);
    332     return cursor;
    333 }
    334 
    335 void ResetFrameBuffer(void)
    336 {
    337 	int mem;
    338 	int pwidth;
    339 
    340 	if (x_framebuffer[0])
    341 	{
    342 		free(x_framebuffer[0]->data);
    343 		free(x_framebuffer[0]);
    344 	}
    345 
    346 // alloc an extra line in case we want to wrap, and allocate the z-buffer
    347 	pwidth = x_visinfo->depth / 8;
    348 	if (pwidth == 3) pwidth = 4;
    349 	mem = ((vid.width*pwidth+7)&~7) * vid.height;
    350 
    351 	x_framebuffer[0] = XCreateImage(	x_disp,
    352 		x_vis,
    353 		x_visinfo->depth,
    354 		ZPixmap,
    355 		0,
    356 		malloc(mem),
    357 		vid.width, vid.height,
    358 		32,
    359 		0);
    360 
    361 	if (!x_framebuffer[0])
    362 		Sys_Error("VID: XCreateImage failed\n");
    363 
    364 	vid.buffer = (byte*) (x_framebuffer[0]);
    365 }
    366 
    367 void ResetSharedFrameBuffers(void)
    368 {
    369 	int size;
    370 	int key;
    371 	int minsize = getpagesize();
    372 	int frm;
    373 
    374 	for (frm=0 ; frm<2 ; frm++)
    375 	{
    376 	// free up old frame buffer memory
    377 		if (x_framebuffer[frm])
    378 		{
    379 			XShmDetach(x_disp, &x_shminfo[frm]);
    380 			free(x_framebuffer[frm]);
    381 			shmdt(x_shminfo[frm].shmaddr);
    382 		}
    383 
    384 	// create the image
    385 		x_framebuffer[frm] = XShmCreateImage(	x_disp,
    386 						x_vis,
    387 						x_visinfo->depth,
    388 						ZPixmap,
    389 						0,
    390 						&x_shminfo[frm],
    391 						vid.width,
    392 						vid.height );
    393 
    394 	// grab shared memory
    395 
    396 		size = x_framebuffer[frm]->bytes_per_line
    397 			* x_framebuffer[frm]->height;
    398 		if (size < minsize)
    399 			Sys_Error("VID: Window must use at least %d bytes\n", minsize);
    400 
    401 		key = random();
    402 		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
    403 		if (x_shminfo[frm].shmid==-1)
    404 			Sys_Error("VID: Could not get any shared memory\n");
    405 
    406 		// attach to the shared memory segment
    407 		x_shminfo[frm].shmaddr =
    408 			(void *) shmat(x_shminfo[frm].shmid, 0, 0);
    409 
    410 		ri.Con_Printf(PRINT_ALL, 
    411 			"MITSHM shared memory (id=%d, addr=0x%lx)\n", 
    412 			x_shminfo[frm].shmid,
    413 			(long) x_shminfo[frm].shmaddr);
    414 
    415 		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
    416 
    417 	// get the X server to attach to it
    418 
    419 		if (!XShmAttach(x_disp, &x_shminfo[frm]))
    420 			Sys_Error("VID: XShmAttach() failed\n");
    421 		XSync(x_disp, 0);
    422 		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
    423 	}
    424 
    425 }
    426 
    427 // ========================================================================
    428 // Tragic death handler
    429 // ========================================================================
    430 
    431 void TragicDeath(int signal_num)
    432 {
    433 	XAutoRepeatOn(x_disp);
    434 	XCloseDisplay(x_disp);
    435 	Sys_Error("This death brought to you by the number %d\n", signal_num);
    436 }
    437 
    438 int XLateKey(XKeyEvent *ev)
    439 {
    440 
    441 	int key;
    442 	char buf[64];
    443 	KeySym keysym;
    444 
    445 	key = 0;
    446 
    447 	XLookupString(ev, buf, sizeof buf, &keysym, 0);
    448 
    449 	switch(keysym)
    450 	{
    451 		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
    452 		case XK_Page_Up:	 key = K_PGUP; break;
    453 
    454 		case XK_KP_Page_Down: key = K_KP_PGDN; break;
    455 		case XK_Page_Down:	 key = K_PGDN; break;
    456 
    457 		case XK_KP_Home: key = K_KP_HOME; break;
    458 		case XK_Home:	 key = K_HOME; break;
    459 
    460 		case XK_KP_End:  key = K_KP_END; break;
    461 		case XK_End:	 key = K_END; break;
    462 
    463 		case XK_KP_Left: key = K_KP_LEFTARROW; break;
    464 		case XK_Left:	 key = K_LEFTARROW; break;
    465 
    466 		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
    467 		case XK_Right:	key = K_RIGHTARROW;		break;
    468 
    469 		case XK_KP_Down: key = K_KP_DOWNARROW; break;
    470 		case XK_Down:	 key = K_DOWNARROW; break;
    471 
    472 		case XK_KP_Up:   key = K_KP_UPARROW; break;
    473 		case XK_Up:		 key = K_UPARROW;	 break;
    474 
    475 		case XK_Escape: key = K_ESCAPE;		break;
    476 
    477 		case XK_KP_Enter: key = K_KP_ENTER;	break;
    478 		case XK_Return: key = K_ENTER;		 break;
    479 
    480 		case XK_Tab:		key = K_TAB;			 break;
    481 
    482 		case XK_F1:		 key = K_F1;				break;
    483 
    484 		case XK_F2:		 key = K_F2;				break;
    485 
    486 		case XK_F3:		 key = K_F3;				break;
    487 
    488 		case XK_F4:		 key = K_F4;				break;
    489 
    490 		case XK_F5:		 key = K_F5;				break;
    491 
    492 		case XK_F6:		 key = K_F6;				break;
    493 
    494 		case XK_F7:		 key = K_F7;				break;
    495 
    496 		case XK_F8:		 key = K_F8;				break;
    497 
    498 		case XK_F9:		 key = K_F9;				break;
    499 
    500 		case XK_F10:		key = K_F10;			 break;
    501 
    502 		case XK_F11:		key = K_F11;			 break;
    503 
    504 		case XK_F12:		key = K_F12;			 break;
    505 
    506 		case XK_BackSpace: key = K_BACKSPACE; break;
    507 
    508 		case XK_KP_Delete: key = K_KP_DEL; break;
    509 		case XK_Delete: key = K_DEL; break;
    510 
    511 		case XK_Pause:	key = K_PAUSE;		 break;
    512 
    513 		case XK_Shift_L:
    514 		case XK_Shift_R:	key = K_SHIFT;		break;
    515 
    516 		case XK_Execute: 
    517 		case XK_Control_L: 
    518 		case XK_Control_R:	key = K_CTRL;		 break;
    519 
    520 		case XK_Alt_L:	
    521 		case XK_Meta_L: 
    522 		case XK_Alt_R:	
    523 		case XK_Meta_R: key = K_ALT;			break;
    524 
    525 		case XK_KP_Begin: key = K_KP_5;	break;
    526 
    527 		case XK_Insert:key = K_INS; break;
    528 		case XK_KP_Insert: key = K_KP_INS; break;
    529 
    530 		case XK_KP_Multiply: key = '*'; break;
    531 		case XK_KP_Add:  key = K_KP_PLUS; break;
    532 		case XK_KP_Subtract: key = K_KP_MINUS; break;
    533 		case XK_KP_Divide: key = K_KP_SLASH; break;
    534 
    535 #if 0
    536 		case 0x021: key = '1';break;/* [!] */
    537 		case 0x040: key = '2';break;/* [@] */
    538 		case 0x023: key = '3';break;/* [#] */
    539 		case 0x024: key = '4';break;/* [$] */
    540 		case 0x025: key = '5';break;/* [%] */
    541 		case 0x05e: key = '6';break;/* [^] */
    542 		case 0x026: key = '7';break;/* [&] */
    543 		case 0x02a: key = '8';break;/* [*] */
    544 		case 0x028: key = '9';;break;/* [(] */
    545 		case 0x029: key = '0';break;/* [)] */
    546 		case 0x05f: key = '-';break;/* [_] */
    547 		case 0x02b: key = '=';break;/* [+] */
    548 		case 0x07c: key = '\'';break;/* [|] */
    549 		case 0x07d: key = '[';break;/* [}] */
    550 		case 0x07b: key = ']';break;/* [{] */
    551 		case 0x022: key = '\'';break;/* ["] */
    552 		case 0x03a: key = ';';break;/* [:] */
    553 		case 0x03f: key = '/';break;/* [?] */
    554 		case 0x03e: key = '.';break;/* [>] */
    555 		case 0x03c: key = ',';break;/* [<] */
    556 #endif
    557 
    558 		default:
    559 			key = *(unsigned char*)buf;
    560 			if (key >= 'A' && key <= 'Z')
    561 				key = key - 'A' + 'a';
    562 			break;
    563 	} 
    564 
    565 	return key;
    566 }
    567 
    568 void GetEvent(void)
    569 {
    570 	XEvent x_event;
    571 	int b;
    572    
    573 	XNextEvent(x_disp, &x_event);
    574 	switch(x_event.type) {
    575 	case KeyPress:
    576 		keyq[keyq_head].key = XLateKey(&x_event.xkey);
    577 		keyq[keyq_head].down = true;
    578 		keyq_head = (keyq_head + 1) & 63;
    579 		break;
    580 	case KeyRelease:
    581 		keyq[keyq_head].key = XLateKey(&x_event.xkey);
    582 		keyq[keyq_head].down = false;
    583 		keyq_head = (keyq_head + 1) & 63;
    584 		break;
    585 
    586 	case MotionNotify:
    587 		if (_windowed_mouse->value) {
    588 			mx += ((int)x_event.xmotion.x - (int)(vid.width/2));
    589 			my += ((int)x_event.xmotion.y - (int)(vid.height/2));
    590 
    591 			/* move the mouse to the window center again */
    592 			XSelectInput(x_disp,x_win, STD_EVENT_MASK & ~PointerMotionMask);
    593 			XWarpPointer(x_disp,None,x_win,0,0,0,0, 
    594 				(vid.width/2),(vid.height/2));
    595 			XSelectInput(x_disp,x_win, STD_EVENT_MASK);
    596 		} else {
    597 			mx = ((int)x_event.xmotion.x - (int)p_mouse_x);
    598 			my = ((int)x_event.xmotion.y - (int)p_mouse_y);
    599 			p_mouse_x=x_event.xmotion.x;
    600 			p_mouse_y=x_event.xmotion.y;
    601 		}
    602 		break;
    603 
    604 	case ButtonPress:
    605 		b=-1;
    606 		if (x_event.xbutton.button == 1)
    607 			b = 0;
    608 		else if (x_event.xbutton.button == 2)
    609 			b = 2;
    610 		else if (x_event.xbutton.button == 3)
    611 			b = 1;
    612 		if (b>=0)
    613 			mouse_buttonstate |= 1<<b;
    614 		break;
    615 
    616 	case ButtonRelease:
    617 		b=-1;
    618 		if (x_event.xbutton.button == 1)
    619 			b = 0;
    620 		else if (x_event.xbutton.button == 2)
    621 			b = 2;
    622 		else if (x_event.xbutton.button == 3)
    623 			b = 1;
    624 		if (b>=0)
    625 			mouse_buttonstate &= ~(1<<b);
    626 		break;
    627 	
    628 	case ConfigureNotify:
    629 		config_notify_width = x_event.xconfigure.width;
    630 		config_notify_height = x_event.xconfigure.height;
    631 		config_notify = 1;
    632 		break;
    633 
    634 	default:
    635 		if (doShm && x_event.type == x_shmeventtype)
    636 			oktodraw = true;
    637 	}
    638    
    639 	if (old_windowed_mouse != _windowed_mouse->value) {
    640 		old_windowed_mouse = _windowed_mouse->value;
    641 
    642 		if (!_windowed_mouse->value) {
    643 			/* ungrab the pointer */
    644 			XUngrabPointer(x_disp,CurrentTime);
    645 		} else {
    646 			/* grab the pointer */
    647 			XGrabPointer(x_disp,x_win,True,0,GrabModeAsync,
    648 				GrabModeAsync,x_win,None,CurrentTime);
    649 		}
    650 	}
    651 }
    652 
    653 /*****************************************************************************/
    654 
    655 /*
    656 ** SWimp_Init
    657 **
    658 ** This routine is responsible for initializing the implementation
    659 ** specific stuff in a software rendering subsystem.
    660 */
    661 int SWimp_Init( void *hInstance, void *wndProc )
    662 {
    663 // open the display
    664 	x_disp = XOpenDisplay(0);
    665 	if (!x_disp)
    666 	{
    667 		if (getenv("DISPLAY"))
    668 			Sys_Error("VID: Could not open display [%s]\n",
    669 				getenv("DISPLAY"));
    670 		else
    671 			Sys_Error("VID: Could not open local display\n");
    672 	}
    673 
    674 // catch signals so i can turn on auto-repeat
    675 
    676 	{
    677 		struct sigaction sa;
    678 		sigaction(SIGINT, 0, &sa);
    679 		sa.sa_handler = TragicDeath;
    680 		sigaction(SIGINT, &sa, 0);
    681 		sigaction(SIGTERM, &sa, 0);
    682 	}
    683 
    684 	return true;
    685 }
    686 
    687 /*
    688 ** SWimp_InitGraphics
    689 **
    690 ** This initializes the software refresh's implementation specific
    691 ** graphics subsystem.  In the case of Windows it creates DIB or
    692 ** DDRAW surfaces.
    693 **
    694 ** The necessary width and height parameters are grabbed from
    695 ** vid.width and vid.height.
    696 */
    697 static qboolean SWimp_InitGraphics( qboolean fullscreen )
    698 {
    699 	int pnum, i;
    700 	XVisualInfo template;
    701 	int num_visuals;
    702 	int template_mask;
    703 
    704 	srandom(getpid());
    705 
    706 	// free resources in use
    707 	SWimp_Shutdown ();
    708 
    709 	// let the sound and input subsystems know about the new window
    710 	ri.Vid_NewWindow (vid.width, vid.height);
    711 
    712 	XAutoRepeatOff(x_disp);
    713 
    714 // for debugging only
    715 	XSynchronize(x_disp, True);
    716 
    717 // check for command-line window size
    718 	template_mask = 0;
    719 
    720 #if 0
    721 // specify a visual id
    722 	if ((pnum=COM_CheckParm("-visualid")))
    723 	{
    724 		if (pnum >= com_argc-1)
    725 			Sys_Error("VID: -visualid <id#>\n");
    726 		template.visualid = Q_atoi(com_argv[pnum+1]);
    727 		template_mask = VisualIDMask;
    728 	}
    729 
    730 // If not specified, use default visual
    731 	else
    732 #endif
    733 	{
    734 		int screen;
    735 		screen = XDefaultScreen(x_disp);
    736 		template.visualid =
    737 			XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
    738 		template_mask = VisualIDMask;
    739 	}
    740 
    741 // pick a visual- warn if more than one was available
    742 	x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals);
    743 	if (num_visuals > 1)
    744 	{
    745 		printf("Found more than one visual id at depth %d:\n", template.depth);
    746 		for (i=0 ; i<num_visuals ; i++)
    747 			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
    748 	}
    749 	else if (num_visuals == 0)
    750 	{
    751 		if (template_mask == VisualIDMask)
    752 			Sys_Error("VID: Bad visual id %d\n", template.visualid);
    753 		else
    754 			Sys_Error("VID: No visuals at depth %d\n", template.depth);
    755 	}
    756 
    757 #if 0
    758 	if (verbose)
    759 	{
    760 		printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
    761 		printf("	screen %d\n", x_visinfo->screen);
    762 		printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
    763 		printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
    764 		printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
    765 		printf("	colormap_size %d\n", x_visinfo->colormap_size);
    766 		printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
    767 	}
    768 #endif
    769 
    770 	x_vis = x_visinfo->visual;
    771 
    772 // setup attributes for main window
    773 	{
    774 	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
    775 	   XSetWindowAttributes attribs;
    776 	   Colormap tmpcmap;
    777 	   
    778 	   tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
    779 							 x_visinfo->screen), x_vis, AllocNone);
    780 	   
    781 	   attribs.event_mask = STD_EVENT_MASK;
    782 	   attribs.border_pixel = 0;
    783 	   attribs.colormap = tmpcmap;
    784 
    785 // create the main window
    786 		x_win = XCreateWindow(	x_disp,
    787 			XRootWindow(x_disp, x_visinfo->screen),
    788 			0, 0,	// x, y
    789 			vid.width, vid.height,
    790 			0, // borderwidth
    791 			x_visinfo->depth,
    792 			InputOutput,
    793 			x_vis,
    794 			attribmask,
    795 			&attribs );
    796 		XStoreName(x_disp, x_win, "Quake II");
    797 
    798 		if (x_visinfo->class != TrueColor)
    799 			XFreeColormap(x_disp, tmpcmap);
    800 	}
    801 
    802 	if (x_visinfo->depth == 8)
    803 	{
    804 	// create and upload the palette
    805 		if (x_visinfo->class == PseudoColor)
    806 		{
    807 			x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
    808 			XSetWindowColormap(x_disp, x_win, x_cmap);
    809 		}
    810 
    811 	}
    812 
    813 // inviso cursor
    814 	XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
    815 
    816 // create the GC
    817 	{
    818 		XGCValues xgcvalues;
    819 		int valuemask = GCGraphicsExposures;
    820 		xgcvalues.graphics_exposures = False;
    821 		x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
    822 	}
    823 
    824 // map the window
    825 	XMapWindow(x_disp, x_win);
    826 
    827 // wait for first exposure event
    828 	{
    829 		XEvent event;
    830 		do
    831 		{
    832 			XNextEvent(x_disp, &event);
    833 			if (event.type == Expose && !event.xexpose.count)
    834 				oktodraw = true;
    835 		} while (!oktodraw);
    836 	}
    837 // now safe to draw
    838 
    839 // even if MITSHM is available, make sure it's a local connection
    840 	if (XShmQueryExtension(x_disp))
    841 	{
    842 		char *displayname;
    843 		doShm = true;
    844 		displayname = (char *) getenv("DISPLAY");
    845 		if (displayname)
    846 		{
    847 			char *d = displayname;
    848 			while (*d && (*d != ':')) d++;
    849 			if (*d) *d = 0;
    850 			if (!(!strcasecmp(displayname, "unix") || !*displayname))
    851 				doShm = false;
    852 		}
    853 	}
    854 
    855 	if (doShm)
    856 	{
    857 		x_shmeventtype = XShmGetEventBase(x_disp) + ShmCompletion;
    858 		ResetSharedFrameBuffers();
    859 	}
    860 	else
    861 		ResetFrameBuffer();
    862 
    863 	current_framebuffer = 0;
    864 	vid.rowbytes = x_framebuffer[0]->bytes_per_line;
    865 	vid.buffer = x_framebuffer[0]->data;
    866 
    867 //	XSynchronize(x_disp, False);
    868 
    869 	X11_active = true;
    870 
    871 	return true;
    872 }
    873 
    874 /*
    875 ** SWimp_EndFrame
    876 **
    877 ** This does an implementation specific copy from the backbuffer to the
    878 ** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
    879 ** on whether we're using DIB sections/GDI or DDRAW.
    880 */
    881 void SWimp_EndFrame (void)
    882 {
    883 // if the window changes dimension, skip this frame
    884 #if 0
    885 	if (config_notify)
    886 	{
    887 		fprintf(stderr, "config notify\n");
    888 		config_notify = 0;
    889 		vid.width = config_notify_width & ~7;
    890 		vid.height = config_notify_height;
    891 		if (doShm)
    892 			ResetSharedFrameBuffers();
    893 		else
    894 			ResetFrameBuffer();
    895 		vid.rowbytes = x_framebuffer[0]->bytes_per_line;
    896 		vid.buffer = x_framebuffer[current_framebuffer]->data;
    897 		vid.recalc_refdef = 1;				// force a surface cache flush
    898 		Con_CheckResize();
    899 		Con_Clear_f();
    900 		return;
    901 	}
    902 #endif
    903 
    904 	if (doShm)
    905 	{
    906 
    907 		if (x_visinfo->depth != 8)
    908 			st2_fixup( x_framebuffer[current_framebuffer], 
    909 				0, 0, vid.width, vid.height);	
    910 		if (!XShmPutImage(x_disp, x_win, x_gc,
    911 			x_framebuffer[current_framebuffer], 0, 0,
    912 			0, 0, vid.width, vid.height, True))
    913 				Sys_Error("VID_Update: XShmPutImage failed\n");
    914 		oktodraw = false;
    915 		while (!oktodraw) 
    916 			GetEvent();
    917 		current_framebuffer = !current_framebuffer;
    918 		vid.buffer = x_framebuffer[current_framebuffer]->data;
    919 		XSync(x_disp, False);
    920 	}
    921 	else
    922 	{
    923 		if (x_visinfo->depth != 8)
    924 			st2_fixup( x_framebuffer[current_framebuffer], 
    925 				0, 0, vid.width, vid.height);
    926 		XPutImage(x_disp, x_win, x_gc, x_framebuffer[0],
    927 			0, 0, 0, 0, vid.width, vid.height);
    928 		XSync(x_disp, False);
    929 	}
    930 }
    931 
    932 /*
    933 ** SWimp_SetMode
    934 */
    935 rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
    936 {
    937 	rserr_t retval = rserr_ok;
    938 
    939 	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
    940 
    941 	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
    942 	{
    943 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
    944 		return rserr_invalid_mode;
    945 	}
    946 
    947 	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
    948 
    949 	if ( !SWimp_InitGraphics( false ) ) {
    950 		// failed to set a valid mode in windowed mode
    951 		return rserr_invalid_mode;
    952 	}
    953 
    954 	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
    955 
    956 	return retval;
    957 }
    958 
    959 /*
    960 ** SWimp_SetPalette
    961 **
    962 ** System specific palette setting routine.  A NULL palette means
    963 ** to use the existing palette.  The palette is expected to be in
    964 ** a padded 4-byte xRGB format.
    965 */
    966 void SWimp_SetPalette( const unsigned char *palette )
    967 {
    968 	int i;
    969 	XColor colors[256];
    970 
    971 	if (!X11_active)
    972 		return;
    973 
    974     if ( !palette )
    975         palette = ( const unsigned char * ) sw_state.currentpalette;
    976  
    977 	for(i=0;i<256;i++)
    978 		st2d_8to16table[i]= xlib_rgb(palette[i*4],
    979 			palette[i*4+1],palette[i*4+2]);
    980 
    981 	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
    982 	{
    983 		for (i=0 ; i<256 ; i++)
    984 		{
    985 			colors[i].pixel = i;
    986 			colors[i].flags = DoRed|DoGreen|DoBlue;
    987 			colors[i].red = palette[i*4] * 257;
    988 			colors[i].green = palette[i*4+1] * 257;
    989 			colors[i].blue = palette[i*4+2] * 257;
    990 		}
    991 		XStoreColors(x_disp, x_cmap, colors, 256);
    992 	}
    993 }
    994 
    995 /*
    996 ** SWimp_Shutdown
    997 **
    998 ** System specific graphics subsystem shutdown routine.  Destroys
    999 ** DIBs or DDRAW surfaces as appropriate.
   1000 */
   1001 void SWimp_Shutdown( void )
   1002 {
   1003 	int i;
   1004 
   1005 	if (!X11_active)
   1006 		return;
   1007 
   1008 	if (doShm) {
   1009 		for (i = 0; i < 2; i++)
   1010 			if (x_framebuffer[i]) {
   1011 				XShmDetach(x_disp, &x_shminfo[i]);
   1012 				free(x_framebuffer[i]);
   1013 				shmdt(x_shminfo[i].shmaddr);
   1014 				x_framebuffer[i] = NULL;
   1015 			}
   1016 	} else if (x_framebuffer[0]) {
   1017 		free(x_framebuffer[0]->data);
   1018 		free(x_framebuffer[0]);
   1019 		x_framebuffer[0] = NULL;
   1020 	}
   1021 
   1022 	XDestroyWindow(	x_disp, x_win );
   1023 
   1024 	XAutoRepeatOn(x_disp);
   1025 //	XCloseDisplay(x_disp);
   1026 
   1027 	X11_active = false;
   1028 }
   1029 
   1030 /*
   1031 ** SWimp_AppActivate
   1032 */
   1033 void SWimp_AppActivate( qboolean active )
   1034 {
   1035 }
   1036 
   1037 //===============================================================================
   1038 
   1039 /*
   1040 ================
   1041 Sys_MakeCodeWriteable
   1042 ================
   1043 */
   1044 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
   1045 {
   1046 
   1047 	int r;
   1048 	unsigned long addr;
   1049 	int psize = getpagesize();
   1050 
   1051 	addr = (startaddr & ~(psize-1)) - psize;
   1052 
   1053 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
   1054 //			addr, startaddr+length, length);
   1055 
   1056 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
   1057 
   1058 	if (r < 0)
   1059     		Sys_Error("Protection change failed\n");
   1060 
   1061 }
   1062 
   1063 /*****************************************************************************/
   1064 /* KEYBOARD                                                                  */
   1065 /*****************************************************************************/
   1066 
   1067 Key_Event_fp_t Key_Event_fp;
   1068 
   1069 void KBD_Init(Key_Event_fp_t fp)
   1070 {
   1071 	Key_Event_fp = fp;
   1072 }
   1073 
   1074 void KBD_Update(void)
   1075 {
   1076 // get events from x server
   1077 	if (x_disp)
   1078 	{
   1079 		while (XPending(x_disp)) 
   1080 			GetEvent();
   1081 		while (keyq_head != keyq_tail)
   1082 		{
   1083 			Key_Event_fp(keyq[keyq_tail].key, keyq[keyq_tail].down);
   1084 			keyq_tail = (keyq_tail + 1) & 63;
   1085 		}
   1086 	}
   1087 }
   1088 
   1089 void KBD_Close(void)
   1090 {
   1091 }
   1092 
   1093