commit 161060a46346fa0beeb48b55ed28b2cd330bc4e8 from: rsc date: Sat Oct 11 02:47:43 2003 UTC Lots of X fixes. commit - 4af386f434d5ca3de733951d4f73dd134e879cc2 commit + 161060a46346fa0beeb48b55ed28b2cd330bc4e8 blob - 8013efa56f01f1dc95427eb7498c5545b6b2beb6 blob + 807b8e743aa79f2b6c01b572d420c770b1f5a057 --- src/libdraw/Makefile +++ src/libdraw/Makefile @@ -99,6 +99,7 @@ OFILES=\ x11-mouse.$O\ x11-pixelbits.$O\ x11-unload.$O\ + x11-wsys.$O\ devdraw.$O\ unix.$O\ blob - 41b30620f22e982acc7c164d41bb2a747056d663 blob + 1b19fc1c42a98bf81368b1a519134304a3175651 --- src/libdraw/arith.c +++ src/libdraw/arith.c @@ -167,8 +167,6 @@ drawld2chan[] = { CMAP8, }; -int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 }; - u32int setalpha(u32int color, uchar alpha) { blob - b0036385dbcfa82285fbf70d45dddebb0d6cb011 blob + f4749867140703b0d41a0343a126fc6c1131414a --- src/libdraw/devdraw.c +++ src/libdraw/devdraw.c @@ -138,6 +138,7 @@ void _initdisplaymemimage(Display *d, Memimage *m) { screenimage = m; + m->screenref = 1; client0 = mallocz(sizeof(Client), 1); if(client0 == nil){ fprint(2, "initdraw: allocating client0: out of memory"); @@ -165,7 +166,16 @@ _drawreplacescreenimage(Memimage *m) * about the resize through external means, so all we * need to do is this assignment. */ + Memimage *om; + + qlock(&sdraw.lk); + om = screenimage; screenimage = m; + m->screenref = 1; + if(om && --om->screenref == 0){ + _freememimage(om); + } + qunlock(&sdraw.lk); } static @@ -399,6 +409,8 @@ drawinstall(Client *client, int id, Memimage *i, DScre d->name = 0; d->vers = 0; d->image = i; + if(i->screenref) + ++i->screenref; d->nfchar = 0; d->fchar = 0; d->fromname = 0; @@ -534,11 +546,9 @@ drawfreedimage(DImage *dimage) drawfreedimage(dimage->fromname); goto Return; } - //if(dimage->image == screenimage) /* don't free the display */ - // goto Return; ds = dimage->dscreen; + l = dimage->image; if(ds){ - l = dimage->image; if(l->data == screenimage->data) addflush(l->layer->screenr); if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ @@ -549,8 +559,12 @@ drawfreedimage(DImage *dimage) else memlfree(l); drawfreedscreen(ds); - }else - freememimage(dimage->image); + }else{ + if(l->screenref==0) + freememimage(l); + else if(--l->screenref==0) + _freememimage(l); + } Return: free(dimage->fchar); free(dimage); @@ -732,6 +746,7 @@ _drawmsgread(Display *d, void *a, int n) { int inbuf; + qlock(&sdraw.lk); inbuf = d->obufp - d->obuf; if(n > inbuf) n = inbuf; @@ -740,6 +755,7 @@ _drawmsgread(Display *d, void *a, int n) if(inbuf) memmove(d->obuf, d->obufp-inbuf, inbuf); d->obufp = d->obuf+inbuf; + qunlock(&sdraw.lk); return n; } @@ -776,6 +792,7 @@ _drawmsgwrite(Display *d, void *v, int n) Refreshfn reffn; Refx *refx; + qlock(&sdraw.lk); d->obufp = d->obuf; a = v; m = 0; @@ -1516,6 +1533,7 @@ _drawmsgwrite(Display *d, void *v, int n) continue; } } + qunlock(&sdraw.lk); return oldn - n; Enodrawimage: @@ -1527,9 +1545,11 @@ Enodrawscreen: Eshortdraw: err = "short draw message"; goto error; +/* Eshortread: err = "draw read too short"; goto error; +*/ Eimageexists: err = "image id in use"; goto error; @@ -1551,6 +1571,7 @@ Enotfont: Eindex: err = "character index out of range"; goto error; +/* Enoclient: err = "no such draw client"; goto error; @@ -1560,6 +1581,7 @@ Edepth: Enameused: err = "image name in use"; goto error; +*/ Enoname: err = "no image with that name"; goto error; @@ -1580,7 +1602,8 @@ Ebadarg: goto error; error: - drawerror(display, err); + werrstr("%s", err); + qunlock(&sdraw.lk); return -1; } blob - 632e82385919aeab2525903b0cb38df0591f09cd blob + 7053c171c6837abc070e5a995598ee503f8e65a7 --- src/libdraw/md-line.c +++ src/libdraw/md-line.c @@ -10,6 +10,7 @@ enum Arrow3 = 3, }; +/* static int lmin(int a, int b) @@ -18,6 +19,7 @@ lmin(int a, int b) return a; return b; } +*/ static int blob - dc16e379b744c75f93ae55af57276e668c5fa783 blob + e9fa3f849b3460c32388918c7ca23cd73d194ba8 --- src/libdraw/openfont.c +++ src/libdraw/openfont.c @@ -2,6 +2,8 @@ #include #include +extern vlong _drawflength(int); + Font* openfont(Display *d, char *name) { @@ -13,7 +15,7 @@ openfont(Display *d, char *name) if(fd < 0) return 0; - n = flength(fd); + n = _drawflength(fd); buf = malloc(n+1); if(buf == 0){ close(fd); blob - bcb4e3a1ef7f49020f50ab0852c4501683de9d5d blob + bf397cb5b5f18b964e7060ca4be45d0e7bcf7bb8 --- src/libdraw/subfontname.c +++ src/libdraw/subfontname.c @@ -29,7 +29,9 @@ subfontname(char *cfname, char *fname, int maxdepth) if(maxdepth > 8) maxdepth = 8; - for(i=log2[maxdepth]; i>=0; i--){ + for(i=3; i>=0; i--){ + if((1< maxdepth) + continue; /* try i-bit grey */ snprint(tmp2, sizeof tmp2, "%s.%d", t, i); if(access(tmp2, AREAD) == 0) blob - 2203b0876e47137bc3ca1d18e7ce7e879f7e09db blob + 491bc66c866c2ab163d1d8995f0f68820c48872a --- src/libdraw/unix.c +++ src/libdraw/unix.c @@ -5,7 +5,7 @@ #include vlong -flength(int fd) +_drawflength(int fd) { struct stat s; blob - 19475c747818d4a7b05b110e632f7dc164d34729 blob + 458efc61fdee4de8974315802a1ecd8d0fc6a274 --- src/libdraw/x11-alloc.c +++ src/libdraw/x11-alloc.c @@ -37,20 +37,21 @@ xallocmemimage(Rectangle r, u32int chan, int pixmap) } /* - * Allocate backing store. What we call a 32-bit image - * the X server calls a 24-bit image. + * Allocate backing store. */ - d = m->depth; + if(chan == GREY1) + d = 1; + else + d = _x.depth; if(pixmap != PMundef) xm->pixmap = pixmap; else - xm->pixmap = XCreatePixmap(_x.display, _x.drawable, - Dx(r), Dy(r), d==32 ? 24 : d); + xm->pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), d); /* * We want to align pixels on word boundaries. */ - if(d == 24) + if(m->depth == 24) offset = r.min.x&3; else offset = r.min.x&(31/m->depth); @@ -60,7 +61,7 @@ xallocmemimage(Rectangle r, u32int chan, int pixmap) /* * Wrap our data in an XImage structure. */ - xi = XCreateImage(_x.display, _x.vis, d==32 ? 24 : d, + xi = XCreateImage(_x.display, _x.vis, d, ZPixmap, 0, (char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(u32int)); if(xi == nil){ blob - ee91791d9794c4cb8aef91cc76f170d07047abed blob + 97438740e899e297802ca550fcf6ef45aa59e4aa --- src/libdraw/x11-draw.c +++ src/libdraw/x11-draw.c @@ -17,7 +17,6 @@ void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) { - int drew; Memdrawparam *par; if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil) @@ -116,6 +115,7 @@ xdraw(Memdrawparam *par) } }else{ /* this doesn't work on rob's mac? */ + return 0; gc = _x.gcsimplesrc; if(dst->chan == CMAP8 && _x.usetable) sdval = _x.tox11[sdval]; blob - 85543e838e934f1288d01fba26ff0e372c20da09 blob + 28f6ae4009c89b8dcb73e4f4991a313c6ba6f4f7 --- src/libdraw/x11-init.c +++ src/libdraw/x11-init.c @@ -71,7 +71,7 @@ getimage0(Display *d) fprint(2, "cannot read screen info: %r\n"); abort(); } - + n = _drawmsgread(d, info, sizeof info); if(n != 12*12){ fprint(2, "short screen info\n"); @@ -113,8 +113,8 @@ xerror(XDisplay *d, XErrorEvent *e) { char buf[200]; - print("X error: error_code=%d, request_code=%d, minor=%d\n", - e->error_code, e->request_code, e->minor_code); + 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; @@ -179,6 +179,13 @@ xattach(char *label) _x.usetable = 1; } else + if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi) + || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){ + _x.vis = xvi.visual; + _x.depth = 15; + _x.usetable = 1; + } + else if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi) || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){ _x.vis = xvi.visual; @@ -226,6 +233,9 @@ xattach(char *label) break; case 8: _x.chan = CMAP8; + break; + case 15: + _x.chan = RGB15; break; case 16: /* how to tell RGB15? */ _x.chan = RGB16; @@ -264,7 +274,7 @@ xattach(char *label) memset(&attr, 0, sizeof attr); attr.colormap = _x.cmap; - attr.background_pixel = 0; + attr.background_pixel = ~0; attr.border_pixel = 0; _x.drawable = XCreateWindow( _x.display, /* display */ @@ -274,7 +284,7 @@ xattach(char *label) Dx(r), /* width */ Dy(r), /* height */ 0, /* border width */ - _x.depth, /* depth */ + DefaultDepthOfScreen(xscreen), /* depth */ InputOutput, /* class */ _x.vis, /* visual */ /* valuemask */ @@ -328,6 +338,7 @@ xattach(char *label) */ _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); /* @@ -354,18 +365,22 @@ xattach(char *label) XFlush(_x.display); /* - * Lots of display connections for various threads. + * Lots of display connections for various procs. */ _x.kbdcon = XOpenDisplay(NULL); _x.mousecon = XOpenDisplay(NULL); _x.snarfcon = XOpenDisplay(NULL); + if(0) fprint(2, "x: display=%p kbd=%p mouse=%p snarf=%p\n", + _x.display, _x.kbdcon, _x.mousecon, _x.snarfcon); + _x.black = xscreen->black_pixel; _x.white = xscreen->white_pixel; return _x.screenimage; err0: +fprint(2, "%r\n"); /* * Should do a better job of cleaning up here. */ @@ -551,6 +566,14 @@ setupcmap(XWindow w) 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, @@ -564,6 +587,11 @@ xexpose(XEvent *e, XDisplay *xd) 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; @@ -571,17 +599,29 @@ xexpose(XEvent *e, XDisplay *xd) r.max.y = xe->y+xe->height; XCopyArea(xd, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y); - XFlush(xd); + XSync(xd, False); + qunlock(&_x.screenlock); } int xconfigure(XEvent *e, XDisplay *xd) { + Rectangle r; XConfigureEvent *xe = (XConfigureEvent*)e; if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr)) return 0; - _x.newscreenr = Rect(0, 0, xe->width, xe->height); + 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(xd, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y, + Dx(r), Dy(r), r.min.x, r.min.y); + XSync(xd, False); + } + qunlock(&_x.screenlock); + _x.newscreenr = r; return 1; } @@ -598,7 +638,9 @@ xreplacescreenimage(void) pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth); m = xallocmemimage(r, _x.chan, pixmap); - _x.screenpm = pixmap; + if(_x.nextscreenpm != _x.screenpm) + XFreePixmap(_x.display, _x.nextscreenpm); + _x.nextscreenpm = pixmap; _x.screenr = r; _drawreplacescreenimage(m); return 1; blob - 49ee3fbba8f20d2e01d7d7e6181d6d168e3a0100 blob + 35fd31ea2a07675971e1e83da45b975e003357f6 --- src/libdraw/x11-itrans.c +++ src/libdraw/x11-itrans.c @@ -254,5 +254,131 @@ xsetcursor(Cursor *c) XFreePixmap(_x.display, xsrc); XFreePixmap(_x.display, xmask); XFlush(_x.display); +} + +struct { + char buf[SnarfSize]; + QLock lk; +} clip; + +char* +xgetsnarf(XDisplay *xd) +{ + uchar *data, *xdata; + Atom type; + ulong len, lastlen, dummy; + int fmt, i; + XWindow w; + + qlock(&clip.lk); + w = XGetSelectionOwner(xd, XA_PRIMARY); + if(w == _x.drawable){ + data = (uchar*)strdup(clip.buf); + goto out; + } + if(w == None){ + data = nil; + goto out; + } + /* + * We should be waiting for SelectionNotify here, but it might never + * come, and we have no way to time out. Instead, we will zero the + * property, request our buddy to fill it in for us, and wait until + * he's done. + */ + XChangeProperty(xd, _x.drawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace, (uchar*)"", 0); + XConvertSelection(xd, XA_PRIMARY, XA_STRING, None, _x.drawable, CurrentTime); + XFlush(xd); + lastlen = 0; + for(i=0; i<30; i++){ + usleep(100*1000); + XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, 0, 0, AnyPropertyType, + &type, &fmt, &dummy, &len, &data); + if(lastlen == len && len > 0) + break; + lastlen = len; + } + if(i == 30){ + data = nil; + goto out; + } + /* get the property */ + data = nil; + XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, SnarfSize/4, 0, + AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); + if(type != XA_STRING || len == 0){ + if(xdata) + XFree(xdata); + data = nil; + }else{ + if(xdata){ + data = strdup((char*)xdata); + XFree(xdata); + }else + data = nil; + } +out: + qunlock(&clip.lk); + return data; } +void +xputsnarf(XDisplay *xd, char *data) +{ + if(strlen(data) >= SnarfSize) + return; + qlock(&clip.lk); + strcpy(clip.buf, data); + /* + * BUG: This is wrong. Instead, we should send an event to the + * mouse connection telling it to call XSetSelectionOwner. + */ + XSetSelectionOwner(_x.mousecon, XA_PRIMARY, _x.drawable, CurrentTime); + XFlush(xd); + qunlock(&clip.lk); +} + +int +xselect(XEvent *e, XDisplay *xd) +{ + XEvent r; + XSelectionRequestEvent *xe; + + memset(&r, 0, sizeof r); + xe = (XSelectionRequestEvent*)e; + if(1 || xe->target == XA_STRING){ + qlock(&clip.lk); + XChangeProperty(xd, xe->requestor, xe->property, XA_STRING, 8, + PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)+1); + qunlock(&clip.lk); + r.xselection.property = xe->property; + }else{ + fprint(2, "asked for a %d\n", xe->target); + r.xselection.property = None; + } + + r.xselection.display = xe->display; + /* r.xselection.property filled above */ + r.xselection.target = xe->target; + r.xselection.type = SelectionNotify; + r.xselection.requestor = xe->requestor; + r.xselection.time = xe->time; + r.xselection.send_event = True; + r.xselection.selection = xe->selection; + XSendEvent(xd, xe->requestor, False, 0, &r); + XFlush(xd); + return 0; +} + +void +putsnarf(char *data) +{ + xputsnarf(_x.snarfcon, data); +} + +char* +getsnarf(void) +{ + return xgetsnarf(_x.snarfcon); +} + blob - 188e52bf467d1fd352b4755cdd4f9f42d5aa2716 blob + 92b57814c987dd9e49e76ce9a33b158f1cf87ba7 --- src/libdraw/x11-keyboard.c +++ src/libdraw/x11-keyboard.c @@ -41,8 +41,8 @@ _ioproc(void *arg) kc = arg; threadsetname("kbdproc"); kc->pid = getpid(); + XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask); for(;;){ - XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask); XWindowEvent(_x.kbdcon, _x.drawable, KeyPressMask, &xevent); switch(xevent.type){ case KeyPress: blob - 9fffe34e1046c51d5ba96f990ff6490d109f93d1 blob + 514926da652cc0da5517f6032477c6b8b80e78d1 --- src/libdraw/x11-memdraw.h +++ src/libdraw/x11-memdraw.h @@ -54,7 +54,9 @@ struct Xprivate { XDisplay *mousecon; Rectangle newscreenr; Memimage* screenimage; + QLock screenlock; XDrawable screenpm; + XDrawable nextscreenpm; Rectangle screenr; XDisplay *snarfcon; int toplan9[256]; @@ -73,11 +75,13 @@ extern void xfillcolor(Memimage*, Rectangle, u32int); extern void xfreexdata(Memimage*); extern XImage *xgetxdata(Memimage*, Rectangle); extern void xputxdata(Memimage*, Rectangle); +extern void _initdisplaymemimage(Display*, Memimage*); struct Mouse; extern int xtoplan9mouse(XEvent*, struct Mouse*); extern int xtoplan9kbd(XEvent*); extern void xexpose(XEvent*, XDisplay*); +extern int xselect(XEvent*, XDisplay*); extern int xconfigure(XEvent*, XDisplay*); extern void flushmemscreen(Rectangle); extern void xmoveto(Point); blob - c6a2685107163432d19f99a2ba4f5783a3997c8f blob + 6b5b3922af805dd27d62e48c3fbc6a513fdc2b48 --- src/libdraw/x11-mouse.c +++ src/libdraw/x11-mouse.c @@ -48,6 +48,7 @@ void _ioproc(void *arg) { int one; + ulong mask; Mouse m; Mousectl *mc; XEvent xevent; @@ -57,9 +58,10 @@ _ioproc(void *arg) threadsetname("mouseproc"); memset(&m, 0, sizeof m); mc->pid = getpid(); + mask = MouseMask|ExposureMask|StructureNotifyMask; + XSelectInput(_x.mousecon, _x.drawable, mask); for(;;){ - XSelectInput(_x.mousecon, _x.drawable, MouseMask|ExposureMask|StructureNotifyMask); - XWindowEvent(_x.mousecon, _x.drawable, MouseMask|ExposureMask|StructureNotifyMask, &xevent); + XNextEvent(_x.mousecon, &xevent); switch(xevent.type){ case Expose: xexpose(&xevent, _x.mousecon); @@ -68,6 +70,9 @@ _ioproc(void *arg) if(xconfigure(&xevent, _x.mousecon)) nbsend(mc->resizec, &one); continue; + case SelectionRequest: + xselect(&xevent, _x.mousecon); + continue; case ButtonPress: case ButtonRelease: case MotionNotify: