vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

x11-init.c (19677B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "mem.h"
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include "error.h"
      7 #define Image IMAGE	/* kernel has its own Image */
      8 #include <draw.h>
      9 #include <memdraw.h>
     10 #include <keyboard.h>
     11 #include <cursor.h>
     12 #include "screen.h"
     13 #include "x11-inc.h"
     14 
     15 #define argv0 "vxplan9"
     16 
     17 Xprivate _x;
     18 
     19 static int parsewinsize(char *s, Rectangle *r, int *havemin);
     20 static void plan9cmap(void);
     21 static XGC xgc(XDrawable, int, int);
     22 static int setupcmap(XWindow);
     23 
     24 static int
     25 xerror(XDisplay *d, XErrorEvent *e)
     26 {
     27 	char buf[200];
     28 
     29 	if(e->request_code == 42) /* XSetInputFocus */
     30 		return 0;
     31 	if(e->request_code == 18) /* XChangeProperty */
     32 		return 0;
     33 	/*
     34 	 * BadDrawable happens in apps that get resized a LOT,
     35 	 * e.g. when KDE is configured to resize continuously
     36 	 * during a window drag.
     37 	 */
     38 	if(e->error_code == 9) /* BadDrawable */
     39 		return 0;
     40 
     41 	fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
     42 		e->error_code, e->request_code, e->minor_code, d);
     43 	XGetErrorText(d, e->error_code, buf, sizeof buf);
     44 	fprint(2, "%s\n", buf);
     45 	return 0;
     46 }
     47 
     48 static int
     49 xioerror(XDisplay *d)
     50 {
     51 	/*print("X I/O error\n"); */
     52 	restoretty();
     53 	exit(0);
     54 	/*sysfatal("X I/O error\n");*/
     55 	abort();
     56 	return -1;
     57 }
     58 
     59 Memimage*
     60 _xattach(char *label, char *winsize)
     61 {
     62 	char *argv[2], *disp;
     63 	int i, havemin, height, mask, n, width, x, xrootid, y;
     64 	Rectangle r;
     65 	XClassHint classhint;
     66 	XDrawable pmid;
     67 	XPixmapFormatValues *pfmt;
     68 	XScreen *xscreen;
     69 	XSetWindowAttributes attr;
     70 	XSizeHints normalhint;
     71 	XTextProperty name;
     72 	XVisualInfo xvi;
     73 	XWindow xrootwin;
     74 	XWindowAttributes wattr;
     75 	XWMHints hint;
     76 	Atom atoms[2];
     77 
     78 	/*
     79 	if(XInitThreads() == 0){
     80 		fprint(2, "XInitThreads failed\n");
     81 		abort();
     82 	}
     83 	*/
     84 
     85 	/*
     86 	 * Connect to X server.
     87 	 */
     88 	_x.display = XOpenDisplay(NULL);
     89 	if(_x.display == nil){
     90 		disp = getenv("DISPLAY");
     91 		werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
     92 		free(disp);
     93 		return nil;
     94 	}
     95 	_x.fd = ConnectionNumber(_x.display);
     96 	XSetErrorHandler(xerror);
     97 	XSetIOErrorHandler(xioerror);
     98 	xrootid = DefaultScreen(_x.display);
     99 	xrootwin = DefaultRootWindow(_x.display);
    100 
    101 	/* 
    102 	 * Figure out underlying screen format.
    103 	 */
    104 	if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
    105 	|| XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
    106 		_x.vis = xvi.visual;
    107 		_x.depth = 16;
    108 	}
    109 	else
    110 	if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
    111 	|| XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
    112 		_x.vis = xvi.visual;
    113 		_x.depth = 15;
    114 	}
    115 	else
    116 	if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
    117 	|| XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
    118 		_x.vis = xvi.visual;
    119 		_x.depth = 24;
    120 	}
    121 	else
    122 	if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
    123 	|| XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
    124 		if(_x.depth > 8){
    125 			werrstr("can't deal with colormapped depth %d screens",
    126 				_x.depth);
    127 			goto err0;
    128 		}
    129 		_x.vis = xvi.visual;
    130 		_x.depth = 8;
    131 	}
    132 	else{
    133 		_x.depth = DefaultDepth(_x.display, xrootid);
    134 		if(_x.depth != 8){
    135 			werrstr("can't understand depth %d screen", _x.depth);
    136 			goto err0;
    137 		}
    138 		_x.vis = DefaultVisual(_x.display, xrootid);
    139 	}
    140 
    141 	if(DefaultDepth(_x.display, xrootid) == _x.depth)
    142 		_x.usetable = 1;
    143 
    144 	/*
    145 	 * _x.depth is only the number of significant pixel bits,
    146 	 * not the total number of pixel bits.  We need to walk the
    147 	 * display list to find how many actual bits are used
    148 	 * per pixel.
    149 	 */
    150 	_x.chan = 0;
    151 	pfmt = XListPixmapFormats(_x.display, &n);
    152 	for(i=0; i<n; i++){
    153 		if(pfmt[i].depth == _x.depth){
    154 			switch(pfmt[i].bits_per_pixel){
    155 			case 1:	/* untested */
    156 				_x.chan = GREY1;
    157 				break;
    158 			case 2:	/* untested */
    159 				_x.chan = GREY2;
    160 				break;
    161 			case 4:	/* untested */
    162 				_x.chan = GREY4;
    163 				break;
    164 			case 8:
    165 				_x.chan = CMAP8;
    166 				break;
    167 			case 15:
    168 				_x.chan = RGB15;
    169 				break;
    170 			case 16: /* how to tell RGB15? */
    171 				_x.chan = RGB16;
    172 				break;
    173 			case 24: /* untested (impossible?) */
    174 				_x.chan = RGB24;
    175 				break;
    176 			case 32:
    177 				_x.chan = XRGB32;
    178 				break;
    179 			}
    180 		}
    181 	}
    182 	if(_x.chan == 0){
    183 		werrstr("could not determine screen pixel format");
    184 		goto err0;
    185 	}
    186 
    187 	/*
    188 	 * Set up color map if necessary.
    189 	 */
    190 	xscreen = DefaultScreenOfDisplay(_x.display);
    191 	_x.cmap = DefaultColormapOfScreen(xscreen);
    192 	if(_x.vis->class != StaticColor){
    193 		plan9cmap();
    194 		setupcmap(xrootwin);
    195 	}
    196 
    197 	/*
    198 	 * We get to choose the initial rectangle size.
    199 	 * This is arbitrary.  In theory we should read the
    200 	 * command line and allow the traditional X options.
    201 	 */
    202 	mask = 0;
    203 	x = 0;
    204 	y = 0;
    205 	if(winsize && winsize[0]){
    206 		if(parsewinsize(winsize, &r, &havemin) < 0)
    207 			panic("bad window size: %r");
    208 	}else{
    209 		/*
    210 		 * Parse the various X resources.  Thanks to Peter Canning.
    211 		 */
    212 		char *screen_resources, *display_resources, *geom, 
    213 			*geomrestype, *home, *file;
    214 		XrmDatabase database;
    215 		XrmValue geomres;
    216 
    217 		database = XrmGetDatabase(_x.display);
    218 		screen_resources = XScreenResourceString(xscreen);
    219 		if(screen_resources != nil){
    220 			XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
    221 			XFree(screen_resources);
    222 		}
    223 
    224 		display_resources = XResourceManagerString(_x.display);
    225 		if(display_resources == nil){
    226 			home = getenv("HOME");
    227 			if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
    228 				XrmCombineFileDatabase(file, &database, False);
    229 				free(file);
    230 			}
    231 		}else
    232 			XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
    233 
    234 		geom = smprint("%s.geometry", label);
    235 		if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
    236 			mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
    237 		free(geom);
    238 
    239 		if((mask & WidthValue) && (mask & HeightValue)){
    240 			r = Rect(0, 0, width, height);
    241 		}else{
    242 			r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
    243 					HeightOfScreen(xscreen)*3/4);
    244 			if(Dx(r) > Dy(r)*3/2)
    245 				r.max.x = r.min.x + Dy(r)*3/2;
    246 			if(Dy(r) > Dx(r)*3/2)
    247 				r.max.y = r.min.y + Dx(r)*3/2;
    248 		}
    249 		if(mask & XNegative){
    250 			x += WidthOfScreen(xscreen);
    251 		}
    252 		if(mask & YNegative){
    253 			y += HeightOfScreen(xscreen);
    254 		}
    255 		havemin = 0;
    256 	}
    257 	screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
    258 	mouserect = Rect(0, 0, Dx(r), Dy(r));
    259 
    260 	memset(&attr, 0, sizeof attr);
    261 	attr.colormap = _x.cmap;
    262 	attr.background_pixel = ~0;
    263 	attr.border_pixel = 0;
    264 	_x.drawable = XCreateWindow(
    265 		_x.display,	/* display */
    266 		xrootwin,	/* parent */
    267 		x,		/* x */
    268 		y,		/* y */
    269 		Dx(r),		/* width */
    270 	 	Dy(r),		/* height */
    271 		0,		/* border width */
    272 		_x.depth,	/* depth */
    273 		InputOutput,	/* class */
    274 		_x.vis,		/* visual */
    275 				/* valuemask */
    276 		CWBackPixel|CWBorderPixel|CWColormap,
    277 		&attr		/* attributes (the above aren't?!) */
    278 	);
    279 
    280 	/*
    281 	 * Label and other properties required by ICCCCM.
    282 	 */
    283 	memset(&name, 0, sizeof name);
    284 	if(label == nil)
    285 		label = "pjw-face-here";
    286 	name.value = (uchar*)label;
    287 	name.encoding = XA_STRING;
    288 	name.format = 8;
    289 	name.nitems = strlen((char*)name.value);
    290 
    291 	memset(&normalhint, 0, sizeof normalhint);
    292 	normalhint.flags = PSize|PMaxSize;
    293 	if(winsize && winsize[0]){
    294 		normalhint.flags &= ~PSize;
    295 		normalhint.flags |= USSize;
    296 		normalhint.width = Dx(r);
    297 		normalhint.height = Dy(r);
    298 	}else{
    299 		if((mask & WidthValue) && (mask & HeightValue)){
    300 			normalhint.flags &= ~PSize;
    301 			normalhint.flags |= USSize;
    302 			normalhint.width = width;
    303 			normalhint.height = height;
    304 		}
    305 		if((mask & WidthValue) && (mask & HeightValue)){
    306 			normalhint.flags |= USPosition;
    307 			normalhint.x = x;
    308 			normalhint.y = y;
    309 		}
    310 	}
    311 
    312 	normalhint.max_width = WidthOfScreen(xscreen);
    313 	normalhint.max_height = HeightOfScreen(xscreen);
    314 
    315 	memset(&hint, 0, sizeof hint);
    316 	hint.flags = InputHint|StateHint;
    317 	hint.input = 1;
    318 	hint.initial_state = NormalState;
    319 
    320 	memset(&classhint, 0, sizeof classhint);
    321 	classhint.res_name = label;
    322 	classhint.res_class = label;
    323 
    324 	argv[0] = label;
    325 	argv[1] = nil;
    326 
    327 	XSetWMProperties(
    328 		_x.display,	/* display */
    329 		_x.drawable,	/* window */
    330 		&name,		/* XA_WM_NAME property */
    331 		&name,		/* XA_WM_ICON_NAME property */
    332 		argv,		/* XA_WM_COMMAND */
    333 		1,		/* argc */
    334 		&normalhint,	/* XA_WM_NORMAL_HINTS */
    335 		&hint,		/* XA_WM_HINTS */
    336 		&classhint	/* XA_WM_CLASSHINTS */
    337 	);
    338 	XFlush(_x.display);
    339 
    340 	if(havemin){
    341 		XWindowChanges ch;
    342 
    343 		memset(&ch, 0, sizeof ch);
    344 		ch.x = r.min.x;
    345 		ch.y = r.min.y;
    346 		XConfigureWindow(_x.display, _x.drawable, CWX|CWY, &ch);
    347 		/*
    348 		 * Must pretend origin is 0,0 for X.
    349 		 */
    350 		r = Rect(0,0,Dx(r),Dy(r));
    351 	}
    352 
    353 	_x.kmcon = XOpenDisplay(NULL);
    354 	if(_x.kmcon == nil)
    355 		panic("XOpenDisplay kmcon");
    356 
    357 	_x.snarfcon = XOpenDisplay(NULL);
    358 	if(_x.snarfcon == nil)
    359 		panic("XOpenDisplay snarfcon");
    360 
    361 	/*
    362 	 * Look up clipboard atom.
    363 	 */
    364 	_x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
    365 	_x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
    366 	_x.targets = XInternAtom(_x.display, "TARGETS", False);
    367 	_x.text = XInternAtom(_x.display, "TEXT", False);
    368 	_x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
    369 	_x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
    370 	_x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
    371 	_x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
    372 	_x.wmstate = XInternAtom(_x.display, "_NET_WM_STATE", False);
    373 	_x.wmfullscreen = XInternAtom(_x.display, "_NET_WM_STATE_FULLSCREEN", False);
    374 
    375 	atoms[0] = _x.takefocus;
    376 	atoms[1] = _x.losefocus;
    377 	XChangeProperty(_x.display, _x.drawable, _x.wmprotos, XA_ATOM, 32,
    378 		PropModeReplace, (uchar*)atoms, 2);
    379 
    380 	/*
    381 	 * Put the window on the screen, check to see what size we actually got.
    382 	 */
    383 	XMapWindow(_x.display, _x.drawable);
    384 	XSync(_x.display, False);
    385 
    386 	if(!XGetWindowAttributes(_x.display, _x.drawable, &wattr))
    387 		fprint(2, "XGetWindowAttributes failed\n");
    388 	else if(wattr.width && wattr.height){
    389 		if(wattr.width != Dx(r) || wattr.height != Dy(r)){
    390 			r.max.x = r.min.x + wattr.width;
    391 			r.max.y = r.min.y + wattr.height;
    392 		}
    393 	}else
    394 		fprint(2, "XGetWindowAttributes: bad attrs\n");
    395 
    396 	/*
    397 	 * Allocate our local backing store.
    398 	 */
    399 	_x.screenr = r;
    400 	_x.screenpm = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
    401 	_x.nextscreenpm = _x.screenpm;
    402 	_x.screenimage = _xallocmemimage(r, _x.chan, _x.screenpm);
    403 	if(_x.screenimage == nil)
    404 		panic("_xallocmemimage failed");
    405 
    406 	/*
    407 	 * Figure out physical window location.
    408 	 */
    409 	int rx, ry;
    410 	XWindow w;
    411 	if(XTranslateCoordinates(_x.display, _x.drawable,
    412 			DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &w))
    413 		r = Rect(rx, ry, Dx(r), Dy(r));
    414 	windowrect = r;
    415 
    416 	/*
    417 	 * Allocate some useful graphics contexts for the future.
    418 	 */
    419 	_x.gcfill	= xgc(_x.screenpm, FillSolid, -1);
    420 	_x.gccopy	= xgc(_x.screenpm, -1, -1);
    421 	_x.gcsimplesrc 	= xgc(_x.screenpm, FillStippled, -1);
    422 	_x.gczero	= xgc(_x.screenpm, -1, -1);
    423 	_x.gcreplsrc	= xgc(_x.screenpm, FillTiled, -1);
    424 
    425 	pmid = XCreatePixmap(_x.display, _x.drawable, 1, 1, 1);
    426 	_x.gcfill0	= xgc(pmid, FillSolid, 0);
    427 	_x.gccopy0	= xgc(pmid, -1, -1);
    428 	_x.gcsimplesrc0	= xgc(pmid, FillStippled, -1);
    429 	_x.gczero0	= xgc(pmid, -1, -1);
    430 	_x.gcreplsrc0	= xgc(pmid, FillTiled, -1);
    431 	XFreePixmap(_x.display, pmid);
    432 
    433 	termreplacescreenimage(_x.screenimage);
    434 	return _x.screenimage;
    435 
    436 err0:
    437 	/*
    438 	 * Should do a better job of cleaning up here.
    439 	 */
    440 	XCloseDisplay(_x.display);
    441 	return nil;
    442 }
    443 
    444 int
    445 _xsetlabel(char *label)
    446 {
    447 	XTextProperty name;
    448 
    449 	/*
    450 	 * Label and other properties required by ICCCCM.
    451 	 */
    452 	memset(&name, 0, sizeof name);
    453 	if(label == nil)
    454 		label = "pjw-face-here";
    455 	name.value = (uchar*)label;
    456 	name.encoding = XA_STRING;
    457 	name.format = 8;
    458 	name.nitems = strlen((char*)name.value);
    459 
    460 	XSetWMProperties(
    461 		_x.display,	/* display */
    462 		_x.drawable,	/* window */
    463 		&name,		/* XA_WM_NAME property */
    464 		&name,		/* XA_WM_ICON_NAME property */
    465 		nil,		/* XA_WM_COMMAND */
    466 		0,		/* argc */
    467 		nil,		/* XA_WM_NORMAL_HINTS */
    468 		nil,		/* XA_WM_HINTS */
    469 		nil	/* XA_WM_CLASSHINTS */
    470 	);
    471 	XFlush(_x.display);
    472 	return 0;
    473 }
    474 
    475 /*
    476  * Create a GC with a particular fill style and XXX.
    477  * Disable generation of GraphicsExpose/NoExpose events in the GC.
    478  */
    479 static XGC
    480 xgc(XDrawable d, int fillstyle, int foreground)
    481 {
    482 	XGC gc;
    483 	XGCValues v;
    484 
    485 	memset(&v, 0, sizeof v);
    486 	v.function = GXcopy;
    487 	v.graphics_exposures = False;
    488 	gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
    489 	if(fillstyle != -1)
    490 		XSetFillStyle(_x.display, gc, fillstyle);
    491 	if(foreground != -1)
    492 		XSetForeground(_x.display, gc, 0);
    493 	return gc;
    494 }
    495 
    496 /*
    497  * Initialize map with the Plan 9 rgbv color map.
    498  */
    499 static void
    500 plan9cmap(void)
    501 {
    502 	int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
    503 	static int once;
    504 
    505 	if(once)
    506 		return;
    507 	once = 1;
    508 
    509 	for(r=0; r!=4; r++)
    510 	for(g = 0; g != 4; g++)
    511 	for(b = 0; b!=4; b++)
    512 	for(v = 0; v!=4; v++){
    513 		den=r;
    514 		if(g > den)
    515 			den=g;
    516 		if(b > den)
    517 			den=b;
    518 		/* divide check -- pick grey shades */
    519 		if(den==0)
    520 			cr=cg=cb=v*17;
    521 		else {
    522 			num=17*(4*den+v);
    523 			cr=r*num/den;
    524 			cg=g*num/den;
    525 			cb=b*num/den;
    526 		}
    527 		idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
    528 		_x.map[idx].red = cr*0x0101;
    529 		_x.map[idx].green = cg*0x0101;
    530 		_x.map[idx].blue = cb*0x0101;
    531 		_x.map[idx].pixel = idx;
    532 		_x.map[idx].flags = DoRed|DoGreen|DoBlue;
    533 
    534 		v7 = v >> 1;
    535 		idx7 = r*32 + v7*16 + g*4 + b;
    536 		if((v & 1) == v7){
    537 			_x.map7to8[idx7][0] = idx;
    538 			if(den == 0) { 		/* divide check -- pick grey shades */
    539 				cr = ((255.0/7.0)*v7)+0.5;
    540 				cg = cr;
    541 				cb = cr;
    542 			}
    543 			else {
    544 				num=17*15*(4*den+v7*2)/14;
    545 				cr=r*num/den;
    546 				cg=g*num/den;
    547 				cb=b*num/den;
    548 			}
    549 			_x.map7[idx7].red = cr*0x0101;
    550 			_x.map7[idx7].green = cg*0x0101;
    551 			_x.map7[idx7].blue = cb*0x0101;
    552 			_x.map7[idx7].pixel = idx7;
    553 			_x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
    554 		}
    555 		else
    556 			_x.map7to8[idx7][1] = idx;
    557 	}
    558 }
    559 
    560 /*
    561  * Initialize and install the rgbv color map as a private color map
    562  * for this application.  It gets the best colors when it has the
    563  * cursor focus.
    564  *
    565  * We always choose the best depth possible, but that might not
    566  * be the default depth.  On such "suboptimal" systems, we have to allocate an
    567  * empty color map anyway, according to Axel Belinfante.
    568  */
    569 static int 
    570 setupcmap(XWindow w)
    571 {
    572 	char buf[30];
    573 	int i;
    574 	uint32 p, pp;
    575 	XColor c;
    576 
    577 	if(_x.depth <= 1)
    578 		return 0;
    579 
    580 	if(_x.depth >= 24) {
    581 		if(_x.usetable == 0)
    582 			_x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone); 
    583 
    584 		/*
    585 		 * The pixel value returned from XGetPixel needs to
    586 		 * be converted to RGB so we can call rgb2cmap()
    587 		 * to translate between 24 bit X and our color. Unfortunately,
    588 		 * the return value appears to be display server endian 
    589 		 * dependant. Therefore, we run some heuristics to later
    590 		 * determine how to mask the int value correctly.
    591 		 * Yeah, I know we can look at _x.vis->byte_order but 
    592 		 * some displays say MSB even though they run on LSB.
    593 		 * Besides, this is more anal.
    594 		 */
    595 		c = _x.map[19];	/* known to have different R, G, B values */
    596 		if(!XAllocColor(_x.display, _x.cmap, &c)){
    597 			werrstr("XAllocColor: %r");
    598 			return -1;
    599 		}
    600 		p  = c.pixel;
    601 		pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
    602 		if(pp != _x.map[19].pixel) {
    603 			/* check if endian is other way */
    604 			pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
    605 			if(pp != _x.map[19].pixel){
    606 				werrstr("cannot detect X server byte order");
    607 				return -1;
    608 			}
    609 
    610 			switch(_x.chan){
    611 			case RGB24:
    612 				_x.chan = BGR24;
    613 				break;
    614 			case XRGB32:
    615 				_x.chan = XBGR32;
    616 				break;
    617 			default:
    618 				werrstr("cannot byteswap channel %s",
    619 					chantostr(buf, _x.chan));
    620 				break;
    621 			}
    622 		}
    623 	}else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
    624 		/*
    625 		 * Do nothing.  We have no way to express a
    626 		 * mixed-endian 16-bit screen, so pretend they don't exist.
    627 		 */
    628 		if(_x.usetable == 0)
    629 			_x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
    630 	}else if(_x.vis->class == PseudoColor){
    631 		if(_x.usetable == 0){
    632 			_x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll); 
    633 			XStoreColors(_x.display, _x.cmap, _x.map, 256);
    634 			for(i = 0; i < 256; i++){
    635 				_x.tox11[i] = i;
    636 				_x.toplan9[i] = i;
    637 			}
    638 		}else{
    639 			for(i = 0; i < 128; i++){
    640 				c = _x.map7[i];
    641 				if(!XAllocColor(_x.display, _x.cmap, &c)){
    642 					werrstr("can't allocate colors in 7-bit map");
    643 					return -1;
    644 				}
    645 				_x.tox11[_x.map7to8[i][0]] = c.pixel;
    646 				_x.tox11[_x.map7to8[i][1]] = c.pixel;
    647 				_x.toplan9[c.pixel] = _x.map7to8[i][0];
    648 			}
    649 		}
    650 	}else{
    651 		werrstr("unsupported visual class %d", _x.vis->class);
    652 		return -1;
    653 	}
    654 	return 0;
    655 }
    656 
    657 void
    658 flushmemscreen(Rectangle r)
    659 {
    660 	static Lock flushlock;
    661 
    662 	if(up && !up->nlocks.ref && _x.nextscreenpm != _x.screenpm){
    663 		qlock(&_x.screenlock);
    664 		XSync(_x.display, False);
    665 		XFreePixmap(_x.display, _x.screenpm);
    666 		_x.screenpm = _x.nextscreenpm;
    667 		qunlock(&_x.screenlock);
    668 	}
    669 
    670 	if(r.min.x >= r.max.x || r.min.y >= r.max.y)
    671 		return;
    672 	lock(&flushlock);
    673 	XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
    674 		Dx(r), Dy(r), r.min.x, r.min.y);
    675 	XFlush(_x.display);
    676 	unlock(&flushlock);
    677 }
    678 
    679 void
    680 _xexpose(XEvent *e)
    681 {
    682 	XExposeEvent *xe;
    683 	Rectangle r;
    684 
    685 	qlock(&_x.screenlock);
    686 	if(_x.screenpm != _x.nextscreenpm){
    687 		qunlock(&_x.screenlock);
    688 		return;
    689 	}
    690 	xe = (XExposeEvent*)e;
    691 	r.min.x = xe->x;
    692 	r.min.y = xe->y;
    693 	r.max.x = xe->x+xe->width;
    694 	r.max.y = xe->y+xe->height;
    695 	XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
    696 		Dx(r), Dy(r), r.min.x, r.min.y);
    697 	XSync(_x.display, False);
    698 	qunlock(&_x.screenlock);
    699 }
    700 
    701 int
    702 _xdestroy(XEvent *e)
    703 {
    704 	XDestroyWindowEvent *xe;
    705 
    706 	xe = (XDestroyWindowEvent*)e;
    707 	if(xe->window == _x.drawable){
    708 		_x.destroyed = 1;
    709 		return 1;
    710 	}
    711 	return 0;
    712 }
    713 
    714 int
    715 _xconfigure(XEvent *e)
    716 {
    717 	Rectangle r;
    718 	XConfigureEvent *xe = (XConfigureEvent*)e;
    719 
    720 	if(!fullscreen){
    721 		int rx, ry;
    722 		XWindow w;
    723 		if(XTranslateCoordinates(_x.kmcon, _x.drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &w))
    724 			windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
    725 	}
    726 
    727 	if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr))
    728 		return 0;
    729 	r = Rect(0, 0, xe->width, xe->height);
    730 	mouserect = r;
    731 
    732 	qlock(&_x.screenlock);
    733 	if(_x.screenpm != _x.nextscreenpm){
    734 		XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
    735 			Dx(r), Dy(r), r.min.x, r.min.y);
    736 		XSync(_x.display, False);
    737 	}
    738 	qunlock(&_x.screenlock);
    739 	_x.newscreenr = r;
    740 	return 1;
    741 }
    742 
    743 int
    744 _xreplacescreenimage(void)
    745 {
    746 	Memimage *m;
    747 	XDrawable pixmap;
    748 	Rectangle r;
    749 
    750 	r = _x.newscreenr;
    751 
    752 	pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
    753 	m = _xallocmemimage(r, _x.chan, pixmap);
    754 	if(_x.nextscreenpm != _x.screenpm)
    755 		XFreePixmap(_x.display, _x.nextscreenpm);
    756 	_x.nextscreenpm = pixmap;
    757 	_x.screenr = r;
    758 	_x.screenimage = m;
    759 	termreplacescreenimage(m);
    760 	drawreplacescreenimage(m);
    761 	_x.screenpm = _x.nextscreenpm;
    762 	return 1;
    763 }
    764 
    765 static int
    766 parsewinsize(char *s, Rectangle *r, int *havemin)
    767 {
    768 	char c, *os;
    769 	int i, j, k, l;
    770 
    771 	os = s;
    772 	*havemin = 0;
    773 	*r = Rect(0,0,0,0);
    774 	if(!isdigit((uchar)*s))
    775 		goto oops;
    776 	i = strtol(s, &s, 0);
    777 	if(*s == 'x'){
    778 		s++;
    779 		if(!isdigit((uchar)*s))
    780 			goto oops;
    781 		j = strtol(s, &s, 0);
    782 		r->max.x = i;
    783 		r->max.y = j;
    784 		if(*s == 0)
    785 			return 0;
    786 		if(*s != '@')
    787 			goto oops;
    788 
    789 		s++;
    790 		if(!isdigit((uchar)*s))
    791 			goto oops;
    792 		i = strtol(s, &s, 0);
    793 		if(*s != ',' && *s != ' ')
    794 			goto oops;
    795 		s++;
    796 		if(!isdigit((uchar)*s))
    797 			goto oops;
    798 		j = strtol(s, &s, 0);
    799 		if(*s != 0)
    800 			goto oops;
    801 		*r = rectaddpt(*r, Pt(i,j));
    802 		*havemin = 1;
    803 		return 0;
    804 	}
    805 
    806 	c = *s;
    807 	if(c != ' ' && c != ',')
    808 		goto oops;
    809 	s++;
    810 	if(!isdigit((uchar)*s))
    811 		goto oops;
    812 	j = strtol(s, &s, 0);
    813 	if(*s != c)
    814 		goto oops;
    815 	s++;
    816 	if(!isdigit((uchar)*s))
    817 		goto oops;
    818 	k = strtol(s, &s, 0);
    819 	if(*s != c)
    820 		goto oops;
    821 	s++;
    822 	if(!isdigit((uchar)*s))
    823 		goto oops;
    824 	l = strtol(s, &s, 0);
    825 	if(*s != 0)
    826 		goto oops;
    827 	*r = Rect(i,j,k,l);
    828 	*havemin = 1;
    829 	return 0;
    830 
    831 oops:
    832 	werrstr("bad syntax in window size '%s'", os);
    833 	return -1;
    834 }