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