doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

i_video.c (17378B)


      1 #include <stdlib.h>
      2 #include <unistd.h>
      3 #include <sys/ipc.h>
      4 #include <sys/shm.h>
      5 #include <X11/Xlib.h>
      6 #include <X11/Xutil.h>
      7 #include <X11/keysym.h>
      8 #include <X11/extensions/XShm.h>
      9 
     10 int XShmGetEventBase( Display* dpy ); 
     11 
     12 #include <stdarg.h>
     13 #include <sys/time.h>
     14 #include <sys/types.h>
     15 #include <sys/socket.h>
     16 #include <netinet/in.h>
     17 #include <errno.h>
     18 #include <signal.h>
     19 #include "doomstat.h"
     20 #include "i_system.h"
     21 #include "v_video.h"
     22 #include "m_argv.h"
     23 #include "d_main.h"
     24 #include "doomdef.h"
     25 
     26 #define POINTER_WARP_COUNTDOWN	1
     27 
     28 byte gammatable[5][256] = {
     29 	{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
     30 	17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
     31 	33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
     32 	49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
     33 	65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
     34 	81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
     35 	97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
     36 	113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
     37 	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
     38 	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
     39 	160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
     40 	176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
     41 	192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
     42 	208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
     43 	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
     44 	240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
     45 
     46 	{2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
     47 	32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
     48 	56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
     49 	78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
     50 	99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
     51 	115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
     52 	130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
     53 	146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
     54 	161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
     55 	175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
     56 	190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
     57 	205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
     58 	219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
     59 	233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
     60 	247,248,249,250,251,252,252,253,254,255},
     61 
     62 	{4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
     63 	43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
     64 	70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
     65 	94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
     66 	113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
     67 	129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
     68 	144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
     69 	160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
     70 	174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
     71 	188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
     72 	202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
     73 	216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
     74 	229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
     75 	242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
     76 	255},
     77 
     78 	{8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
     79 	57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
     80 	86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
     81 	108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
     82 	125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
     83 	141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
     84 	155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
     85 	169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
     86 	183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
     87 	195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
     88 	207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
     89 	219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
     90 	231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
     91 	242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
     92 	253,253,254,254,255},
     93 
     94 	{16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
     95 	78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
     96 	107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
     97 	125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
     98 	142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
     99 	156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
    100 	169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
    101 	182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
    102 	193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
    103 	204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
    104 	214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
    105 	224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
    106 	234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
    107 	243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
    108 	251,252,252,253,254,254,255,255}
    109 };
    110 
    111 Display*        X_display = 0;
    112 Window          X_mainWindow;
    113 Colormap        X_cmap;
    114 Visual*         X_visual;
    115 GC              X_gc;
    116 XEvent          X_event;
    117 int             X_screen;
    118 XVisualInfo     X_visualinfo;
    119 XImage*         image;
    120 int             X_width;
    121 int             X_height;
    122 boolean         doShm;
    123 XShmSegmentInfo X_shminfo;
    124 int             X_shmeventtype;
    125 boolean         grabMouse;
    126 int             doPointerWarp = POINTER_WARP_COUNTDOWN;
    127 static int      multiply = 1;
    128 
    129 int
    130 xlatekey()
    131 {
    132 	int rc;
    133 
    134 	switch (rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0)) {
    135 		case XK_Left:   rc = KEY_LEFTARROW;  break;
    136 		case XK_Right:  rc = KEY_RIGHTARROW; break;
    137 		case XK_Down:   rc = KEY_DOWNARROW;  break;
    138 		case XK_Up:     rc = KEY_UPARROW;    break;
    139 		case XK_Escape: rc = KEY_ESCAPE;     break;
    140 		case XK_Return: rc = KEY_ENTER;      break;
    141 		case XK_Tab:    rc = KEY_TAB;        break;
    142 		case XK_F1:     rc = KEY_F1;         break;
    143 		case XK_F2:     rc = KEY_F2;         break;
    144 		case XK_F3:     rc = KEY_F3;         break;
    145 		case XK_F4:     rc = KEY_F4;         break;
    146 		case XK_F5:     rc = KEY_F5;         break;
    147 		case XK_F6:     rc = KEY_F6;         break;
    148 		case XK_F7:     rc = KEY_F7;         break;
    149 		case XK_F8:     rc = KEY_F8;         break;
    150 		case XK_F9:     rc = KEY_F9;         break;
    151 		case XK_F10:    rc = KEY_F10;        break;
    152 		case XK_F11:    rc = KEY_F11;        break;
    153 		case XK_F12:    rc = KEY_F12;        break;
    154 		case XK_BackSpace:
    155 		case XK_Delete: rc = KEY_BACKSPACE;  break;
    156 		case XK_Pause:  rc = KEY_PAUSE;      break;
    157 		case XK_KP_Equal:
    158 		case XK_equal:  rc = KEY_EQUALS;     break;
    159 		case XK_KP_Subtract:
    160 		case XK_minus:  rc = KEY_MINUS;      break;
    161 		case XK_Shift_L:
    162 		case XK_Shift_R: rc = KEY_RSHIFT;    break;
    163 		case XK_Control_L:
    164 		case XK_Control_R: rc = KEY_RCTRL;   break;
    165 		case XK_Alt_L:
    166 		case XK_Meta_L:
    167 		case XK_Alt_R:
    168 		case XK_Meta_R: rc = KEY_RALT;       break;
    169 		default:
    170 			if (rc >= XK_space && rc <= XK_asciitilde)
    171 				rc = rc - XK_space + 0x20;
    172 			if (rc >= 'A' && rc <= 'Z')
    173 				rc = rc - 0x41 + 0x61;
    174 			break;
    175 	}
    176 	return rc;
    177 }
    178 
    179 void
    180 I_ShutdownGraphics()
    181 {
    182 	if (!XShmDetach(X_display, &X_shminfo))
    183 		I_Error("XShmDetach() failed in I_ShutdownGraphics()");
    184 	shmdt(X_shminfo.shmaddr);
    185 	shmctl(X_shminfo.shmid, IPC_RMID, 0);
    186 	image->data = NULL;
    187 }
    188 
    189 static int lastmousex = 0;
    190 static int lastmousey = 0;
    191 boolean    mousemoved = false;
    192 boolean    shmFinished;
    193 
    194 void
    195 I_GetEvent()
    196 {
    197 	event_t event;
    198 		
    199 	XNextEvent(X_display, &X_event);
    200 	switch (X_event.type) {
    201 		case KeyPress:
    202 			event.type = ev_keydown;
    203 			event.data1 = xlatekey();
    204 			D_PostEvent(&event);
    205 			break;
    206 		case KeyRelease:
    207 			event.type = ev_keyup;
    208 			event.data1 = xlatekey();
    209 			D_PostEvent(&event);
    210 			break;
    211 		case ButtonPress:
    212 			event.type = ev_mouse;
    213 			event.data1 =
    214 				(X_event.xbutton.state & Button1Mask)
    215 				| (X_event.xbutton.state & Button2Mask ? 2 : 0)
    216 				| (X_event.xbutton.state & Button3Mask ? 4 : 0)
    217 				| (X_event.xbutton.button == Button1)
    218 				| (X_event.xbutton.button == Button2 ? 2 : 0)
    219 				| (X_event.xbutton.button == Button3 ? 4 : 0);
    220 			event.data2 = event.data3 = 0;
    221 			D_PostEvent(&event);
    222 			break;
    223 		case ButtonRelease:
    224 			event.type = ev_mouse;
    225 			event.data1 =
    226 				(X_event.xbutton.state & Button1Mask)
    227 				| (X_event.xbutton.state & Button2Mask ? 2 : 0)
    228 				| (X_event.xbutton.state & Button3Mask ? 4 : 0);
    229 			event.data1 =
    230 				event.data1
    231 				^ (X_event.xbutton.button == Button1 ? 1 : 0)
    232 				^ (X_event.xbutton.button == Button2 ? 2 : 0)
    233 				^ (X_event.xbutton.button == Button3 ? 4 : 0);
    234 			event.data2 = event.data3 = 0;
    235 			D_PostEvent(&event);
    236 			break;
    237 		case MotionNotify:
    238 			event.type = ev_mouse;
    239 			event.data1 =
    240 				(X_event.xmotion.state & Button1Mask)
    241 				| (X_event.xmotion.state & Button2Mask ? 2 : 0)
    242 				| (X_event.xmotion.state & Button3Mask ? 4 : 0);
    243 			event.data2 = (X_event.xmotion.x - lastmousex) << 2;
    244 			event.data3 = (lastmousey - X_event.xmotion.y) << 2;
    245 			if (event.data2 || event.data3) {
    246 				lastmousex = X_event.xmotion.x;
    247 				lastmousey = X_event.xmotion.y;
    248 				if (X_event.xmotion.x != X_width/2 && X_event.xmotion.y != X_height/2) {
    249 					D_PostEvent(&event);
    250 					mousemoved = false;
    251 				} else
    252 					mousemoved = true;
    253 			}
    254 			break;
    255 		case Expose:
    256 		case ConfigureNotify:
    257 			break;
    258 		default:
    259 			if (doShm && X_event.type == X_shmeventtype)
    260 				shmFinished = true;
    261 			break;
    262 	}
    263 }
    264 
    265 Cursor
    266 createnullcursor(Display* display, Window root)
    267 {
    268 	Pixmap    cursormask;
    269 	XGCValues xgc;
    270 	GC        gc;
    271 	XColor    dummycolour;
    272 	Cursor    cursor;
    273 
    274 	cursormask = XCreatePixmap(display, root, 1, 1, 1);
    275 	xgc.function = GXclear;
    276 	gc = XCreateGC(display, cursormask, GCFunction, &xgc);
    277 	XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
    278 	dummycolour.pixel = 0;
    279 	dummycolour.red = 0;
    280 	dummycolour.flags = 04;
    281 	cursor = XCreatePixmapCursor(display, cursormask, cursormask, &dummycolour,&dummycolour, 0,0);
    282 	XFreePixmap(display,cursormask);
    283 	XFreeGC(display,gc);
    284 	return cursor;
    285 }
    286 
    287 void
    288 I_StartTic()
    289 {
    290 	if (!X_display)
    291 		return;
    292 	while (XPending(X_display))
    293 		I_GetEvent();
    294 	if (grabMouse) {
    295 		if (!--doPointerWarp) {
    296 			XWarpPointer(X_display, None, X_mainWindow, 0, 0, 0, 0, X_width/2, X_height/2);
    297 			doPointerWarp = POINTER_WARP_COUNTDOWN;
    298 		}
    299 	}
    300 	mousemoved = false;
    301 }
    302 
    303 void
    304 I_UpdateNoBlit()
    305 {
    306 }
    307 
    308 double		exptable2[256*256];
    309 
    310 void
    311 InitExpand2()
    312 {
    313 	double* exp;
    314 	int     i, j;
    315 	union {
    316 		unsigned u[2];
    317 		double   d;
    318 	} pixel;
    319 	printf("building exptable2...\n");
    320 	exp = exptable2;
    321 	for (i = 0; i < 256; ++i) {
    322 		pixel.u[0] = i | (i << 8) | (i << 16) | (i << 24);
    323 		for (j = 0; j < 256; ++j) {
    324 			pixel.u[1] = j | (j << 8) | (j << 16) | (j << 24);
    325 			*exp++ = pixel.d;
    326 		}
    327 	}
    328 	printf ("done.\n");
    329 }
    330 
    331 static XColor colors[256];
    332 
    333 void
    334 I_FinishUpdate()
    335 {
    336 	XColor* color;
    337 	uchar*  screen, *p;
    338 	uint    x, y;
    339 
    340 	screen = screens[0];
    341 	p = (uchar*)image->data;
    342 	for (y = 0; y < SCREENHEIGHT * multiply; ++y) {
    343 		for (x = 0; x < SCREENWIDTH * multiply; ++x) {
    344 			color = &colors[screen[x/multiply + (y/multiply) * SCREENWIDTH]];
    345 			*p++ = (uchar)color->blue;
    346 			*p++ = (uchar)color->green;
    347 			*p++ = (uchar)color->red;
    348 			++p; /*alpha*/
    349 		}
    350 	}
    351 	if (doShm) {
    352 		if (!XShmPutImage(X_display, X_mainWindow, X_gc, image, 0, 0, 0, 0, X_width, X_height, True))
    353 			I_Error("XShmPutImage() failed\n");
    354 		shmFinished = false;
    355 		for (I_GetEvent(); !shmFinished;
    356 			I_GetEvent());
    357 	} else {
    358 		XPutImage(X_display, X_mainWindow, X_gc, image, 0, 0, 0, 0, X_width, X_height);
    359 		XSync(X_display, False);
    360 	}
    361 }
    362 
    363 void
    364 I_ReadScreen(byte* scr)
    365 {
    366 	memcpy(scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
    367 }
    368 
    369 
    370 void
    371 I_SetPalette(byte* palette)
    372 {
    373 	static boolean firstcall = true;
    374 	int            i, c;
    375 
    376 	/*
    377 	if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8) {
    378 	*/
    379 		if (firstcall) {
    380 			firstcall = false;
    381 			for (i = 0; i < 256; ++i) {
    382 				colors[i].pixel = i;
    383 				colors[i].flags = DoRed|DoGreen|DoBlue;
    384 			}
    385 		}
    386 		for (i = 0; i < 256; ++i) {
    387 			c = gammatable[usegamma][*palette++];
    388 			colors[i].red = (c<<8) + c;
    389 			c = gammatable[usegamma][*palette++];
    390 			colors[i].green = (c<<8) + c;
    391 			c = gammatable[usegamma][*palette++];
    392 			colors[i].blue = (c<<8) + c;
    393 		}
    394 	/*
    395 		XStoreColors(X_display, X_cmap, colors, 256);
    396 	}
    397 	*/
    398 }
    399 
    400 void
    401 grabsharedmemory(int size)
    402 {
    403 	struct shmid_ds shminfo;
    404 	int             key, minsize, id, rc, pollution;
    405 	
    406 	key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm';
    407 	minsize = 320 * 200;
    408 	pollution = 5;
    409 	do {
    410 		id = shmget((key_t) key, minsize, 0777); 
    411 		if (id != -1) {
    412 			rc = shmctl(id, IPC_STAT, &shminfo); 
    413 			if (!rc)  {
    414 				if (shminfo.shm_nattch) {
    415 					fprintf(stderr, "User %d appears to be running DOOM. Is that wise?\n", shminfo.shm_cpid);
    416 					++key;
    417 				} else {
    418 					if (getuid() == shminfo.shm_perm.cuid) {
    419 						rc = shmctl(id, IPC_RMID, 0);
    420 						if (!rc)
    421 							fprintf(stderr, "Was able to kill my old shared memory\n");
    422 						else
    423 							I_Error("Was NOT able to kill my old shared memory");
    424 						id = shmget((key_t)key, size, IPC_CREAT|0777);
    425 						if (id == -1)
    426 							I_Error("Could not get shared memory");
    427 						rc = shmctl(id, IPC_STAT, &shminfo);
    428 						break;
    429 					}
    430 					if (size >= shminfo.shm_segsz) {
    431 						fprintf(stderr, "will use %d's stale shared memory\n", shminfo.shm_cpid);
    432 						break;
    433 					} else {
    434 						fprintf(stderr, "warning: can't use stale shared memory belonging to id %d, key=0x%x\n", shminfo.shm_cpid, key);
    435 						++key;
    436 					}
    437 				}
    438 			} else
    439 				I_Error("could not get stats on key=%d", key);
    440 		} else {
    441 			id = shmget((key_t)key, size, IPC_CREAT|0777);
    442 			if (id == -1) {
    443 				fprintf(stderr, "errno=%d\n", errno);
    444 				I_Error("Could not get any shared memory");
    445 			}
    446 			break;
    447 		}
    448 	} while (--pollution);
    449 	if (!pollution)
    450 		I_Error("Sorry, system too polluted with stale shared memory segments.\n");
    451 	X_shminfo.shmid = id;
    452 	image->data = X_shminfo.shmaddr = shmat(id, 0, 0);
    453 	fprintf(stderr, "shared memory id=%d, addr=%p\n", id, image->data);
    454 }
    455 
    456 void
    457 I_InitGraphics()
    458 {
    459 	XSetWindowAttributes attribs;
    460 	XGCValues            xgcvalues;
    461 	char                 *displayname, *d;
    462 	ulong                attribmask;
    463 	int                  pnum, oktodraw, valuemask;
    464 
    465 	signal(SIGINT, (void(*)(int))I_Quit);
    466 	if (M_CheckParm("-2"))
    467 		multiply = 2;
    468 	if (M_CheckParm("-3"))
    469 		multiply = 3;
    470 	if (M_CheckParm("-4"))
    471 		multiply = 4;
    472 	X_width = SCREENWIDTH * multiply;
    473 	X_height = SCREENHEIGHT * multiply;
    474 	if ((pnum = M_CheckParm("-disp"))) 
    475 		displayname = myargv[pnum+1];
    476 	else
    477 		displayname = 0;
    478 	grabMouse = !!M_CheckParm("-grabmouse");
    479 	X_display = XOpenDisplay(displayname);
    480 	if (!X_display) {
    481 		if (displayname)
    482 			I_Error("Could not open display [%s]", displayname);
    483 		else
    484 			I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
    485 	}
    486 	X_screen = DefaultScreen(X_display);
    487 	if (!XMatchVisualInfo(X_display, X_screen, 24, TrueColor, &X_visualinfo))
    488 		I_Error("xdoom currently only supports 256-color PseudoColor screens");
    489 	X_visual = X_visualinfo.visual;
    490 	doShm = XShmQueryExtension(X_display);
    491 	if (doShm) {
    492 		if (!displayname)
    493 			displayname = (char*)getenv("DISPLAY");
    494 		if (displayname) {
    495 			d = displayname;
    496 			while (*d && (*d != ':'))
    497 				++d;
    498 			if (*d)
    499 				*d = 0;
    500 			if (!(!strcasecmp(displayname, "unix") || !*displayname))
    501 				doShm = false;
    502 		}
    503 	}
    504 	fprintf(stderr, "Using MITSHM extension\n");
    505 	X_cmap = XCreateColormap(X_display, RootWindow(X_display, X_screen), X_visual, AllocNone);
    506 	attribmask = CWEventMask | CWColormap | CWBorderPixel;
    507 	attribs.event_mask = KeyPressMask | KeyReleaseMask | ExposureMask;
    508 	attribs.colormap = X_cmap;
    509 	attribs.border_pixel = 0;
    510 	X_mainWindow = XCreateWindow(X_display, RootWindow(X_display, X_screen), 0, 0, X_width, X_height, 0, 24, InputOutput, X_visual, attribmask, &attribs);
    511 	XDefineCursor(X_display, X_mainWindow, createnullcursor(X_display, X_mainWindow));
    512 	valuemask = GCGraphicsExposures;
    513 	xgcvalues.graphics_exposures = False;
    514 	X_gc = XCreateGC(X_display, X_mainWindow, valuemask, &xgcvalues);
    515 	XMapWindow(X_display, X_mainWindow);
    516 	oktodraw = 0;
    517 	while (!oktodraw) {
    518 		XNextEvent(X_display, &X_event);
    519 		if (X_event.type == Expose && !X_event.xexpose.count)
    520 			oktodraw = 1;
    521 	}
    522 	if (grabMouse)
    523 		XGrabPointer(X_display, X_mainWindow, True, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, X_mainWindow, None, CurrentTime);
    524 	if (doShm) {
    525 		X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
    526 		image = XShmCreateImage(X_display, X_visual, 24, ZPixmap, 0, &X_shminfo, X_width, X_height);
    527 		grabsharedmemory(image->bytes_per_line * image->height);
    528 		if (!image->data) {
    529 			perror("");
    530 			I_Error("shmat() failed in InitGraphics()");
    531 		}
    532 		if (!XShmAttach(X_display, &X_shminfo))
    533 			I_Error("XShmAttach() failed in InitGraphics()");
    534 	} else
    535 		image = XCreateImage(X_display, X_visual, 24, ZPixmap, 0, (char*)malloc(4 * X_width * X_height), X_width, X_height, 8, X_width);
    536 	screens[0] = (uchar*)malloc(SCREENWIDTH * SCREENHEIGHT);
    537 }