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