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