|  | /* | 
|  | * Some of the stuff in this file is not X-dependent and should be elsewhere. | 
|  | */ | 
|  | #include <u.h> | 
|  | #include "x11-inc.h" | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  | #include <memdraw.h> | 
|  | #include <keyboard.h> | 
|  | #include <mouse.h> | 
|  | #include <cursor.h> | 
|  | #include "x11-memdraw.h" | 
|  | #include "devdraw.h" | 
|  |  | 
|  | static void	plan9cmap(void); | 
|  | static int	setupcmap(XWindow); | 
|  | static XGC	xgc(XDrawable, int, int); | 
|  |  | 
|  | Xprivate _x; | 
|  |  | 
|  | static int | 
|  | xerror(XDisplay *d, XErrorEvent *e) | 
|  | { | 
|  | char buf[200]; | 
|  |  | 
|  | if(e->request_code == 42) /* XSetInputFocus */ | 
|  | return 0; | 
|  | if(e->request_code == 18) /* XChangeProperty */ | 
|  | return 0; | 
|  | /* | 
|  | * BadDrawable happens in apps that get resized a LOT, | 
|  | * e.g. when KDE is configured to resize continuously | 
|  | * during a window drag. | 
|  | */ | 
|  | if(e->error_code == 9) /* BadDrawable */ | 
|  | return 0; | 
|  |  | 
|  | fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n", | 
|  | e->error_code, e->request_code, e->minor_code, d); | 
|  | XGetErrorText(d, e->error_code, buf, sizeof buf); | 
|  | fprint(2, "%s\n", buf); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | xioerror(XDisplay *d) | 
|  | { | 
|  | /*print("X I/O error\n"); */ | 
|  | exit(0); | 
|  | /*sysfatal("X I/O error\n");*/ | 
|  | abort(); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | Memimage* | 
|  | _xattach(char *label, char *winsize) | 
|  | { | 
|  | char *argv[2], *disp; | 
|  | int i, havemin, height, mask, n, width, x, xrootid, y; | 
|  | Rectangle r; | 
|  | XClassHint classhint; | 
|  | XDrawable pmid; | 
|  | XPixmapFormatValues *pfmt; | 
|  | XScreen *xscreen; | 
|  | XSetWindowAttributes attr; | 
|  | XSizeHints normalhint; | 
|  | XTextProperty name; | 
|  | XVisualInfo xvi; | 
|  | XWindow xrootwin; | 
|  | XWindowAttributes wattr; | 
|  | XWMHints hint; | 
|  | Atom atoms[2]; | 
|  |  | 
|  | /* | 
|  | if(XInitThreads() == 0){ | 
|  | fprint(2, "XInitThreads failed\n"); | 
|  | abort(); | 
|  | } | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Connect to X server. | 
|  | */ | 
|  | _x.display = XOpenDisplay(NULL); | 
|  | if(_x.display == nil){ | 
|  | disp = getenv("DISPLAY"); | 
|  | werrstr("XOpenDisplay %s: %r", disp ? disp : ":0"); | 
|  | free(disp); | 
|  | return nil; | 
|  | } | 
|  | _x.fd = ConnectionNumber(_x.display); | 
|  | XSetErrorHandler(xerror); | 
|  | XSetIOErrorHandler(xioerror); | 
|  | xrootid = DefaultScreen(_x.display); | 
|  | xrootwin = DefaultRootWindow(_x.display); | 
|  |  | 
|  | /* | 
|  | * Figure out underlying screen format. | 
|  | */ | 
|  | if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi) | 
|  | || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){ | 
|  | _x.vis = xvi.visual; | 
|  | _x.depth = 16; | 
|  | } | 
|  | else | 
|  | if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi) | 
|  | || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){ | 
|  | _x.vis = xvi.visual; | 
|  | _x.depth = 15; | 
|  | } | 
|  | else | 
|  | if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi) | 
|  | || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){ | 
|  | _x.vis = xvi.visual; | 
|  | _x.depth = 24; | 
|  | } | 
|  | else | 
|  | if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi) | 
|  | || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){ | 
|  | if(_x.depth > 8){ | 
|  | werrstr("can't deal with colormapped depth %d screens", | 
|  | _x.depth); | 
|  | goto err0; | 
|  | } | 
|  | _x.vis = xvi.visual; | 
|  | _x.depth = 8; | 
|  | } | 
|  | else{ | 
|  | _x.depth = DefaultDepth(_x.display, xrootid); | 
|  | if(_x.depth != 8){ | 
|  | werrstr("can't understand depth %d screen", _x.depth); | 
|  | goto err0; | 
|  | } | 
|  | _x.vis = DefaultVisual(_x.display, xrootid); | 
|  | } | 
|  |  | 
|  | if(DefaultDepth(_x.display, xrootid) == _x.depth) | 
|  | _x.usetable = 1; | 
|  |  | 
|  | /* | 
|  | * _x.depth is only the number of significant pixel bits, | 
|  | * not the total number of pixel bits.  We need to walk the | 
|  | * display list to find how many actual bits are used | 
|  | * per pixel. | 
|  | */ | 
|  | _x.chan = 0; | 
|  | pfmt = XListPixmapFormats(_x.display, &n); | 
|  | for(i=0; i<n; i++){ | 
|  | if(pfmt[i].depth == _x.depth){ | 
|  | switch(pfmt[i].bits_per_pixel){ | 
|  | case 1:	/* untested */ | 
|  | _x.chan = GREY1; | 
|  | break; | 
|  | case 2:	/* untested */ | 
|  | _x.chan = GREY2; | 
|  | break; | 
|  | case 4:	/* untested */ | 
|  | _x.chan = GREY4; | 
|  | break; | 
|  | case 8: | 
|  | _x.chan = CMAP8; | 
|  | break; | 
|  | case 15: | 
|  | _x.chan = RGB15; | 
|  | break; | 
|  | case 16: /* how to tell RGB15? */ | 
|  | _x.chan = RGB16; | 
|  | break; | 
|  | case 24: /* untested (impossible?) */ | 
|  | _x.chan = RGB24; | 
|  | break; | 
|  | case 32: | 
|  | _x.chan = XRGB32; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if(_x.chan == 0){ | 
|  | werrstr("could not determine screen pixel format"); | 
|  | goto err0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set up color map if necessary. | 
|  | */ | 
|  | xscreen = DefaultScreenOfDisplay(_x.display); | 
|  | _x.cmap = DefaultColormapOfScreen(xscreen); | 
|  | if(_x.vis->class != StaticColor){ | 
|  | plan9cmap(); | 
|  | setupcmap(xrootwin); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * We get to choose the initial rectangle size. | 
|  | * This is arbitrary.  In theory we should read the | 
|  | * command line and allow the traditional X options. | 
|  | */ | 
|  | mask = 0; | 
|  | x = 0; | 
|  | y = 0; | 
|  | if(winsize && winsize[0]){ | 
|  | if(parsewinsize(winsize, &r, &havemin) < 0) | 
|  | sysfatal("%r"); | 
|  | }else{ | 
|  | /* | 
|  | * Parse the various X resources.  Thanks to Peter Canning. | 
|  | */ | 
|  | char *screen_resources, *display_resources, *geom, | 
|  | *geomrestype, *home, *file; | 
|  | XrmDatabase database; | 
|  | XrmValue geomres; | 
|  |  | 
|  | database = XrmGetDatabase(_x.display); | 
|  | screen_resources = XScreenResourceString(xscreen); | 
|  | if(screen_resources != nil){ | 
|  | XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False); | 
|  | XFree(screen_resources); | 
|  | } | 
|  |  | 
|  | display_resources = XResourceManagerString(_x.display); | 
|  | if(display_resources == nil){ | 
|  | home = getenv("HOME"); | 
|  | if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){ | 
|  | XrmCombineFileDatabase(file, &database, False); | 
|  | free(file); | 
|  | } | 
|  | free(home); | 
|  | }else | 
|  | XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False); | 
|  |  | 
|  | geom = smprint("%s.geometry", label); | 
|  | if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres)) | 
|  | mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height); | 
|  | free(geom); | 
|  |  | 
|  | if((mask & WidthValue) && (mask & HeightValue)){ | 
|  | r = Rect(0, 0, width, height); | 
|  | }else{ | 
|  | r = Rect(0, 0, WidthOfScreen(xscreen)*3/4, | 
|  | HeightOfScreen(xscreen)*3/4); | 
|  | if(Dx(r) > Dy(r)*3/2) | 
|  | r.max.x = r.min.x + Dy(r)*3/2; | 
|  | if(Dy(r) > Dx(r)*3/2) | 
|  | r.max.y = r.min.y + Dx(r)*3/2; | 
|  | } | 
|  | if(mask & XNegative){ | 
|  | x += WidthOfScreen(xscreen); | 
|  | } | 
|  | if(mask & YNegative){ | 
|  | y += HeightOfScreen(xscreen); | 
|  | } | 
|  | havemin = 0; | 
|  | } | 
|  | screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen)); | 
|  | windowrect = r; | 
|  |  | 
|  | memset(&attr, 0, sizeof attr); | 
|  | attr.colormap = _x.cmap; | 
|  | attr.background_pixel = ~0; | 
|  | attr.border_pixel = 0; | 
|  | _x.drawable = XCreateWindow( | 
|  | _x.display,	/* display */ | 
|  | xrootwin,	/* parent */ | 
|  | x,		/* x */ | 
|  | y,		/* y */ | 
|  | Dx(r),		/* width */ | 
|  | Dy(r),		/* height */ | 
|  | 0,		/* border width */ | 
|  | _x.depth,	/* depth */ | 
|  | InputOutput,	/* class */ | 
|  | _x.vis,		/* visual */ | 
|  | /* valuemask */ | 
|  | CWBackPixel|CWBorderPixel|CWColormap, | 
|  | &attr		/* attributes (the above aren't?!) */ | 
|  | ); | 
|  |  | 
|  | /* | 
|  | * Label and other properties required by ICCCCM. | 
|  | */ | 
|  | memset(&name, 0, sizeof name); | 
|  | if(label == nil) | 
|  | label = "pjw-face-here"; | 
|  | name.value = (uchar*)label; | 
|  | name.encoding = XA_STRING; | 
|  | name.format = 8; | 
|  | name.nitems = strlen((char*)name.value); | 
|  |  | 
|  | memset(&normalhint, 0, sizeof normalhint); | 
|  | normalhint.flags = PSize|PMaxSize; | 
|  | if(winsize && winsize[0]){ | 
|  | normalhint.flags &= ~PSize; | 
|  | normalhint.flags |= USSize; | 
|  | normalhint.width = Dx(r); | 
|  | normalhint.height = Dy(r); | 
|  | }else{ | 
|  | if((mask & WidthValue) && (mask & HeightValue)){ | 
|  | normalhint.flags &= ~PSize; | 
|  | normalhint.flags |= USSize; | 
|  | normalhint.width = width; | 
|  | normalhint.height = height; | 
|  | } | 
|  | if((mask & WidthValue) && (mask & HeightValue)){ | 
|  | normalhint.flags |= USPosition; | 
|  | normalhint.x = x; | 
|  | normalhint.y = y; | 
|  | } | 
|  | } | 
|  |  | 
|  | normalhint.max_width = WidthOfScreen(xscreen); | 
|  | normalhint.max_height = HeightOfScreen(xscreen); | 
|  |  | 
|  | memset(&hint, 0, sizeof hint); | 
|  | hint.flags = InputHint|StateHint; | 
|  | hint.input = 1; | 
|  | hint.initial_state = NormalState; | 
|  |  | 
|  | memset(&classhint, 0, sizeof classhint); | 
|  | classhint.res_name = label; | 
|  | classhint.res_class = label; | 
|  |  | 
|  | argv[0] = label; | 
|  | argv[1] = nil; | 
|  |  | 
|  | XSetWMProperties( | 
|  | _x.display,	/* display */ | 
|  | _x.drawable,	/* window */ | 
|  | &name,		/* XA_WM_NAME property */ | 
|  | &name,		/* XA_WM_ICON_NAME property */ | 
|  | argv,		/* XA_WM_COMMAND */ | 
|  | 1,		/* argc */ | 
|  | &normalhint,	/* XA_WM_NORMAL_HINTS */ | 
|  | &hint,		/* XA_WM_HINTS */ | 
|  | &classhint	/* XA_WM_CLASSHINTS */ | 
|  | ); | 
|  | XFlush(_x.display); | 
|  |  | 
|  | if(havemin){ | 
|  | XWindowChanges ch; | 
|  |  | 
|  | memset(&ch, 0, sizeof ch); | 
|  | ch.x = r.min.x; | 
|  | ch.y = r.min.y; | 
|  | XConfigureWindow(_x.display, _x.drawable, CWX|CWY, &ch); | 
|  | /* | 
|  | * Must pretend origin is 0,0 for X. | 
|  | */ | 
|  | r = Rect(0,0,Dx(r),Dy(r)); | 
|  | } | 
|  | /* | 
|  | * Look up clipboard atom. | 
|  | */ | 
|  | _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False); | 
|  | _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False); | 
|  | _x.targets = XInternAtom(_x.display, "TARGETS", False); | 
|  | _x.text = XInternAtom(_x.display, "TEXT", False); | 
|  | _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False); | 
|  | _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False); | 
|  | _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False); | 
|  | _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False); | 
|  |  | 
|  | atoms[0] = _x.takefocus; | 
|  | atoms[1] = _x.losefocus; | 
|  | XChangeProperty(_x.display, _x.drawable, _x.wmprotos, XA_ATOM, 32, | 
|  | PropModeReplace, (uchar*)atoms, 2); | 
|  |  | 
|  | /* | 
|  | * Put the window on the screen, check to see what size we actually got. | 
|  | */ | 
|  | XMapWindow(_x.display, _x.drawable); | 
|  | XSync(_x.display, False); | 
|  |  | 
|  | if(!XGetWindowAttributes(_x.display, _x.drawable, &wattr)) | 
|  | fprint(2, "XGetWindowAttributes failed\n"); | 
|  | else if(wattr.width && wattr.height){ | 
|  | if(wattr.width != Dx(r) || wattr.height != Dy(r)){ | 
|  | r.max.x = wattr.width; | 
|  | r.max.y = wattr.height; | 
|  | } | 
|  | }else | 
|  | fprint(2, "XGetWindowAttributes: bad attrs\n"); | 
|  |  | 
|  | /* | 
|  | * Allocate our local backing store. | 
|  | */ | 
|  | _x.screenr = r; | 
|  | _x.screenpm = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth); | 
|  | _x.nextscreenpm = _x.screenpm; | 
|  | _x.screenimage = _xallocmemimage(r, _x.chan, _x.screenpm); | 
|  |  | 
|  | /* | 
|  | * Allocate some useful graphics contexts for the future. | 
|  | */ | 
|  | _x.gcfill	= xgc(_x.screenpm, FillSolid, -1); | 
|  | _x.gccopy	= xgc(_x.screenpm, -1, -1); | 
|  | _x.gcsimplesrc 	= xgc(_x.screenpm, FillStippled, -1); | 
|  | _x.gczero	= xgc(_x.screenpm, -1, -1); | 
|  | _x.gcreplsrc	= xgc(_x.screenpm, FillTiled, -1); | 
|  |  | 
|  | pmid = XCreatePixmap(_x.display, _x.drawable, 1, 1, 1); | 
|  | _x.gcfill0	= xgc(pmid, FillSolid, 0); | 
|  | _x.gccopy0	= xgc(pmid, -1, -1); | 
|  | _x.gcsimplesrc0	= xgc(pmid, FillStippled, -1); | 
|  | _x.gczero0	= xgc(pmid, -1, -1); | 
|  | _x.gcreplsrc0	= xgc(pmid, FillTiled, -1); | 
|  | XFreePixmap(_x.display, pmid); | 
|  |  | 
|  | return _x.screenimage; | 
|  |  | 
|  | err0: | 
|  | /* | 
|  | * Should do a better job of cleaning up here. | 
|  | */ | 
|  | XCloseDisplay(_x.display); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | int | 
|  | _xsetlabel(char *label) | 
|  | { | 
|  | XTextProperty name; | 
|  |  | 
|  | /* | 
|  | * Label and other properties required by ICCCCM. | 
|  | */ | 
|  | memset(&name, 0, sizeof name); | 
|  | if(label == nil) | 
|  | label = "pjw-face-here"; | 
|  | name.value = (uchar*)label; | 
|  | name.encoding = XA_STRING; | 
|  | name.format = 8; | 
|  | name.nitems = strlen((char*)name.value); | 
|  |  | 
|  | XSetWMProperties( | 
|  | _x.display,	/* display */ | 
|  | _x.drawable,	/* window */ | 
|  | &name,		/* XA_WM_NAME property */ | 
|  | &name,		/* XA_WM_ICON_NAME property */ | 
|  | nil,		/* XA_WM_COMMAND */ | 
|  | 0,		/* argc */ | 
|  | nil,		/* XA_WM_NORMAL_HINTS */ | 
|  | nil,		/* XA_WM_HINTS */ | 
|  | nil	/* XA_WM_CLASSHINTS */ | 
|  | ); | 
|  | XFlush(_x.display); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Create a GC with a particular fill style and XXX. | 
|  | * Disable generation of GraphicsExpose/NoExpose events in the GC. | 
|  | */ | 
|  | static XGC | 
|  | xgc(XDrawable d, int fillstyle, int foreground) | 
|  | { | 
|  | XGC gc; | 
|  | XGCValues v; | 
|  |  | 
|  | memset(&v, 0, sizeof v); | 
|  | v.function = GXcopy; | 
|  | v.graphics_exposures = False; | 
|  | gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v); | 
|  | if(fillstyle != -1) | 
|  | XSetFillStyle(_x.display, gc, fillstyle); | 
|  | if(foreground != -1) | 
|  | XSetForeground(_x.display, gc, 0); | 
|  | return gc; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Initialize map with the Plan 9 rgbv color map. | 
|  | */ | 
|  | static void | 
|  | plan9cmap(void) | 
|  | { | 
|  | int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7; | 
|  | static int once; | 
|  |  | 
|  | if(once) | 
|  | return; | 
|  | once = 1; | 
|  |  | 
|  | for(r=0; r!=4; r++) | 
|  | for(g = 0; g != 4; g++) | 
|  | for(b = 0; b!=4; b++) | 
|  | for(v = 0; v!=4; v++){ | 
|  | den=r; | 
|  | if(g > den) | 
|  | den=g; | 
|  | if(b > den) | 
|  | den=b; | 
|  | /* divide check -- pick grey shades */ | 
|  | if(den==0) | 
|  | cr=cg=cb=v*17; | 
|  | else { | 
|  | num=17*(4*den+v); | 
|  | cr=r*num/den; | 
|  | cg=g*num/den; | 
|  | cb=b*num/den; | 
|  | } | 
|  | idx = r*64 + v*16 + ((g*4 + b + v - r) & 15); | 
|  | _x.map[idx].red = cr*0x0101; | 
|  | _x.map[idx].green = cg*0x0101; | 
|  | _x.map[idx].blue = cb*0x0101; | 
|  | _x.map[idx].pixel = idx; | 
|  | _x.map[idx].flags = DoRed|DoGreen|DoBlue; | 
|  |  | 
|  | v7 = v >> 1; | 
|  | idx7 = r*32 + v7*16 + g*4 + b; | 
|  | if((v & 1) == v7){ | 
|  | _x.map7to8[idx7][0] = idx; | 
|  | if(den == 0) { 		/* divide check -- pick grey shades */ | 
|  | cr = ((255.0/7.0)*v7)+0.5; | 
|  | cg = cr; | 
|  | cb = cr; | 
|  | } | 
|  | else { | 
|  | num=17*15*(4*den+v7*2)/14; | 
|  | cr=r*num/den; | 
|  | cg=g*num/den; | 
|  | cb=b*num/den; | 
|  | } | 
|  | _x.map7[idx7].red = cr*0x0101; | 
|  | _x.map7[idx7].green = cg*0x0101; | 
|  | _x.map7[idx7].blue = cb*0x0101; | 
|  | _x.map7[idx7].pixel = idx7; | 
|  | _x.map7[idx7].flags = DoRed|DoGreen|DoBlue; | 
|  | } | 
|  | else | 
|  | _x.map7to8[idx7][1] = idx; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Initialize and install the rgbv color map as a private color map | 
|  | * for this application.  It gets the best colors when it has the | 
|  | * cursor focus. | 
|  | * | 
|  | * We always choose the best depth possible, but that might not | 
|  | * be the default depth.  On such "suboptimal" systems, we have to allocate an | 
|  | * empty color map anyway, according to Axel Belinfante. | 
|  | */ | 
|  | static int | 
|  | setupcmap(XWindow w) | 
|  | { | 
|  | char buf[30]; | 
|  | int i; | 
|  | u32int p, pp; | 
|  | XColor c; | 
|  |  | 
|  | if(_x.depth <= 1) | 
|  | return 0; | 
|  |  | 
|  | if(_x.depth >= 24) { | 
|  | if(_x.usetable == 0) | 
|  | _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone); | 
|  |  | 
|  | /* | 
|  | * The pixel value returned from XGetPixel needs to | 
|  | * be converted to RGB so we can call rgb2cmap() | 
|  | * to translate between 24 bit X and our color. Unfortunately, | 
|  | * the return value appears to be display server endian | 
|  | * dependant. Therefore, we run some heuristics to later | 
|  | * determine how to mask the int value correctly. | 
|  | * Yeah, I know we can look at _x.vis->byte_order but | 
|  | * some displays say MSB even though they run on LSB. | 
|  | * Besides, this is more anal. | 
|  | */ | 
|  | c = _x.map[19];	/* known to have different R, G, B values */ | 
|  | if(!XAllocColor(_x.display, _x.cmap, &c)){ | 
|  | werrstr("XAllocColor: %r"); | 
|  | return -1; | 
|  | } | 
|  | p  = c.pixel; | 
|  | pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff); | 
|  | if(pp != _x.map[19].pixel) { | 
|  | /* check if endian is other way */ | 
|  | pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff); | 
|  | if(pp != _x.map[19].pixel){ | 
|  | werrstr("cannot detect X server byte order"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | switch(_x.chan){ | 
|  | case RGB24: | 
|  | _x.chan = BGR24; | 
|  | break; | 
|  | case XRGB32: | 
|  | _x.chan = XBGR32; | 
|  | break; | 
|  | default: | 
|  | werrstr("cannot byteswap channel %s", | 
|  | chantostr(buf, _x.chan)); | 
|  | break; | 
|  | } | 
|  | } | 
|  | }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){ | 
|  | /* | 
|  | * Do nothing.  We have no way to express a | 
|  | * mixed-endian 16-bit screen, so pretend they don't exist. | 
|  | */ | 
|  | if(_x.usetable == 0) | 
|  | _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone); | 
|  | }else if(_x.vis->class == PseudoColor){ | 
|  | if(_x.usetable == 0){ | 
|  | _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll); | 
|  | XStoreColors(_x.display, _x.cmap, _x.map, 256); | 
|  | for(i = 0; i < 256; i++){ | 
|  | _x.tox11[i] = i; | 
|  | _x.toplan9[i] = i; | 
|  | } | 
|  | }else{ | 
|  | for(i = 0; i < 128; i++){ | 
|  | c = _x.map7[i]; | 
|  | if(!XAllocColor(_x.display, _x.cmap, &c)){ | 
|  | werrstr("can't allocate colors in 7-bit map"); | 
|  | return -1; | 
|  | } | 
|  | _x.tox11[_x.map7to8[i][0]] = c.pixel; | 
|  | _x.tox11[_x.map7to8[i][1]] = c.pixel; | 
|  | _x.toplan9[c.pixel] = _x.map7to8[i][0]; | 
|  | } | 
|  | } | 
|  | }else{ | 
|  | werrstr("unsupported visual class %d", _x.vis->class); | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | _flushmemscreen(Rectangle r) | 
|  | { | 
|  | if(_x.nextscreenpm != _x.screenpm){ | 
|  | qlock(&_x.screenlock); | 
|  | XSync(_x.display, False); | 
|  | XFreePixmap(_x.display, _x.screenpm); | 
|  | _x.screenpm = _x.nextscreenpm; | 
|  | qunlock(&_x.screenlock); | 
|  | } | 
|  |  | 
|  | if(r.min.x >= r.max.x || r.min.y >= r.max.y) | 
|  | return; | 
|  | XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y, | 
|  | Dx(r), Dy(r), r.min.x, r.min.y); | 
|  | XFlush(_x.display); | 
|  | } | 
|  |  | 
|  | void | 
|  | _xexpose(XEvent *e) | 
|  | { | 
|  | XExposeEvent *xe; | 
|  | Rectangle r; | 
|  |  | 
|  | qlock(&_x.screenlock); | 
|  | if(_x.screenpm != _x.nextscreenpm){ | 
|  | qunlock(&_x.screenlock); | 
|  | return; | 
|  | } | 
|  | xe = (XExposeEvent*)e; | 
|  | r.min.x = xe->x; | 
|  | r.min.y = xe->y; | 
|  | r.max.x = xe->x+xe->width; | 
|  | r.max.y = xe->y+xe->height; | 
|  | XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y, | 
|  | Dx(r), Dy(r), r.min.x, r.min.y); | 
|  | XSync(_x.display, False); | 
|  | qunlock(&_x.screenlock); | 
|  | } | 
|  |  | 
|  | int | 
|  | _xdestroy(XEvent *e) | 
|  | { | 
|  | XDestroyWindowEvent *xe; | 
|  |  | 
|  | xe = (XDestroyWindowEvent*)e; | 
|  | if(xe->window == _x.drawable){ | 
|  | _x.destroyed = 1; | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | _xconfigure(XEvent *e) | 
|  | { | 
|  | Rectangle r; | 
|  | XConfigureEvent *xe = (XConfigureEvent*)e; | 
|  |  | 
|  | if(!fullscreen){ | 
|  | int rx, ry; | 
|  | XWindow w; | 
|  | if(XTranslateCoordinates(_x.display, _x.drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &w)) | 
|  | windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height); | 
|  | } | 
|  |  | 
|  | if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr)) | 
|  | return 0; | 
|  | r = Rect(0, 0, xe->width, xe->height); | 
|  |  | 
|  | qlock(&_x.screenlock); | 
|  | if(_x.screenpm != _x.nextscreenpm){ | 
|  | XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y, | 
|  | Dx(r), Dy(r), r.min.x, r.min.y); | 
|  | XSync(_x.display, False); | 
|  | } | 
|  | qunlock(&_x.screenlock); | 
|  | _x.newscreenr = r; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | _xreplacescreenimage(void) | 
|  | { | 
|  | Memimage *m; | 
|  | XDrawable pixmap; | 
|  | Rectangle r; | 
|  |  | 
|  | r = _x.newscreenr; | 
|  |  | 
|  | pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth); | 
|  | m = _xallocmemimage(r, _x.chan, pixmap); | 
|  | if(_x.nextscreenpm != _x.screenpm) | 
|  | XFreePixmap(_x.display, _x.nextscreenpm); | 
|  | _x.nextscreenpm = pixmap; | 
|  | _x.screenr = r; | 
|  | _drawreplacescreenimage(m); | 
|  | return 1; | 
|  | } |