1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 44cvar_t _windowed_mouse = {"_windowed_mouse","0", true}; 45cvar_t m_filter = {"m_filter","0", true}; 46float old_windowed_mouse; 47 48qboolean mouse_avail; 49int mouse_buttons=3; 50int mouse_oldbuttonstate; 51int mouse_buttonstate; 52float mouse_x, mouse_y; 53float old_mouse_x, old_mouse_y; 54int p_mouse_x; 55int p_mouse_y; 56int ignorenext; 57int bits_per_pixel; 58 59typedef struct 60{ 61 int input; 62 int output; 63} keymap_t; 64 65viddef_t vid; // global video state 66unsigned short d_8to16table[256]; 67 68int num_shades=32; 69 70int d_con_indirect = 0; 71 72int vid_buffersize; 73 74static qboolean doShm; 75static Display *x_disp; 76static Colormap x_cmap; 77static Window x_win; 78static GC x_gc; 79static Visual *x_vis; 80static XVisualInfo *x_visinfo; 81//static XImage *x_image; 82 83static int x_shmeventtype; 84//static XShmSegmentInfo x_shminfo; 85 86static qboolean oktodraw = false; 87 88int XShmQueryExtension(Display *); 89int XShmGetEventBase(Display *); 90 91int current_framebuffer; 92static XImage *x_framebuffer[2] = { 0, 0 }; 93static XShmSegmentInfo x_shminfo[2]; 94 95static int verbose=0; 96 97static byte current_palette[768]; 98 99static long X11_highhunkmark; 100static long X11_buffersize; 101 102int vid_surfcachesize; 103void *vid_surfcache; 104 105void (*vid_menudrawfn)(void); 106void (*vid_menukeyfn)(int key); 107void VID_MenuKey (int key); 108 109typedef unsigned short PIXEL16; 110typedef unsigned long PIXEL24; 111static PIXEL16 st2d_8to16table[256]; 112static PIXEL24 st2d_8to24table[256]; 113static int shiftmask_fl=0; 114static long r_shift,g_shift,b_shift; 115static unsigned long r_mask,g_mask,b_mask; 116 117void 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 129PIXEL16 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 156PIXEL24 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 183void 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 219void 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 260void 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 271static 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 293void 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 350void 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 442void 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 674void VID_ShiftPalette(unsigned char *p) 675{ 676 VID_SetPalette(p); 677} 678 679 680 681void 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 711void VID_Shutdown (void) 712{ 713 Con_Printf("VID_Shutdown\n"); 714 XAutoRepeatOn(x_disp); 715 XCloseDisplay(x_disp); 716} 717 718int 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 849struct 850{ 851 int key; 852 int down; 853} keyq[64]; 854int keyq_head=0; 855int keyq_tail=0; 856 857int config_notify=0; 858int config_notify_width; 859int config_notify_height; 860 861void 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 957void 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 1040static int dither; 1041 1042void VID_DitherOn(void) 1043{ 1044 if (dither == 0) 1045 { 1046 vid.recalc_refdef = 1; 1047 dither = 1; 1048 } 1049} 1050 1051void VID_DitherOff(void) 1052{ 1053 if (dither) 1054 { 1055 vid.recalc_refdef = 1; 1056 dither = 0; 1057 } 1058} 1059 1060int Sys_OpenWindow(void) 1061{ 1062 return 0; 1063} 1064 1065void Sys_EraseWindow(int window) 1066{ 1067} 1068 1069void Sys_DrawCircle(int window, int x, int y, int r) 1070{ 1071} 1072 1073void Sys_DisplayWindow(int window) 1074{ 1075} 1076 1077void 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 1092char *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 1122void 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 1127void 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 1132void 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 1142void IN_Shutdown (void) 1143{ 1144 mouse_avail = 0; 1145} 1146 1147void 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 1163void 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