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