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