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