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 
Force_CenterView_f(void)113 static void Force_CenterView_f (void)
114 {
115 	in_state->viewangles[PITCH] = 0;
116 }
117 
RW_IN_MLookDown(void)118 static void RW_IN_MLookDown (void)
119 {
120 	mlooking = true;
121 }
122 
RW_IN_MLookUp(void)123 static void RW_IN_MLookUp (void)
124 {
125 	mlooking = false;
126 	in_state->IN_CenterView_fp ();
127 }
128 
RW_IN_Init(in_state_t * in_state_p)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 
RW_IN_Shutdown(void)157 void RW_IN_Shutdown(void)
158 {
159 	mouse_avail = false;
160 }
161 
162 /*
163 ===========
164 IN_Commands
165 ===========
166 */
RW_IN_Commands(void)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 */
RW_IN_Move(usercmd_t * cmd)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 
RW_IN_Frame(void)231 void RW_IN_Frame (void)
232 {
233 }
234 
RW_IN_Activate(void)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 
shiftmask_init()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 
xlib_rgb(int r,int g,int b)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 
st2_fixup(XImage * framebuf,int x,int y,int width,int height)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 
CreateNullCursor(Display * display,Window root)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 
ResetFrameBuffer(void)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 
ResetSharedFrameBuffers(void)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 
TragicDeath(int signal_num)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 
XLateKey(XKeyEvent * ev)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 
GetEvent(void)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 */
SWimp_Init(void * hInstance,void * wndProc)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 */
SWimp_InitGraphics(qboolean fullscreen)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 */
SWimp_EndFrame(void)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 */
SWimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)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 */
SWimp_SetPalette(const unsigned char * palette)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 */
SWimp_Shutdown(void)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 */
SWimp_AppActivate(qboolean active)1033 void SWimp_AppActivate( qboolean active )
1034 {
1035 }
1036 
1037 //===============================================================================
1038 
1039 /*
1040 ================
1041 Sys_MakeCodeWriteable
1042 ================
1043 */
Sys_MakeCodeWriteable(unsigned long startaddr,unsigned long length)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 
KBD_Init(Key_Event_fp_t fp)1069 void KBD_Init(Key_Event_fp_t fp)
1070 {
1071 	Key_Event_fp = fp;
1072 }
1073 
KBD_Update(void)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 
KBD_Close(void)1089 void KBD_Close(void)
1090 {
1091 }
1092 
1093 
1094