|
|
1.1 root 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:
113: static void Force_CenterView_f (void)
114: {
115: in_state->viewangles[PITCH] = 0;
116: }
117:
118: static void RW_IN_MLookDown (void)
119: {
120: mlooking = true;
121: }
122:
123: static void RW_IN_MLookUp (void)
124: {
125: mlooking = false;
126: in_state->IN_CenterView_fp ();
127: }
128:
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:
157: void RW_IN_Shutdown(void)
158: {
159: mouse_avail = false;
160: }
161:
162: /*
163: ===========
164: IN_Commands
165: ===========
166: */
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: */
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:
231: void RW_IN_Frame (void)
232: {
233: }
234:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: */
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: */
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: */
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: */
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: */
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: */
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: */
1033: void SWimp_AppActivate( qboolean active )
1034: {
1035: }
1036:
1037: //===============================================================================
1038:
1039: /*
1040: ================
1041: Sys_MakeCodeWriteable
1042: ================
1043: */
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:
1069: void KBD_Init(Key_Event_fp_t fp)
1070: {
1071: Key_Event_fp = fp;
1072: }
1073:
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:
1089: void KBD_Close(void)
1090: {
1091: }
1092:
1093:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.