|
|
1.1 ! root 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.