home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / vid_x.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  25.8 KB  |  1,117 lines

  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  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.  
  600. void VID_ShiftPalette(unsigned char *p)
  601. {
  602.     VID_SetPalette(p);
  603. }
  604.  
  605.  
  606.  
  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.  
  636. void    VID_Shutdown (void)
  637. {
  638.     Con_Printf("VID_Shutdown\n");
  639.     XAutoRepeatOn(x_disp);
  640.     XCloseDisplay(x_disp);
  641. }
  642.  
  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.                               
  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.  
  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.  
  950. void VID_DitherOn(void)
  951. {
  952.     if (dither == 0)
  953.     {
  954.         vid.recalc_refdef = 1;
  955.         dither = 1;
  956.     }
  957. }
  958.  
  959. void VID_DitherOff(void)
  960. {
  961.     if (dither)
  962.     {
  963.         vid.recalc_refdef = 1;
  964.         dither = 0;
  965.     }
  966. }
  967.  
  968. int Sys_OpenWindow(void)
  969. {
  970.     return 0;
  971. }
  972.  
  973. void Sys_EraseWindow(int window)
  974. {
  975. }
  976.  
  977. void Sys_DrawCircle(int window, int x, int y, int r)
  978. {
  979. }
  980.  
  981. void Sys_DisplayWindow(int window)
  982. {
  983. }
  984.  
  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.  
  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.  
  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.  
  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.  
  1050. void IN_Shutdown (void)
  1051. {
  1052.    mouse_avail = 0;
  1053. }
  1054.  
  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.  
  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.  
  1109. void VID_LockBuffer (void)
  1110. {
  1111. }
  1112.  
  1113. void VID_UnlockBuffer (void)
  1114. {
  1115. }
  1116.  
  1117.