aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/devdraw/x11-init.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-06-25 19:18:39 +0000
committerrsc <devnull@localhost>2006-06-25 19:18:39 +0000
commitc66b52501b630f6c0cdee1ed6cf81ad153e1183f (patch)
treeec935772fd77c3aa2337598c25a6c71ba84a9275 /src/cmd/devdraw/x11-init.c
parentf97f53744067400bec4dbd7aae5eafde54e99b7f (diff)
downloadplan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.tar.gz
plan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.tar.bz2
plan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.zip
new draw server
Diffstat (limited to 'src/cmd/devdraw/x11-init.c')
-rw-r--r--src/cmd/devdraw/x11-init.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/src/cmd/devdraw/x11-init.c b/src/cmd/devdraw/x11-init.c
new file mode 100644
index 00000000..9820ea24
--- /dev/null
+++ b/src/cmd/devdraw/x11-init.c
@@ -0,0 +1,788 @@
+/*
+ * 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"
+
+static int parsewinsize(char*, Rectangle*, int*);
+
+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;
+
+ print("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);
+ print("%s\n", buf);
+ return 0;
+}
+
+static int
+xioerror(XDisplay *d)
+{
+ /*print("X I/O error\n"); */
+ 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;
+ }
+
+ 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(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr))
+ return 0;
+ if(xe->width==0 || xe->height==0)
+ fprint(2, "ignoring resize to %dx%d\n", xe->width, xe->height);
+ 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;
+ if(eqrect(_x.screenr, r))
+ return 0;
+
+ 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;
+}
+
+static int
+parsewinsize(char *s, Rectangle *r, int *havemin)
+{
+ char c, *os;
+ int i, j, k, l;
+
+ os = s;
+ *havemin = 0;
+ *r = Rect(0,0,0,0);
+ if(!isdigit((uchar)*s))
+ goto oops;
+ i = strtol(s, &s, 0);
+ if(*s == 'x'){
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ j = strtol(s, &s, 0);
+ r->max.x = i;
+ r->max.y = j;
+ if(*s == 0)
+ return 0;
+ if(*s != '@')
+ goto oops;
+
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ i = strtol(s, &s, 0);
+ if(*s != ',' && *s != ' ')
+ goto oops;
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ j = strtol(s, &s, 0);
+ if(*s != 0)
+ goto oops;
+ *r = rectaddpt(*r, Pt(i,j));
+ *havemin = 1;
+ return 0;
+ }
+
+ c = *s;
+ if(c != ' ' && c != ',')
+ goto oops;
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ j = strtol(s, &s, 0);
+ if(*s != c)
+ goto oops;
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ k = strtol(s, &s, 0);
+ if(*s != c)
+ goto oops;
+ s++;
+ if(!isdigit((uchar)*s))
+ goto oops;
+ l = strtol(s, &s, 0);
+ if(*s != 0)
+ goto oops;
+ *r = Rect(i,j,k,l);
+ *havemin = 1;
+ return 0;
+
+oops:
+ werrstr("bad syntax in window size '%s'", os);
+ return -1;
+}