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