Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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