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#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 42cvar_t m_filter = {"m_filter","0", true}; 43 44qboolean mouse_avail; 45int mouse_buttons=3; 46int mouse_oldbuttonstate; 47int mouse_buttonstate; 48float mouse_x, mouse_y; 49float old_mouse_x, old_mouse_y; 50int p_mouse_x; 51int p_mouse_y; 52qboolean mouse_grabbed = false; // we grab it when console is up 53 54int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; 55byte *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 64typedef 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 76typedef struct 77{ 78 int modenum; 79 int iscur; 80 char desc[256]; 81} modedesc_t; 82 83extern void M_Menu_Options_f (void); 84extern void M_Print (int cx, int cy, char *str); 85extern void M_PrintWhite (int cx, int cy, char *str); 86extern void M_DrawCharacter (int cx, int line, int num); 87extern void M_DrawTransPic (int x, int y, qpic_t *pic); 88extern void M_DrawPic (int x, int y, qpic_t *pic); 89 90extern int sb_updates; 91extern int x_root, y_root; // root window relative mouse coords 92 93typedef struct 94{ 95 int input; 96 int output; 97} keymap_t; 98 99viddef_t vid; // global video state 100unsigned short d_8to16table[256]; 101 102int num_shades=32; 103 104int d_con_indirect = 0; 105 106int vid_buffersize; 107 108#define STD_EVENT_MASK \ 109( KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ 110PointerMotionMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask | \ 111ExposureMask | StructureNotifyMask ) 112 113qboolean x_fullscreen = true; 114Display *x_disp = NULL; 115int x_screen, x_screen_width, x_screen_height; 116int x_center_width, x_center_height; 117int x_std_event_mask = STD_EVENT_MASK; 118Window x_win, x_root_win; 119qboolean mouse_in_window = false; 120int global_dx, global_dy; 121 122static qboolean doShm; 123static Colormap x_cmap; 124static GC x_gc; 125static Visual *x_vis; 126static XVisualInfo *x_visinfo; 127static Atom aHints = 0; 128static Atom aWMDelete = 0; 129 130static int x_shmeventtype; 131//static XShmSegmentInfo x_shminfo; 132 133static qboolean oktodraw = false; 134 135int XShmQueryExtension(Display *); 136int XShmGetEventBase(Display *); 137 138int current_framebuffer; 139static XImage *x_framebuffer[2] = { 0, 0 }; 140static XShmSegmentInfo x_shminfo[2]; 141 142static int verbose=1; 143 144static byte current_palette[768]; 145 146typedef unsigned short PIXEL16; 147typedef unsigned long PIXEL24; 148static PIXEL16 st2d_8to16table[256]; 149static PIXEL24 st2d_8to24table[256]; 150static int shiftmask_fl=0; 151static long r_shift,g_shift,b_shift; 152static unsigned long r_mask,g_mask,b_mask; 153 154void 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 166PIXEL16 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 193PIXEL24 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 220void 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 256void 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================ 294D_BeginDirectRect 295================ 296*/ 297void 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================ 305D_EndDirectRect 306================ 307*/ 308void 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================= 316VID_Gamma_f 317 318Keybinding command 319================= 320*/ 321 322byte vid_gamma[256]; 323 324void 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 356void 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 367static 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 389void 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 426void 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 493void 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 506void 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 512byte surfcache[1024*1024]; 513 514// 515// VID_SetWindowTitle - set the window and icon titles 516// 517 518void 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 544qboolean 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 569void 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 808void VID_ShiftPalette(unsigned char *p) 809{ 810 VID_SetPalette(p); 811} 812 813void 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 843void 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 855int 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 916struct 917{ 918 int key; 919 int down; 920} keyq[64]; 921int keyq_head=0; 922int keyq_tail=0; 923 924int config_notify=0; 925int config_notify_width; 926int config_notify_height; 927 928void 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 1012void 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 { 1061printf("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 1105static int dither; 1106 1107void VID_DitherOn(void) 1108{ 1109 if (dither == 0) 1110 { 1111 vid.recalc_refdef = 1; 1112 dither = 1; 1113 } 1114} 1115 1116void VID_DitherOff(void) 1117{ 1118 if (dither) 1119 { 1120 vid.recalc_refdef = 1; 1121 dither = 0; 1122 } 1123} 1124 1125void VID_SetDefaultMode( void ) 1126{ 1127} 1128 1129int I_OpenWindow(void) 1130{ 1131 return 0; 1132} 1133 1134void I_EraseWindow(int window) 1135{ 1136} 1137 1138void I_DrawCircle(int window, int x, int y, int r) 1139{ 1140} 1141 1142void I_DisplayWindow(int window) 1143{ 1144} 1145 1146void 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 1161char *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 1191void 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 1200void IN_Shutdown (void) 1201{ 1202 mouse_avail = 0; 1203} 1204 1205void 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 1221void 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