1 /*
2 Copyright (C) 1997-2001 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 /*
21 ** RW_X11.C
22 **
23 ** This file contains ALL Linux specific stuff having to do with the
24 ** software refresh.  When a port is being made the following functions
25 ** must be implemented by the port:
26 **
27 ** SWimp_EndFrame
28 ** SWimp_Init
29 ** SWimp_InitGraphics
30 ** SWimp_SetPalette
31 ** SWimp_Shutdown
32 ** SWimp_SwitchFullscreen
33 */
34 
35 #include <ctype.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #ifdef Joystick
39 #include <fcntl.h>
40 //#include "joystick.h"
41 #endif
42 #include <unistd.h>
43 #include <signal.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <sys/ipc.h>
48 #include <sys/shm.h>
49 #include <sys/mman.h>
50 
51 #include <X11/Xlib.h>
52 #include <X11/Xutil.h>
53 #include <X11/Xatom.h>
54 #include <X11/keysym.h>
55 #include <X11/extensions/XShm.h>
56 #include <X11/extensions/Xxf86dga.h>
57 #ifdef OPENGL
58 #include <X11/extensions/xf86vmode.h>
59 #endif
60 #ifdef Joystick
61 # if defined (__linux__)
62 #include <linux/joystick.h>
63 # elif defined (__DragonFly__)
64 #include <sys/joystick.h>
65 # endif
66 #include <glob.h>
67 #endif
68 
69 #ifdef OPENGL
70 #include "../ref_gl/gl_local.h"
71 #include <dlfcn.h>
72 #else
73 #include "../ref_soft/r_local.h"
74 #endif
75 
76 #include "../client/keys.h"
77 #include "../linux/rw_linux.h"
78 
79 #ifdef OPENGL
80 #include <GL/glx.h>
81 #include "../linux/glw_linux.h"
82 
83 glwstate_t glw_state;
84 static int scrnum;
85 static GLXContext ctx = NULL;
86 static cvar_t	*r_fakeFullscreen;
87 static qboolean vidmode_ext = false;
88 
89 static XF86VidModeModeInfo **vidmodes;
90 static int num_vidmodes;
91 static qboolean vidmode_active = false;
92 static XF86VidModeGamma oldgamma;
93 
94 //GLX Functions
95 static XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList );
96 static GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
97 static void (*qglXDestroyContext)( Display *dpy, GLXContext ctx );
98 static Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx);
99 static void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask );
100 static void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable );
101 #endif
102 
103 /*****************************************************************************/
104 
105 static qboolean			doShm;
106 static Display			*dpy;
107 #ifndef OPENGL
108 static Colormap			x_cmap;
109 static GC			x_gc;
110 #endif
111 
112 #ifdef REDBLUE
113 static GC				x_gc;
114 #endif
115 
116 static Window			win;
117 static Visual			*x_vis;
118 static XVisualInfo		*x_visinfo;
119 static int win_x, win_y;
120 static Atom wmDeleteWindow;
121 
122 qboolean mouse_active;
123 int mx, my, mouse_buttonstate;
124 
125 #define KEY_MASK (KeyPressMask | KeyReleaseMask)
126 #define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
127 		    PointerMotionMask | ButtonMotionMask )
128 #define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask | ExposureMask )
129 
130 static int				x_shmeventtype;
131 //static XShmSegmentInfo	x_shminfo;
132 
133 static qboolean			oktodraw = false;
134 static qboolean			ignorefirst = false;
135 static qboolean			exposureflag = false;
136 #ifndef OPENGL
137 static qboolean			X11_active = false;
138 #endif
139 
140 qboolean have_stencil = false;
141 
142 int XShmQueryExtension(Display *);
143 int XShmGetEventBase(Display *);
144 
145 int current_framebuffer;
146 static XImage			*x_framebuffer[2] = { 0, 0 };
147 static XShmSegmentInfo	x_shminfo[2];
148 
149 int config_notify=0;
150 int config_notify_width;
151 int config_notify_height;
152 
153 typedef unsigned short PIXEL16;
154 typedef unsigned int PIXEL24;
155 #ifdef REDBLUE
156 static PIXEL16 st2d_8to16table_s[2][256];
157 static PIXEL24 st2d_8to24table_s[2][256];
158 #endif
159 static PIXEL16 st2d_8to16table[256];
160 static PIXEL24 st2d_8to24table[256];
161 
162 static int shiftmask_fl=0;
163 static long r_shift,g_shift,b_shift;
164 static unsigned long r_mask,g_mask,b_mask;
165 
shiftmask_init(void)166 void shiftmask_init(void)
167 {
168     unsigned int x;
169     r_mask=x_vis->red_mask;
170     g_mask=x_vis->green_mask;
171     b_mask=x_vis->blue_mask;
172     for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
173     for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
174     for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
175     shiftmask_fl=1;
176 }
177 
xlib_rgb16(int r,int g,int b)178 PIXEL16 xlib_rgb16(int r,int g,int b)
179 {
180     PIXEL16 p;
181     if(shiftmask_fl==0) shiftmask_init();
182     p=0;
183 
184     if(r_shift>0) {
185         p=(r<<(r_shift))&r_mask;
186     } else if(r_shift<0) {
187         p=(r>>(-r_shift))&r_mask;
188     } else p|=(r&r_mask);
189 
190     if(g_shift>0) {
191         p|=(g<<(g_shift))&g_mask;
192     } else if(g_shift<0) {
193         p|=(g>>(-g_shift))&g_mask;
194     } else p|=(g&g_mask);
195 
196     if(b_shift>0) {
197         p|=(b<<(b_shift))&b_mask;
198     } else if(b_shift<0) {
199         p|=(b>>(-b_shift))&b_mask;
200     } else p|=(b&b_mask);
201 
202     return p;
203 }
204 
xlib_rgb24(int r,int g,int b)205 PIXEL24 xlib_rgb24(int r,int g,int b)
206 {
207     PIXEL24 p;
208     if(shiftmask_fl==0) shiftmask_init();
209     p=0;
210 
211     if(r_shift>0) {
212         p=(r<<(r_shift))&r_mask;
213     } else if(r_shift<0) {
214         p=(r>>(-r_shift))&r_mask;
215     } else p|=(r&r_mask);
216 
217     if(g_shift>0) {
218         p|=(g<<(g_shift))&g_mask;
219     } else if(g_shift<0) {
220         p|=(g>>(-g_shift))&g_mask;
221     } else p|=(g&g_mask);
222 
223     if(b_shift>0) {
224         p|=(b<<(b_shift))&b_mask;
225     } else if(b_shift<0) {
226         p|=(b>>(-b_shift))&b_mask;
227     } else p|=(b&b_mask);
228 
229     return p;
230 }
231 
232 
st2_fixup(XImage * framebuf,int x,int y,int width,int height)233 void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
234 {
235   int yi;
236 	byte *src;
237 	PIXEL16 *dest;
238 	register int count, n;
239 
240 	if( (x<0)||(y<0) )return;
241 
242 	for (yi = y; yi < (y+height); yi++) {
243 		src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
244 
245 		// Duff's Device
246 		count = width;
247 		n = (count + 7) / 8;
248 		dest = ((PIXEL16 *)src) + x+width - 1;
249 		src += x+width - 1;
250 
251 		switch (count % 8) {
252 		case 0:	do {	*dest-- = st2d_8to16table[*src--];
253 		case 7:			*dest-- = st2d_8to16table[*src--];
254 		case 6:			*dest-- = st2d_8to16table[*src--];
255 		case 5:			*dest-- = st2d_8to16table[*src--];
256 		case 4:			*dest-- = st2d_8to16table[*src--];
257 		case 3:			*dest-- = st2d_8to16table[*src--];
258 		case 2:			*dest-- = st2d_8to16table[*src--];
259 		case 1:			*dest-- = st2d_8to16table[*src--];
260 				} while (--n > 0);
261 		}
262 
263 //		for(xi = (x+width-1); xi >= x; xi--) {
264 //			dest[xi] = st2d_8to16table[src[xi]];
265 //		}
266 	}
267 }
268 
269 #ifdef REDBLUE
st2_fixup_stereo(XImage * framebuf1,XImage * framebuf2,int x,int y,int width,int height)270 void st2_fixup_stereo( XImage *framebuf1, XImage *framebuf2,
271 		       int x, int y, int width, int height)
272 {
273   int yi;
274   unsigned char *src;
275   PIXEL16 *dest;
276   register int count, n;
277 
278   if( (x<0)||(y<0) )return;
279 
280   for (yi = y; yi < (y+height); yi++) {
281     src = &framebuf1->data [yi * framebuf1->bytes_per_line];
282 
283     // Duff's Device
284     count = width;
285     n = (count + 7) / 8;
286     dest = ((PIXEL16 *)src) + x+width - 1;
287     src += x+width - 1;
288 
289     switch (count % 8) {
290     case 0:	do {	*dest-- = st2d_8to16table_s[0][*src--];
291     case 7:			*dest-- = st2d_8to16table_s[0][*src--];
292     case 6:			*dest-- = st2d_8to16table_s[0][*src--];
293     case 5:			*dest-- = st2d_8to16table_s[0][*src--];
294     case 4:			*dest-- = st2d_8to16table_s[0][*src--];
295     case 3:			*dest-- = st2d_8to16table_s[0][*src--];
296     case 2:			*dest-- = st2d_8to16table_s[0][*src--];
297     case 1:			*dest-- = st2d_8to16table_s[0][*src--];
298     } while (--n > 0);
299     }
300   }
301 
302   for (yi = y; yi < (y+height); yi++) {
303     src = &framebuf1->data [yi * framebuf1->bytes_per_line];
304 
305     // Duff's Device
306     count = width;
307     n = (count + 7) / 8;
308     dest = ((PIXEL16 *)src) + x+width - 1;
309     src = &framebuf2->data [yi * framebuf2->bytes_per_line];
310     src += x+width - 1;
311 
312     switch (count % 8) {
313     case 0:	do {	*dest-- += st2d_8to16table_s[1][*src--];
314     case 7:			*dest-- += st2d_8to16table_s[1][*src--];
315     case 6:			*dest-- += st2d_8to16table_s[1][*src--];
316     case 5:			*dest-- += st2d_8to16table_s[1][*src--];
317     case 4:			*dest-- += st2d_8to16table_s[1][*src--];
318     case 3:			*dest-- += st2d_8to16table_s[1][*src--];
319     case 2:			*dest-- += st2d_8to16table_s[1][*src--];
320     case 1:			*dest-- += st2d_8to16table_s[1][*src--];
321     } while (--n > 0);
322     }
323 
324   }
325 }
326 #endif
327 
st3_fixup(XImage * framebuf,int x,int y,int width,int height)328 void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
329 {
330 	int yi;
331 	byte *src;
332 	PIXEL24 *dest;
333 	register int count, n;
334 
335 	if( (x<0)||(y<0) )return;
336 
337 	for (yi = y; yi < (y+height); yi++) {
338 		src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
339 
340 		// Duff's Device
341 		count = width;
342 		n = (count + 7) / 8;
343 		dest = ((PIXEL24 *)src) + x+width - 1;
344 		src += x+width - 1;
345 
346 		switch (count % 8) {
347 		case 0:	do {	*dest-- = st2d_8to24table[*src--];
348 		case 7:			*dest-- = st2d_8to24table[*src--];
349 		case 6:			*dest-- = st2d_8to24table[*src--];
350 		case 5:			*dest-- = st2d_8to24table[*src--];
351 		case 4:			*dest-- = st2d_8to24table[*src--];
352 		case 3:			*dest-- = st2d_8to24table[*src--];
353 		case 2:			*dest-- = st2d_8to24table[*src--];
354 		case 1:			*dest-- = st2d_8to24table[*src--];
355 				} while (--n > 0);
356 		}
357 
358 //		for(xi = (x+width-1); xi >= x; xi--) {
359 //			dest[xi] = st2d_8to16table[src[xi]];
360 //		}
361 	}
362 }
363 
364 #ifdef REDBLUE
st3_fixup_stereo(XImage * framebuf1,XImage * framebuf2,int x,int y,int width,int height)365 void st3_fixup_stereo( XImage *framebuf1, XImage *framebuf2,
366 		       int x, int y, int width, int height)
367 {
368   int yi;
369   unsigned char *src;
370   PIXEL24 *dest;
371   register int count, n;
372 
373 
374   if( (x<0)||(y<0) )return;
375 
376   for (yi = y; yi < (y+height); yi++) {
377     src = &framebuf1->data [yi * framebuf1->bytes_per_line];
378 
379     // Duff's Device
380     count = width;
381     n = (count + 7) / 8;
382     dest = ((PIXEL24 *)src) + x+width - 1;
383     src += x+width - 1;
384 
385     switch (count % 8) {
386     case 0:	do {	*dest-- = st2d_8to24table_s[0][*src--];
387     case 7:			*dest-- = st2d_8to24table_s[0][*src--];
388     case 6:			*dest-- = st2d_8to24table_s[0][*src--];
389     case 5:			*dest-- = st2d_8to24table_s[0][*src--];
390     case 4:			*dest-- = st2d_8to24table_s[0][*src--];
391     case 3:			*dest-- = st2d_8to24table_s[0][*src--];
392     case 2:			*dest-- = st2d_8to24table_s[0][*src--];
393     case 1:			*dest-- = st2d_8to24table_s[0][*src--];
394     } while (--n > 0);
395     }
396   }
397 
398   for (yi = y; yi < (y+height); yi++) {
399     src = &framebuf1->data [yi * framebuf1->bytes_per_line];
400 
401     // Duff's Device
402     count = width;
403     n = (count + 7) / 8;
404     dest = ((PIXEL24 *)src) + x+width - 1;
405     src = &framebuf2->data [yi * framebuf2->bytes_per_line];
406     src += x+width - 1;
407 
408     switch (count % 8) {
409     case 0:	do {	*dest-- += st2d_8to24table_s[1][*src--];
410     case 7:			*dest-- += st2d_8to24table_s[1][*src--];
411     case 6:			*dest-- += st2d_8to24table_s[1][*src--];
412     case 5:			*dest-- += st2d_8to24table_s[1][*src--];
413     case 4:			*dest-- += st2d_8to24table_s[1][*src--];
414     case 3:			*dest-- += st2d_8to24table_s[1][*src--];
415     case 2:			*dest-- += st2d_8to24table_s[1][*src--];
416     case 1:			*dest-- += st2d_8to24table_s[1][*src--];
417     } while (--n > 0);
418     }
419   }
420 }
421 #endif
422 
423 
424 // Console variables that we need to access from this module
425 
426 /*****************************************************************************/
427 /* MOUSE                                                                     */
428 /*****************************************************************************/
429 
430 // this is inside the renderer shared lib, so these are called from vid_so
431 
432 static qboolean dgamouse = false;
433 
434 static cvar_t	*in_dgamouse;
435 
436 static cvar_t	*vid_xpos;		     // X coordinate of window position
437 static cvar_t	*vid_ypos;		     // Y coordinate of window position
438 
439 #ifdef Joystick
440 static int joy_fd;
441 #endif
442 
443 static Time myxtime;
444 
445 #ifdef Joystick
OpenJoystick(cvar_t * joy_dev)446 qboolean OpenJoystick(cvar_t *joy_dev) {
447   int i, err;
448   glob_t pglob;
449   struct joystick j;
450 
451   err = glob(joy_dev->string, 0, NULL, &pglob);
452 
453   if (err) {
454     switch (err) {
455     case GLOB_NOSPACE:
456       ri.Con_Printf(PRINT_ALL, "Error, out of memory while looking for joysticks\n");
457       break;
458     case GLOB_NOMATCH:
459       ri.Con_Printf(PRINT_ALL, "No joysticks found\n");
460       break;
461     default:
462       ri.Con_Printf(PRINT_ALL, "Error #%d while looking for joysticks\n",err);
463     }
464     goto out;
465   }
466 
467   for (i=0;i<pglob.gl_pathc;i++) {
468     ri.Con_Printf(PRINT_ALL, "Trying joystick dev %s\n", pglob.gl_pathv[i]);
469     joy_fd = open (pglob.gl_pathv[i], O_RDONLY | O_NONBLOCK);
470     if (joy_fd == -1) {
471       ri.Con_Printf(PRINT_ALL, "Error opening joystick dev %s\n",
472 		    pglob.gl_pathv[i]);
473       goto out;
474     }
475     else if (read(joy_fd, &j, sizeof(struct joystick)) != -1) {
476       ri.Con_Printf(PRINT_ALL, "Using joystick dev %s\n", pglob.gl_pathv[i]);
477       return true;
478     }
479   }
480 out:
481   globfree(&pglob);
482   return false;
483 }
484 #endif
485 
RW_IN_PlatformInit()486 void RW_IN_PlatformInit() {
487   in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
488 }
489 
490 // ========================================================================
491 // makes a null cursor
492 // ========================================================================
493 
CreateNullCursor(Display * display,Window root)494 static Cursor CreateNullCursor(Display *display, Window root)
495 {
496     Pixmap cursormask;
497     XGCValues xgc;
498     GC gc;
499     XColor dummycolour;
500     Cursor cursor;
501 
502     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
503     xgc.function = GXclear;
504     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
505     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
506     dummycolour.pixel = 0;
507     dummycolour.red = 0;
508     dummycolour.flags = 04;
509     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
510           &dummycolour,&dummycolour, 0,0);
511     XFreePixmap(display,cursormask);
512     XFreeGC(display,gc);
513     return cursor;
514 }
515 
install_grabs(void)516 static void install_grabs(void)
517 {
518 
519 // inviso cursor
520 	XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
521 
522 	XGrabPointer(dpy, win,
523 				 True,
524 				 0,
525 				 GrabModeAsync, GrabModeAsync,
526 				 win,
527 				 None,
528 				 CurrentTime);
529 
530 	if (in_dgamouse->value) {
531 		int MajorVersion, MinorVersion;
532 
533 		if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
534 			// unable to query, probalby not supported
535 			ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
536 			ri.Cvar_Set( "in_dgamouse", "0" );
537 		} else {
538 			dgamouse = true;
539 			XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
540 			XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
541 		}
542 	} else
543 		XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
544 
545 	XGrabKeyboard(dpy, win,
546 		      False,
547 		      GrabModeAsync, GrabModeAsync,
548 		      CurrentTime);
549 
550 	mouse_active = true;
551 
552 	ignorefirst = true;
553 
554 //	XSync(dpy, True);
555 }
556 
uninstall_grabs(void)557 static void uninstall_grabs(void)
558 {
559 	if (!dpy || !win)
560 		return;
561 
562 	if (dgamouse) {
563 		dgamouse = false;
564 		XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
565 	}
566 
567 	XUngrabPointer(dpy, CurrentTime);
568 	XUngrabKeyboard(dpy, CurrentTime);
569 
570 // inviso cursor
571 	XUndefineCursor(dpy, win);
572 
573 	mouse_active = false;
574 }
575 
IN_DeactivateMouse(void)576 static void IN_DeactivateMouse( void )
577 {
578   //***BAD***
579   //if (!mouse_avail || !dpy || !win)
580   //return;
581 
582   if (mouse_active) {
583     uninstall_grabs();
584     mouse_active = false;
585   }
586 }
587 
IN_ActivateMouse(void)588 static void IN_ActivateMouse( void )
589 {
590   //***BAD***
591   //if (!mouse_avail || !dpy || !win)
592   //return;
593 
594   if (!mouse_active) {
595     mx = my = 0; // don't spazz
596     install_grabs();
597     mouse_active = true;
598   }
599 }
600 
getMouse(int * x,int * y,int * state)601 void getMouse(int *x, int *y, int *state) {
602   *x = mx;
603   *y = my;
604   *state = mouse_buttonstate;
605 }
606 
doneMouse()607 void doneMouse() {
608   mx = my = 0;
609 }
610 
RW_IN_Activate(qboolean active)611 void RW_IN_Activate(qboolean active)
612 {
613   if (active)
614     IN_ActivateMouse();
615   else
616     IN_DeactivateMouse();
617 }
618 
619 #ifdef Joystick
CloseJoystick(void)620 qboolean CloseJoystick(void) {
621   if (close(joy_fd))
622     ri.Con_Printf(PRINT_ALL, "Error, Problem closing joystick.");
623   return true;
624 }
625 #endif
626 
627 /*****************************************************************************/
628 
RW_Sys_GetClipboardData()629 char *RW_Sys_GetClipboardData()
630 {
631   Window sowner;
632   Atom type, property;
633   unsigned long len, bytes_left, tmp;
634   unsigned char *data;
635   int format, result;
636   char *ret = NULL;
637 
638   sowner = XGetSelectionOwner(dpy, XA_PRIMARY);
639 
640   if (sowner != None) {
641     property = XInternAtom(dpy,
642 			   "GETCLIPBOARDDATA_PROP",
643 			   False);
644 
645     XConvertSelection(dpy,
646 		      XA_PRIMARY, XA_STRING,
647 		      property, win, myxtime); /* myxtime == time of last X event */
648     XFlush(dpy);
649 
650     XGetWindowProperty(dpy,
651 		       win, property,
652 		       0, 0, False, AnyPropertyType,
653 		       &type, &format, &len,
654 		       &bytes_left, &data);
655     if (bytes_left > 0) {
656       result =
657 	XGetWindowProperty(dpy,
658 			   win, property,
659 			   0, bytes_left, True, AnyPropertyType,
660 			   &type, &format, &len,
661 			   &tmp, &data);
662       if (result == Success) {
663 	ret = strdup(data);
664       }
665       XFree(data);
666     }
667   }
668   return ret;
669 }
670 
671 /*****************************************************************************/
672 #ifndef OPENGL
ResetFrameBuffer(void)673 void ResetFrameBuffer(void)
674 {
675   int mem;
676   int pwidth;
677 
678   if (x_framebuffer[0]) {
679     free(x_framebuffer[0]->data);
680     free(x_framebuffer[0]);
681   }
682 
683 #ifdef REDBLUE
684   if (x_framebuffer[1]) {
685     free(x_framebuffer[1]->data);
686     free(x_framebuffer[1]);
687   }
688 #endif
689 
690   // alloc an extra line in case we want to wrap, and allocate the z-buffer
691   pwidth = x_visinfo->depth / 8;
692   if (pwidth == 3) pwidth = 4;
693   mem = ((vid.width*pwidth+7)&~7) * vid.height;
694 
695   x_framebuffer[0] = XCreateImage(dpy,
696 				  x_vis,
697 				  x_visinfo->depth,
698 				  ZPixmap,
699 				  0,
700 				  malloc(mem),
701 				  vid.width, vid.height,
702 				  32,
703 				  0);
704 
705   if (!x_framebuffer[0])
706     Sys_Error("VID: XCreateImage failed\n");
707 
708 #ifdef REDBLUE
709   x_framebuffer[1] = XCreateImage(dpy,
710 				  x_vis,
711 				  x_visinfo->depth,
712 				  ZPixmap,
713 				  0,
714 				  malloc(mem),
715 				  vid.width, vid.height,
716 				  32,
717 				  0);
718 
719   if (!x_framebuffer[1])
720     Sys_Error("VID: XCreateImage failed\n");
721 #endif
722 
723   vid.buffer = (byte*) (x_framebuffer[0]->data);
724 }
725 #endif
726 
ResetSharedFrameBuffers(void)727 void ResetSharedFrameBuffers(void)
728 {
729   int size;
730   int key;
731   int minsize = getpagesize();
732   int frm;
733 
734   for (frm=0 ; frm<2 ; frm++)
735     {
736       // free up old frame buffer memory
737       if (x_framebuffer[frm])
738 	{
739 	  XShmDetach(dpy, &x_shminfo[frm]);
740 	  free(x_framebuffer[frm]);
741 	  shmdt(x_shminfo[frm].shmaddr);
742 	}
743 
744       // create the image
745       x_framebuffer[frm] = XShmCreateImage(	dpy,
746 						x_vis,
747 						x_visinfo->depth,
748 						ZPixmap,
749 						0,
750 						&x_shminfo[frm],
751 						vid.width,
752 						vid.height );
753 
754 	// grab shared memory
755 
756 		size = x_framebuffer[frm]->bytes_per_line
757 			* x_framebuffer[frm]->height;
758 		if (size < minsize)
759 			Sys_Error("VID: Window must use at least %d bytes\n", minsize);
760 
761 		key = random();
762 		x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
763 		if (x_shminfo[frm].shmid==-1)
764 			Sys_Error("VID: Could not get any shared memory\n");
765 
766 		// attach to the shared memory segment
767 		x_shminfo[frm].shmaddr =
768 			(void *) shmat(x_shminfo[frm].shmid, 0, 0);
769 
770 		ri.Con_Printf(PRINT_DEVELOPER, "MITSHM shared memory (id=%d, addr=0x%lx)\n",
771 			x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
772 
773 		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
774 
775 	// get the X server to attach to it
776 
777 		if (!XShmAttach(dpy, &x_shminfo[frm]))
778 			Sys_Error("VID: XShmAttach() failed\n");
779 		XSync(dpy, 0);
780 		shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
781 	}
782 
783 }
784 
785 // ========================================================================
786 // Tragic death handler
787 // ========================================================================
788 
TragicDeath(int signal_num)789 void TragicDeath(int signal_num)
790 {
791 //	XAutoRepeatOn(dpy);
792 	XCloseDisplay(dpy);
793 	Sys_Error("This death brought to you by the number %d\n", signal_num);
794 }
795 
XLateKey(XKeyEvent * ev)796 int XLateKey(XKeyEvent *ev)
797 {
798 
799 	int key;
800 	char buf[64];
801 	KeySym keysym;
802 
803 	key = 0;
804 
805 	XLookupString(ev, buf, sizeof buf, &keysym, 0);
806 
807 	switch(keysym)
808 	{
809 		case XK_KP_Page_Up:	 key = K_KP_PGUP; break;
810 		case XK_Page_Up:	 key = K_PGUP; break;
811 
812 		case XK_KP_Page_Down: key = K_KP_PGDN; break;
813 		case XK_Page_Down:	 key = K_PGDN; break;
814 
815 		case XK_KP_Home: key = K_KP_HOME; break;
816 		case XK_Home:	 key = K_HOME; break;
817 
818 		case XK_KP_End:  key = K_KP_END; break;
819 		case XK_End:	 key = K_END; break;
820 
821 		case XK_KP_Left: key = K_KP_LEFTARROW; break;
822 		case XK_Left:	 key = K_LEFTARROW; break;
823 
824 		case XK_KP_Right: key = K_KP_RIGHTARROW; break;
825 		case XK_Right:	key = K_RIGHTARROW;		break;
826 
827 		case XK_KP_Down: key = K_KP_DOWNARROW; break;
828 		case XK_Down:	 key = K_DOWNARROW; break;
829 
830 		case XK_KP_Up:   key = K_KP_UPARROW; break;
831 		case XK_Up:		 key = K_UPARROW;	 break;
832 
833 		case XK_Escape: key = K_ESCAPE;		break;
834 
835 		case XK_KP_Enter: key = K_KP_ENTER;	break;
836 		case XK_Return: key = K_ENTER;		 break;
837 
838 		case XK_Tab:		key = K_TAB;			 break;
839 
840 		case XK_F1:		 key = K_F1;				break;
841 
842 		case XK_F2:		 key = K_F2;				break;
843 
844 		case XK_F3:		 key = K_F3;				break;
845 
846 		case XK_F4:		 key = K_F4;				break;
847 
848 		case XK_F5:		 key = K_F5;				break;
849 
850 		case XK_F6:		 key = K_F6;				break;
851 
852 		case XK_F7:		 key = K_F7;				break;
853 
854 		case XK_F8:		 key = K_F8;				break;
855 
856 		case XK_F9:		 key = K_F9;				break;
857 
858 		case XK_F10:		key = K_F10;			 break;
859 
860 		case XK_F11:		key = K_F11;			 break;
861 
862 		case XK_F12:		key = K_F12;			 break;
863 
864 		case XK_BackSpace: key = K_BACKSPACE; break;
865 
866 		case XK_KP_Delete: key = K_KP_DEL; break;
867 		case XK_Delete: key = K_DEL; break;
868 
869 		case XK_Pause:	key = K_PAUSE;		 break;
870 
871 		case XK_Shift_L:
872 		case XK_Shift_R:	key = K_SHIFT;		break;
873 
874 		case XK_Execute:
875 		case XK_Control_L:
876 		case XK_Control_R:	key = K_CTRL;		 break;
877 
878 		case XK_Alt_L:
879 		case XK_Meta_L:
880 		case XK_Alt_R:
881 		case XK_Meta_R: key = K_ALT;			break;
882 
883 		case XK_KP_Begin: key = K_KP_5;	break;
884 
885 		case XK_Insert:key = K_INS; break;
886 		case XK_KP_Insert: key = K_KP_INS; break;
887 
888 		case XK_KP_Multiply: key = '*'; break;
889 		case XK_KP_Add:  key = K_KP_PLUS; break;
890 		case XK_KP_Subtract: key = K_KP_MINUS; break;
891 		case XK_KP_Divide: key = K_KP_SLASH; break;
892 
893 #if 0
894 		case 0x021: key = '1';break;/* [!] */
895 		case 0x040: key = '2';break;/* [@] */
896 		case 0x023: key = '3';break;/* [#] */
897 		case 0x024: key = '4';break;/* [$] */
898 		case 0x025: key = '5';break;/* [%] */
899 		case 0x05e: key = '6';break;/* [^] */
900 		case 0x026: key = '7';break;/* [&] */
901 		case 0x02a: key = '8';break;/* [*] */
902 		case 0x028: key = '9';;break;/* [(] */
903 		case 0x029: key = '0';break;/* [)] */
904 		case 0x05f: key = '-';break;/* [_] */
905 		case 0x02b: key = '=';break;/* [+] */
906 		case 0x07c: key = '\'';break;/* [|] */
907 		case 0x07d: key = '[';break;/* [}] */
908 		case 0x07b: key = ']';break;/* [{] */
909 		case 0x022: key = '\'';break;/* ["] */
910 		case 0x03a: key = ';';break;/* [:] */
911 		case 0x03f: key = '/';break;/* [?] */
912 		case 0x03e: key = '.';break;/* [>] */
913 		case 0x03c: key = ',';break;/* [<] */
914 #endif
915 
916 		default:
917 			key = *(unsigned char*)buf;
918 			if (key >= 'A' && key <= 'Z')
919 				key = key - 'A' + 'a';
920 			if (key >= 1 && key <= 26) /* ctrl+alpha */
921 				key = key + 'a' - 1;
922 			break;
923 	}
924 
925 	return key;
926 }
927 
928 /* Check to see if this is a repeated key.
929    (idea shamelessly lifted from SDL who...)
930    (idea shamelessly lifted from GII -- thanks guys! :)
931    This has bugs if two keys are being pressed simultaneously and the
932    events start getting interleaved.
933 */
X11_KeyRepeat(Display * display,XEvent * event)934 int X11_KeyRepeat(Display *display, XEvent *event)
935 {
936 	XEvent peekevent;
937 	int repeated;
938 
939 	repeated = 0;
940 	if ( XPending(display) ) {
941 		XPeekEvent(display, &peekevent);
942 		if ( (peekevent.type == KeyPress) &&
943 (peekevent.xkey.keycode == event->xkey.keycode) &&
944 ((peekevent.xkey.time-event->xkey.time) < 2) ) {
945 			repeated = 1;
946 			XNextEvent(display, &peekevent);
947 		}
948 	}
949 	return(repeated);
950 }
951 
HandleEvents(void)952 void HandleEvents(void)
953 {
954   XEvent event;
955   int b;
956   qboolean dowarp = false;
957   int mwx = vid.width/2;
958   int mwy = vid.height/2;
959 
960   in_state_t *in_state = getState();
961 
962   while (XPending(dpy)) {
963     XNextEvent(dpy, &event);
964 
965     switch(event.type) {
966     case KeyPress:
967       myxtime = event.xkey.time;
968       if (in_state && in_state->Key_Event_fp)
969 	in_state->Key_Event_fp (XLateKey(&event.xkey), true);
970       break;
971     case KeyRelease:
972       if (! X11_KeyRepeat(dpy, &event)) {
973 	if (in_state && in_state->Key_Event_fp)
974 	  in_state->Key_Event_fp (XLateKey(&event.xkey), false);
975       }
976       break;
977 
978     case MotionNotify:
979       if (ignorefirst) {
980 	ignorefirst = false;
981 	break;
982       }
983       if (mouse_active) {
984 	if (dgamouse) {
985 	  mx += (event.xmotion.x + win_x)*2;
986 	  my += (event.xmotion.y + win_y)*2;
987 	}
988 	else
989 	  {
990 	    mx += ((int)event.xmotion.x - mwx)*2;
991 	    my -= ((int)event.xmotion.y - mwy)*2;
992 	    mwx = event.xmotion.x;
993 	    mwy = event.xmotion.y;
994 
995 	    if (mx || my)
996 	      dowarp = true;
997 	  }
998       }
999       break;
1000 
1001     case ButtonPress:
1002       myxtime = event.xbutton.time;
1003 
1004       b=-1;
1005       if (event.xbutton.button == 1)
1006 	b = 0;
1007       else if (event.xbutton.button == 2)
1008 	b = 2;
1009       else if (event.xbutton.button == 3)
1010 	b = 1;
1011       else if (event.xbutton.button == 4)
1012 	in_state->Key_Event_fp (K_MWHEELUP, 1);
1013       else if (event.xbutton.button == 5)
1014 	in_state->Key_Event_fp (K_MWHEELDOWN, 1);
1015       else if (event.xbutton.button == 6)
1016 	in_state->Key_Event_fp (K_MOUSE4, 1);
1017       else if (event.xbutton.button == 7)
1018 	in_state->Key_Event_fp (K_MOUSE5, 1);
1019       if (b>=0)
1020 	mouse_buttonstate |= 1<<b;
1021       break;
1022 
1023     case ButtonRelease:
1024       b=-1;
1025       if (event.xbutton.button == 1)
1026 	b = 0;
1027       else if (event.xbutton.button == 2)
1028 	b = 2;
1029       else if (event.xbutton.button == 3)
1030 	b = 1;
1031       else if (event.xbutton.button == 4)
1032 	in_state->Key_Event_fp (K_MWHEELUP, 0);
1033       else if (event.xbutton.button == 5)
1034 	in_state->Key_Event_fp (K_MWHEELDOWN, 0);
1035       else if (event.xbutton.button == 6)
1036 	in_state->Key_Event_fp (K_MOUSE4, 0);
1037       else if (event.xbutton.button == 7)
1038 	in_state->Key_Event_fp (K_MOUSE5, 0);
1039       if (b>=0)
1040 	mouse_buttonstate &= ~(1<<b);
1041       break;
1042 
1043     case CreateNotify :
1044       ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
1045       ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
1046       vid_xpos->modified = false;
1047       vid_ypos->modified = false;
1048       win_x = event.xcreatewindow.x;
1049       win_y = event.xcreatewindow.y;
1050       break;
1051 
1052     case ConfigureNotify :
1053       ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
1054       ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
1055       vid_xpos->modified = false;
1056       vid_ypos->modified = false;
1057       win_x = event.xconfigure.x;
1058       win_y = event.xconfigure.y;
1059       config_notify_width = event.xconfigure.width;
1060       config_notify_height = event.xconfigure.height;
1061       if (config_notify_width != vid.width ||
1062 	  config_notify_height != vid.height)
1063 	XMoveResizeWindow(dpy, win, win_x, win_y, vid.width, vid.height);
1064       config_notify = 1;
1065       break;
1066 
1067     case ClientMessage:
1068       if (event.xclient.data.l[0] == wmDeleteWindow)
1069 	ri.Cmd_ExecuteText(EXEC_NOW, "quit");
1070       break;
1071     default:
1072       if (doShm && event.type == x_shmeventtype)
1073 	oktodraw = true;
1074       if (event.type == Expose && !event.xexpose.count)
1075 	exposureflag = true;
1076     }
1077   }
1078 
1079   if (dowarp) {
1080     /* move the mouse to the window center again */
1081     XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);
1082   }
1083 }
1084 
1085 /*****************************************************************************/
1086 
1087 #ifndef OPENGL
1088 /*
1089 ** SWimp_Init
1090 **
1091 ** This routine is responsible for initializing the implementation
1092 ** specific stuff in a software rendering subsystem.
1093 */
SWimp_Init(void * hInstance,void * wndProc)1094 int SWimp_Init( void *hInstance, void *wndProc )
1095 {
1096 
1097   vid_xpos = ri.Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
1098   vid_ypos = ri.Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
1099 
1100   // open the display
1101   dpy = XOpenDisplay(NULL);
1102   if (!dpy)
1103     {
1104       if (getenv("DISPLAY"))
1105 	Sys_Error("VID: Could not open display [%s]\n",
1106 		  getenv("DISPLAY"));
1107       else
1108 	Sys_Error("VID: Could not open local display\n");
1109     }
1110 
1111   // catch signals so i can turn on auto-repeat
1112 
1113   {
1114     struct sigaction sa;
1115     sigaction(SIGINT, 0, &sa);
1116     sa.sa_handler = TragicDeath;
1117     sigaction(SIGINT, &sa, 0);
1118     sigaction(SIGTERM, &sa, 0);
1119   }
1120 
1121   return true;
1122 }
1123 #endif
1124 
1125 #ifndef OPENGL
1126 /*
1127 ** SWimp_InitGraphics
1128 **
1129 ** This initializes the software refresh's implementation specific
1130 ** graphics subsystem.  In the case of Windows it creates DIB or
1131 ** DDRAW surfaces.
1132 **
1133 ** The necessary width and height parameters are grabbed from
1134 ** vid.width and vid.height.
1135 */
SWimp_InitGraphics(qboolean fullscreen)1136 static qboolean SWimp_InitGraphics( qboolean fullscreen )
1137 {
1138 	int i;
1139 	XVisualInfo template;
1140 	int num_visuals;
1141 	int template_mask;
1142 	Window root;
1143 	//int pnum;
1144 
1145 	srandom(getpid());
1146 
1147 	// free resources in use
1148 	SWimp_Shutdown ();
1149 
1150 	// let the sound and input subsystems know about the new window
1151 	ri.Vid_NewWindow (vid.width, vid.height);
1152 
1153 //	XAutoRepeatOff(dpy);
1154 
1155 // for debugging only
1156 	XSynchronize(dpy, True);
1157 
1158 // check for command-line window size
1159 	template_mask = 0;
1160 
1161 #if 0
1162 // specify a visual id
1163 	if ((pnum=COM_CheckParm("-visualid")))
1164 	{
1165 		if (pnum >= com_argc-1)
1166 			Sys_Error("VID: -visualid <id#>\n");
1167 		template.visualid = Q_atoi(com_argv[pnum+1]);
1168 		template_mask = VisualIDMask;
1169 	}
1170 
1171 // If not specified, use default visual
1172 	else
1173 #endif
1174 	{
1175 		int screen;
1176 		screen = XDefaultScreen(dpy);
1177 		template.visualid =
1178 			XVisualIDFromVisual(XDefaultVisual(dpy, screen));
1179 		template_mask = VisualIDMask;
1180 	}
1181 
1182 // pick a visual- warn if more than one was available
1183 	x_visinfo = XGetVisualInfo(dpy, template_mask, &template, &num_visuals);
1184 	if (num_visuals > 1)
1185 	{
1186 		printf("Found more than one visual id at depth %d:\n", template.depth);
1187 		for (i=0 ; i<num_visuals ; i++)
1188 			printf("	-visualid %d\n", (int)(x_visinfo[i].visualid));
1189 	}
1190 	else if (num_visuals == 0)
1191 	{
1192 		if (template_mask == VisualIDMask)
1193 			Sys_Error("VID: Bad visual id %d\n", template.visualid);
1194 		else
1195 			Sys_Error("VID: No visuals at depth %d\n", template.depth);
1196 	}
1197 
1198 #if 0
1199 	printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
1200 	printf("	screen %d\n", x_visinfo->screen);
1201 	printf("	red_mask 0x%x\n", (int)(x_visinfo->red_mask));
1202 	printf("	green_mask 0x%x\n", (int)(x_visinfo->green_mask));
1203 	printf("	blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
1204 	printf("	colormap_size %d\n", x_visinfo->colormap_size);
1205 	printf("	bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
1206 #endif
1207 
1208 	x_vis = x_visinfo->visual;
1209 	root = XRootWindow(dpy, x_visinfo->screen);
1210 
1211 // setup attributes for main window
1212 	{
1213 	   int attribmask = CWEventMask  | CWColormap | CWBorderPixel;
1214 	   XSetWindowAttributes attribs;
1215 	   XSizeHints *sizehints;
1216 	   XWMHints *wmhints;
1217 	   Colormap tmpcmap;
1218 
1219 	   tmpcmap = XCreateColormap(dpy, root, x_vis, AllocNone);
1220 
1221 	   attribs.event_mask = X_MASK;
1222 	   attribs.border_pixel = 0;
1223 	   attribs.colormap = tmpcmap;
1224 
1225 // create the main window
1226 		win = XCreateWindow(dpy, root, (int)vid_xpos->value, (int)vid_ypos->value,
1227 			vid.width, vid.height, 0, x_visinfo->depth, InputOutput, x_vis,
1228 			attribmask, &attribs );
1229 
1230 		sizehints = XAllocSizeHints();
1231 		if (sizehints) {
1232 			sizehints->min_width = vid.width;
1233 			sizehints->min_height = vid.height;
1234 			sizehints->max_width = vid.width;
1235 			sizehints->max_height = vid.height;
1236 			sizehints->base_width = vid.width;
1237 			sizehints->base_height = vid.height;
1238 
1239 			sizehints->flags = PMinSize | PMaxSize | PBaseSize;
1240 		}
1241 
1242 		wmhints = XAllocWMHints();
1243 		if (wmhints) {
1244 			#include "q2icon.xbm"
1245 
1246 			Pixmap icon_pixmap, icon_mask;
1247 			unsigned long fg, bg;
1248 			int i;
1249 
1250 			fg = BlackPixel(dpy, x_visinfo->screen);
1251 			bg = WhitePixel(dpy, x_visinfo->screen);
1252 			icon_pixmap = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, fg, bg, x_visinfo->depth);
1253 			for (i = 0; i < sizeof(q2icon_bits); i++)
1254 				q2icon_bits[i] = ~q2icon_bits[i];
1255 			icon_mask = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, bg, fg, x_visinfo->depth);
1256 
1257 			wmhints->flags = IconPixmapHint|IconMaskHint;
1258 			wmhints->icon_pixmap = icon_pixmap;
1259 			wmhints->icon_mask = icon_mask;
1260 		}
1261 
1262 		XSetWMProperties(dpy, win, NULL, NULL, NULL, 0,
1263 			sizehints, wmhints, None);
1264 		if (sizehints)
1265 			XFree(sizehints);
1266 		if (wmhints)
1267 			XFree(wmhints);
1268 
1269 		XStoreName(dpy, win, "Quake II");
1270 
1271 		wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1272 		XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
1273 
1274 		if (x_visinfo->class != TrueColor)
1275 			XFreeColormap(dpy, tmpcmap);
1276 	}
1277 
1278 	if (x_visinfo->depth == 8)
1279 	{
1280 	// create and upload the palette
1281 		if (x_visinfo->class == PseudoColor)
1282 		{
1283 			x_cmap = XCreateColormap(dpy, win, x_vis, AllocAll);
1284 			XSetWindowColormap(dpy, win, x_cmap);
1285 		}
1286 
1287 	}
1288 
1289 // create the GC
1290 	{
1291 		XGCValues xgcvalues;
1292 		int valuemask = GCGraphicsExposures;
1293 		xgcvalues.graphics_exposures = False;
1294 		x_gc = XCreateGC(dpy, win, valuemask, &xgcvalues );
1295 	}
1296 
1297 	XMapWindow(dpy, win);
1298 	XMoveWindow(dpy, win, (int)vid_xpos->value, (int)vid_ypos->value);
1299 
1300 // wait for first exposure event
1301 	{
1302 	  exposureflag = false;
1303 	  do
1304 	    {
1305 	      HandleEvents();
1306 	    } while (!exposureflag);
1307 	}
1308 	// now safe to draw
1309 #ifdef REDBLUE
1310 	doShm = false;
1311 #endif
1312 // even if MITSHM is available, make sure it's a local connection
1313 #ifdef REDBLUE
1314 	/*
1315 #endif
1316 	if (XShmQueryExtension(dpy))
1317 	{
1318 		char *displayname;
1319 		doShm = true;
1320 		displayname = (char *) getenv("DISPLAY");
1321 		if (displayname)
1322 		{
1323 			char *dptr = strdup(displayname);
1324 			char *d;
1325 
1326 			d = dptr;
1327 			while (*d && (*d != ':')) d++;
1328 			if (*d) *d = 0;
1329 			if (!(!strcasecmp(displayname, "unix") || !*displayname))
1330 				doShm = false;
1331 
1332 			free(dptr);
1333 		}
1334 	}
1335 #ifdef REDBLUE
1336 	*/
1337 #endif
1338 	if (doShm)
1339 	{
1340 		x_shmeventtype = XShmGetEventBase(dpy) + ShmCompletion;
1341 		ResetSharedFrameBuffers();
1342 	}
1343 	else
1344 		ResetFrameBuffer();
1345 
1346 	current_framebuffer = 0;
1347 	vid.rowbytes = x_framebuffer[0]->bytes_per_line;
1348 	vid.buffer = (byte *)x_framebuffer[0]->data;
1349 
1350 //	XSynchronize(dpy, False);
1351 
1352 	X11_active = true;
1353 
1354 	return true;
1355 }
1356 #endif
1357 
1358 #ifndef OPENGL
1359 /*
1360 ** SWimp_EndFrame
1361 **
1362 ** This does an implementation specific copy from the backbuffer to the
1363 ** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
1364 ** on whether we're using DIB sections/GDI or DDRAW.
1365 */
SWimp_EndFrame(void)1366 void SWimp_EndFrame (void)
1367 {
1368 // if the window changes dimension, skip this frame
1369 #if 0
1370 	if (config_notify)
1371 	{
1372 		fprintf(stderr, "config notify\n");
1373 		config_notify = 0;
1374 		vid.width = config_notify_width & ~7;
1375 		vid.height = config_notify_height;
1376 		if (doShm)
1377 			ResetSharedFrameBuffers();
1378 		else
1379 			ResetFrameBuffer();
1380 		vid.rowbytes = x_framebuffer[0]->bytes_per_line;
1381 		vid.buffer = x_framebuffer[current_framebuffer]->data;
1382 		vid.recalc_refdef = 1;				// force a surface cache flush
1383 		Con_CheckResize();
1384 		Con_Clear_f();
1385 		return;
1386 	}
1387 #endif
1388 
1389 	if (doShm)
1390 	{
1391 	  if (x_visinfo->depth == 16)
1392 	    st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
1393 	  else if (x_visinfo->depth == 24)
1394 	    st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
1395 		if (!XShmPutImage(dpy, win, x_gc,
1396 			x_framebuffer[current_framebuffer], 0, 0, 0, 0, vid.width, vid.height, True))
1397 			Sys_Error("VID_Update: XShmPutImage failed\n");
1398 		oktodraw = false;
1399 		while (!oktodraw)
1400 			HandleEvents();
1401 		current_framebuffer = !current_framebuffer;
1402 		vid.buffer = (byte *)x_framebuffer[current_framebuffer]->data;
1403 		XSync(dpy, False);
1404 	}
1405 	else
1406 	{
1407 
1408 #ifdef REDBLUE
1409 	  if (x_visinfo->depth == 16)
1410 	    st2_fixup_stereo( x_framebuffer[0], x_framebuffer[1],
1411 			      0, 0, vid.width, vid.height);
1412 	  else if (x_visinfo->depth == 24)
1413 	    st3_fixup_stereo( x_framebuffer[0], x_framebuffer[1],
1414 			      0, 0, vid.width, vid.height);
1415 #else
1416 	  if (x_visinfo->depth == 16)
1417 	    st2_fixup( x_framebuffer[current_framebuffer],
1418 		       0, 0, vid.width, vid.height);
1419 	  else if (x_visinfo->depth == 24)
1420 	    st3_fixup( x_framebuffer[current_framebuffer],
1421 		       0, 0, vid.width, vid.height);
1422 #endif
1423 	  XPutImage(dpy, win, x_gc, x_framebuffer[0], 0,
1424 		    0, 0, 0, vid.width, vid.height);
1425 	  XSync(dpy, False);
1426 	}
1427 }
1428 #endif
1429 
1430 #ifndef OPENGL
1431 /*
1432 ** SWimp_SetMode
1433 */
SWimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)1434 rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
1435 {
1436 	rserr_t retval = rserr_ok;
1437 
1438 	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
1439 
1440 	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
1441 	{
1442 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
1443 		return rserr_invalid_mode;
1444 	}
1445 
1446 	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
1447 
1448 	if ( !SWimp_InitGraphics( false ) ) {
1449 		// failed to set a valid mode in windowed mode
1450 		return rserr_invalid_mode;
1451 	}
1452 
1453 	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
1454 
1455 	return retval;
1456 }
1457 #endif
1458 
1459 #ifndef OPENGL
1460 /*
1461 ** SWimp_SetPalette
1462 **
1463 ** System specific palette setting routine.  A NULL palette means
1464 ** to use the existing palette.  The palette is expected to be in
1465 ** a padded 4-byte xRGB format.
1466 */
SWimp_SetPalette(const unsigned char * palette)1467 void SWimp_SetPalette( const unsigned char *palette )
1468 {
1469 	int i;
1470 	XColor colors[256];
1471 
1472 	if (!X11_active)
1473 		return;
1474 
1475 	if ( !palette )
1476 		palette = ( const unsigned char * ) sw_state.currentpalette;
1477 
1478 	for(i=0;i<256;i++) {
1479 #ifdef REDBLUE
1480 	  int tmp = (30*palette[i*4] + 59*palette[i*4+1] + 11*palette[i*4+2]) / 100;
1481 	  st2d_8to16table_s[0][i]= xlib_rgb16(tmp,0,0);
1482 	  st2d_8to24table_s[0][i]= xlib_rgb24(tmp,0,0);
1483 	  st2d_8to16table_s[1][i]= xlib_rgb16(0,0,tmp);
1484 	  st2d_8to24table_s[1][i]= xlib_rgb24(0,0,tmp);
1485 #endif
1486 	  st2d_8to16table[i]= xlib_rgb16(palette[i*4],
1487 					 palette[i*4+1],palette[i*4+2]);
1488 	  st2d_8to24table[i]= xlib_rgb24(palette[i*4],
1489 					 palette[i*4+1],palette[i*4+2]);
1490 	}
1491 
1492 	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
1493 	{
1494 		for (i=0 ; i<256 ; i++)
1495 		{
1496 			colors[i].pixel = i;
1497 			colors[i].flags = DoRed|DoGreen|DoBlue;
1498 			colors[i].red = palette[i*4] * 257;
1499 			colors[i].green = palette[i*4+1] * 257;
1500 			colors[i].blue = palette[i*4+2] * 257;
1501 		}
1502 		XStoreColors(dpy, x_cmap, colors, 256);
1503 	}
1504 }
1505 #endif
1506 
1507 #ifndef OPENGL
1508 /*
1509 ** SWimp_Shutdown
1510 **
1511 ** System specific graphics subsystem shutdown routine.  Destroys
1512 ** DIBs or DDRAW surfaces as appropriate.
1513 */
SWimp_Shutdown(void)1514 void SWimp_Shutdown( void )
1515 {
1516 	int i;
1517 
1518 	if (!X11_active)
1519 		return;
1520 
1521 	if (doShm) {
1522 		for (i = 0; i < 2; i++)
1523 			if (x_framebuffer[i]) {
1524 				XShmDetach(dpy, &x_shminfo[i]);
1525 				free(x_framebuffer[i]);
1526 				shmdt(x_shminfo[i].shmaddr);
1527 				x_framebuffer[i] = NULL;
1528 			}
1529 	} else {
1530 	  if (x_framebuffer[0]) {
1531 	    free(x_framebuffer[0]->data);
1532 	    free(x_framebuffer[0]);
1533 	    x_framebuffer[0] = NULL;
1534 	  }
1535 	  if (x_framebuffer[1]) {
1536 	    free(x_framebuffer[1]->data);
1537 	    free(x_framebuffer[1]);
1538 	    x_framebuffer[1] = NULL;
1539 	  }
1540 	}
1541 
1542 	XDestroyWindow(	dpy, win );
1543 
1544 	win = 0;
1545 
1546 //	XAutoRepeatOn(dpy);
1547 //	XCloseDisplay(dpy);
1548 
1549 	X11_active = false;
1550 }
1551 #endif
1552 
1553 #ifndef OPENGL
1554 /*
1555 ** SWimp_AppActivate
1556 */
SWimp_AppActivate(qboolean active)1557 void SWimp_AppActivate( qboolean active )
1558 {
1559 }
1560 
1561 #ifdef REDBLUE
SetStereoBuffer(int buf)1562 void SetStereoBuffer(int buf)
1563 {
1564   if (x_framebuffer[buf])
1565     vid.buffer = (byte*) (x_framebuffer[buf]->data);
1566   else
1567     printf("SetStereoBuffer: x_framebuffer[%d] is NULL\n", buf);
1568 }
1569 #endif
1570 #endif
1571 //===============================================================================
1572 
1573 /*
1574 ================
1575 Sys_MakeCodeWriteable
1576 ================
1577 */
Sys_MakeCodeWriteable(unsigned long startaddr,unsigned long length)1578 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
1579 {
1580 
1581 	int r;
1582 	unsigned long addr;
1583 	int psize = getpagesize();
1584 
1585 	addr = (startaddr & ~(psize-1)) - psize;
1586 
1587 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
1588 //			addr, startaddr+length, length);
1589 
1590 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
1591 
1592 	if (r < 0)
1593     		Sys_Error("Protection change failed\n");
1594 
1595 }
1596 
1597 /*****************************************************************************/
1598 /* KEYBOARD                                                                  */
1599 /*****************************************************************************/
1600 
1601 Key_Event_fp_t Key_Event_fp;
1602 
KBD_Init(Key_Event_fp_t fp)1603 void KBD_Init(Key_Event_fp_t fp)
1604 {
1605   Key_Event_fp = fp;
1606 }
1607 
KBD_Update(void)1608 void KBD_Update(void)
1609 {
1610   // get events from x server
1611   HandleEvents();
1612 }
1613 
KBD_Close(void)1614 void KBD_Close(void)
1615 {
1616 }
1617 
1618 #ifdef OPENGL
1619 
1620 qboolean GLimp_InitGL (void);
1621 
signal_handler(int sig)1622 static void signal_handler(int sig)
1623 {
1624 	printf("Received signal %d, exiting...\n", sig);
1625 	GLimp_Shutdown();
1626 	_exit(0);
1627 }
1628 
InitSig(void)1629 static void InitSig(void)
1630 {
1631 	signal(SIGHUP, signal_handler);
1632 	signal(SIGQUIT, signal_handler);
1633 	signal(SIGILL, signal_handler);
1634 	signal(SIGTRAP, signal_handler);
1635 	signal(SIGIOT, signal_handler);
1636 	signal(SIGBUS, signal_handler);
1637 	signal(SIGFPE, signal_handler);
1638 	signal(SIGSEGV, signal_handler);
1639 	signal(SIGTERM, signal_handler);
1640 }
1641 
1642 /*
1643 ** GLimp_AppActivate
1644 */
GLimp_AppActivate(qboolean active)1645 void GLimp_AppActivate( qboolean active )
1646 {
1647 }
1648 
1649 /*
1650 ** GLimp_BeginFrame
1651 */
GLimp_BeginFrame(float camera_seperation)1652 void GLimp_BeginFrame( float camera_seperation )
1653 {
1654 }
1655 
1656 
1657 /*
1658 ** GLimp_EndFrame
1659 **
1660 ** Responsible for doing a swapbuffers and possibly for other stuff
1661 ** as yet to be determined.  Probably better not to make this a GLimp
1662 ** function and instead do a call to GLimp_SwapBuffers.
1663 */
GLimp_EndFrame(void)1664 void GLimp_EndFrame (void)
1665 {
1666 	qglFlush();
1667 	qglXSwapBuffers(dpy, win);
1668 }
1669 
1670 /*
1671 ** GLimp_Init
1672 **
1673 ** This routine is responsible for initializing the OS specific portions
1674 ** of OpenGL.
1675 */
GLimp_Init(void * hinstance,void * wndproc)1676 int GLimp_Init( void *hinstance, void *wndproc )
1677 {
1678 	InitSig();
1679 
1680 	if ( glw_state.OpenGLLib) {
1681 		#define GPA( a ) dlsym( glw_state.OpenGLLib, a )
1682 
1683 		qglXChooseVisual             =  GPA("glXChooseVisual");
1684 		qglXCreateContext            =  GPA("glXCreateContext");
1685 		qglXDestroyContext           =  GPA("glXDestroyContext");
1686 		qglXMakeCurrent              =  GPA("glXMakeCurrent");
1687 		qglXCopyContext              =  GPA("glXCopyContext");
1688 		qglXSwapBuffers              =  GPA("glXSwapBuffers");
1689 
1690 		return true;
1691 	}
1692 
1693 	return false;
1694 }
1695 
1696 /*
1697 ** GLimp_SetMode
1698 */
GLimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)1699 int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
1700 {
1701 	int width, height;
1702 	int attrib[] = {
1703 		GLX_RGBA,
1704 		GLX_RED_SIZE, 1,
1705 		GLX_GREEN_SIZE, 1,
1706 		GLX_BLUE_SIZE, 1,
1707 		GLX_DOUBLEBUFFER,
1708 		GLX_DEPTH_SIZE, 1,
1709 		None
1710 	};
1711 	Window root;
1712 	XVisualInfo *visinfo;
1713 	XSetWindowAttributes attr;
1714 	XSizeHints *sizehints;
1715 	XWMHints *wmhints;
1716 	unsigned long mask;
1717 	int MajorVersion, MinorVersion;
1718 	int actualWidth, actualHeight;
1719 	int i;
1720 
1721 	r_fakeFullscreen = ri.Cvar_Get( "r_fakeFullscreen", "0", CVAR_ARCHIVE);
1722 
1723 	ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
1724 
1725 	if (fullscreen)
1726 		ri.Con_Printf (PRINT_ALL, "...setting fullscreen mode %d:", mode );
1727 	else
1728 		ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
1729 
1730 	if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
1731 	{
1732 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
1733 		return rserr_invalid_mode;
1734 	}
1735 
1736 	ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
1737 
1738 	// destroy the existing window
1739 	GLimp_Shutdown ();
1740 
1741 #if 0 // this breaks getenv()? - sbf
1742 	// Mesa VooDoo hacks
1743 	if (fullscreen)
1744 		putenv("MESA_GLX_FX=fullscreen");
1745 	else
1746 		putenv("MESA_GLX_FX=window");
1747 #endif
1748 
1749 	if (!(dpy = XOpenDisplay(NULL))) {
1750 		fprintf(stderr, "Error couldn't open the X display\n");
1751 		return rserr_invalid_mode;
1752 	}
1753 
1754 	scrnum = DefaultScreen(dpy);
1755 	root = RootWindow(dpy, scrnum);
1756 
1757 	// Get video mode list
1758 	MajorVersion = MinorVersion = 0;
1759 	if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
1760 		vidmode_ext = false;
1761 	} else {
1762 		ri.Con_Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n",
1763 			MajorVersion, MinorVersion);
1764 		vidmode_ext = true;
1765 	}
1766 
1767 	visinfo = qglXChooseVisual(dpy, scrnum, attrib);
1768 	if (!visinfo) {
1769 		fprintf(stderr, "Error couldn't get an RGB, Double-buffered, Depth visual\n");
1770 		return rserr_invalid_mode;
1771 	}
1772 
1773 	gl_state.hwgamma = false;
1774 
1775 	if (vidmode_ext) {
1776 		int best_fit, best_dist, dist, x, y;
1777 
1778 		XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
1779 
1780 		// Are we going fullscreen?  If so, let's change video mode
1781 		if (fullscreen && !r_fakeFullscreen->value) {
1782 			best_dist = 9999999;
1783 			best_fit = -1;
1784 
1785 			for (i = 0; i < num_vidmodes; i++) {
1786 				if (width > vidmodes[i]->hdisplay ||
1787 					height > vidmodes[i]->vdisplay)
1788 					continue;
1789 
1790 				x = width - vidmodes[i]->hdisplay;
1791 				y = height - vidmodes[i]->vdisplay;
1792 				dist = (x * x) + (y * y);
1793 				if (dist < best_dist) {
1794 					best_dist = dist;
1795 					best_fit = i;
1796 				}
1797 			}
1798 
1799 			if (best_fit != -1) {
1800 				actualWidth = vidmodes[best_fit]->hdisplay;
1801 				actualHeight = vidmodes[best_fit]->vdisplay;
1802 
1803 				// change to the mode
1804 				XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
1805 				vidmode_active = true;
1806 
1807 				if (XF86VidModeGetGamma(dpy, scrnum, &oldgamma)) {
1808 					gl_state.hwgamma = true;
1809 					/* We can not reliably detect hardware gamma
1810 					   changes across software gamma calls, which
1811 					   can reset the flag, so change it anyway */
1812 					vid_gamma->modified = true;
1813 					ri.Con_Printf( PRINT_ALL, "Using hardware gamma\n");
1814 				}
1815 
1816 				// Move the viewport to top left
1817 				XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
1818 			} else
1819 				fullscreen = 0;
1820 		}
1821 	}
1822 
1823 	/* window attributes */
1824 	attr.background_pixel = 0;
1825 	attr.border_pixel = 0;
1826 	attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
1827 	attr.event_mask = X_MASK;
1828 	if (vidmode_active) {
1829 		mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
1830 			CWEventMask | CWOverrideRedirect;
1831 		attr.override_redirect = True;
1832 		attr.backing_store = NotUseful;
1833 		attr.save_under = False;
1834 	} else
1835 		mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
1836 
1837 	win = XCreateWindow(dpy, root, 0, 0, width, height,
1838 						0, visinfo->depth, InputOutput,
1839 						visinfo->visual, mask, &attr);
1840 
1841 	sizehints = XAllocSizeHints();
1842 	if (sizehints) {
1843 		sizehints->min_width = width;
1844 		sizehints->min_height = height;
1845 		sizehints->max_width = width;
1846 		sizehints->max_height = height;
1847 		sizehints->base_width = width;
1848 		sizehints->base_height = vid.height;
1849 
1850 		sizehints->flags = PMinSize | PMaxSize | PBaseSize;
1851 	}
1852 
1853 	wmhints = XAllocWMHints();
1854 	if (wmhints) {
1855 		#include "q2icon.xbm"
1856 
1857 		Pixmap icon_pixmap, icon_mask;
1858 		unsigned long fg, bg;
1859 		int i;
1860 
1861 		fg = BlackPixel(dpy, visinfo->screen);
1862 		bg = WhitePixel(dpy, visinfo->screen);
1863 		icon_pixmap = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, fg, bg, visinfo->depth);
1864 		for (i = 0; i < sizeof(q2icon_bits); i++)
1865 			q2icon_bits[i] = ~q2icon_bits[i];
1866 		icon_mask = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, bg, fg, visinfo->depth);
1867 
1868 		wmhints->flags = IconPixmapHint|IconMaskHint;
1869 		wmhints->icon_pixmap = icon_pixmap;
1870 		wmhints->icon_mask = icon_mask;
1871 	}
1872 
1873 	XSetWMProperties(dpy, win, NULL, NULL, NULL, 0,
1874 			sizehints, wmhints, None);
1875 	if (sizehints)
1876 		XFree(sizehints);
1877 	if (wmhints)
1878 		XFree(wmhints);
1879 
1880 	XStoreName(dpy, win, "Quake II");
1881 
1882 	wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1883 	XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
1884 
1885 	XMapWindow(dpy, win);
1886 
1887 	if (vidmode_active) {
1888 		XMoveWindow(dpy, win, 0, 0);
1889 		XRaiseWindow(dpy, win);
1890 		XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
1891 		XFlush(dpy);
1892 		// Move the viewport to top left
1893 		XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
1894 	}
1895 
1896 	XFlush(dpy);
1897 
1898 	ctx = qglXCreateContext(dpy, visinfo, NULL, True);
1899 
1900 	qglXMakeCurrent(dpy, win, ctx);
1901 
1902 	*pwidth = width;
1903 	*pheight = height;
1904 
1905 	// let the sound and input subsystems know about the new window
1906 	ri.Vid_NewWindow (width, height);
1907 
1908 	qglXMakeCurrent(dpy, win, ctx);
1909 
1910 	return rserr_ok;
1911 }
1912 
Fake_glColorTableEXT(GLenum target,GLenum internalformat,GLsizei width,GLenum format,GLenum type,const GLvoid * table)1913 void Fake_glColorTableEXT( GLenum target, GLenum internalformat,
1914                              GLsizei width, GLenum format, GLenum type,
1915                              const GLvoid *table )
1916 {
1917 	byte temptable[256][4];
1918 	byte *intbl;
1919 	int i;
1920 
1921 	for (intbl = (byte *)table, i = 0; i < 256; i++) {
1922 		temptable[i][2] = *intbl++;
1923 		temptable[i][1] = *intbl++;
1924 		temptable[i][0] = *intbl++;
1925 		temptable[i][3] = 255;
1926 	}
1927 	qgl3DfxSetPaletteEXT((GLuint *)temptable);
1928 }
1929 
1930 /*
1931 ** GLimp_Shutdown
1932 **
1933 ** This routine does all OS specific shutdown procedures for the OpenGL
1934 ** subsystem.  Under OpenGL this means NULLing out the current DC and
1935 ** HGLRC, deleting the rendering context, and releasing the DC acquired
1936 ** for the window.  The state structure is also nulled out.
1937 **
1938 */
GLimp_Shutdown(void)1939 void GLimp_Shutdown( void )
1940 {
1941 	uninstall_grabs();
1942 	mouse_active = false;
1943 	dgamouse = false;
1944 
1945 	if (dpy) {
1946 		if (ctx)
1947 			qglXDestroyContext(dpy, ctx);
1948 		if (win)
1949 			XDestroyWindow(dpy, win);
1950 		if (gl_state.hwgamma) {
1951 			XF86VidModeSetGamma(dpy, scrnum, &oldgamma);
1952 			/* The gamma has changed, but SetMode will change it
1953 			   anyway, so why bother?
1954 			vid_gamma->modified = true; */
1955 		}
1956 		if (vidmode_active)
1957 			XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
1958 		XUngrabKeyboard(dpy, CurrentTime);
1959 		XCloseDisplay(dpy);
1960 	}
1961 	ctx = NULL;
1962 	dpy = NULL;
1963 	win = 0;
1964 	ctx = NULL;
1965 /*
1966 	qglXChooseVisual             = NULL;
1967 	qglXCreateContext            = NULL;
1968 	qglXDestroyContext           = NULL;
1969 	qglXMakeCurrent              = NULL;
1970 	qglXCopyContext              = NULL;
1971 	qglXSwapBuffers              = NULL;
1972 */
1973 }
1974 #endif
1975 
1976 #ifdef Joystick
PlatformJoyCommands(int * axis_vals,int * axis_map)1977 void PlatformJoyCommands(int *axis_vals, int *axis_map) {
1978   struct joystick j;
1979   in_state_t *in_state = getState();
1980 
1981   /*
1982    * FreeBSD does not fully support multi-buttoned joysticks.
1983    */
1984   if (read(joy_fd, &j, sizeof(struct joystick)) != -1) {
1985     if (j.b1)
1986       in_state->Key_Event_fp (K_JOY1, true);
1987     else
1988       in_state->Key_Event_fp (K_JOY1, false);
1989     if (j.b2)
1990       in_state->Key_Event_fp (K_JOY2, true);
1991     else
1992       in_state->Key_Event_fp (K_JOY2, false);
1993     axis_vals[axis_map[0]] = j.x;
1994     axis_vals[axis_map[1]] = j.y;
1995   }
1996 }
1997 #endif
1998